diff options
author | David Howells <dhowells@redhat.com> | 2018-04-06 09:17:23 -0400 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2018-04-09 16:18:58 -0400 |
commit | 37ab636880cbc95ba87a5790bee23a1c813089c6 (patch) | |
tree | 931c5387eeefbab0b326b62532644dd6a32c78f0 /fs | |
parent | 6f8880d8e68155726a2a22e8787cfebf1ffcab08 (diff) |
afs: Implement @cell substitution handling
Implement @cell substitution handling such that if @cell is seen as a name
in a dynamic root mount, then the name of the root cell for that network
namespace will be substituted for @cell during lookup.
The substitution of @cell for the current net namespace is set by writing
the cell name to /proc/fs/afs/rootcell. The value can be obtained by
reading the file.
For example:
# mount -t afs none /kafs -o dyn
# echo grand.central.org >/proc/fs/afs/rootcell
# ls /kafs/@cell
archive/ cvs/ doc/ local/ project/ service/ software/ user/ www/
# cat /proc/fs/afs/rootcell
grand.central.org
Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/afs/cell.c | 2 | ||||
-rw-r--r-- | fs/afs/dir.c | 53 | ||||
-rw-r--r-- | fs/afs/proc.c | 35 |
3 files changed, 89 insertions, 1 deletions
diff --git a/fs/afs/cell.c b/fs/afs/cell.c index 721425b98b31..fdf4c36cff79 100644 --- a/fs/afs/cell.c +++ b/fs/afs/cell.c | |||
@@ -130,6 +130,8 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net, | |||
130 | _leave(" = -ENAMETOOLONG"); | 130 | _leave(" = -ENAMETOOLONG"); |
131 | return ERR_PTR(-ENAMETOOLONG); | 131 | return ERR_PTR(-ENAMETOOLONG); |
132 | } | 132 | } |
133 | if (namelen == 5 && memcmp(name, "@cell", 5) == 0) | ||
134 | return ERR_PTR(-EINVAL); | ||
133 | 135 | ||
134 | _enter("%*.*s,%s", namelen, namelen, name, vllist); | 136 | _enter("%*.*s,%s", namelen, namelen, name, vllist); |
135 | 137 | ||
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 3ebd741b74d0..b073976db8d2 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
@@ -909,6 +909,55 @@ success: | |||
909 | } | 909 | } |
910 | 910 | ||
911 | /* | 911 | /* |
912 | * Look up @cell in a dynroot directory. This is a substitution for the | ||
913 | * local cell name for the net namespace. | ||
914 | */ | ||
915 | static struct dentry *afs_lookup_atcell(struct dentry *dentry) | ||
916 | { | ||
917 | struct afs_cell *cell; | ||
918 | struct afs_net *net = afs_d2net(dentry); | ||
919 | struct dentry *ret; | ||
920 | unsigned int seq = 0; | ||
921 | char *name; | ||
922 | int len; | ||
923 | |||
924 | if (!net->ws_cell) | ||
925 | return ERR_PTR(-ENOENT); | ||
926 | |||
927 | ret = ERR_PTR(-ENOMEM); | ||
928 | name = kmalloc(AFS_MAXCELLNAME + 1, GFP_KERNEL); | ||
929 | if (!name) | ||
930 | goto out_p; | ||
931 | |||
932 | rcu_read_lock(); | ||
933 | do { | ||
934 | read_seqbegin_or_lock(&net->cells_lock, &seq); | ||
935 | cell = rcu_dereference_raw(net->ws_cell); | ||
936 | if (cell) { | ||
937 | len = cell->name_len; | ||
938 | memcpy(name, cell->name, len + 1); | ||
939 | } | ||
940 | } while (need_seqretry(&net->cells_lock, seq)); | ||
941 | done_seqretry(&net->cells_lock, seq); | ||
942 | rcu_read_unlock(); | ||
943 | |||
944 | ret = ERR_PTR(-ENOENT); | ||
945 | if (!cell) | ||
946 | goto out_n; | ||
947 | |||
948 | ret = lookup_one_len(name, dentry->d_parent, len); | ||
949 | |||
950 | /* We don't want to d_add() the @cell dentry here as we don't want to | ||
951 | * the cached dentry to hide changes to the local cell name. | ||
952 | */ | ||
953 | |||
954 | out_n: | ||
955 | kfree(name); | ||
956 | out_p: | ||
957 | return ret; | ||
958 | } | ||
959 | |||
960 | /* | ||
912 | * Look up an entry in a dynroot directory. | 961 | * Look up an entry in a dynroot directory. |
913 | */ | 962 | */ |
914 | static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry, | 963 | static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry, |
@@ -929,6 +978,10 @@ static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentr | |||
929 | return ERR_PTR(-ENAMETOOLONG); | 978 | return ERR_PTR(-ENAMETOOLONG); |
930 | } | 979 | } |
931 | 980 | ||
981 | if (dentry->d_name.len == 5 && | ||
982 | memcmp(dentry->d_name.name, "@cell", 5) == 0) | ||
983 | return afs_lookup_atcell(dentry); | ||
984 | |||
932 | inode = afs_try_auto_mntpt(dentry, dir); | 985 | inode = afs_try_auto_mntpt(dentry, dir); |
933 | if (IS_ERR(inode)) { | 986 | if (IS_ERR(inode)) { |
934 | ret = PTR_ERR(inode); | 987 | ret = PTR_ERR(inode); |
diff --git a/fs/afs/proc.c b/fs/afs/proc.c index 15650cd59404..76f6df32cde0 100644 --- a/fs/afs/proc.c +++ b/fs/afs/proc.c | |||
@@ -334,7 +334,40 @@ inval: | |||
334 | static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf, | 334 | static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf, |
335 | size_t size, loff_t *_pos) | 335 | size_t size, loff_t *_pos) |
336 | { | 336 | { |
337 | return 0; | 337 | struct afs_cell *cell; |
338 | struct afs_net *net = afs_proc2net(file); | ||
339 | unsigned int seq = 0; | ||
340 | char name[AFS_MAXCELLNAME + 1]; | ||
341 | int len; | ||
342 | |||
343 | if (*_pos > 0) | ||
344 | return 0; | ||
345 | if (!net->ws_cell) | ||
346 | return 0; | ||
347 | |||
348 | rcu_read_lock(); | ||
349 | do { | ||
350 | read_seqbegin_or_lock(&net->cells_lock, &seq); | ||
351 | len = 0; | ||
352 | cell = rcu_dereference_raw(net->ws_cell); | ||
353 | if (cell) { | ||
354 | len = cell->name_len; | ||
355 | memcpy(name, cell->name, len); | ||
356 | } | ||
357 | } while (need_seqretry(&net->cells_lock, seq)); | ||
358 | done_seqretry(&net->cells_lock, seq); | ||
359 | rcu_read_unlock(); | ||
360 | |||
361 | if (!len) | ||
362 | return 0; | ||
363 | |||
364 | name[len++] = '\n'; | ||
365 | if (len > size) | ||
366 | len = size; | ||
367 | if (copy_to_user(buf, name, len) != 0) | ||
368 | return -EFAULT; | ||
369 | *_pos = 1; | ||
370 | return len; | ||
338 | } | 371 | } |
339 | 372 | ||
340 | /* | 373 | /* |