]> asedeno.scripts.mit.edu Git - linux.git/blob - fs/afs/dynroot.c
Merge branch 'for-5.3/uclogic' into for-linus
[linux.git] / fs / afs / dynroot.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* AFS dynamic root handling
3  *
4  * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
5  * Written by David Howells (dhowells@redhat.com)
6  */
7
8 #include <linux/fs.h>
9 #include <linux/namei.h>
10 #include <linux/dns_resolver.h>
11 #include "internal.h"
12
13 const struct file_operations afs_dynroot_file_operations = {
14         .open           = dcache_dir_open,
15         .release        = dcache_dir_close,
16         .iterate_shared = dcache_readdir,
17         .llseek         = dcache_dir_lseek,
18 };
19
20 /*
21  * Probe to see if a cell may exist.  This prevents positive dentries from
22  * being created unnecessarily.
23  */
24 static int afs_probe_cell_name(struct dentry *dentry)
25 {
26         struct afs_cell *cell;
27         const char *name = dentry->d_name.name;
28         size_t len = dentry->d_name.len;
29         int ret;
30
31         /* Names prefixed with a dot are R/W mounts. */
32         if (name[0] == '.') {
33                 if (len == 1)
34                         return -EINVAL;
35                 name++;
36                 len--;
37         }
38
39         cell = afs_lookup_cell_rcu(afs_d2net(dentry), name, len);
40         if (!IS_ERR(cell)) {
41                 afs_put_cell(afs_d2net(dentry), cell);
42                 return 0;
43         }
44
45         ret = dns_query("afsdb", name, len, "srv=1", NULL, NULL, false);
46         if (ret == -ENODATA)
47                 ret = -EDESTADDRREQ;
48         return ret;
49 }
50
51 /*
52  * Try to auto mount the mountpoint with pseudo directory, if the autocell
53  * operation is setted.
54  */
55 struct inode *afs_try_auto_mntpt(struct dentry *dentry, struct inode *dir)
56 {
57         struct afs_vnode *vnode = AFS_FS_I(dir);
58         struct inode *inode;
59         int ret = -ENOENT;
60
61         _enter("%p{%pd}, {%llx:%llu}",
62                dentry, dentry, vnode->fid.vid, vnode->fid.vnode);
63
64         if (!test_bit(AFS_VNODE_AUTOCELL, &vnode->flags))
65                 goto out;
66
67         ret = afs_probe_cell_name(dentry);
68         if (ret < 0)
69                 goto out;
70
71         inode = afs_iget_pseudo_dir(dir->i_sb, false);
72         if (IS_ERR(inode)) {
73                 ret = PTR_ERR(inode);
74                 goto out;
75         }
76
77         _leave("= %p", inode);
78         return inode;
79
80 out:
81         _leave("= %d", ret);
82         return ret == -ENOENT ? NULL : ERR_PTR(ret);
83 }
84
85 /*
86  * Look up @cell in a dynroot directory.  This is a substitution for the
87  * local cell name for the net namespace.
88  */
89 static struct dentry *afs_lookup_atcell(struct dentry *dentry)
90 {
91         struct afs_cell *cell;
92         struct afs_net *net = afs_d2net(dentry);
93         struct dentry *ret;
94         unsigned int seq = 0;
95         char *name;
96         int len;
97
98         if (!net->ws_cell)
99                 return ERR_PTR(-ENOENT);
100
101         ret = ERR_PTR(-ENOMEM);
102         name = kmalloc(AFS_MAXCELLNAME + 1, GFP_KERNEL);
103         if (!name)
104                 goto out_p;
105
106         rcu_read_lock();
107         do {
108                 read_seqbegin_or_lock(&net->cells_lock, &seq);
109                 cell = rcu_dereference_raw(net->ws_cell);
110                 if (cell) {
111                         len = cell->name_len;
112                         memcpy(name, cell->name, len + 1);
113                 }
114         } while (need_seqretry(&net->cells_lock, seq));
115         done_seqretry(&net->cells_lock, seq);
116         rcu_read_unlock();
117
118         ret = ERR_PTR(-ENOENT);
119         if (!cell)
120                 goto out_n;
121
122         ret = lookup_one_len(name, dentry->d_parent, len);
123
124         /* We don't want to d_add() the @cell dentry here as we don't want to
125          * the cached dentry to hide changes to the local cell name.
126          */
127
128 out_n:
129         kfree(name);
130 out_p:
131         return ret;
132 }
133
134 /*
135  * Look up an entry in a dynroot directory.
136  */
137 static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry,
138                                          unsigned int flags)
139 {
140         _enter("%pd", dentry);
141
142         ASSERTCMP(d_inode(dentry), ==, NULL);
143
144         if (dentry->d_name.len >= AFSNAMEMAX) {
145                 _leave(" = -ENAMETOOLONG");
146                 return ERR_PTR(-ENAMETOOLONG);
147         }
148
149         if (dentry->d_name.len == 5 &&
150             memcmp(dentry->d_name.name, "@cell", 5) == 0)
151                 return afs_lookup_atcell(dentry);
152
153         return d_splice_alias(afs_try_auto_mntpt(dentry, dir), dentry);
154 }
155
156 const struct inode_operations afs_dynroot_inode_operations = {
157         .lookup         = afs_dynroot_lookup,
158 };
159
160 /*
161  * Dirs in the dynamic root don't need revalidation.
162  */
163 static int afs_dynroot_d_revalidate(struct dentry *dentry, unsigned int flags)
164 {
165         return 1;
166 }
167
168 /*
169  * Allow the VFS to enquire as to whether a dentry should be unhashed (mustn't
170  * sleep)
171  * - called from dput() when d_count is going to 0.
172  * - return 1 to request dentry be unhashed, 0 otherwise
173  */
174 static int afs_dynroot_d_delete(const struct dentry *dentry)
175 {
176         return d_really_is_positive(dentry);
177 }
178
179 const struct dentry_operations afs_dynroot_dentry_operations = {
180         .d_revalidate   = afs_dynroot_d_revalidate,
181         .d_delete       = afs_dynroot_d_delete,
182         .d_release      = afs_d_release,
183         .d_automount    = afs_d_automount,
184 };
185
186 /*
187  * Create a manually added cell mount directory.
188  * - The caller must hold net->proc_cells_lock
189  */
190 int afs_dynroot_mkdir(struct afs_net *net, struct afs_cell *cell)
191 {
192         struct super_block *sb = net->dynroot_sb;
193         struct dentry *root, *subdir;
194         int ret;
195
196         if (!sb || atomic_read(&sb->s_active) == 0)
197                 return 0;
198
199         /* Let the ->lookup op do the creation */
200         root = sb->s_root;
201         inode_lock(root->d_inode);
202         subdir = lookup_one_len(cell->name, root, cell->name_len);
203         if (IS_ERR(subdir)) {
204                 ret = PTR_ERR(subdir);
205                 goto unlock;
206         }
207
208         /* Note that we're retaining an extra ref on the dentry */
209         subdir->d_fsdata = (void *)1UL;
210         ret = 0;
211 unlock:
212         inode_unlock(root->d_inode);
213         return ret;
214 }
215
216 /*
217  * Remove a manually added cell mount directory.
218  * - The caller must hold net->proc_cells_lock
219  */
220 void afs_dynroot_rmdir(struct afs_net *net, struct afs_cell *cell)
221 {
222         struct super_block *sb = net->dynroot_sb;
223         struct dentry *root, *subdir;
224
225         if (!sb || atomic_read(&sb->s_active) == 0)
226                 return;
227
228         root = sb->s_root;
229         inode_lock(root->d_inode);
230
231         /* Don't want to trigger a lookup call, which will re-add the cell */
232         subdir = try_lookup_one_len(cell->name, root, cell->name_len);
233         if (IS_ERR_OR_NULL(subdir)) {
234                 _debug("lookup %ld", PTR_ERR(subdir));
235                 goto no_dentry;
236         }
237
238         _debug("rmdir %pd %u", subdir, d_count(subdir));
239
240         if (subdir->d_fsdata) {
241                 _debug("unpin %u", d_count(subdir));
242                 subdir->d_fsdata = NULL;
243                 dput(subdir);
244         }
245         dput(subdir);
246 no_dentry:
247         inode_unlock(root->d_inode);
248         _leave("");
249 }
250
251 /*
252  * Populate a newly created dynamic root with cell names.
253  */
254 int afs_dynroot_populate(struct super_block *sb)
255 {
256         struct afs_cell *cell;
257         struct afs_net *net = afs_sb2net(sb);
258         int ret;
259
260         mutex_lock(&net->proc_cells_lock);
261
262         net->dynroot_sb = sb;
263         hlist_for_each_entry(cell, &net->proc_cells, proc_link) {
264                 ret = afs_dynroot_mkdir(net, cell);
265                 if (ret < 0)
266                         goto error;
267         }
268
269         ret = 0;
270 out:
271         mutex_unlock(&net->proc_cells_lock);
272         return ret;
273
274 error:
275         net->dynroot_sb = NULL;
276         goto out;
277 }
278
279 /*
280  * When a dynamic root that's in the process of being destroyed, depopulate it
281  * of pinned directories.
282  */
283 void afs_dynroot_depopulate(struct super_block *sb)
284 {
285         struct afs_net *net = afs_sb2net(sb);
286         struct dentry *root = sb->s_root, *subdir, *tmp;
287
288         /* Prevent more subdirs from being created */
289         mutex_lock(&net->proc_cells_lock);
290         if (net->dynroot_sb == sb)
291                 net->dynroot_sb = NULL;
292         mutex_unlock(&net->proc_cells_lock);
293
294         inode_lock(root->d_inode);
295
296         /* Remove all the pins for dirs created for manually added cells */
297         list_for_each_entry_safe(subdir, tmp, &root->d_subdirs, d_child) {
298                 if (subdir->d_fsdata) {
299                         subdir->d_fsdata = NULL;
300                         dput(subdir);
301                 }
302         }
303
304         inode_unlock(root->d_inode);
305 }