~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/afs/dynroot.c

Version: ~ [ linux-5.9-rc6 ] ~ [ linux-5.8.10 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.66 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.146 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.198 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.236 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.236 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp