summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2018-04-06 09:17:25 -0400
committerDavid Howells <dhowells@redhat.com>2018-04-09 16:54:00 -0400
commit66c7e1d319a5b3a57de688a36200e463ec87e88e (patch)
treef38f631e9fe71179b007e53bcebe712c3ed23fc3
parenta4ff7401fbfa06fba3aac14db5b33c5b76298f2c (diff)
afs: Split the dynroot stuff out and give it its own ops tables
Split the AFS dynamic root stuff out of the main directory handling file and into its own file as they share little in common. The dynamic root code also gets its own dentry and inode ops tables. Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--fs/afs/Makefile1
-rw-r--r--fs/afs/dir.c180
-rw-r--r--fs/afs/dynroot.c209
-rw-r--r--fs/afs/internal.h12
-rw-r--r--fs/afs/super.c11
5 files changed, 228 insertions, 185 deletions
diff --git a/fs/afs/Makefile b/fs/afs/Makefile
index 45b7fc405fa6..6a055423c192 100644
--- a/fs/afs/Makefile
+++ b/fs/afs/Makefile
@@ -12,6 +12,7 @@ kafs-objs := \
12 cell.o \ 12 cell.o \
13 cmservice.o \ 13 cmservice.o \
14 dir.o \ 14 dir.o \
15 dynroot.o \
15 file.o \ 16 file.o \
16 flock.o \ 17 flock.o \
17 fsclient.o \ 18 fsclient.o \
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 08b499504f63..405ebd609b87 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -10,25 +10,19 @@
10 */ 10 */
11 11
12#include <linux/kernel.h> 12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/fs.h> 13#include <linux/fs.h>
16#include <linux/namei.h> 14#include <linux/namei.h>
17#include <linux/pagemap.h> 15#include <linux/pagemap.h>
18#include <linux/ctype.h> 16#include <linux/ctype.h>
19#include <linux/sched.h> 17#include <linux/sched.h>
20#include <linux/dns_resolver.h>
21#include "internal.h" 18#include "internal.h"
22 19
23static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, 20static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
24 unsigned int flags); 21 unsigned int flags);
25static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry,
26 unsigned int flags);
27static int afs_dir_open(struct inode *inode, struct file *file); 22static int afs_dir_open(struct inode *inode, struct file *file);
28static int afs_readdir(struct file *file, struct dir_context *ctx); 23static int afs_readdir(struct file *file, struct dir_context *ctx);
29static int afs_d_revalidate(struct dentry *dentry, unsigned int flags); 24static int afs_d_revalidate(struct dentry *dentry, unsigned int flags);
30static int afs_d_delete(const struct dentry *dentry); 25static int afs_d_delete(const struct dentry *dentry);
31static void afs_d_release(struct dentry *dentry);
32static int afs_lookup_one_filldir(struct dir_context *ctx, const char *name, int nlen, 26static int afs_lookup_one_filldir(struct dir_context *ctx, const char *name, int nlen,
33 loff_t fpos, u64 ino, unsigned dtype); 27 loff_t fpos, u64 ino, unsigned dtype);
34static int afs_lookup_filldir(struct dir_context *ctx, const char *name, int nlen, 28static int afs_lookup_filldir(struct dir_context *ctx, const char *name, int nlen,
@@ -69,17 +63,6 @@ const struct inode_operations afs_dir_inode_operations = {
69 .listxattr = afs_listxattr, 63 .listxattr = afs_listxattr,
70}; 64};
71 65
72const struct file_operations afs_dynroot_file_operations = {
73 .open = dcache_dir_open,
74 .release = dcache_dir_close,
75 .iterate_shared = dcache_readdir,
76 .llseek = dcache_dir_lseek,
77};
78
79const struct inode_operations afs_dynroot_inode_operations = {
80 .lookup = afs_dynroot_lookup,
81};
82
83const struct dentry_operations afs_fs_dentry_operations = { 66const struct dentry_operations afs_fs_dentry_operations = {
84 .d_revalidate = afs_d_revalidate, 67 .d_revalidate = afs_d_revalidate,
85 .d_delete = afs_d_delete, 68 .d_delete = afs_d_delete,
@@ -703,71 +686,6 @@ out:
703} 686}
704 687
705/* 688/*
706 * Probe to see if a cell may exist. This prevents positive dentries from
707 * being created unnecessarily.
708 */
709static int afs_probe_cell_name(struct dentry *dentry)
710{
711 struct afs_cell *cell;
712 const char *name = dentry->d_name.name;
713 size_t len = dentry->d_name.len;
714 int ret;
715
716 /* Names prefixed with a dot are R/W mounts. */
717 if (name[0] == '.') {
718 if (len == 1)
719 return -EINVAL;
720 name++;
721 len--;
722 }
723
724 cell = afs_lookup_cell_rcu(afs_d2net(dentry), name, len);
725 if (!IS_ERR(cell)) {
726 afs_put_cell(afs_d2net(dentry), cell);
727 return 0;
728 }
729
730 ret = dns_query("afsdb", name, len, "ipv4", NULL, NULL);
731 if (ret == -ENODATA)
732 ret = -EDESTADDRREQ;
733 return ret;
734}
735
736/*
737 * Try to auto mount the mountpoint with pseudo directory, if the autocell
738 * operation is setted.
739 */
740static struct inode *afs_try_auto_mntpt(struct dentry *dentry, struct inode *dir)
741{
742 struct afs_vnode *vnode = AFS_FS_I(dir);
743 struct inode *inode;
744 int ret = -ENOENT;
745
746 _enter("%p{%pd}, {%x:%u}",
747 dentry, dentry, vnode->fid.vid, vnode->fid.vnode);
748
749 if (!test_bit(AFS_VNODE_AUTOCELL, &vnode->flags))
750 goto out;
751
752 ret = afs_probe_cell_name(dentry);
753 if (ret < 0)
754 goto out;
755
756 inode = afs_iget_pseudo_dir(dir->i_sb, false);
757 if (IS_ERR(inode)) {
758 ret = PTR_ERR(inode);
759 goto out;
760 }
761
762 _leave("= %p", inode);
763 return inode;
764
765out:
766 _leave("= %d", ret);
767 return ERR_PTR(ret);
768}
769
770/*
771 * Look up an entry in a directory with @sys substitution. 689 * Look up an entry in a directory with @sys substitution.
772 */ 690 */
773static struct dentry *afs_lookup_atsys(struct inode *dir, struct dentry *dentry, 691static struct dentry *afs_lookup_atsys(struct inode *dir, struct dentry *dentry,
@@ -911,105 +829,12 @@ success:
911} 829}
912 830
913/* 831/*
914 * Look up @cell in a dynroot directory. This is a substitution for the
915 * local cell name for the net namespace.
916 */
917static struct dentry *afs_lookup_atcell(struct dentry *dentry)
918{
919 struct afs_cell *cell;
920 struct afs_net *net = afs_d2net(dentry);
921 struct dentry *ret;
922 unsigned int seq = 0;
923 char *name;
924 int len;
925
926 if (!net->ws_cell)
927 return ERR_PTR(-ENOENT);
928
929 ret = ERR_PTR(-ENOMEM);
930 name = kmalloc(AFS_MAXCELLNAME + 1, GFP_KERNEL);
931 if (!name)
932 goto out_p;
933
934 rcu_read_lock();
935 do {
936 read_seqbegin_or_lock(&net->cells_lock, &seq);
937 cell = rcu_dereference_raw(net->ws_cell);
938 if (cell) {
939 len = cell->name_len;
940 memcpy(name, cell->name, len + 1);
941 }
942 } while (need_seqretry(&net->cells_lock, seq));
943 done_seqretry(&net->cells_lock, seq);
944 rcu_read_unlock();
945
946 ret = ERR_PTR(-ENOENT);
947 if (!cell)
948 goto out_n;
949
950 ret = lookup_one_len(name, dentry->d_parent, len);
951
952 /* We don't want to d_add() the @cell dentry here as we don't want to
953 * the cached dentry to hide changes to the local cell name.
954 */
955
956out_n:
957 kfree(name);
958out_p:
959 return ret;
960}
961
962/*
963 * Look up an entry in a dynroot directory.
964 */
965static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry,
966 unsigned int flags)
967{
968 struct afs_vnode *vnode;
969 struct inode *inode;
970 int ret;
971
972 vnode = AFS_FS_I(dir);
973
974 _enter("%pd", dentry);
975
976 ASSERTCMP(d_inode(dentry), ==, NULL);
977
978 if (dentry->d_name.len >= AFSNAMEMAX) {
979 _leave(" = -ENAMETOOLONG");
980 return ERR_PTR(-ENAMETOOLONG);
981 }
982
983 if (dentry->d_name.len == 5 &&
984 memcmp(dentry->d_name.name, "@cell", 5) == 0)
985 return afs_lookup_atcell(dentry);
986
987 inode = afs_try_auto_mntpt(dentry, dir);
988 if (IS_ERR(inode)) {
989 ret = PTR_ERR(inode);
990 if (ret == -ENOENT) {
991 d_add(dentry, NULL);
992 _leave(" = NULL [negative]");
993 return NULL;
994 }
995 _leave(" = %d [do]", ret);
996 return ERR_PTR(ret);
997 }
998
999 d_add(dentry, inode);
1000 _leave(" = 0 { ino=%lu v=%u }",
1001 d_inode(dentry)->i_ino, d_inode(dentry)->i_generation);
1002 return NULL;
1003}
1004
1005/*
1006 * check that a dentry lookup hit has found a valid entry 832 * check that a dentry lookup hit has found a valid entry
1007 * - NOTE! the hit can be a negative hit too, so we can't assume we have an 833 * - NOTE! the hit can be a negative hit too, so we can't assume we have an
1008 * inode 834 * inode
1009 */ 835 */
1010static int afs_d_revalidate(struct dentry *dentry, unsigned int flags) 836static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
1011{ 837{
1012 struct afs_super_info *as = dentry->d_sb->s_fs_info;
1013 struct afs_vnode *vnode, *dir; 838 struct afs_vnode *vnode, *dir;
1014 struct afs_fid uninitialized_var(fid); 839 struct afs_fid uninitialized_var(fid);
1015 struct dentry *parent; 840 struct dentry *parent;
@@ -1021,9 +846,6 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
1021 if (flags & LOOKUP_RCU) 846 if (flags & LOOKUP_RCU)
1022 return -ECHILD; 847 return -ECHILD;
1023 848
1024 if (as->dyn_root)
1025 return 1;
1026
1027 if (d_really_is_positive(dentry)) { 849 if (d_really_is_positive(dentry)) {
1028 vnode = AFS_FS_I(d_inode(dentry)); 850 vnode = AFS_FS_I(d_inode(dentry));
1029 _enter("{v={%x:%u} n=%pd fl=%lx},", 851 _enter("{v={%x:%u} n=%pd fl=%lx},",
@@ -1181,7 +1003,7 @@ zap:
1181/* 1003/*
1182 * handle dentry release 1004 * handle dentry release
1183 */ 1005 */
1184static void afs_d_release(struct dentry *dentry) 1006void afs_d_release(struct dentry *dentry)
1185{ 1007{
1186 _enter("%pd", dentry); 1008 _enter("%pd", dentry);
1187} 1009}
diff --git a/fs/afs/dynroot.c b/fs/afs/dynroot.c
new file mode 100644
index 000000000000..983f3946ab57
--- /dev/null
+++ b/fs/afs/dynroot.c
@@ -0,0 +1,209 @@
1/* dir.c: AFS dynamic root handling
2 *
3 * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11
12#include <linux/fs.h>
13#include <linux/namei.h>
14#include <linux/dns_resolver.h>
15#include "internal.h"
16
17const struct file_operations afs_dynroot_file_operations = {
18 .open = dcache_dir_open,
19 .release = dcache_dir_close,
20 .iterate_shared = dcache_readdir,
21 .llseek = dcache_dir_lseek,
22};
23
24/*
25 * Probe to see if a cell may exist. This prevents positive dentries from
26 * being created unnecessarily.
27 */
28static int afs_probe_cell_name(struct dentry *dentry)
29{
30 struct afs_cell *cell;
31 const char *name = dentry->d_name.name;
32 size_t len = dentry->d_name.len;
33 int ret;
34
35 /* Names prefixed with a dot are R/W mounts. */
36 if (name[0] == '.') {
37 if (len == 1)
38 return -EINVAL;
39 name++;
40 len--;
41 }
42
43 cell = afs_lookup_cell_rcu(afs_d2net(dentry), name, len);
44 if (!IS_ERR(cell)) {
45 afs_put_cell(afs_d2net(dentry), cell);
46 return 0;
47 }
48
49 ret = dns_query("afsdb", name, len, "ipv4", NULL, NULL);
50 if (ret == -ENODATA)
51 ret = -EDESTADDRREQ;
52 return ret;
53}
54
55/*
56 * Try to auto mount the mountpoint with pseudo directory, if the autocell
57 * operation is setted.
58 */
59struct inode *afs_try_auto_mntpt(struct dentry *dentry, struct inode *dir)
60{
61 struct afs_vnode *vnode = AFS_FS_I(dir);
62 struct inode *inode;
63 int ret = -ENOENT;
64
65 _enter("%p{%pd}, {%x:%u}",
66 dentry, dentry, vnode->fid.vid, vnode->fid.vnode);
67
68 if (!test_bit(AFS_VNODE_AUTOCELL, &vnode->flags))
69 goto out;
70
71 ret = afs_probe_cell_name(dentry);
72 if (ret < 0)
73 goto out;
74
75 inode = afs_iget_pseudo_dir(dir->i_sb, false);
76 if (IS_ERR(inode)) {
77 ret = PTR_ERR(inode);
78 goto out;
79 }
80
81 _leave("= %p", inode);
82 return inode;
83
84out:
85 _leave("= %d", ret);
86 return ERR_PTR(ret);
87}
88
89/*
90 * Look up @cell in a dynroot directory. This is a substitution for the
91 * local cell name for the net namespace.
92 */
93static struct dentry *afs_lookup_atcell(struct dentry *dentry)
94{
95 struct afs_cell *cell;
96 struct afs_net *net = afs_d2net(dentry);
97 struct dentry *ret;
98 unsigned int seq = 0;
99 char *name;
100 int len;
101
102 if (!net->ws_cell)
103 return ERR_PTR(-ENOENT);
104
105 ret = ERR_PTR(-ENOMEM);
106 name = kmalloc(AFS_MAXCELLNAME + 1, GFP_KERNEL);
107 if (!name)
108 goto out_p;
109
110 rcu_read_lock();
111 do {
112 read_seqbegin_or_lock(&net->cells_lock, &seq);
113 cell = rcu_dereference_raw(net->ws_cell);
114 if (cell) {
115 len = cell->name_len;
116 memcpy(name, cell->name, len + 1);
117 }
118 } while (need_seqretry(&net->cells_lock, seq));
119 done_seqretry(&net->cells_lock, seq);
120 rcu_read_unlock();
121
122 ret = ERR_PTR(-ENOENT);
123 if (!cell)
124 goto out_n;
125
126 ret = lookup_one_len(name, dentry->d_parent, len);
127
128 /* We don't want to d_add() the @cell dentry here as we don't want to
129 * the cached dentry to hide changes to the local cell name.
130 */
131
132out_n:
133 kfree(name);
134out_p:
135 return ret;
136}
137
138/*
139 * Look up an entry in a dynroot directory.
140 */
141static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry,
142 unsigned int flags)
143{
144 struct afs_vnode *vnode;
145 struct inode *inode;
146 int ret;
147
148 vnode = AFS_FS_I(dir);
149
150 _enter("%pd", dentry);
151
152 ASSERTCMP(d_inode(dentry), ==, NULL);
153
154 if (dentry->d_name.len >= AFSNAMEMAX) {
155 _leave(" = -ENAMETOOLONG");
156 return ERR_PTR(-ENAMETOOLONG);
157 }
158
159 if (dentry->d_name.len == 5 &&
160 memcmp(dentry->d_name.name, "@cell", 5) == 0)
161 return afs_lookup_atcell(dentry);
162
163 inode = afs_try_auto_mntpt(dentry, dir);
164 if (IS_ERR(inode)) {
165 ret = PTR_ERR(inode);
166 if (ret == -ENOENT) {
167 d_add(dentry, NULL);
168 _leave(" = NULL [negative]");
169 return NULL;
170 }
171 _leave(" = %d [do]", ret);
172 return ERR_PTR(ret);
173 }
174
175 d_add(dentry, inode);
176 _leave(" = 0 { ino=%lu v=%u }",
177 d_inode(dentry)->i_ino, d_inode(dentry)->i_generation);
178 return NULL;
179}
180
181const struct inode_operations afs_dynroot_inode_operations = {
182 .lookup = afs_dynroot_lookup,
183};
184
185/*
186 * Dirs in the dynamic root don't need revalidation.
187 */
188static int afs_dynroot_d_revalidate(struct dentry *dentry, unsigned int flags)
189{
190 return 1;
191}
192
193/*
194 * Allow the VFS to enquire as to whether a dentry should be unhashed (mustn't
195 * sleep)
196 * - called from dput() when d_count is going to 0.
197 * - return 1 to request dentry be unhashed, 0 otherwise
198 */
199static int afs_dynroot_d_delete(const struct dentry *dentry)
200{
201 return d_really_is_positive(dentry);
202}
203
204const struct dentry_operations afs_dynroot_dentry_operations = {
205 .d_revalidate = afs_dynroot_d_revalidate,
206 .d_delete = afs_dynroot_d_delete,
207 .d_release = afs_d_release,
208 .d_automount = afs_d_automount,
209};
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index adf9b17d328c..b6ec46ae03c3 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -671,11 +671,19 @@ extern bool afs_cm_incoming_call(struct afs_call *);
671 */ 671 */
672extern const struct file_operations afs_dir_file_operations; 672extern const struct file_operations afs_dir_file_operations;
673extern const struct inode_operations afs_dir_inode_operations; 673extern const struct inode_operations afs_dir_inode_operations;
674extern const struct file_operations afs_dynroot_file_operations;
675extern const struct inode_operations afs_dynroot_inode_operations;
676extern const struct dentry_operations afs_fs_dentry_operations; 674extern const struct dentry_operations afs_fs_dentry_operations;
677 675
678extern bool afs_dir_check_page(struct inode *, struct page *); 676extern bool afs_dir_check_page(struct inode *, struct page *);
677extern void afs_d_release(struct dentry *);
678
679/*
680 * dynroot.c
681 */
682extern const struct file_operations afs_dynroot_file_operations;
683extern const struct inode_operations afs_dynroot_inode_operations;
684extern const struct dentry_operations afs_dynroot_dentry_operations;
685
686extern struct inode *afs_try_auto_mntpt(struct dentry *, struct inode *);
679 687
680/* 688/*
681 * file.c 689 * file.c
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 3623c952b6ff..65081ec3c36e 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -154,7 +154,7 @@ static int afs_show_devname(struct seq_file *m, struct dentry *root)
154 seq_puts(m, "none"); 154 seq_puts(m, "none");
155 return 0; 155 return 0;
156 } 156 }
157 157
158 switch (volume->type) { 158 switch (volume->type) {
159 case AFSVL_RWVOL: 159 case AFSVL_RWVOL:
160 break; 160 break;
@@ -269,7 +269,7 @@ static int afs_parse_device_name(struct afs_mount_params *params,
269 int cellnamesz; 269 int cellnamesz;
270 270
271 _enter(",%s", name); 271 _enter(",%s", name);
272 272
273 if (!name) { 273 if (!name) {
274 printk(KERN_ERR "kAFS: no volume name specified\n"); 274 printk(KERN_ERR "kAFS: no volume name specified\n");
275 return -EINVAL; 275 return -EINVAL;
@@ -418,7 +418,10 @@ static int afs_fill_super(struct super_block *sb,
418 if (!sb->s_root) 418 if (!sb->s_root)
419 goto error; 419 goto error;
420 420
421 sb->s_d_op = &afs_fs_dentry_operations; 421 if (params->dyn_root)
422 sb->s_d_op = &afs_dynroot_dentry_operations;
423 else
424 sb->s_d_op = &afs_fs_dentry_operations;
422 425
423 _leave(" = 0"); 426 _leave(" = 0");
424 return 0; 427 return 0;
@@ -676,7 +679,7 @@ static int afs_statfs(struct dentry *dentry, struct kstatfs *buf)
676 buf->f_bfree = 0; 679 buf->f_bfree = 0;
677 return 0; 680 return 0;
678 } 681 }
679 682
680 key = afs_request_key(vnode->volume->cell); 683 key = afs_request_key(vnode->volume->cell);
681 if (IS_ERR(key)) 684 if (IS_ERR(key))
682 return PTR_ERR(key); 685 return PTR_ERR(key);