diff options
-rw-r--r-- | fs/afs/Makefile | 1 | ||||
-rw-r--r-- | fs/afs/afs.h | 27 | ||||
-rw-r--r-- | fs/afs/callback.c | 5 | ||||
-rw-r--r-- | fs/afs/cell.c | 98 | ||||
-rw-r--r-- | fs/afs/cmservice.c | 3 | ||||
-rw-r--r-- | fs/afs/dir.c | 51 | ||||
-rw-r--r-- | fs/afs/file.c | 60 | ||||
-rw-r--r-- | fs/afs/fsclient.c | 9 | ||||
-rw-r--r-- | fs/afs/inode.c | 21 | ||||
-rw-r--r-- | fs/afs/internal.h | 106 | ||||
-rw-r--r-- | fs/afs/mntpt.c | 12 | ||||
-rw-r--r-- | fs/afs/rxrpc.c | 137 | ||||
-rw-r--r-- | fs/afs/security.c | 345 | ||||
-rw-r--r-- | fs/afs/super.c | 142 | ||||
-rw-r--r-- | fs/afs/vlclient.c | 6 | ||||
-rw-r--r-- | fs/afs/vlocation.c | 26 | ||||
-rw-r--r-- | fs/afs/vnode.c | 25 | ||||
-rw-r--r-- | fs/afs/volume.c | 109 |
18 files changed, 945 insertions, 238 deletions
diff --git a/fs/afs/Makefile b/fs/afs/Makefile index 66bdc219ccde..cca198b2caed 100644 --- a/fs/afs/Makefile +++ b/fs/afs/Makefile | |||
@@ -15,6 +15,7 @@ kafs-objs := \ | |||
15 | mntpt.o \ | 15 | mntpt.o \ |
16 | proc.o \ | 16 | proc.o \ |
17 | rxrpc.o \ | 17 | rxrpc.o \ |
18 | security.o \ | ||
18 | server.o \ | 19 | server.o \ |
19 | super.o \ | 20 | super.o \ |
20 | vlclient.o \ | 21 | vlclient.o \ |
diff --git a/fs/afs/afs.h b/fs/afs/afs.h index b9d2d2ceaf43..d959092aaf4b 100644 --- a/fs/afs/afs.h +++ b/fs/afs/afs.h | |||
@@ -14,6 +14,9 @@ | |||
14 | 14 | ||
15 | #include <linux/in.h> | 15 | #include <linux/in.h> |
16 | 16 | ||
17 | #define AFS_MAXCELLNAME 64 /* maximum length of a cell name */ | ||
18 | #define AFS_MAXVOLNAME 64 /* maximum length of a volume name */ | ||
19 | |||
17 | typedef unsigned afs_volid_t; | 20 | typedef unsigned afs_volid_t; |
18 | typedef unsigned afs_vnodeid_t; | 21 | typedef unsigned afs_vnodeid_t; |
19 | typedef unsigned long long afs_dataversion_t; | 22 | typedef unsigned long long afs_dataversion_t; |
@@ -75,6 +78,26 @@ struct afs_volume_info { | |||
75 | }; | 78 | }; |
76 | 79 | ||
77 | /* | 80 | /* |
81 | * AFS security ACE access mask | ||
82 | */ | ||
83 | typedef u32 afs_access_t; | ||
84 | #define AFS_ACE_READ 0x00000001U /* - permission to read a file/dir */ | ||
85 | #define AFS_ACE_WRITE 0x00000002U /* - permission to write/chmod a file */ | ||
86 | #define AFS_ACE_INSERT 0x00000004U /* - permission to create dirent in a dir */ | ||
87 | #define AFS_ACE_LOOKUP 0x00000008U /* - permission to lookup a file/dir in a dir */ | ||
88 | #define AFS_ACE_DELETE 0x00000010U /* - permission to delete a dirent from a dir */ | ||
89 | #define AFS_ACE_LOCK 0x00000020U /* - permission to lock a file */ | ||
90 | #define AFS_ACE_ADMINISTER 0x00000040U /* - permission to change ACL */ | ||
91 | #define AFS_ACE_USER_A 0x01000000U /* - 'A' user-defined permission */ | ||
92 | #define AFS_ACE_USER_B 0x02000000U /* - 'B' user-defined permission */ | ||
93 | #define AFS_ACE_USER_C 0x04000000U /* - 'C' user-defined permission */ | ||
94 | #define AFS_ACE_USER_D 0x08000000U /* - 'D' user-defined permission */ | ||
95 | #define AFS_ACE_USER_E 0x10000000U /* - 'E' user-defined permission */ | ||
96 | #define AFS_ACE_USER_F 0x20000000U /* - 'F' user-defined permission */ | ||
97 | #define AFS_ACE_USER_G 0x40000000U /* - 'G' user-defined permission */ | ||
98 | #define AFS_ACE_USER_H 0x80000000U /* - 'H' user-defined permission */ | ||
99 | |||
100 | /* | ||
78 | * AFS file status information | 101 | * AFS file status information |
79 | */ | 102 | */ |
80 | struct afs_file_status { | 103 | struct afs_file_status { |
@@ -87,8 +110,8 @@ struct afs_file_status { | |||
87 | afs_dataversion_t data_version; /* current data version */ | 110 | afs_dataversion_t data_version; /* current data version */ |
88 | unsigned author; /* author ID */ | 111 | unsigned author; /* author ID */ |
89 | unsigned owner; /* owner ID */ | 112 | unsigned owner; /* owner ID */ |
90 | unsigned caller_access; /* access rights for authenticated caller */ | 113 | afs_access_t caller_access; /* access rights for authenticated caller */ |
91 | unsigned anon_access; /* access rights for unauthenticated caller */ | 114 | afs_access_t anon_access; /* access rights for unauthenticated caller */ |
92 | umode_t mode; /* UNIX mode */ | 115 | umode_t mode; /* UNIX mode */ |
93 | struct afs_fid parent; /* parent file ID */ | 116 | struct afs_fid parent; /* parent file ID */ |
94 | time_t mtime_client; /* last time client changed data */ | 117 | time_t mtime_client; /* last time client changed data */ |
diff --git a/fs/afs/callback.c b/fs/afs/callback.c index 611215547142..e674bebbb8b1 100644 --- a/fs/afs/callback.c +++ b/fs/afs/callback.c | |||
@@ -72,7 +72,10 @@ void afs_broken_callback_work(struct work_struct *work) | |||
72 | return; /* someone else is dealing with it */ | 72 | return; /* someone else is dealing with it */ |
73 | 73 | ||
74 | if (test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) { | 74 | if (test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) { |
75 | if (afs_vnode_fetch_status(vnode) < 0) | 75 | if (S_ISDIR(vnode->vfs_inode.i_mode)) |
76 | afs_clear_permits(vnode); | ||
77 | |||
78 | if (afs_vnode_fetch_status(vnode, NULL, NULL) < 0) | ||
76 | goto out; | 79 | goto out; |
77 | 80 | ||
78 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) | 81 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) |
diff --git a/fs/afs/cell.c b/fs/afs/cell.c index 733c60246ab0..9b1311a1df51 100644 --- a/fs/afs/cell.c +++ b/fs/afs/cell.c | |||
@@ -11,6 +11,9 @@ | |||
11 | 11 | ||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | #include <linux/key.h> | ||
15 | #include <linux/ctype.h> | ||
16 | #include <keys/rxrpc-type.h> | ||
14 | #include "internal.h" | 17 | #include "internal.h" |
15 | 18 | ||
16 | DECLARE_RWSEM(afs_proc_cells_sem); | 19 | DECLARE_RWSEM(afs_proc_cells_sem); |
@@ -23,45 +26,43 @@ static DECLARE_WAIT_QUEUE_HEAD(afs_cells_freeable_wq); | |||
23 | static struct afs_cell *afs_cell_root; | 26 | static struct afs_cell *afs_cell_root; |
24 | 27 | ||
25 | /* | 28 | /* |
26 | * create a cell record | 29 | * allocate a cell record and fill in its name, VL server address list and |
27 | * - "name" is the name of the cell | 30 | * allocate an anonymous key |
28 | * - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format | ||
29 | */ | 31 | */ |
30 | struct afs_cell *afs_cell_create(const char *name, char *vllist) | 32 | static struct afs_cell *afs_cell_alloc(const char *name, char *vllist) |
31 | { | 33 | { |
32 | struct afs_cell *cell; | 34 | struct afs_cell *cell; |
33 | char *next; | 35 | size_t namelen; |
36 | char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next; | ||
34 | int ret; | 37 | int ret; |
35 | 38 | ||
36 | _enter("%s,%s", name, vllist); | 39 | _enter("%s,%s", name, vllist); |
37 | 40 | ||
38 | BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */ | 41 | BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */ |
39 | 42 | ||
43 | namelen = strlen(name); | ||
44 | if (namelen > AFS_MAXCELLNAME) | ||
45 | return ERR_PTR(-ENAMETOOLONG); | ||
46 | |||
40 | /* allocate and initialise a cell record */ | 47 | /* allocate and initialise a cell record */ |
41 | cell = kmalloc(sizeof(struct afs_cell) + strlen(name) + 1, GFP_KERNEL); | 48 | cell = kzalloc(sizeof(struct afs_cell) + namelen + 1, GFP_KERNEL); |
42 | if (!cell) { | 49 | if (!cell) { |
43 | _leave(" = -ENOMEM"); | 50 | _leave(" = -ENOMEM"); |
44 | return ERR_PTR(-ENOMEM); | 51 | return ERR_PTR(-ENOMEM); |
45 | } | 52 | } |
46 | 53 | ||
47 | down_write(&afs_cells_sem); | 54 | memcpy(cell->name, name, namelen); |
55 | cell->name[namelen] = 0; | ||
48 | 56 | ||
49 | memset(cell, 0, sizeof(struct afs_cell)); | ||
50 | atomic_set(&cell->usage, 1); | 57 | atomic_set(&cell->usage, 1); |
51 | |||
52 | INIT_LIST_HEAD(&cell->link); | 58 | INIT_LIST_HEAD(&cell->link); |
53 | |||
54 | rwlock_init(&cell->servers_lock); | 59 | rwlock_init(&cell->servers_lock); |
55 | INIT_LIST_HEAD(&cell->servers); | 60 | INIT_LIST_HEAD(&cell->servers); |
56 | |||
57 | init_rwsem(&cell->vl_sem); | 61 | init_rwsem(&cell->vl_sem); |
58 | INIT_LIST_HEAD(&cell->vl_list); | 62 | INIT_LIST_HEAD(&cell->vl_list); |
59 | spin_lock_init(&cell->vl_lock); | 63 | spin_lock_init(&cell->vl_lock); |
60 | 64 | ||
61 | strcpy(cell->name, name); | ||
62 | |||
63 | /* fill in the VL server list from the rest of the string */ | 65 | /* fill in the VL server list from the rest of the string */ |
64 | ret = -EINVAL; | ||
65 | do { | 66 | do { |
66 | unsigned a, b, c, d; | 67 | unsigned a, b, c, d; |
67 | 68 | ||
@@ -70,18 +71,73 @@ struct afs_cell *afs_cell_create(const char *name, char *vllist) | |||
70 | *next++ = 0; | 71 | *next++ = 0; |
71 | 72 | ||
72 | if (sscanf(vllist, "%u.%u.%u.%u", &a, &b, &c, &d) != 4) | 73 | if (sscanf(vllist, "%u.%u.%u.%u", &a, &b, &c, &d) != 4) |
73 | goto badaddr; | 74 | goto bad_address; |
74 | 75 | ||
75 | if (a > 255 || b > 255 || c > 255 || d > 255) | 76 | if (a > 255 || b > 255 || c > 255 || d > 255) |
76 | goto badaddr; | 77 | goto bad_address; |
77 | 78 | ||
78 | cell->vl_addrs[cell->vl_naddrs++].s_addr = | 79 | cell->vl_addrs[cell->vl_naddrs++].s_addr = |
79 | htonl((a << 24) | (b << 16) | (c << 8) | d); | 80 | htonl((a << 24) | (b << 16) | (c << 8) | d); |
80 | 81 | ||
81 | if (cell->vl_naddrs >= AFS_CELL_MAX_ADDRS) | 82 | } while (cell->vl_naddrs < AFS_CELL_MAX_ADDRS && (vllist = next)); |
82 | break; | 83 | |
84 | /* create a key to represent an anonymous user */ | ||
85 | memcpy(keyname, "afs@", 4); | ||
86 | dp = keyname + 4; | ||
87 | cp = cell->name; | ||
88 | do { | ||
89 | *dp++ = toupper(*cp); | ||
90 | } while (*cp++); | ||
91 | cell->anonymous_key = key_alloc(&key_type_rxrpc, keyname, 0, 0, current, | ||
92 | KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA); | ||
93 | if (IS_ERR(cell->anonymous_key)) { | ||
94 | _debug("no key"); | ||
95 | ret = PTR_ERR(cell->anonymous_key); | ||
96 | goto error; | ||
97 | } | ||
98 | |||
99 | ret = key_instantiate_and_link(cell->anonymous_key, NULL, 0, | ||
100 | NULL, NULL); | ||
101 | if (ret < 0) { | ||
102 | _debug("instantiate failed"); | ||
103 | goto error; | ||
104 | } | ||
105 | |||
106 | _debug("anon key %p{%x}", | ||
107 | cell->anonymous_key, key_serial(cell->anonymous_key)); | ||
108 | |||
109 | _leave(" = %p", cell); | ||
110 | return cell; | ||
111 | |||
112 | bad_address: | ||
113 | printk(KERN_ERR "kAFS: bad VL server IP address\n"); | ||
114 | ret = -EINVAL; | ||
115 | error: | ||
116 | key_put(cell->anonymous_key); | ||
117 | kfree(cell); | ||
118 | _leave(" = %d", ret); | ||
119 | return ERR_PTR(ret); | ||
120 | } | ||
83 | 121 | ||
84 | } while ((vllist = next)); | 122 | /* |
123 | * create a cell record | ||
124 | * - "name" is the name of the cell | ||
125 | * - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format | ||
126 | */ | ||
127 | struct afs_cell *afs_cell_create(const char *name, char *vllist) | ||
128 | { | ||
129 | struct afs_cell *cell; | ||
130 | int ret; | ||
131 | |||
132 | _enter("%s,%s", name, vllist); | ||
133 | |||
134 | cell = afs_cell_alloc(name, vllist); | ||
135 | if (IS_ERR(cell)) { | ||
136 | _leave(" = %ld", PTR_ERR(cell)); | ||
137 | return cell; | ||
138 | } | ||
139 | |||
140 | down_write(&afs_cells_sem); | ||
85 | 141 | ||
86 | /* add a proc directory for this cell */ | 142 | /* add a proc directory for this cell */ |
87 | ret = afs_proc_cell_setup(cell); | 143 | ret = afs_proc_cell_setup(cell); |
@@ -109,10 +165,9 @@ struct afs_cell *afs_cell_create(const char *name, char *vllist) | |||
109 | _leave(" = %p", cell); | 165 | _leave(" = %p", cell); |
110 | return cell; | 166 | return cell; |
111 | 167 | ||
112 | badaddr: | ||
113 | printk(KERN_ERR "kAFS: bad VL server IP address\n"); | ||
114 | error: | 168 | error: |
115 | up_write(&afs_cells_sem); | 169 | up_write(&afs_cells_sem); |
170 | key_put(cell->anonymous_key); | ||
116 | kfree(cell); | 171 | kfree(cell); |
117 | _leave(" = %d", ret); | 172 | _leave(" = %d", ret); |
118 | return ERR_PTR(ret); | 173 | return ERR_PTR(ret); |
@@ -301,6 +356,7 @@ static void afs_cell_destroy(struct afs_cell *cell) | |||
301 | cachefs_relinquish_cookie(cell->cache, 0); | 356 | cachefs_relinquish_cookie(cell->cache, 0); |
302 | #endif | 357 | #endif |
303 | 358 | ||
359 | key_put(cell->anonymous_key); | ||
304 | kfree(cell); | 360 | kfree(cell); |
305 | 361 | ||
306 | _leave(" [destroyed]"); | 362 | _leave(" [destroyed]"); |
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c index c7141175391b..c3ec57a237bf 100644 --- a/fs/afs/cmservice.c +++ b/fs/afs/cmservice.c | |||
@@ -28,6 +28,7 @@ static void afs_cm_destructor(struct afs_call *); | |||
28 | * CB.CallBack operation type | 28 | * CB.CallBack operation type |
29 | */ | 29 | */ |
30 | static const struct afs_call_type afs_SRXCBCallBack = { | 30 | static const struct afs_call_type afs_SRXCBCallBack = { |
31 | .name = "CB.CallBack", | ||
31 | .deliver = afs_deliver_cb_callback, | 32 | .deliver = afs_deliver_cb_callback, |
32 | .abort_to_error = afs_abort_to_error, | 33 | .abort_to_error = afs_abort_to_error, |
33 | .destructor = afs_cm_destructor, | 34 | .destructor = afs_cm_destructor, |
@@ -37,6 +38,7 @@ static const struct afs_call_type afs_SRXCBCallBack = { | |||
37 | * CB.InitCallBackState operation type | 38 | * CB.InitCallBackState operation type |
38 | */ | 39 | */ |
39 | static const struct afs_call_type afs_SRXCBInitCallBackState = { | 40 | static const struct afs_call_type afs_SRXCBInitCallBackState = { |
41 | .name = "CB.InitCallBackState", | ||
40 | .deliver = afs_deliver_cb_init_call_back_state, | 42 | .deliver = afs_deliver_cb_init_call_back_state, |
41 | .abort_to_error = afs_abort_to_error, | 43 | .abort_to_error = afs_abort_to_error, |
42 | .destructor = afs_cm_destructor, | 44 | .destructor = afs_cm_destructor, |
@@ -46,6 +48,7 @@ static const struct afs_call_type afs_SRXCBInitCallBackState = { | |||
46 | * CB.Probe operation type | 48 | * CB.Probe operation type |
47 | */ | 49 | */ |
48 | static const struct afs_call_type afs_SRXCBProbe = { | 50 | static const struct afs_call_type afs_SRXCBProbe = { |
51 | .name = "CB.Probe", | ||
49 | .deliver = afs_deliver_cb_probe, | 52 | .deliver = afs_deliver_cb_probe, |
50 | .abort_to_error = afs_abort_to_error, | 53 | .abort_to_error = afs_abort_to_error, |
51 | .destructor = afs_cm_destructor, | 54 | .destructor = afs_cm_destructor, |
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index d7697f6f3b7f..87368417e4d3 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/fs.h> | 16 | #include <linux/fs.h> |
17 | #include <linux/pagemap.h> | 17 | #include <linux/pagemap.h> |
18 | #include <linux/ctype.h> | ||
18 | #include "internal.h" | 19 | #include "internal.h" |
19 | 20 | ||
20 | static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, | 21 | static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, |
@@ -28,11 +29,13 @@ static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, | |||
28 | 29 | ||
29 | const struct file_operations afs_dir_file_operations = { | 30 | const struct file_operations afs_dir_file_operations = { |
30 | .open = afs_dir_open, | 31 | .open = afs_dir_open, |
32 | .release = afs_release, | ||
31 | .readdir = afs_dir_readdir, | 33 | .readdir = afs_dir_readdir, |
32 | }; | 34 | }; |
33 | 35 | ||
34 | const struct inode_operations afs_dir_inode_operations = { | 36 | const struct inode_operations afs_dir_inode_operations = { |
35 | .lookup = afs_dir_lookup, | 37 | .lookup = afs_dir_lookup, |
38 | .permission = afs_permission, | ||
36 | .getattr = afs_inode_getattr, | 39 | .getattr = afs_inode_getattr, |
37 | #if 0 /* TODO */ | 40 | #if 0 /* TODO */ |
38 | .create = afs_dir_create, | 41 | .create = afs_dir_create, |
@@ -169,13 +172,17 @@ static inline void afs_dir_put_page(struct page *page) | |||
169 | /* | 172 | /* |
170 | * get a page into the pagecache | 173 | * get a page into the pagecache |
171 | */ | 174 | */ |
172 | static struct page *afs_dir_get_page(struct inode *dir, unsigned long index) | 175 | static struct page *afs_dir_get_page(struct inode *dir, unsigned long index, |
176 | struct key *key) | ||
173 | { | 177 | { |
174 | struct page *page; | 178 | struct page *page; |
179 | struct file file = { | ||
180 | .private_data = key, | ||
181 | }; | ||
175 | 182 | ||
176 | _enter("{%lu},%lu", dir->i_ino, index); | 183 | _enter("{%lu},%lu", dir->i_ino, index); |
177 | 184 | ||
178 | page = read_mapping_page(dir->i_mapping, index, NULL); | 185 | page = read_mapping_page(dir->i_mapping, index, &file); |
179 | if (!IS_ERR(page)) { | 186 | if (!IS_ERR(page)) { |
180 | wait_on_page_locked(page); | 187 | wait_on_page_locked(page); |
181 | kmap(page); | 188 | kmap(page); |
@@ -207,8 +214,7 @@ static int afs_dir_open(struct inode *inode, struct file *file) | |||
207 | if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(inode)->flags)) | 214 | if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(inode)->flags)) |
208 | return -ENOENT; | 215 | return -ENOENT; |
209 | 216 | ||
210 | _leave(" = 0"); | 217 | return afs_open(inode, file); |
211 | return 0; | ||
212 | } | 218 | } |
213 | 219 | ||
214 | /* | 220 | /* |
@@ -311,7 +317,7 @@ static int afs_dir_iterate_block(unsigned *fpos, | |||
311 | * iterate through the data blob that lists the contents of an AFS directory | 317 | * iterate through the data blob that lists the contents of an AFS directory |
312 | */ | 318 | */ |
313 | static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie, | 319 | static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie, |
314 | filldir_t filldir) | 320 | filldir_t filldir, struct key *key) |
315 | { | 321 | { |
316 | union afs_dir_block *dblock; | 322 | union afs_dir_block *dblock; |
317 | struct afs_dir_page *dbuf; | 323 | struct afs_dir_page *dbuf; |
@@ -336,7 +342,7 @@ static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie, | |||
336 | blkoff = *fpos & ~(sizeof(union afs_dir_block) - 1); | 342 | blkoff = *fpos & ~(sizeof(union afs_dir_block) - 1); |
337 | 343 | ||
338 | /* fetch the appropriate page from the directory */ | 344 | /* fetch the appropriate page from the directory */ |
339 | page = afs_dir_get_page(dir, blkoff / PAGE_SIZE); | 345 | page = afs_dir_get_page(dir, blkoff / PAGE_SIZE, key); |
340 | if (IS_ERR(page)) { | 346 | if (IS_ERR(page)) { |
341 | ret = PTR_ERR(page); | 347 | ret = PTR_ERR(page); |
342 | break; | 348 | break; |
@@ -381,9 +387,11 @@ static int afs_dir_readdir(struct file *file, void *cookie, filldir_t filldir) | |||
381 | _enter("{%Ld,{%lu}}", | 387 | _enter("{%Ld,{%lu}}", |
382 | file->f_pos, file->f_path.dentry->d_inode->i_ino); | 388 | file->f_pos, file->f_path.dentry->d_inode->i_ino); |
383 | 389 | ||
390 | ASSERT(file->private_data != NULL); | ||
391 | |||
384 | fpos = file->f_pos; | 392 | fpos = file->f_pos; |
385 | ret = afs_dir_iterate(file->f_path.dentry->d_inode, &fpos, | 393 | ret = afs_dir_iterate(file->f_path.dentry->d_inode, &fpos, |
386 | cookie, filldir); | 394 | cookie, filldir, file->private_data); |
387 | file->f_pos = fpos; | 395 | file->f_pos = fpos; |
388 | 396 | ||
389 | _leave(" = %d", ret); | 397 | _leave(" = %d", ret); |
@@ -424,7 +432,7 @@ static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, | |||
424 | * do a lookup in a directory | 432 | * do a lookup in a directory |
425 | */ | 433 | */ |
426 | static int afs_do_lookup(struct inode *dir, struct dentry *dentry, | 434 | static int afs_do_lookup(struct inode *dir, struct dentry *dentry, |
427 | struct afs_fid *fid) | 435 | struct afs_fid *fid, struct key *key) |
428 | { | 436 | { |
429 | struct afs_dir_lookup_cookie cookie; | 437 | struct afs_dir_lookup_cookie cookie; |
430 | struct afs_super_info *as; | 438 | struct afs_super_info *as; |
@@ -442,7 +450,8 @@ static int afs_do_lookup(struct inode *dir, struct dentry *dentry, | |||
442 | cookie.found = 0; | 450 | cookie.found = 0; |
443 | 451 | ||
444 | fpos = 0; | 452 | fpos = 0; |
445 | ret = afs_dir_iterate(dir, &fpos, &cookie, afs_dir_lookup_filldir); | 453 | ret = afs_dir_iterate(dir, &fpos, &cookie, afs_dir_lookup_filldir, |
454 | key); | ||
446 | if (ret < 0) { | 455 | if (ret < 0) { |
447 | _leave(" = %d [iter]", ret); | 456 | _leave(" = %d [iter]", ret); |
448 | return ret; | 457 | return ret; |
@@ -468,6 +477,7 @@ static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, | |||
468 | struct afs_vnode *vnode; | 477 | struct afs_vnode *vnode; |
469 | struct afs_fid fid; | 478 | struct afs_fid fid; |
470 | struct inode *inode; | 479 | struct inode *inode; |
480 | struct key *key; | ||
471 | int ret; | 481 | int ret; |
472 | 482 | ||
473 | _enter("{%lu},%p{%s}", dir->i_ino, dentry, dentry->d_name.name); | 483 | _enter("{%lu},%p{%s}", dir->i_ino, dentry, dentry->d_name.name); |
@@ -483,14 +493,22 @@ static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, | |||
483 | return ERR_PTR(-ESTALE); | 493 | return ERR_PTR(-ESTALE); |
484 | } | 494 | } |
485 | 495 | ||
486 | ret = afs_do_lookup(dir, dentry, &fid); | 496 | key = afs_request_key(vnode->volume->cell); |
497 | if (IS_ERR(key)) { | ||
498 | _leave(" = %ld [key]", PTR_ERR(key)); | ||
499 | return ERR_PTR(PTR_ERR(key)); | ||
500 | } | ||
501 | |||
502 | ret = afs_do_lookup(dir, dentry, &fid, key); | ||
487 | if (ret < 0) { | 503 | if (ret < 0) { |
504 | key_put(key); | ||
488 | _leave(" = %d [do]", ret); | 505 | _leave(" = %d [do]", ret); |
489 | return ERR_PTR(ret); | 506 | return ERR_PTR(ret); |
490 | } | 507 | } |
491 | 508 | ||
492 | /* instantiate the dentry */ | 509 | /* instantiate the dentry */ |
493 | inode = afs_iget(dir->i_sb, &fid); | 510 | inode = afs_iget(dir->i_sb, key, &fid); |
511 | key_put(key); | ||
494 | if (IS_ERR(inode)) { | 512 | if (IS_ERR(inode)) { |
495 | _leave(" = %ld", PTR_ERR(inode)); | 513 | _leave(" = %ld", PTR_ERR(inode)); |
496 | return ERR_PTR(PTR_ERR(inode)); | 514 | return ERR_PTR(PTR_ERR(inode)); |
@@ -559,6 +577,7 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
559 | struct afs_fid fid; | 577 | struct afs_fid fid; |
560 | struct dentry *parent; | 578 | struct dentry *parent; |
561 | struct inode *inode, *dir; | 579 | struct inode *inode, *dir; |
580 | struct key *key; | ||
562 | int ret; | 581 | int ret; |
563 | 582 | ||
564 | vnode = AFS_FS_I(dentry->d_inode); | 583 | vnode = AFS_FS_I(dentry->d_inode); |
@@ -566,6 +585,10 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
566 | _enter("{sb=%p n=%s fl=%lx},", | 585 | _enter("{sb=%p n=%s fl=%lx},", |
567 | dentry->d_sb, dentry->d_name.name, vnode->flags); | 586 | dentry->d_sb, dentry->d_name.name, vnode->flags); |
568 | 587 | ||
588 | key = afs_request_key(vnode->volume->cell); | ||
589 | if (IS_ERR(key)) | ||
590 | key = NULL; | ||
591 | |||
569 | /* lock down the parent dentry so we can peer at it */ | 592 | /* lock down the parent dentry so we can peer at it */ |
570 | parent = dget_parent(dentry); | 593 | parent = dget_parent(dentry); |
571 | 594 | ||
@@ -595,7 +618,7 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
595 | _debug("dir modified"); | 618 | _debug("dir modified"); |
596 | 619 | ||
597 | /* search the directory for this vnode */ | 620 | /* search the directory for this vnode */ |
598 | ret = afs_do_lookup(dir, dentry, &fid); | 621 | ret = afs_do_lookup(dir, dentry, &fid, key); |
599 | if (ret == -ENOENT) { | 622 | if (ret == -ENOENT) { |
600 | _debug("%s: dirent not found", dentry->d_name.name); | 623 | _debug("%s: dirent not found", dentry->d_name.name); |
601 | goto not_found; | 624 | goto not_found; |
@@ -637,7 +660,7 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
637 | test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) { | 660 | test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) { |
638 | _debug("%s: changed", dentry->d_name.name); | 661 | _debug("%s: changed", dentry->d_name.name); |
639 | set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); | 662 | set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); |
640 | if (afs_vnode_fetch_status(vnode) < 0) { | 663 | if (afs_vnode_fetch_status(vnode, NULL, key) < 0) { |
641 | mutex_unlock(&vnode->cb_broken_lock); | 664 | mutex_unlock(&vnode->cb_broken_lock); |
642 | goto out_bad; | 665 | goto out_bad; |
643 | } | 666 | } |
@@ -667,6 +690,7 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
667 | 690 | ||
668 | out_valid: | 691 | out_valid: |
669 | dput(parent); | 692 | dput(parent); |
693 | key_put(key); | ||
670 | _leave(" = 1 [valid]"); | 694 | _leave(" = 1 [valid]"); |
671 | return 1; | 695 | return 1; |
672 | 696 | ||
@@ -688,6 +712,7 @@ out_bad: | |||
688 | shrink_dcache_parent(dentry); | 712 | shrink_dcache_parent(dentry); |
689 | d_drop(dentry); | 713 | d_drop(dentry); |
690 | dput(parent); | 714 | dput(parent); |
715 | key_put(key); | ||
691 | 716 | ||
692 | _leave(" = 0 [bad]"); | 717 | _leave(" = 0 [bad]"); |
693 | return 0; | 718 | return 0; |
diff --git a/fs/afs/file.c b/fs/afs/file.c index 6990327e75dd..101bbb8c0d8b 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c | |||
@@ -17,17 +17,23 @@ | |||
17 | #include <linux/pagemap.h> | 17 | #include <linux/pagemap.h> |
18 | #include "internal.h" | 18 | #include "internal.h" |
19 | 19 | ||
20 | #if 0 | ||
21 | static int afs_file_open(struct inode *inode, struct file *file); | ||
22 | static int afs_file_release(struct inode *inode, struct file *file); | ||
23 | #endif | ||
24 | |||
25 | static int afs_file_readpage(struct file *file, struct page *page); | 20 | static int afs_file_readpage(struct file *file, struct page *page); |
26 | static void afs_file_invalidatepage(struct page *page, unsigned long offset); | 21 | static void afs_file_invalidatepage(struct page *page, unsigned long offset); |
27 | static int afs_file_releasepage(struct page *page, gfp_t gfp_flags); | 22 | static int afs_file_releasepage(struct page *page, gfp_t gfp_flags); |
28 | 23 | ||
24 | const struct file_operations afs_file_operations = { | ||
25 | .open = afs_open, | ||
26 | .release = afs_release, | ||
27 | .llseek = generic_file_llseek, | ||
28 | .read = do_sync_read, | ||
29 | .aio_read = generic_file_aio_read, | ||
30 | .mmap = generic_file_readonly_mmap, | ||
31 | .sendfile = generic_file_sendfile, | ||
32 | }; | ||
33 | |||
29 | const struct inode_operations afs_file_inode_operations = { | 34 | const struct inode_operations afs_file_inode_operations = { |
30 | .getattr = afs_inode_getattr, | 35 | .getattr = afs_inode_getattr, |
36 | .permission = afs_permission, | ||
31 | }; | 37 | }; |
32 | 38 | ||
33 | const struct address_space_operations afs_fs_aops = { | 39 | const struct address_space_operations afs_fs_aops = { |
@@ -38,6 +44,41 @@ const struct address_space_operations afs_fs_aops = { | |||
38 | }; | 44 | }; |
39 | 45 | ||
40 | /* | 46 | /* |
47 | * open an AFS file or directory and attach a key to it | ||
48 | */ | ||
49 | int afs_open(struct inode *inode, struct file *file) | ||
50 | { | ||
51 | struct afs_vnode *vnode = AFS_FS_I(inode); | ||
52 | struct key *key; | ||
53 | |||
54 | _enter("{%x:%x},", vnode->fid.vid, vnode->fid.vnode); | ||
55 | |||
56 | key = afs_request_key(vnode->volume->cell); | ||
57 | if (IS_ERR(key)) { | ||
58 | _leave(" = %ld [key]", PTR_ERR(key)); | ||
59 | return PTR_ERR(key); | ||
60 | } | ||
61 | |||
62 | file->private_data = key; | ||
63 | _leave(" = 0"); | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | /* | ||
68 | * release an AFS file or directory and discard its key | ||
69 | */ | ||
70 | int afs_release(struct inode *inode, struct file *file) | ||
71 | { | ||
72 | struct afs_vnode *vnode = AFS_FS_I(inode); | ||
73 | |||
74 | _enter("{%x:%x},", vnode->fid.vid, vnode->fid.vnode); | ||
75 | |||
76 | key_put(file->private_data); | ||
77 | _leave(" = 0"); | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | /* | ||
41 | * deal with notification that a page was read from the cache | 82 | * deal with notification that a page was read from the cache |
42 | */ | 83 | */ |
43 | #ifdef AFS_CACHING_SUPPORT | 84 | #ifdef AFS_CACHING_SUPPORT |
@@ -79,13 +120,18 @@ static int afs_file_readpage(struct file *file, struct page *page) | |||
79 | { | 120 | { |
80 | struct afs_vnode *vnode; | 121 | struct afs_vnode *vnode; |
81 | struct inode *inode; | 122 | struct inode *inode; |
123 | struct key *key; | ||
82 | size_t len; | 124 | size_t len; |
83 | off_t offset; | 125 | off_t offset; |
84 | int ret; | 126 | int ret; |
85 | 127 | ||
86 | inode = page->mapping->host; | 128 | inode = page->mapping->host; |
87 | 129 | ||
88 | _enter("{%lu},{%lu}", inode->i_ino, page->index); | 130 | ASSERT(file != NULL); |
131 | key = file->private_data; | ||
132 | ASSERT(key != NULL); | ||
133 | |||
134 | _enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index); | ||
89 | 135 | ||
90 | vnode = AFS_FS_I(inode); | 136 | vnode = AFS_FS_I(inode); |
91 | 137 | ||
@@ -124,7 +170,7 @@ static int afs_file_readpage(struct file *file, struct page *page) | |||
124 | 170 | ||
125 | /* read the contents of the file from the server into the | 171 | /* read the contents of the file from the server into the |
126 | * page */ | 172 | * page */ |
127 | ret = afs_vnode_fetch_data(vnode, offset, len, page); | 173 | ret = afs_vnode_fetch_data(vnode, key, offset, len, page); |
128 | if (ret < 0) { | 174 | if (ret < 0) { |
129 | if (ret == -ENOENT) { | 175 | if (ret == -ENOENT) { |
130 | _debug("got NOENT from server" | 176 | _debug("got NOENT from server" |
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 167ca615c2e6..321b489aa90f 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c | |||
@@ -148,6 +148,7 @@ static int afs_deliver_fs_fetch_status(struct afs_call *call, | |||
148 | * FS.FetchStatus operation type | 148 | * FS.FetchStatus operation type |
149 | */ | 149 | */ |
150 | static const struct afs_call_type afs_RXFSFetchStatus = { | 150 | static const struct afs_call_type afs_RXFSFetchStatus = { |
151 | .name = "FS.FetchStatus", | ||
151 | .deliver = afs_deliver_fs_fetch_status, | 152 | .deliver = afs_deliver_fs_fetch_status, |
152 | .abort_to_error = afs_abort_to_error, | 153 | .abort_to_error = afs_abort_to_error, |
153 | .destructor = afs_flat_call_destructor, | 154 | .destructor = afs_flat_call_destructor, |
@@ -157,6 +158,7 @@ static const struct afs_call_type afs_RXFSFetchStatus = { | |||
157 | * fetch the status information for a file | 158 | * fetch the status information for a file |
158 | */ | 159 | */ |
159 | int afs_fs_fetch_file_status(struct afs_server *server, | 160 | int afs_fs_fetch_file_status(struct afs_server *server, |
161 | struct key *key, | ||
160 | struct afs_vnode *vnode, | 162 | struct afs_vnode *vnode, |
161 | struct afs_volsync *volsync, | 163 | struct afs_volsync *volsync, |
162 | const struct afs_wait_mode *wait_mode) | 164 | const struct afs_wait_mode *wait_mode) |
@@ -164,12 +166,13 @@ int afs_fs_fetch_file_status(struct afs_server *server, | |||
164 | struct afs_call *call; | 166 | struct afs_call *call; |
165 | __be32 *bp; | 167 | __be32 *bp; |
166 | 168 | ||
167 | _enter(""); | 169 | _enter(",%x,,,", key_serial(key)); |
168 | 170 | ||
169 | call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, 120); | 171 | call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, 120); |
170 | if (!call) | 172 | if (!call) |
171 | return -ENOMEM; | 173 | return -ENOMEM; |
172 | 174 | ||
175 | call->key = key; | ||
173 | call->reply = vnode; | 176 | call->reply = vnode; |
174 | call->reply2 = volsync; | 177 | call->reply2 = volsync; |
175 | call->service_id = FS_SERVICE; | 178 | call->service_id = FS_SERVICE; |
@@ -279,6 +282,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call, | |||
279 | * FS.FetchData operation type | 282 | * FS.FetchData operation type |
280 | */ | 283 | */ |
281 | static const struct afs_call_type afs_RXFSFetchData = { | 284 | static const struct afs_call_type afs_RXFSFetchData = { |
285 | .name = "FS.FetchData", | ||
282 | .deliver = afs_deliver_fs_fetch_data, | 286 | .deliver = afs_deliver_fs_fetch_data, |
283 | .abort_to_error = afs_abort_to_error, | 287 | .abort_to_error = afs_abort_to_error, |
284 | .destructor = afs_flat_call_destructor, | 288 | .destructor = afs_flat_call_destructor, |
@@ -288,6 +292,7 @@ static const struct afs_call_type afs_RXFSFetchData = { | |||
288 | * fetch data from a file | 292 | * fetch data from a file |
289 | */ | 293 | */ |
290 | int afs_fs_fetch_data(struct afs_server *server, | 294 | int afs_fs_fetch_data(struct afs_server *server, |
295 | struct key *key, | ||
291 | struct afs_vnode *vnode, | 296 | struct afs_vnode *vnode, |
292 | off_t offset, size_t length, | 297 | off_t offset, size_t length, |
293 | struct page *buffer, | 298 | struct page *buffer, |
@@ -303,6 +308,7 @@ int afs_fs_fetch_data(struct afs_server *server, | |||
303 | if (!call) | 308 | if (!call) |
304 | return -ENOMEM; | 309 | return -ENOMEM; |
305 | 310 | ||
311 | call->key = key; | ||
306 | call->reply = vnode; | 312 | call->reply = vnode; |
307 | call->reply2 = volsync; | 313 | call->reply2 = volsync; |
308 | call->reply3 = buffer; | 314 | call->reply3 = buffer; |
@@ -338,6 +344,7 @@ static int afs_deliver_fs_give_up_callbacks(struct afs_call *call, | |||
338 | * FS.GiveUpCallBacks operation type | 344 | * FS.GiveUpCallBacks operation type |
339 | */ | 345 | */ |
340 | static const struct afs_call_type afs_RXFSGiveUpCallBacks = { | 346 | static const struct afs_call_type afs_RXFSGiveUpCallBacks = { |
347 | .name = "FS.GiveUpCallBacks", | ||
341 | .deliver = afs_deliver_fs_give_up_callbacks, | 348 | .deliver = afs_deliver_fs_give_up_callbacks, |
342 | .abort_to_error = afs_abort_to_error, | 349 | .abort_to_error = afs_abort_to_error, |
343 | .destructor = afs_flat_call_destructor, | 350 | .destructor = afs_flat_call_destructor, |
diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 18863315211f..227336228299 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c | |||
@@ -29,7 +29,7 @@ struct afs_iget_data { | |||
29 | /* | 29 | /* |
30 | * map the AFS file status to the inode member variables | 30 | * map the AFS file status to the inode member variables |
31 | */ | 31 | */ |
32 | static int afs_inode_map_status(struct afs_vnode *vnode) | 32 | static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key) |
33 | { | 33 | { |
34 | struct inode *inode = AFS_VNODE_TO_I(vnode); | 34 | struct inode *inode = AFS_VNODE_TO_I(vnode); |
35 | 35 | ||
@@ -44,7 +44,7 @@ static int afs_inode_map_status(struct afs_vnode *vnode) | |||
44 | case AFS_FTYPE_FILE: | 44 | case AFS_FTYPE_FILE: |
45 | inode->i_mode = S_IFREG | vnode->status.mode; | 45 | inode->i_mode = S_IFREG | vnode->status.mode; |
46 | inode->i_op = &afs_file_inode_operations; | 46 | inode->i_op = &afs_file_inode_operations; |
47 | inode->i_fop = &generic_ro_fops; | 47 | inode->i_fop = &afs_file_operations; |
48 | break; | 48 | break; |
49 | case AFS_FTYPE_DIR: | 49 | case AFS_FTYPE_DIR: |
50 | inode->i_mode = S_IFDIR | vnode->status.mode; | 50 | inode->i_mode = S_IFDIR | vnode->status.mode; |
@@ -73,7 +73,7 @@ static int afs_inode_map_status(struct afs_vnode *vnode) | |||
73 | 73 | ||
74 | /* check to see whether a symbolic link is really a mountpoint */ | 74 | /* check to see whether a symbolic link is really a mountpoint */ |
75 | if (vnode->status.type == AFS_FTYPE_SYMLINK) { | 75 | if (vnode->status.type == AFS_FTYPE_SYMLINK) { |
76 | afs_mntpt_check_symlink(vnode); | 76 | afs_mntpt_check_symlink(vnode, key); |
77 | 77 | ||
78 | if (test_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags)) { | 78 | if (test_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags)) { |
79 | inode->i_mode = S_IFDIR | vnode->status.mode; | 79 | inode->i_mode = S_IFDIR | vnode->status.mode; |
@@ -115,7 +115,8 @@ static int afs_iget5_set(struct inode *inode, void *opaque) | |||
115 | /* | 115 | /* |
116 | * inode retrieval | 116 | * inode retrieval |
117 | */ | 117 | */ |
118 | inline struct inode *afs_iget(struct super_block *sb, struct afs_fid *fid) | 118 | inline struct inode *afs_iget(struct super_block *sb, struct key *key, |
119 | struct afs_fid *fid) | ||
119 | { | 120 | { |
120 | struct afs_iget_data data = { .fid = *fid }; | 121 | struct afs_iget_data data = { .fid = *fid }; |
121 | struct afs_super_info *as; | 122 | struct afs_super_info *as; |
@@ -157,10 +158,10 @@ inline struct inode *afs_iget(struct super_block *sb, struct afs_fid *fid) | |||
157 | 158 | ||
158 | /* okay... it's a new inode */ | 159 | /* okay... it's a new inode */ |
159 | set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); | 160 | set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); |
160 | ret = afs_vnode_fetch_status(vnode); | 161 | ret = afs_vnode_fetch_status(vnode, NULL, key); |
161 | if (ret < 0) | 162 | if (ret < 0) |
162 | goto bad_inode; | 163 | goto bad_inode; |
163 | ret = afs_inode_map_status(vnode); | 164 | ret = afs_inode_map_status(vnode, key); |
164 | if (ret < 0) | 165 | if (ret < 0) |
165 | goto bad_inode; | 166 | goto bad_inode; |
166 | 167 | ||
@@ -201,6 +202,7 @@ int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, | |||
201 | */ | 202 | */ |
202 | void afs_clear_inode(struct inode *inode) | 203 | void afs_clear_inode(struct inode *inode) |
203 | { | 204 | { |
205 | struct afs_permits *permits; | ||
204 | struct afs_vnode *vnode; | 206 | struct afs_vnode *vnode; |
205 | 207 | ||
206 | vnode = AFS_FS_I(inode); | 208 | vnode = AFS_FS_I(inode); |
@@ -233,5 +235,12 @@ void afs_clear_inode(struct inode *inode) | |||
233 | vnode->cache = NULL; | 235 | vnode->cache = NULL; |
234 | #endif | 236 | #endif |
235 | 237 | ||
238 | mutex_lock(&vnode->permits_lock); | ||
239 | permits = vnode->permits; | ||
240 | rcu_assign_pointer(vnode->permits, NULL); | ||
241 | mutex_unlock(&vnode->permits_lock); | ||
242 | if (permits) | ||
243 | call_rcu(&permits->rcu, afs_zap_permits); | ||
244 | |||
236 | _leave(""); | 245 | _leave(""); |
237 | } | 246 | } |
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index afc6f0f30259..8bed2429d01f 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/pagemap.h> | 15 | #include <linux/pagemap.h> |
16 | #include <linux/skbuff.h> | 16 | #include <linux/skbuff.h> |
17 | #include <linux/rxrpc.h> | 17 | #include <linux/rxrpc.h> |
18 | #include <linux/key.h> | ||
18 | #include "afs.h" | 19 | #include "afs.h" |
19 | #include "afs_vl.h" | 20 | #include "afs_vl.h" |
20 | 21 | ||
@@ -32,6 +33,17 @@ typedef enum { | |||
32 | AFS_VL_UNCERTAIN, /* uncertain state (update failed) */ | 33 | AFS_VL_UNCERTAIN, /* uncertain state (update failed) */ |
33 | } __attribute__((packed)) afs_vlocation_state_t; | 34 | } __attribute__((packed)) afs_vlocation_state_t; |
34 | 35 | ||
36 | struct afs_mount_params { | ||
37 | bool rwpath; /* T if the parent should be considered R/W */ | ||
38 | bool force; /* T to force cell type */ | ||
39 | afs_voltype_t type; /* type of volume requested */ | ||
40 | int volnamesz; /* size of volume name */ | ||
41 | const char *volname; /* name of volume to mount */ | ||
42 | struct afs_cell *cell; /* cell in which to find volume */ | ||
43 | struct afs_volume *volume; /* volume record */ | ||
44 | struct key *key; /* key to use for secure mounting */ | ||
45 | }; | ||
46 | |||
35 | /* | 47 | /* |
36 | * definition of how to wait for the completion of an operation | 48 | * definition of how to wait for the completion of an operation |
37 | */ | 49 | */ |
@@ -95,6 +107,8 @@ struct afs_call { | |||
95 | }; | 107 | }; |
96 | 108 | ||
97 | struct afs_call_type { | 109 | struct afs_call_type { |
110 | const char *name; | ||
111 | |||
98 | /* deliver request or reply data to an call | 112 | /* deliver request or reply data to an call |
99 | * - returning an error will cause the call to be aborted | 113 | * - returning an error will cause the call to be aborted |
100 | */ | 114 | */ |
@@ -128,8 +142,8 @@ extern struct file_system_type afs_fs_type; | |||
128 | * entry in the cached cell catalogue | 142 | * entry in the cached cell catalogue |
129 | */ | 143 | */ |
130 | struct afs_cache_cell { | 144 | struct afs_cache_cell { |
131 | char name[64]; /* cell name (padded with NULs) */ | 145 | char name[AFS_MAXCELLNAME]; /* cell name (padded with NULs) */ |
132 | struct in_addr vl_servers[15]; /* cached cell VL servers */ | 146 | struct in_addr vl_servers[15]; /* cached cell VL servers */ |
133 | }; | 147 | }; |
134 | 148 | ||
135 | /* | 149 | /* |
@@ -138,6 +152,7 @@ struct afs_cache_cell { | |||
138 | struct afs_cell { | 152 | struct afs_cell { |
139 | atomic_t usage; | 153 | atomic_t usage; |
140 | struct list_head link; /* main cell list link */ | 154 | struct list_head link; /* main cell list link */ |
155 | struct key *anonymous_key; /* anonymous user key for this cell */ | ||
141 | struct list_head proc_link; /* /proc cell list link */ | 156 | struct list_head proc_link; /* /proc cell list link */ |
142 | struct proc_dir_entry *proc_dir; /* /proc dir for this cell */ | 157 | struct proc_dir_entry *proc_dir; /* /proc dir for this cell */ |
143 | #ifdef AFS_CACHING_SUPPORT | 158 | #ifdef AFS_CACHING_SUPPORT |
@@ -163,7 +178,9 @@ struct afs_cell { | |||
163 | * entry in the cached volume location catalogue | 178 | * entry in the cached volume location catalogue |
164 | */ | 179 | */ |
165 | struct afs_cache_vlocation { | 180 | struct afs_cache_vlocation { |
166 | uint8_t name[64 + 1]; /* volume name (lowercase, padded with NULs) */ | 181 | /* volume name (lowercase, padded with NULs) */ |
182 | uint8_t name[AFS_MAXVOLNAME + 1]; | ||
183 | |||
167 | uint8_t nservers; /* number of entries used in servers[] */ | 184 | uint8_t nservers; /* number of entries used in servers[] */ |
168 | uint8_t vidmask; /* voltype mask for vid[] */ | 185 | uint8_t vidmask; /* voltype mask for vid[] */ |
169 | uint8_t srvtmask[8]; /* voltype masks for servers[] */ | 186 | uint8_t srvtmask[8]; /* voltype masks for servers[] */ |
@@ -281,7 +298,8 @@ struct afs_vnode { | |||
281 | #ifdef AFS_CACHING_SUPPORT | 298 | #ifdef AFS_CACHING_SUPPORT |
282 | struct cachefs_cookie *cache; /* caching cookie */ | 299 | struct cachefs_cookie *cache; /* caching cookie */ |
283 | #endif | 300 | #endif |
284 | 301 | struct afs_permits *permits; /* cache of permits so far obtained */ | |
302 | struct mutex permits_lock; /* lock for altering permits list */ | ||
285 | wait_queue_head_t update_waitq; /* status fetch waitqueue */ | 303 | wait_queue_head_t update_waitq; /* status fetch waitqueue */ |
286 | unsigned update_cnt; /* number of outstanding ops that will update the | 304 | unsigned update_cnt; /* number of outstanding ops that will update the |
287 | * status */ | 305 | * status */ |
@@ -296,12 +314,13 @@ struct afs_vnode { | |||
296 | #define AFS_VNODE_DIR_CHANGED 6 /* set if vnode's parent dir metadata changed */ | 314 | #define AFS_VNODE_DIR_CHANGED 6 /* set if vnode's parent dir metadata changed */ |
297 | #define AFS_VNODE_DIR_MODIFIED 7 /* set if vnode's parent dir data modified */ | 315 | #define AFS_VNODE_DIR_MODIFIED 7 /* set if vnode's parent dir data modified */ |
298 | 316 | ||
317 | long acl_order; /* ACL check count (callback break count) */ | ||
318 | |||
299 | /* outstanding callback notification on this file */ | 319 | /* outstanding callback notification on this file */ |
300 | struct rb_node server_rb; /* link in server->fs_vnodes */ | 320 | struct rb_node server_rb; /* link in server->fs_vnodes */ |
301 | struct rb_node cb_promise; /* link in server->cb_promises */ | 321 | struct rb_node cb_promise; /* link in server->cb_promises */ |
302 | struct work_struct cb_broken_work; /* work to be done on callback break */ | 322 | struct work_struct cb_broken_work; /* work to be done on callback break */ |
303 | struct mutex cb_broken_lock; /* lock against multiple attempts to fix break */ | 323 | struct mutex cb_broken_lock; /* lock against multiple attempts to fix break */ |
304 | // struct list_head cb_hash_link; /* link in master callback hash */ | ||
305 | time_t cb_expires; /* time at which callback expires */ | 324 | time_t cb_expires; /* time at which callback expires */ |
306 | time_t cb_expires_at; /* time used to order cb_promise */ | 325 | time_t cb_expires_at; /* time used to order cb_promise */ |
307 | unsigned cb_version; /* callback version */ | 326 | unsigned cb_version; /* callback version */ |
@@ -310,6 +329,23 @@ struct afs_vnode { | |||
310 | bool cb_promised; /* true if promise still holds */ | 329 | bool cb_promised; /* true if promise still holds */ |
311 | }; | 330 | }; |
312 | 331 | ||
332 | /* | ||
333 | * cached security record for one user's attempt to access a vnode | ||
334 | */ | ||
335 | struct afs_permit { | ||
336 | struct key *key; /* RxRPC ticket holding a security context */ | ||
337 | afs_access_t access_mask; /* access mask for this key */ | ||
338 | }; | ||
339 | |||
340 | /* | ||
341 | * cache of security records from attempts to access a vnode | ||
342 | */ | ||
343 | struct afs_permits { | ||
344 | struct rcu_head rcu; /* disposal procedure */ | ||
345 | int count; /* number of records */ | ||
346 | struct afs_permit permits[0]; /* the permits so far examined */ | ||
347 | }; | ||
348 | |||
313 | /*****************************************************************************/ | 349 | /*****************************************************************************/ |
314 | /* | 350 | /* |
315 | * callback.c | 351 | * callback.c |
@@ -352,11 +388,17 @@ extern bool afs_cm_incoming_call(struct afs_call *); | |||
352 | extern const struct inode_operations afs_dir_inode_operations; | 388 | extern const struct inode_operations afs_dir_inode_operations; |
353 | extern const struct file_operations afs_dir_file_operations; | 389 | extern const struct file_operations afs_dir_file_operations; |
354 | 390 | ||
391 | extern int afs_permission(struct inode *, int, struct nameidata *); | ||
392 | |||
355 | /* | 393 | /* |
356 | * file.c | 394 | * file.c |
357 | */ | 395 | */ |
358 | extern const struct address_space_operations afs_fs_aops; | 396 | extern const struct address_space_operations afs_fs_aops; |
359 | extern const struct inode_operations afs_file_inode_operations; | 397 | extern const struct inode_operations afs_file_inode_operations; |
398 | extern const struct file_operations afs_file_operations; | ||
399 | |||
400 | extern int afs_open(struct inode *, struct file *); | ||
401 | extern int afs_release(struct inode *, struct file *); | ||
360 | 402 | ||
361 | #ifdef AFS_CACHING_SUPPORT | 403 | #ifdef AFS_CACHING_SUPPORT |
362 | extern int afs_cache_get_page_cookie(struct page *, struct cachefs_page **); | 404 | extern int afs_cache_get_page_cookie(struct page *, struct cachefs_page **); |
@@ -365,22 +407,24 @@ extern int afs_cache_get_page_cookie(struct page *, struct cachefs_page **); | |||
365 | /* | 407 | /* |
366 | * fsclient.c | 408 | * fsclient.c |
367 | */ | 409 | */ |
368 | extern int afs_fs_fetch_file_status(struct afs_server *, | 410 | extern int afs_fs_fetch_file_status(struct afs_server *, struct key *, |
369 | struct afs_vnode *, | 411 | struct afs_vnode *, struct afs_volsync *, |
370 | struct afs_volsync *, | ||
371 | const struct afs_wait_mode *); | 412 | const struct afs_wait_mode *); |
372 | extern int afs_fs_give_up_callbacks(struct afs_server *, | 413 | extern int afs_fs_give_up_callbacks(struct afs_server *, |
373 | const struct afs_wait_mode *); | 414 | const struct afs_wait_mode *); |
374 | extern int afs_fs_fetch_data(struct afs_server *, struct afs_vnode *, off_t, | 415 | extern int afs_fs_fetch_data(struct afs_server *, struct key *, |
375 | size_t, struct page *, struct afs_volsync *, | 416 | struct afs_vnode *, off_t, size_t, struct page *, |
417 | struct afs_volsync *, | ||
376 | const struct afs_wait_mode *); | 418 | const struct afs_wait_mode *); |
377 | 419 | ||
378 | /* | 420 | /* |
379 | * inode.c | 421 | * inode.c |
380 | */ | 422 | */ |
381 | extern struct inode *afs_iget(struct super_block *, struct afs_fid *); | 423 | extern struct inode *afs_iget(struct super_block *, struct key *, |
424 | struct afs_fid *); | ||
382 | extern int afs_inode_getattr(struct vfsmount *, struct dentry *, | 425 | extern int afs_inode_getattr(struct vfsmount *, struct dentry *, |
383 | struct kstat *); | 426 | struct kstat *); |
427 | extern void afs_zap_permits(struct rcu_head *); | ||
384 | extern void afs_clear_inode(struct inode *); | 428 | extern void afs_clear_inode(struct inode *); |
385 | 429 | ||
386 | /* | 430 | /* |
@@ -402,17 +446,11 @@ extern const struct inode_operations afs_mntpt_inode_operations; | |||
402 | extern const struct file_operations afs_mntpt_file_operations; | 446 | extern const struct file_operations afs_mntpt_file_operations; |
403 | extern unsigned long afs_mntpt_expiry_timeout; | 447 | extern unsigned long afs_mntpt_expiry_timeout; |
404 | 448 | ||
405 | extern int afs_mntpt_check_symlink(struct afs_vnode *); | 449 | extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *); |
406 | extern void afs_mntpt_kill_timer(void); | 450 | extern void afs_mntpt_kill_timer(void); |
407 | extern void afs_umount_begin(struct vfsmount *, int); | 451 | extern void afs_umount_begin(struct vfsmount *, int); |
408 | 452 | ||
409 | /* | 453 | /* |
410 | * super.c | ||
411 | */ | ||
412 | extern int afs_fs_init(void); | ||
413 | extern void afs_fs_exit(void); | ||
414 | |||
415 | /* | ||
416 | * proc.c | 454 | * proc.c |
417 | */ | 455 | */ |
418 | extern int afs_proc_init(void); | 456 | extern int afs_proc_init(void); |
@@ -436,6 +474,14 @@ extern int afs_extract_data(struct afs_call *, struct sk_buff *, bool, void *, | |||
436 | size_t); | 474 | size_t); |
437 | 475 | ||
438 | /* | 476 | /* |
477 | * security.c | ||
478 | */ | ||
479 | extern void afs_clear_permits(struct afs_vnode *); | ||
480 | extern void afs_cache_permit(struct afs_vnode *, struct key *, long); | ||
481 | extern struct key *afs_request_key(struct afs_cell *); | ||
482 | extern int afs_permission(struct inode *, int, struct nameidata *); | ||
483 | |||
484 | /* | ||
439 | * server.c | 485 | * server.c |
440 | */ | 486 | */ |
441 | extern spinlock_t afs_server_peer_lock; | 487 | extern spinlock_t afs_server_peer_lock; |
@@ -449,16 +495,23 @@ extern void afs_put_server(struct afs_server *); | |||
449 | extern void __exit afs_purge_servers(void); | 495 | extern void __exit afs_purge_servers(void); |
450 | 496 | ||
451 | /* | 497 | /* |
498 | * super.c | ||
499 | */ | ||
500 | extern int afs_fs_init(void); | ||
501 | extern void afs_fs_exit(void); | ||
502 | |||
503 | /* | ||
452 | * vlclient.c | 504 | * vlclient.c |
453 | */ | 505 | */ |
454 | #ifdef AFS_CACHING_SUPPORT | 506 | #ifdef AFS_CACHING_SUPPORT |
455 | extern struct cachefs_index_def afs_vlocation_cache_index_def; | 507 | extern struct cachefs_index_def afs_vlocation_cache_index_def; |
456 | #endif | 508 | #endif |
457 | 509 | ||
458 | extern int afs_vl_get_entry_by_name(struct in_addr *, const char *, | 510 | extern int afs_vl_get_entry_by_name(struct in_addr *, struct key *, |
459 | struct afs_cache_vlocation *, | 511 | const char *, struct afs_cache_vlocation *, |
460 | const struct afs_wait_mode *); | 512 | const struct afs_wait_mode *); |
461 | extern int afs_vl_get_entry_by_id(struct in_addr *, afs_volid_t, afs_voltype_t, | 513 | extern int afs_vl_get_entry_by_id(struct in_addr *, struct key *, |
514 | afs_volid_t, afs_voltype_t, | ||
462 | struct afs_cache_vlocation *, | 515 | struct afs_cache_vlocation *, |
463 | const struct afs_wait_mode *); | 516 | const struct afs_wait_mode *); |
464 | 517 | ||
@@ -469,6 +522,7 @@ extern int afs_vl_get_entry_by_id(struct in_addr *, afs_volid_t, afs_voltype_t, | |||
469 | 522 | ||
470 | extern int __init afs_vlocation_update_init(void); | 523 | extern int __init afs_vlocation_update_init(void); |
471 | extern struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *, | 524 | extern struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *, |
525 | struct key *, | ||
472 | const char *, size_t); | 526 | const char *, size_t); |
473 | extern void afs_put_vlocation(struct afs_vlocation *); | 527 | extern void afs_put_vlocation(struct afs_vlocation *); |
474 | extern void __exit afs_vlocation_purge(void); | 528 | extern void __exit afs_vlocation_purge(void); |
@@ -492,9 +546,10 @@ static inline struct inode *AFS_VNODE_TO_I(struct afs_vnode *vnode) | |||
492 | return &vnode->vfs_inode; | 546 | return &vnode->vfs_inode; |
493 | } | 547 | } |
494 | 548 | ||
495 | extern int afs_vnode_fetch_status(struct afs_vnode *); | 549 | extern int afs_vnode_fetch_status(struct afs_vnode *, struct afs_vnode *, |
496 | extern int afs_vnode_fetch_data(struct afs_vnode *vnode, off_t, size_t, | 550 | struct key *); |
497 | struct page *); | 551 | extern int afs_vnode_fetch_data(struct afs_vnode *, struct key *, |
552 | off_t, size_t, struct page *); | ||
498 | 553 | ||
499 | /* | 554 | /* |
500 | * volume.c | 555 | * volume.c |
@@ -506,8 +561,7 @@ extern struct cachefs_index_def afs_volume_cache_index_def; | |||
506 | #define afs_get_volume(V) do { atomic_inc(&(V)->usage); } while(0) | 561 | #define afs_get_volume(V) do { atomic_inc(&(V)->usage); } while(0) |
507 | 562 | ||
508 | extern void afs_put_volume(struct afs_volume *); | 563 | extern void afs_put_volume(struct afs_volume *); |
509 | extern struct afs_volume *afs_volume_lookup(const char *, struct afs_cell *, | 564 | extern struct afs_volume *afs_volume_lookup(struct afs_mount_params *); |
510 | int); | ||
511 | extern struct afs_server *afs_volume_pick_fileserver(struct afs_vnode *); | 565 | extern struct afs_server *afs_volume_pick_fileserver(struct afs_vnode *); |
512 | extern int afs_volume_release_fileserver(struct afs_vnode *, | 566 | extern int afs_volume_release_fileserver(struct afs_vnode *, |
513 | struct afs_server *, int); | 567 | struct afs_server *, int); |
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index 08c11a0b66bd..b905ae37f912 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c | |||
@@ -48,8 +48,11 @@ unsigned long afs_mntpt_expiry_timeout = 10 * 60; | |||
48 | * check a symbolic link to see whether it actually encodes a mountpoint | 48 | * check a symbolic link to see whether it actually encodes a mountpoint |
49 | * - sets the AFS_VNODE_MOUNTPOINT flag on the vnode appropriately | 49 | * - sets the AFS_VNODE_MOUNTPOINT flag on the vnode appropriately |
50 | */ | 50 | */ |
51 | int afs_mntpt_check_symlink(struct afs_vnode *vnode) | 51 | int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key) |
52 | { | 52 | { |
53 | struct file file = { | ||
54 | .private_data = key, | ||
55 | }; | ||
53 | struct page *page; | 56 | struct page *page; |
54 | size_t size; | 57 | size_t size; |
55 | char *buf; | 58 | char *buf; |
@@ -58,7 +61,7 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode) | |||
58 | _enter("{%u,%u}", vnode->fid.vnode, vnode->fid.unique); | 61 | _enter("{%u,%u}", vnode->fid.vnode, vnode->fid.unique); |
59 | 62 | ||
60 | /* read the contents of the symlink into the pagecache */ | 63 | /* read the contents of the symlink into the pagecache */ |
61 | page = read_mapping_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0, NULL); | 64 | page = read_mapping_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0, &file); |
62 | if (IS_ERR(page)) { | 65 | if (IS_ERR(page)) { |
63 | ret = PTR_ERR(page); | 66 | ret = PTR_ERR(page); |
64 | goto out; | 67 | goto out; |
@@ -214,7 +217,7 @@ static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
214 | struct vfsmount *newmnt; | 217 | struct vfsmount *newmnt; |
215 | int err; | 218 | int err; |
216 | 219 | ||
217 | _enter("%p{%s},{%s:%p{%s}}", | 220 | _enter("%p{%s},{%s:%p{%s},}", |
218 | dentry, | 221 | dentry, |
219 | dentry->d_name.name, | 222 | dentry->d_name.name, |
220 | nd->mnt->mnt_devname, | 223 | nd->mnt->mnt_devname, |
@@ -234,7 +237,8 @@ static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
234 | err = do_add_mount(newmnt, nd, MNT_SHRINKABLE, &afs_vfsmounts); | 237 | err = do_add_mount(newmnt, nd, MNT_SHRINKABLE, &afs_vfsmounts); |
235 | switch (err) { | 238 | switch (err) { |
236 | case 0: | 239 | case 0: |
237 | path_release(nd); | 240 | mntput(nd->mnt); |
241 | dput(nd->dentry); | ||
238 | nd->mnt = newmnt; | 242 | nd->mnt = newmnt; |
239 | nd->dentry = dget(newmnt->mnt_root); | 243 | nd->dentry = dget(newmnt->mnt_root); |
240 | schedule_delayed_work(&afs_mntpt_expiry_timer, | 244 | schedule_delayed_work(&afs_mntpt_expiry_timer, |
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index b92774231b3c..e86c527d87a1 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c | |||
@@ -17,6 +17,8 @@ | |||
17 | 17 | ||
18 | static struct socket *afs_socket; /* my RxRPC socket */ | 18 | static struct socket *afs_socket; /* my RxRPC socket */ |
19 | static struct workqueue_struct *afs_async_calls; | 19 | static struct workqueue_struct *afs_async_calls; |
20 | static atomic_t afs_outstanding_calls; | ||
21 | static atomic_t afs_outstanding_skbs; | ||
20 | 22 | ||
21 | static void afs_wake_up_call_waiter(struct afs_call *); | 23 | static void afs_wake_up_call_waiter(struct afs_call *); |
22 | static int afs_wait_for_call_to_complete(struct afs_call *); | 24 | static int afs_wait_for_call_to_complete(struct afs_call *); |
@@ -45,6 +47,7 @@ static const struct afs_wait_mode afs_async_incoming_call = { | |||
45 | 47 | ||
46 | /* asynchronous incoming call initial processing */ | 48 | /* asynchronous incoming call initial processing */ |
47 | static const struct afs_call_type afs_RXCMxxxx = { | 49 | static const struct afs_call_type afs_RXCMxxxx = { |
50 | .name = "CB.xxxx", | ||
48 | .deliver = afs_deliver_cm_op_id, | 51 | .deliver = afs_deliver_cm_op_id, |
49 | .abort_to_error = afs_abort_to_error, | 52 | .abort_to_error = afs_abort_to_error, |
50 | }; | 53 | }; |
@@ -118,10 +121,67 @@ void afs_close_socket(void) | |||
118 | 121 | ||
119 | _debug("dework"); | 122 | _debug("dework"); |
120 | destroy_workqueue(afs_async_calls); | 123 | destroy_workqueue(afs_async_calls); |
124 | |||
125 | ASSERTCMP(atomic_read(&afs_outstanding_skbs), ==, 0); | ||
126 | ASSERTCMP(atomic_read(&afs_outstanding_calls), ==, 0); | ||
121 | _leave(""); | 127 | _leave(""); |
122 | } | 128 | } |
123 | 129 | ||
124 | /* | 130 | /* |
131 | * note that the data in a socket buffer is now delivered and that the buffer | ||
132 | * should be freed | ||
133 | */ | ||
134 | static void afs_data_delivered(struct sk_buff *skb) | ||
135 | { | ||
136 | if (!skb) { | ||
137 | _debug("DLVR NULL [%d]", atomic_read(&afs_outstanding_skbs)); | ||
138 | dump_stack(); | ||
139 | } else { | ||
140 | _debug("DLVR %p{%u} [%d]", | ||
141 | skb, skb->mark, atomic_read(&afs_outstanding_skbs)); | ||
142 | if (atomic_dec_return(&afs_outstanding_skbs) == -1) | ||
143 | BUG(); | ||
144 | rxrpc_kernel_data_delivered(skb); | ||
145 | } | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * free a socket buffer | ||
150 | */ | ||
151 | static void afs_free_skb(struct sk_buff *skb) | ||
152 | { | ||
153 | if (!skb) { | ||
154 | _debug("FREE NULL [%d]", atomic_read(&afs_outstanding_skbs)); | ||
155 | dump_stack(); | ||
156 | } else { | ||
157 | _debug("FREE %p{%u} [%d]", | ||
158 | skb, skb->mark, atomic_read(&afs_outstanding_skbs)); | ||
159 | if (atomic_dec_return(&afs_outstanding_skbs) == -1) | ||
160 | BUG(); | ||
161 | rxrpc_kernel_free_skb(skb); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | /* | ||
166 | * free a call | ||
167 | */ | ||
168 | static void afs_free_call(struct afs_call *call) | ||
169 | { | ||
170 | _debug("DONE %p{%s} [%d]", | ||
171 | call, call->type->name, atomic_read(&afs_outstanding_calls)); | ||
172 | if (atomic_dec_return(&afs_outstanding_calls) == -1) | ||
173 | BUG(); | ||
174 | |||
175 | ASSERTCMP(call->rxcall, ==, NULL); | ||
176 | ASSERT(!work_pending(&call->async_work)); | ||
177 | ASSERT(skb_queue_empty(&call->rx_queue)); | ||
178 | ASSERT(call->type->name != NULL); | ||
179 | |||
180 | kfree(call->request); | ||
181 | kfree(call); | ||
182 | } | ||
183 | |||
184 | /* | ||
125 | * allocate a call with flat request and reply buffers | 185 | * allocate a call with flat request and reply buffers |
126 | */ | 186 | */ |
127 | struct afs_call *afs_alloc_flat_call(const struct afs_call_type *type, | 187 | struct afs_call *afs_alloc_flat_call(const struct afs_call_type *type, |
@@ -133,30 +193,32 @@ struct afs_call *afs_alloc_flat_call(const struct afs_call_type *type, | |||
133 | if (!call) | 193 | if (!call) |
134 | goto nomem_call; | 194 | goto nomem_call; |
135 | 195 | ||
196 | _debug("CALL %p{%s} [%d]", | ||
197 | call, type->name, atomic_read(&afs_outstanding_calls)); | ||
198 | atomic_inc(&afs_outstanding_calls); | ||
199 | |||
200 | call->type = type; | ||
201 | call->request_size = request_size; | ||
202 | call->reply_max = reply_size; | ||
203 | |||
136 | if (request_size) { | 204 | if (request_size) { |
137 | call->request = kmalloc(request_size, GFP_NOFS); | 205 | call->request = kmalloc(request_size, GFP_NOFS); |
138 | if (!call->request) | 206 | if (!call->request) |
139 | goto nomem_request; | 207 | goto nomem_free; |
140 | } | 208 | } |
141 | 209 | ||
142 | if (reply_size) { | 210 | if (reply_size) { |
143 | call->buffer = kmalloc(reply_size, GFP_NOFS); | 211 | call->buffer = kmalloc(reply_size, GFP_NOFS); |
144 | if (!call->buffer) | 212 | if (!call->buffer) |
145 | goto nomem_buffer; | 213 | goto nomem_free; |
146 | } | 214 | } |
147 | 215 | ||
148 | call->type = type; | ||
149 | call->request_size = request_size; | ||
150 | call->reply_max = reply_size; | ||
151 | |||
152 | init_waitqueue_head(&call->waitq); | 216 | init_waitqueue_head(&call->waitq); |
153 | skb_queue_head_init(&call->rx_queue); | 217 | skb_queue_head_init(&call->rx_queue); |
154 | return call; | 218 | return call; |
155 | 219 | ||
156 | nomem_buffer: | 220 | nomem_free: |
157 | kfree(call->request); | 221 | afs_free_call(call); |
158 | nomem_request: | ||
159 | kfree(call); | ||
160 | nomem_call: | 222 | nomem_call: |
161 | return NULL; | 223 | return NULL; |
162 | } | 224 | } |
@@ -188,6 +250,12 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, | |||
188 | 250 | ||
189 | _enter("%x,{%d},", addr->s_addr, ntohs(call->port)); | 251 | _enter("%x,{%d},", addr->s_addr, ntohs(call->port)); |
190 | 252 | ||
253 | ASSERT(call->type != NULL); | ||
254 | ASSERT(call->type->name != NULL); | ||
255 | |||
256 | _debug("MAKE %p{%s} [%d]", | ||
257 | call, call->type->name, atomic_read(&afs_outstanding_calls)); | ||
258 | |||
191 | call->wait_mode = wait_mode; | 259 | call->wait_mode = wait_mode; |
192 | INIT_WORK(&call->async_work, afs_process_async_call); | 260 | INIT_WORK(&call->async_work, afs_process_async_call); |
193 | 261 | ||
@@ -203,6 +271,7 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, | |||
203 | /* create a call */ | 271 | /* create a call */ |
204 | rxcall = rxrpc_kernel_begin_call(afs_socket, &srx, call->key, | 272 | rxcall = rxrpc_kernel_begin_call(afs_socket, &srx, call->key, |
205 | (unsigned long) call, gfp); | 273 | (unsigned long) call, gfp); |
274 | call->key = NULL; | ||
206 | if (IS_ERR(rxcall)) { | 275 | if (IS_ERR(rxcall)) { |
207 | ret = PTR_ERR(rxcall); | 276 | ret = PTR_ERR(rxcall); |
208 | goto error_kill_call; | 277 | goto error_kill_call; |
@@ -237,10 +306,10 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, | |||
237 | error_do_abort: | 306 | error_do_abort: |
238 | rxrpc_kernel_abort_call(rxcall, RX_USER_ABORT); | 307 | rxrpc_kernel_abort_call(rxcall, RX_USER_ABORT); |
239 | rxrpc_kernel_end_call(rxcall); | 308 | rxrpc_kernel_end_call(rxcall); |
309 | call->rxcall = NULL; | ||
240 | error_kill_call: | 310 | error_kill_call: |
241 | call->type->destructor(call); | 311 | call->type->destructor(call); |
242 | ASSERT(skb_queue_empty(&call->rx_queue)); | 312 | afs_free_call(call); |
243 | kfree(call); | ||
244 | _leave(" = %d", ret); | 313 | _leave(" = %d", ret); |
245 | return ret; | 314 | return ret; |
246 | } | 315 | } |
@@ -257,15 +326,19 @@ static void afs_rx_interceptor(struct sock *sk, unsigned long user_call_ID, | |||
257 | 326 | ||
258 | _enter("%p,,%u", call, skb->mark); | 327 | _enter("%p,,%u", call, skb->mark); |
259 | 328 | ||
329 | _debug("ICPT %p{%u} [%d]", | ||
330 | skb, skb->mark, atomic_read(&afs_outstanding_skbs)); | ||
331 | |||
260 | ASSERTCMP(sk, ==, afs_socket->sk); | 332 | ASSERTCMP(sk, ==, afs_socket->sk); |
333 | atomic_inc(&afs_outstanding_skbs); | ||
261 | 334 | ||
262 | if (!call) { | 335 | if (!call) { |
263 | /* its an incoming call for our callback service */ | 336 | /* its an incoming call for our callback service */ |
264 | __skb_queue_tail(&afs_incoming_calls, skb); | 337 | skb_queue_tail(&afs_incoming_calls, skb); |
265 | schedule_work(&afs_collect_incoming_call_work); | 338 | schedule_work(&afs_collect_incoming_call_work); |
266 | } else { | 339 | } else { |
267 | /* route the messages directly to the appropriate call */ | 340 | /* route the messages directly to the appropriate call */ |
268 | __skb_queue_tail(&call->rx_queue, skb); | 341 | skb_queue_tail(&call->rx_queue, skb); |
269 | call->wait_mode->rx_wakeup(call); | 342 | call->wait_mode->rx_wakeup(call); |
270 | } | 343 | } |
271 | 344 | ||
@@ -317,9 +390,9 @@ static void afs_deliver_to_call(struct afs_call *call) | |||
317 | call->state = AFS_CALL_ERROR; | 390 | call->state = AFS_CALL_ERROR; |
318 | break; | 391 | break; |
319 | } | 392 | } |
320 | rxrpc_kernel_data_delivered(skb); | 393 | afs_data_delivered(skb); |
321 | skb = NULL; | 394 | skb = NULL; |
322 | break; | 395 | continue; |
323 | case RXRPC_SKB_MARK_FINAL_ACK: | 396 | case RXRPC_SKB_MARK_FINAL_ACK: |
324 | _debug("Rcv ACK"); | 397 | _debug("Rcv ACK"); |
325 | call->state = AFS_CALL_COMPLETE; | 398 | call->state = AFS_CALL_COMPLETE; |
@@ -350,19 +423,19 @@ static void afs_deliver_to_call(struct afs_call *call) | |||
350 | break; | 423 | break; |
351 | } | 424 | } |
352 | 425 | ||
353 | rxrpc_kernel_free_skb(skb); | 426 | afs_free_skb(skb); |
354 | } | 427 | } |
355 | 428 | ||
356 | /* make sure the queue is empty if the call is done with (we might have | 429 | /* make sure the queue is empty if the call is done with (we might have |
357 | * aborted the call early because of an unmarshalling error) */ | 430 | * aborted the call early because of an unmarshalling error) */ |
358 | if (call->state >= AFS_CALL_COMPLETE) { | 431 | if (call->state >= AFS_CALL_COMPLETE) { |
359 | while ((skb = skb_dequeue(&call->rx_queue))) | 432 | while ((skb = skb_dequeue(&call->rx_queue))) |
360 | rxrpc_kernel_free_skb(skb); | 433 | afs_free_skb(skb); |
361 | if (call->incoming) { | 434 | if (call->incoming) { |
362 | rxrpc_kernel_end_call(call->rxcall); | 435 | rxrpc_kernel_end_call(call->rxcall); |
436 | call->rxcall = NULL; | ||
363 | call->type->destructor(call); | 437 | call->type->destructor(call); |
364 | ASSERT(skb_queue_empty(&call->rx_queue)); | 438 | afs_free_call(call); |
365 | kfree(call); | ||
366 | } | 439 | } |
367 | } | 440 | } |
368 | 441 | ||
@@ -409,14 +482,14 @@ static int afs_wait_for_call_to_complete(struct afs_call *call) | |||
409 | _debug("call incomplete"); | 482 | _debug("call incomplete"); |
410 | rxrpc_kernel_abort_call(call->rxcall, RX_CALL_DEAD); | 483 | rxrpc_kernel_abort_call(call->rxcall, RX_CALL_DEAD); |
411 | while ((skb = skb_dequeue(&call->rx_queue))) | 484 | while ((skb = skb_dequeue(&call->rx_queue))) |
412 | rxrpc_kernel_free_skb(skb); | 485 | afs_free_skb(skb); |
413 | } | 486 | } |
414 | 487 | ||
415 | _debug("call complete"); | 488 | _debug("call complete"); |
416 | rxrpc_kernel_end_call(call->rxcall); | 489 | rxrpc_kernel_end_call(call->rxcall); |
490 | call->rxcall = NULL; | ||
417 | call->type->destructor(call); | 491 | call->type->destructor(call); |
418 | ASSERT(skb_queue_empty(&call->rx_queue)); | 492 | afs_free_call(call); |
419 | kfree(call); | ||
420 | _leave(" = %d", ret); | 493 | _leave(" = %d", ret); |
421 | return ret; | 494 | return ret; |
422 | } | 495 | } |
@@ -459,9 +532,7 @@ static void afs_delete_async_call(struct work_struct *work) | |||
459 | 532 | ||
460 | _enter(""); | 533 | _enter(""); |
461 | 534 | ||
462 | ASSERT(skb_queue_empty(&call->rx_queue)); | 535 | afs_free_call(call); |
463 | ASSERT(!work_pending(&call->async_work)); | ||
464 | kfree(call); | ||
465 | 536 | ||
466 | _leave(""); | 537 | _leave(""); |
467 | } | 538 | } |
@@ -489,6 +560,7 @@ static void afs_process_async_call(struct work_struct *work) | |||
489 | 560 | ||
490 | /* kill the call */ | 561 | /* kill the call */ |
491 | rxrpc_kernel_end_call(call->rxcall); | 562 | rxrpc_kernel_end_call(call->rxcall); |
563 | call->rxcall = NULL; | ||
492 | if (call->type->destructor) | 564 | if (call->type->destructor) |
493 | call->type->destructor(call); | 565 | call->type->destructor(call); |
494 | 566 | ||
@@ -526,7 +598,7 @@ static void afs_collect_incoming_call(struct work_struct *work) | |||
526 | _debug("new call"); | 598 | _debug("new call"); |
527 | 599 | ||
528 | /* don't need the notification */ | 600 | /* don't need the notification */ |
529 | rxrpc_kernel_free_skb(skb); | 601 | afs_free_skb(skb); |
530 | 602 | ||
531 | if (!call) { | 603 | if (!call) { |
532 | call = kzalloc(sizeof(struct afs_call), GFP_KERNEL); | 604 | call = kzalloc(sizeof(struct afs_call), GFP_KERNEL); |
@@ -541,6 +613,11 @@ static void afs_collect_incoming_call(struct work_struct *work) | |||
541 | init_waitqueue_head(&call->waitq); | 613 | init_waitqueue_head(&call->waitq); |
542 | skb_queue_head_init(&call->rx_queue); | 614 | skb_queue_head_init(&call->rx_queue); |
543 | call->state = AFS_CALL_AWAIT_OP_ID; | 615 | call->state = AFS_CALL_AWAIT_OP_ID; |
616 | |||
617 | _debug("CALL %p{%s} [%d]", | ||
618 | call, call->type->name, | ||
619 | atomic_read(&afs_outstanding_calls)); | ||
620 | atomic_inc(&afs_outstanding_calls); | ||
544 | } | 621 | } |
545 | 622 | ||
546 | rxcall = rxrpc_kernel_accept_call(afs_socket, | 623 | rxcall = rxrpc_kernel_accept_call(afs_socket, |
@@ -551,7 +628,8 @@ static void afs_collect_incoming_call(struct work_struct *work) | |||
551 | } | 628 | } |
552 | } | 629 | } |
553 | 630 | ||
554 | kfree(call); | 631 | if (call) |
632 | afs_free_call(call); | ||
555 | } | 633 | } |
556 | 634 | ||
557 | /* | 635 | /* |
@@ -629,8 +707,7 @@ void afs_send_empty_reply(struct afs_call *call) | |||
629 | rxrpc_kernel_end_call(call->rxcall); | 707 | rxrpc_kernel_end_call(call->rxcall); |
630 | call->rxcall = NULL; | 708 | call->rxcall = NULL; |
631 | call->type->destructor(call); | 709 | call->type->destructor(call); |
632 | ASSERT(skb_queue_empty(&call->rx_queue)); | 710 | afs_free_call(call); |
633 | kfree(call); | ||
634 | _leave(" [error]"); | 711 | _leave(" [error]"); |
635 | return; | 712 | return; |
636 | } | 713 | } |
diff --git a/fs/afs/security.c b/fs/afs/security.c new file mode 100644 index 000000000000..cbdd7f7162fa --- /dev/null +++ b/fs/afs/security.c | |||
@@ -0,0 +1,345 @@ | |||
1 | /* AFS security handling | ||
2 | * | ||
3 | * Copyright (C) 2007 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 License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/fs.h> | ||
15 | #include <linux/ctype.h> | ||
16 | #include <keys/rxrpc-type.h> | ||
17 | #include "internal.h" | ||
18 | |||
19 | /* | ||
20 | * get a key | ||
21 | */ | ||
22 | struct key *afs_request_key(struct afs_cell *cell) | ||
23 | { | ||
24 | struct key *key; | ||
25 | |||
26 | _enter("{%x}", key_serial(cell->anonymous_key)); | ||
27 | |||
28 | _debug("key %s", cell->anonymous_key->description); | ||
29 | key = request_key(&key_type_rxrpc, cell->anonymous_key->description, | ||
30 | NULL); | ||
31 | if (IS_ERR(key)) { | ||
32 | if (PTR_ERR(key) != -ENOKEY) { | ||
33 | _leave(" = %ld", PTR_ERR(key)); | ||
34 | return key; | ||
35 | } | ||
36 | |||
37 | /* act as anonymous user */ | ||
38 | _leave(" = {%x} [anon]", key_serial(cell->anonymous_key)); | ||
39 | return key_get(cell->anonymous_key); | ||
40 | } else { | ||
41 | /* act as authorised user */ | ||
42 | _leave(" = {%x} [auth]", key_serial(key)); | ||
43 | return key; | ||
44 | } | ||
45 | } | ||
46 | |||
47 | /* | ||
48 | * dispose of a permits list | ||
49 | */ | ||
50 | void afs_zap_permits(struct rcu_head *rcu) | ||
51 | { | ||
52 | struct afs_permits *permits = | ||
53 | container_of(rcu, struct afs_permits, rcu); | ||
54 | int loop; | ||
55 | |||
56 | _enter("{%d}", permits->count); | ||
57 | |||
58 | for (loop = permits->count - 1; loop >= 0; loop--) | ||
59 | key_put(permits->permits[loop].key); | ||
60 | kfree(permits); | ||
61 | } | ||
62 | |||
63 | /* | ||
64 | * dispose of a permits list in which all the key pointers have been copied | ||
65 | */ | ||
66 | static void afs_dispose_of_permits(struct rcu_head *rcu) | ||
67 | { | ||
68 | struct afs_permits *permits = | ||
69 | container_of(rcu, struct afs_permits, rcu); | ||
70 | |||
71 | _enter("{%d}", permits->count); | ||
72 | |||
73 | kfree(permits); | ||
74 | } | ||
75 | |||
76 | /* | ||
77 | * get the authorising vnode - this is the specified inode itself if it's a | ||
78 | * directory or it's the parent directory if the specified inode is a file or | ||
79 | * symlink | ||
80 | * - the caller must release the ref on the inode | ||
81 | */ | ||
82 | static struct afs_vnode *afs_get_auth_inode(struct afs_vnode *vnode, | ||
83 | struct key *key) | ||
84 | { | ||
85 | struct afs_vnode *auth_vnode; | ||
86 | struct inode *auth_inode; | ||
87 | |||
88 | _enter(""); | ||
89 | |||
90 | if (S_ISDIR(vnode->vfs_inode.i_mode)) { | ||
91 | auth_inode = igrab(&vnode->vfs_inode); | ||
92 | ASSERT(auth_inode != NULL); | ||
93 | } else { | ||
94 | auth_inode = afs_iget(vnode->vfs_inode.i_sb, key, | ||
95 | &vnode->status.parent); | ||
96 | if (IS_ERR(auth_inode)) | ||
97 | return ERR_PTR(PTR_ERR(auth_inode)); | ||
98 | } | ||
99 | |||
100 | auth_vnode = AFS_FS_I(auth_inode); | ||
101 | _leave(" = {%x}", auth_vnode->fid.vnode); | ||
102 | return auth_vnode; | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * clear the permit cache on a directory vnode | ||
107 | */ | ||
108 | void afs_clear_permits(struct afs_vnode *vnode) | ||
109 | { | ||
110 | struct afs_permits *permits; | ||
111 | |||
112 | _enter("{%x}", vnode->fid.vnode); | ||
113 | |||
114 | mutex_lock(&vnode->permits_lock); | ||
115 | permits = vnode->permits; | ||
116 | rcu_assign_pointer(vnode->permits, NULL); | ||
117 | mutex_unlock(&vnode->permits_lock); | ||
118 | |||
119 | if (permits) | ||
120 | call_rcu(&permits->rcu, afs_zap_permits); | ||
121 | _leave(""); | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * add the result obtained for a vnode to its or its parent directory's cache | ||
126 | * for the key used to access it | ||
127 | */ | ||
128 | void afs_cache_permit(struct afs_vnode *vnode, struct key *key, long acl_order) | ||
129 | { | ||
130 | struct afs_permits *permits, *xpermits; | ||
131 | struct afs_permit *permit; | ||
132 | struct afs_vnode *auth_vnode; | ||
133 | int count, loop; | ||
134 | |||
135 | _enter("{%x},%x,%lx", vnode->fid.vnode, key_serial(key), acl_order); | ||
136 | |||
137 | auth_vnode = afs_get_auth_inode(vnode, key); | ||
138 | if (IS_ERR(auth_vnode)) { | ||
139 | _leave(" [get error %ld]", PTR_ERR(auth_vnode)); | ||
140 | return; | ||
141 | } | ||
142 | |||
143 | mutex_lock(&auth_vnode->permits_lock); | ||
144 | |||
145 | /* guard against a rename being detected whilst we waited for the | ||
146 | * lock */ | ||
147 | if (memcmp(&auth_vnode->fid, &vnode->status.parent, | ||
148 | sizeof(struct afs_fid)) != 0) { | ||
149 | _debug("renamed"); | ||
150 | goto out_unlock; | ||
151 | } | ||
152 | |||
153 | /* have to be careful as the directory's callback may be broken between | ||
154 | * us receiving the status we're trying to cache and us getting the | ||
155 | * lock to update the cache for the status */ | ||
156 | if (auth_vnode->acl_order - acl_order > 0) { | ||
157 | _debug("ACL changed?"); | ||
158 | goto out_unlock; | ||
159 | } | ||
160 | |||
161 | /* always update the anonymous mask */ | ||
162 | _debug("anon access %x", vnode->status.anon_access); | ||
163 | auth_vnode->status.anon_access = vnode->status.anon_access; | ||
164 | if (key == vnode->volume->cell->anonymous_key) | ||
165 | goto out_unlock; | ||
166 | |||
167 | xpermits = auth_vnode->permits; | ||
168 | count = 0; | ||
169 | if (xpermits) { | ||
170 | /* see if the permit is already in the list | ||
171 | * - if it is then we just amend the list | ||
172 | */ | ||
173 | count = xpermits->count; | ||
174 | permit = xpermits->permits; | ||
175 | for (loop = count; loop > 0; loop--) { | ||
176 | if (permit->key == key) { | ||
177 | permit->access_mask = | ||
178 | vnode->status.caller_access; | ||
179 | goto out_unlock; | ||
180 | } | ||
181 | permit++; | ||
182 | } | ||
183 | } | ||
184 | |||
185 | permits = kmalloc(sizeof(*permits) + sizeof(*permit) * (count + 1), | ||
186 | GFP_NOFS); | ||
187 | if (!permits) | ||
188 | goto out_unlock; | ||
189 | |||
190 | memcpy(permits->permits, xpermits->permits, | ||
191 | count * sizeof(struct afs_permit)); | ||
192 | |||
193 | _debug("key %x access %x", | ||
194 | key_serial(key), vnode->status.caller_access); | ||
195 | permits->permits[count].access_mask = vnode->status.caller_access; | ||
196 | permits->permits[count].key = key_get(key); | ||
197 | permits->count = count + 1; | ||
198 | |||
199 | rcu_assign_pointer(auth_vnode->permits, permits); | ||
200 | if (xpermits) | ||
201 | call_rcu(&xpermits->rcu, afs_dispose_of_permits); | ||
202 | |||
203 | out_unlock: | ||
204 | mutex_unlock(&auth_vnode->permits_lock); | ||
205 | iput(&auth_vnode->vfs_inode); | ||
206 | _leave(""); | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * check with the fileserver to see if the directory or parent directory is | ||
211 | * permitted to be accessed with this authorisation, and if so, what access it | ||
212 | * is granted | ||
213 | */ | ||
214 | static int afs_check_permit(struct afs_vnode *vnode, struct key *key, | ||
215 | afs_access_t *_access) | ||
216 | { | ||
217 | struct afs_permits *permits; | ||
218 | struct afs_permit *permit; | ||
219 | struct afs_vnode *auth_vnode; | ||
220 | bool valid; | ||
221 | int loop, ret; | ||
222 | |||
223 | _enter(""); | ||
224 | |||
225 | auth_vnode = afs_get_auth_inode(vnode, key); | ||
226 | if (IS_ERR(auth_vnode)) { | ||
227 | *_access = 0; | ||
228 | _leave(" = %ld", PTR_ERR(auth_vnode)); | ||
229 | return PTR_ERR(auth_vnode); | ||
230 | } | ||
231 | |||
232 | ASSERT(S_ISDIR(auth_vnode->vfs_inode.i_mode)); | ||
233 | |||
234 | /* check the permits to see if we've got one yet */ | ||
235 | if (key == auth_vnode->volume->cell->anonymous_key) { | ||
236 | _debug("anon"); | ||
237 | *_access = auth_vnode->status.anon_access; | ||
238 | valid = true; | ||
239 | } else { | ||
240 | valid = false; | ||
241 | rcu_read_lock(); | ||
242 | permits = rcu_dereference(auth_vnode->permits); | ||
243 | if (permits) { | ||
244 | permit = permits->permits; | ||
245 | for (loop = permits->count; loop > 0; loop--) { | ||
246 | if (permit->key == key) { | ||
247 | _debug("found in cache"); | ||
248 | *_access = permit->access_mask; | ||
249 | valid = true; | ||
250 | break; | ||
251 | } | ||
252 | permit++; | ||
253 | } | ||
254 | } | ||
255 | rcu_read_unlock(); | ||
256 | } | ||
257 | |||
258 | if (!valid) { | ||
259 | /* check the status on the file we're actually interested in | ||
260 | * (the post-processing will cache the result on auth_vnode) */ | ||
261 | _debug("no valid permit"); | ||
262 | |||
263 | set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); | ||
264 | ret = afs_vnode_fetch_status(vnode, auth_vnode, key); | ||
265 | if (ret < 0) { | ||
266 | iput(&auth_vnode->vfs_inode); | ||
267 | *_access = 0; | ||
268 | _leave(" = %d", ret); | ||
269 | return ret; | ||
270 | } | ||
271 | } | ||
272 | |||
273 | *_access = vnode->status.caller_access; | ||
274 | iput(&auth_vnode->vfs_inode); | ||
275 | _leave(" = 0 [access %x]", *_access); | ||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | /* | ||
280 | * check the permissions on an AFS file | ||
281 | * - AFS ACLs are attached to directories only, and a file is controlled by its | ||
282 | * parent directory's ACL | ||
283 | */ | ||
284 | int afs_permission(struct inode *inode, int mask, struct nameidata *nd) | ||
285 | { | ||
286 | struct afs_vnode *vnode = AFS_FS_I(inode); | ||
287 | afs_access_t access; | ||
288 | struct key *key; | ||
289 | int ret; | ||
290 | |||
291 | _enter("{%x:%x},%x,", vnode->fid.vid, vnode->fid.vnode, mask); | ||
292 | |||
293 | key = afs_request_key(vnode->volume->cell); | ||
294 | if (IS_ERR(key)) { | ||
295 | _leave(" = %ld [key]", PTR_ERR(key)); | ||
296 | return PTR_ERR(key); | ||
297 | } | ||
298 | |||
299 | /* check the permits to see if we've got one yet */ | ||
300 | ret = afs_check_permit(vnode, key, &access); | ||
301 | if (ret < 0) { | ||
302 | key_put(key); | ||
303 | _leave(" = %d [check]", ret); | ||
304 | return ret; | ||
305 | } | ||
306 | |||
307 | /* interpret the access mask */ | ||
308 | _debug("REQ %x ACC %x on %s", | ||
309 | mask, access, S_ISDIR(inode->i_mode) ? "dir" : "file"); | ||
310 | |||
311 | if (S_ISDIR(inode->i_mode)) { | ||
312 | if (mask & MAY_EXEC) { | ||
313 | if (!(access & AFS_ACE_LOOKUP)) | ||
314 | goto permission_denied; | ||
315 | } else if (mask & MAY_READ) { | ||
316 | if (!(access & AFS_ACE_READ)) | ||
317 | goto permission_denied; | ||
318 | } else if (mask & MAY_WRITE) { | ||
319 | if (!(access & (AFS_ACE_DELETE | /* rmdir, unlink, rename from */ | ||
320 | AFS_ACE_INSERT | /* create, mkdir, symlink, rename to */ | ||
321 | AFS_ACE_WRITE))) /* chmod */ | ||
322 | goto permission_denied; | ||
323 | } else { | ||
324 | BUG(); | ||
325 | } | ||
326 | } else { | ||
327 | if (!(access & AFS_ACE_LOOKUP)) | ||
328 | goto permission_denied; | ||
329 | if (mask & (MAY_EXEC | MAY_READ)) { | ||
330 | if (!(access & AFS_ACE_READ)) | ||
331 | goto permission_denied; | ||
332 | } else if (mask & MAY_WRITE) { | ||
333 | if (!(access & AFS_ACE_WRITE)) | ||
334 | goto permission_denied; | ||
335 | } | ||
336 | } | ||
337 | |||
338 | key_put(key); | ||
339 | return generic_permission(inode, mask, NULL); | ||
340 | |||
341 | permission_denied: | ||
342 | key_put(key); | ||
343 | _leave(" = -EACCES"); | ||
344 | return -EACCES; | ||
345 | } | ||
diff --git a/fs/afs/super.c b/fs/afs/super.c index 77e68759788f..497350a5463b 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c | |||
@@ -24,12 +24,6 @@ | |||
24 | 24 | ||
25 | #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */ | 25 | #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */ |
26 | 26 | ||
27 | struct afs_mount_params { | ||
28 | int rwpath; | ||
29 | struct afs_cell *default_cell; | ||
30 | struct afs_volume *volume; | ||
31 | }; | ||
32 | |||
33 | static void afs_i_init_once(void *foo, struct kmem_cache *cachep, | 27 | static void afs_i_init_once(void *foo, struct kmem_cache *cachep, |
34 | unsigned long flags); | 28 | unsigned long flags); |
35 | 29 | ||
@@ -150,8 +144,8 @@ static int want_no_value(char *const *_value, const char *option) | |||
150 | * - this function has been shamelessly adapted from the ext3 fs which | 144 | * - this function has been shamelessly adapted from the ext3 fs which |
151 | * shamelessly adapted it from the msdos fs | 145 | * shamelessly adapted it from the msdos fs |
152 | */ | 146 | */ |
153 | static int afs_super_parse_options(struct afs_mount_params *params, | 147 | static int afs_parse_options(struct afs_mount_params *params, |
154 | char *options, const char **devname) | 148 | char *options, const char **devname) |
155 | { | 149 | { |
156 | struct afs_cell *cell; | 150 | struct afs_cell *cell; |
157 | char *key, *value; | 151 | char *key, *value; |
@@ -183,8 +177,8 @@ static int afs_super_parse_options(struct afs_mount_params *params, | |||
183 | cell = afs_cell_lookup(value, strlen(value)); | 177 | cell = afs_cell_lookup(value, strlen(value)); |
184 | if (IS_ERR(cell)) | 178 | if (IS_ERR(cell)) |
185 | return PTR_ERR(cell); | 179 | return PTR_ERR(cell); |
186 | afs_put_cell(params->default_cell); | 180 | afs_put_cell(params->cell); |
187 | params->default_cell = cell; | 181 | params->cell = cell; |
188 | } else { | 182 | } else { |
189 | printk("kAFS: Unknown mount option: '%s'\n", key); | 183 | printk("kAFS: Unknown mount option: '%s'\n", key); |
190 | ret = -EINVAL; | 184 | ret = -EINVAL; |
@@ -199,6 +193,99 @@ error: | |||
199 | } | 193 | } |
200 | 194 | ||
201 | /* | 195 | /* |
196 | * parse a device name to get cell name, volume name, volume type and R/W | ||
197 | * selector | ||
198 | * - this can be one of the following: | ||
199 | * "%[cell:]volume[.]" R/W volume | ||
200 | * "#[cell:]volume[.]" R/O or R/W volume (rwpath=0), | ||
201 | * or R/W (rwpath=1) volume | ||
202 | * "%[cell:]volume.readonly" R/O volume | ||
203 | * "#[cell:]volume.readonly" R/O volume | ||
204 | * "%[cell:]volume.backup" Backup volume | ||
205 | * "#[cell:]volume.backup" Backup volume | ||
206 | */ | ||
207 | static int afs_parse_device_name(struct afs_mount_params *params, | ||
208 | const char *name) | ||
209 | { | ||
210 | struct afs_cell *cell; | ||
211 | const char *cellname, *suffix; | ||
212 | int cellnamesz; | ||
213 | |||
214 | _enter(",%s", name); | ||
215 | |||
216 | if (!name) { | ||
217 | printk(KERN_ERR "kAFS: no volume name specified\n"); | ||
218 | return -EINVAL; | ||
219 | } | ||
220 | |||
221 | if ((name[0] != '%' && name[0] != '#') || !name[1]) { | ||
222 | printk(KERN_ERR "kAFS: unparsable volume name\n"); | ||
223 | return -EINVAL; | ||
224 | } | ||
225 | |||
226 | /* determine the type of volume we're looking for */ | ||
227 | params->type = AFSVL_ROVOL; | ||
228 | params->force = false; | ||
229 | if (params->rwpath || name[0] == '%') { | ||
230 | params->type = AFSVL_RWVOL; | ||
231 | params->force = true; | ||
232 | } | ||
233 | name++; | ||
234 | |||
235 | /* split the cell name out if there is one */ | ||
236 | params->volname = strchr(name, ':'); | ||
237 | if (params->volname) { | ||
238 | cellname = name; | ||
239 | cellnamesz = params->volname - name; | ||
240 | params->volname++; | ||
241 | } else { | ||
242 | params->volname = name; | ||
243 | cellname = NULL; | ||
244 | cellnamesz = 0; | ||
245 | } | ||
246 | |||
247 | /* the volume type is further affected by a possible suffix */ | ||
248 | suffix = strrchr(params->volname, '.'); | ||
249 | if (suffix) { | ||
250 | if (strcmp(suffix, ".readonly") == 0) { | ||
251 | params->type = AFSVL_ROVOL; | ||
252 | params->force = true; | ||
253 | } else if (strcmp(suffix, ".backup") == 0) { | ||
254 | params->type = AFSVL_BACKVOL; | ||
255 | params->force = true; | ||
256 | } else if (suffix[1] == 0) { | ||
257 | } else { | ||
258 | suffix = NULL; | ||
259 | } | ||
260 | } | ||
261 | |||
262 | params->volnamesz = suffix ? | ||
263 | suffix - params->volname : strlen(params->volname); | ||
264 | |||
265 | _debug("cell %*.*s [%p]", | ||
266 | cellnamesz, cellnamesz, cellname ?: "", params->cell); | ||
267 | |||
268 | /* lookup the cell record */ | ||
269 | if (cellname || !params->cell) { | ||
270 | cell = afs_cell_lookup(cellname, cellnamesz); | ||
271 | if (IS_ERR(cell)) { | ||
272 | printk(KERN_ERR "kAFS: unable to lookup cell '%s'\n", | ||
273 | cellname ?: ""); | ||
274 | return PTR_ERR(cell); | ||
275 | } | ||
276 | afs_put_cell(params->cell); | ||
277 | params->cell = cell; | ||
278 | } | ||
279 | |||
280 | _debug("CELL:%s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s", | ||
281 | params->cell->name, params->cell, | ||
282 | params->volnamesz, params->volnamesz, params->volname, | ||
283 | suffix ?: "-", params->type, params->force ? " FORCE" : ""); | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | /* | ||
202 | * check a superblock to see if it's the one we're looking for | 289 | * check a superblock to see if it's the one we're looking for |
203 | */ | 290 | */ |
204 | static int afs_test_super(struct super_block *sb, void *data) | 291 | static int afs_test_super(struct super_block *sb, void *data) |
@@ -244,7 +331,7 @@ static int afs_fill_super(struct super_block *sb, void *data) | |||
244 | fid.vid = as->volume->vid; | 331 | fid.vid = as->volume->vid; |
245 | fid.vnode = 1; | 332 | fid.vnode = 1; |
246 | fid.unique = 1; | 333 | fid.unique = 1; |
247 | inode = afs_iget(sb, &fid); | 334 | inode = afs_iget(sb, params->key, &fid); |
248 | if (IS_ERR(inode)) | 335 | if (IS_ERR(inode)) |
249 | goto error_inode; | 336 | goto error_inode; |
250 | 337 | ||
@@ -285,31 +372,40 @@ static int afs_get_sb(struct file_system_type *fs_type, | |||
285 | struct afs_mount_params params; | 372 | struct afs_mount_params params; |
286 | struct super_block *sb; | 373 | struct super_block *sb; |
287 | struct afs_volume *vol; | 374 | struct afs_volume *vol; |
375 | struct key *key; | ||
288 | int ret; | 376 | int ret; |
289 | 377 | ||
290 | _enter(",,%s,%p", dev_name, options); | 378 | _enter(",,%s,%p", dev_name, options); |
291 | 379 | ||
292 | memset(¶ms, 0, sizeof(params)); | 380 | memset(¶ms, 0, sizeof(params)); |
293 | 381 | ||
294 | /* parse the options */ | 382 | /* parse the options and device name */ |
295 | if (options) { | 383 | if (options) { |
296 | ret = afs_super_parse_options(¶ms, options, &dev_name); | 384 | ret = afs_parse_options(¶ms, options, &dev_name); |
297 | if (ret < 0) | 385 | if (ret < 0) |
298 | goto error; | 386 | goto error; |
299 | if (!dev_name) { | ||
300 | printk("kAFS: no volume name specified\n"); | ||
301 | ret = -EINVAL; | ||
302 | goto error; | ||
303 | } | ||
304 | } | 387 | } |
305 | 388 | ||
389 | |||
390 | ret = afs_parse_device_name(¶ms, dev_name); | ||
391 | if (ret < 0) | ||
392 | goto error; | ||
393 | |||
394 | /* try and do the mount securely */ | ||
395 | key = afs_request_key(params.cell); | ||
396 | if (IS_ERR(key)) { | ||
397 | _leave(" = %ld [key]", PTR_ERR(key)); | ||
398 | ret = PTR_ERR(key); | ||
399 | goto error; | ||
400 | } | ||
401 | params.key = key; | ||
402 | |||
306 | /* parse the device name */ | 403 | /* parse the device name */ |
307 | vol = afs_volume_lookup(dev_name, params.default_cell, params.rwpath); | 404 | vol = afs_volume_lookup(¶ms); |
308 | if (IS_ERR(vol)) { | 405 | if (IS_ERR(vol)) { |
309 | ret = PTR_ERR(vol); | 406 | ret = PTR_ERR(vol); |
310 | goto error; | 407 | goto error; |
311 | } | 408 | } |
312 | |||
313 | params.volume = vol; | 409 | params.volume = vol; |
314 | 410 | ||
315 | /* allocate a deviceless superblock */ | 411 | /* allocate a deviceless superblock */ |
@@ -337,13 +433,14 @@ static int afs_get_sb(struct file_system_type *fs_type, | |||
337 | 433 | ||
338 | simple_set_mnt(mnt, sb); | 434 | simple_set_mnt(mnt, sb); |
339 | afs_put_volume(params.volume); | 435 | afs_put_volume(params.volume); |
340 | afs_put_cell(params.default_cell); | 436 | afs_put_cell(params.cell); |
341 | _leave(" = 0 [%p]", sb); | 437 | _leave(" = 0 [%p]", sb); |
342 | return 0; | 438 | return 0; |
343 | 439 | ||
344 | error: | 440 | error: |
345 | afs_put_volume(params.volume); | 441 | afs_put_volume(params.volume); |
346 | afs_put_cell(params.default_cell); | 442 | afs_put_cell(params.cell); |
443 | key_put(params.key); | ||
347 | _leave(" = %d", ret); | 444 | _leave(" = %d", ret); |
348 | return ret; | 445 | return ret; |
349 | } | 446 | } |
@@ -375,6 +472,7 @@ static void afs_i_init_once(void *_vnode, struct kmem_cache *cachep, | |||
375 | memset(vnode, 0, sizeof(*vnode)); | 472 | memset(vnode, 0, sizeof(*vnode)); |
376 | inode_init_once(&vnode->vfs_inode); | 473 | inode_init_once(&vnode->vfs_inode); |
377 | init_waitqueue_head(&vnode->update_waitq); | 474 | init_waitqueue_head(&vnode->update_waitq); |
475 | mutex_init(&vnode->permits_lock); | ||
378 | spin_lock_init(&vnode->lock); | 476 | spin_lock_init(&vnode->lock); |
379 | INIT_WORK(&vnode->cb_broken_work, afs_broken_callback_work); | 477 | INIT_WORK(&vnode->cb_broken_work, afs_broken_callback_work); |
380 | mutex_init(&vnode->cb_broken_lock); | 478 | mutex_init(&vnode->cb_broken_lock); |
diff --git a/fs/afs/vlclient.c b/fs/afs/vlclient.c index 0c7eba174836..36c1306e09e0 100644 --- a/fs/afs/vlclient.c +++ b/fs/afs/vlclient.c | |||
@@ -127,6 +127,7 @@ static int afs_deliver_vl_get_entry_by_xxx(struct afs_call *call, | |||
127 | * VL.GetEntryByName operation type | 127 | * VL.GetEntryByName operation type |
128 | */ | 128 | */ |
129 | static const struct afs_call_type afs_RXVLGetEntryByName = { | 129 | static const struct afs_call_type afs_RXVLGetEntryByName = { |
130 | .name = "VL.GetEntryByName", | ||
130 | .deliver = afs_deliver_vl_get_entry_by_xxx, | 131 | .deliver = afs_deliver_vl_get_entry_by_xxx, |
131 | .abort_to_error = afs_vl_abort_to_error, | 132 | .abort_to_error = afs_vl_abort_to_error, |
132 | .destructor = afs_flat_call_destructor, | 133 | .destructor = afs_flat_call_destructor, |
@@ -136,6 +137,7 @@ static const struct afs_call_type afs_RXVLGetEntryByName = { | |||
136 | * VL.GetEntryById operation type | 137 | * VL.GetEntryById operation type |
137 | */ | 138 | */ |
138 | static const struct afs_call_type afs_RXVLGetEntryById = { | 139 | static const struct afs_call_type afs_RXVLGetEntryById = { |
140 | .name = "VL.GetEntryById", | ||
139 | .deliver = afs_deliver_vl_get_entry_by_xxx, | 141 | .deliver = afs_deliver_vl_get_entry_by_xxx, |
140 | .abort_to_error = afs_vl_abort_to_error, | 142 | .abort_to_error = afs_vl_abort_to_error, |
141 | .destructor = afs_flat_call_destructor, | 143 | .destructor = afs_flat_call_destructor, |
@@ -145,6 +147,7 @@ static const struct afs_call_type afs_RXVLGetEntryById = { | |||
145 | * dispatch a get volume entry by name operation | 147 | * dispatch a get volume entry by name operation |
146 | */ | 148 | */ |
147 | int afs_vl_get_entry_by_name(struct in_addr *addr, | 149 | int afs_vl_get_entry_by_name(struct in_addr *addr, |
150 | struct key *key, | ||
148 | const char *volname, | 151 | const char *volname, |
149 | struct afs_cache_vlocation *entry, | 152 | struct afs_cache_vlocation *entry, |
150 | const struct afs_wait_mode *wait_mode) | 153 | const struct afs_wait_mode *wait_mode) |
@@ -163,6 +166,7 @@ int afs_vl_get_entry_by_name(struct in_addr *addr, | |||
163 | if (!call) | 166 | if (!call) |
164 | return -ENOMEM; | 167 | return -ENOMEM; |
165 | 168 | ||
169 | call->key = key; | ||
166 | call->reply = entry; | 170 | call->reply = entry; |
167 | call->service_id = VL_SERVICE; | 171 | call->service_id = VL_SERVICE; |
168 | call->port = htons(AFS_VL_PORT); | 172 | call->port = htons(AFS_VL_PORT); |
@@ -183,6 +187,7 @@ int afs_vl_get_entry_by_name(struct in_addr *addr, | |||
183 | * dispatch a get volume entry by ID operation | 187 | * dispatch a get volume entry by ID operation |
184 | */ | 188 | */ |
185 | int afs_vl_get_entry_by_id(struct in_addr *addr, | 189 | int afs_vl_get_entry_by_id(struct in_addr *addr, |
190 | struct key *key, | ||
186 | afs_volid_t volid, | 191 | afs_volid_t volid, |
187 | afs_voltype_t voltype, | 192 | afs_voltype_t voltype, |
188 | struct afs_cache_vlocation *entry, | 193 | struct afs_cache_vlocation *entry, |
@@ -197,6 +202,7 @@ int afs_vl_get_entry_by_id(struct in_addr *addr, | |||
197 | if (!call) | 202 | if (!call) |
198 | return -ENOMEM; | 203 | return -ENOMEM; |
199 | 204 | ||
205 | call->key = key; | ||
200 | call->reply = entry; | 206 | call->reply = entry; |
201 | call->service_id = VL_SERVICE; | 207 | call->service_id = VL_SERVICE; |
202 | call->port = htons(AFS_VL_PORT); | 208 | call->port = htons(AFS_VL_PORT); |
diff --git a/fs/afs/vlocation.c b/fs/afs/vlocation.c index 60cb2f408c75..7d9815e9ae0f 100644 --- a/fs/afs/vlocation.c +++ b/fs/afs/vlocation.c | |||
@@ -33,6 +33,7 @@ static struct workqueue_struct *afs_vlocation_update_worker; | |||
33 | * about the volume in question | 33 | * about the volume in question |
34 | */ | 34 | */ |
35 | static int afs_vlocation_access_vl_by_name(struct afs_vlocation *vl, | 35 | static int afs_vlocation_access_vl_by_name(struct afs_vlocation *vl, |
36 | struct key *key, | ||
36 | struct afs_cache_vlocation *vldb) | 37 | struct afs_cache_vlocation *vldb) |
37 | { | 38 | { |
38 | struct afs_cell *cell = vl->cell; | 39 | struct afs_cell *cell = vl->cell; |
@@ -49,7 +50,7 @@ static int afs_vlocation_access_vl_by_name(struct afs_vlocation *vl, | |||
49 | _debug("CellServ[%hu]: %08x", cell->vl_curr_svix, addr.s_addr); | 50 | _debug("CellServ[%hu]: %08x", cell->vl_curr_svix, addr.s_addr); |
50 | 51 | ||
51 | /* attempt to access the VL server */ | 52 | /* attempt to access the VL server */ |
52 | ret = afs_vl_get_entry_by_name(&addr, vl->vldb.name, vldb, | 53 | ret = afs_vl_get_entry_by_name(&addr, key, vl->vldb.name, vldb, |
53 | &afs_sync_call); | 54 | &afs_sync_call); |
54 | switch (ret) { | 55 | switch (ret) { |
55 | case 0: | 56 | case 0: |
@@ -86,6 +87,7 @@ out: | |||
86 | * about the volume in question | 87 | * about the volume in question |
87 | */ | 88 | */ |
88 | static int afs_vlocation_access_vl_by_id(struct afs_vlocation *vl, | 89 | static int afs_vlocation_access_vl_by_id(struct afs_vlocation *vl, |
90 | struct key *key, | ||
89 | afs_volid_t volid, | 91 | afs_volid_t volid, |
90 | afs_voltype_t voltype, | 92 | afs_voltype_t voltype, |
91 | struct afs_cache_vlocation *vldb) | 93 | struct afs_cache_vlocation *vldb) |
@@ -104,7 +106,7 @@ static int afs_vlocation_access_vl_by_id(struct afs_vlocation *vl, | |||
104 | _debug("CellServ[%hu]: %08x", cell->vl_curr_svix, addr.s_addr); | 106 | _debug("CellServ[%hu]: %08x", cell->vl_curr_svix, addr.s_addr); |
105 | 107 | ||
106 | /* attempt to access the VL server */ | 108 | /* attempt to access the VL server */ |
107 | ret = afs_vl_get_entry_by_id(&addr, volid, voltype, vldb, | 109 | ret = afs_vl_get_entry_by_id(&addr, key, volid, voltype, vldb, |
108 | &afs_sync_call); | 110 | &afs_sync_call); |
109 | switch (ret) { | 111 | switch (ret) { |
110 | case 0: | 112 | case 0: |
@@ -188,6 +190,7 @@ static struct afs_vlocation *afs_vlocation_alloc(struct afs_cell *cell, | |||
188 | * update record if we found it in the cache | 190 | * update record if we found it in the cache |
189 | */ | 191 | */ |
190 | static int afs_vlocation_update_record(struct afs_vlocation *vl, | 192 | static int afs_vlocation_update_record(struct afs_vlocation *vl, |
193 | struct key *key, | ||
191 | struct afs_cache_vlocation *vldb) | 194 | struct afs_cache_vlocation *vldb) |
192 | { | 195 | { |
193 | afs_voltype_t voltype; | 196 | afs_voltype_t voltype; |
@@ -228,7 +231,7 @@ static int afs_vlocation_update_record(struct afs_vlocation *vl, | |||
228 | /* contact the server to make sure the volume is still available | 231 | /* contact the server to make sure the volume is still available |
229 | * - TODO: need to handle disconnected operation here | 232 | * - TODO: need to handle disconnected operation here |
230 | */ | 233 | */ |
231 | ret = afs_vlocation_access_vl_by_id(vl, vid, voltype, vldb); | 234 | ret = afs_vlocation_access_vl_by_id(vl, key, vid, voltype, vldb); |
232 | switch (ret) { | 235 | switch (ret) { |
233 | /* net error */ | 236 | /* net error */ |
234 | default: | 237 | default: |
@@ -287,7 +290,8 @@ static void afs_vlocation_apply_update(struct afs_vlocation *vl, | |||
287 | * fill in a volume location record, consulting the cache and the VL server | 290 | * fill in a volume location record, consulting the cache and the VL server |
288 | * both | 291 | * both |
289 | */ | 292 | */ |
290 | static int afs_vlocation_fill_in_record(struct afs_vlocation *vl) | 293 | static int afs_vlocation_fill_in_record(struct afs_vlocation *vl, |
294 | struct key *key) | ||
291 | { | 295 | { |
292 | struct afs_cache_vlocation vldb; | 296 | struct afs_cache_vlocation vldb; |
293 | int ret; | 297 | int ret; |
@@ -310,11 +314,11 @@ static int afs_vlocation_fill_in_record(struct afs_vlocation *vl) | |||
310 | /* try to update a known volume in the cell VL databases by | 314 | /* try to update a known volume in the cell VL databases by |
311 | * ID as the name may have changed */ | 315 | * ID as the name may have changed */ |
312 | _debug("found in cache"); | 316 | _debug("found in cache"); |
313 | ret = afs_vlocation_update_record(vl, &vldb); | 317 | ret = afs_vlocation_update_record(vl, key, &vldb); |
314 | } else { | 318 | } else { |
315 | /* try to look up an unknown volume in the cell VL databases by | 319 | /* try to look up an unknown volume in the cell VL databases by |
316 | * name */ | 320 | * name */ |
317 | ret = afs_vlocation_access_vl_by_name(vl, &vldb); | 321 | ret = afs_vlocation_access_vl_by_name(vl, key, &vldb); |
318 | if (ret < 0) { | 322 | if (ret < 0) { |
319 | printk("kAFS: failed to locate '%s' in cell '%s'\n", | 323 | printk("kAFS: failed to locate '%s' in cell '%s'\n", |
320 | vl->vldb.name, vl->cell->name); | 324 | vl->vldb.name, vl->cell->name); |
@@ -366,14 +370,16 @@ void afs_vlocation_queue_for_updates(struct afs_vlocation *vl) | |||
366 | * - insert/update in the local cache if did get a VL response | 370 | * - insert/update in the local cache if did get a VL response |
367 | */ | 371 | */ |
368 | struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *cell, | 372 | struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *cell, |
373 | struct key *key, | ||
369 | const char *name, | 374 | const char *name, |
370 | size_t namesz) | 375 | size_t namesz) |
371 | { | 376 | { |
372 | struct afs_vlocation *vl; | 377 | struct afs_vlocation *vl; |
373 | int ret; | 378 | int ret; |
374 | 379 | ||
375 | _enter("{%s},%*.*s,%zu", | 380 | _enter("{%s},{%x},%*.*s,%zu", |
376 | cell->name, (int) namesz, (int) namesz, name, namesz); | 381 | cell->name, key_serial(key), |
382 | (int) namesz, (int) namesz, name, namesz); | ||
377 | 383 | ||
378 | if (namesz > sizeof(vl->vldb.name)) { | 384 | if (namesz > sizeof(vl->vldb.name)) { |
379 | _leave(" = -ENAMETOOLONG"); | 385 | _leave(" = -ENAMETOOLONG"); |
@@ -405,7 +411,7 @@ struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *cell, | |||
405 | up_write(&cell->vl_sem); | 411 | up_write(&cell->vl_sem); |
406 | 412 | ||
407 | fill_in_record: | 413 | fill_in_record: |
408 | ret = afs_vlocation_fill_in_record(vl); | 414 | ret = afs_vlocation_fill_in_record(vl, key); |
409 | if (ret < 0) | 415 | if (ret < 0) |
410 | goto error_abandon; | 416 | goto error_abandon; |
411 | vl->state = AFS_VL_VALID; | 417 | vl->state = AFS_VL_VALID; |
@@ -656,7 +662,7 @@ static void afs_vlocation_updater(struct work_struct *work) | |||
656 | vl->upd_rej_cnt = 0; | 662 | vl->upd_rej_cnt = 0; |
657 | vl->upd_busy_cnt = 0; | 663 | vl->upd_busy_cnt = 0; |
658 | 664 | ||
659 | ret = afs_vlocation_update_record(vl, &vldb); | 665 | ret = afs_vlocation_update_record(vl, NULL, &vldb); |
660 | switch (ret) { | 666 | switch (ret) { |
661 | case 0: | 667 | case 0: |
662 | afs_vlocation_apply_update(vl, &vldb); | 668 | afs_vlocation_apply_update(vl, &vldb); |
diff --git a/fs/afs/vnode.c b/fs/afs/vnode.c index d2ca1398474f..160097619ec7 100644 --- a/fs/afs/vnode.c +++ b/fs/afs/vnode.c | |||
@@ -238,9 +238,11 @@ static void afs_vnode_finalise_status_update(struct afs_vnode *vnode, | |||
238 | * - there are any outstanding ops that will fetch the status | 238 | * - there are any outstanding ops that will fetch the status |
239 | * - TODO implement local caching | 239 | * - TODO implement local caching |
240 | */ | 240 | */ |
241 | int afs_vnode_fetch_status(struct afs_vnode *vnode) | 241 | int afs_vnode_fetch_status(struct afs_vnode *vnode, |
242 | struct afs_vnode *auth_vnode, struct key *key) | ||
242 | { | 243 | { |
243 | struct afs_server *server; | 244 | struct afs_server *server; |
245 | unsigned long acl_order; | ||
244 | int ret; | 246 | int ret; |
245 | 247 | ||
246 | DECLARE_WAITQUEUE(myself, current); | 248 | DECLARE_WAITQUEUE(myself, current); |
@@ -260,6 +262,10 @@ int afs_vnode_fetch_status(struct afs_vnode *vnode) | |||
260 | return -ENOENT; | 262 | return -ENOENT; |
261 | } | 263 | } |
262 | 264 | ||
265 | acl_order = 0; | ||
266 | if (auth_vnode) | ||
267 | acl_order = auth_vnode->acl_order; | ||
268 | |||
263 | spin_lock(&vnode->lock); | 269 | spin_lock(&vnode->lock); |
264 | 270 | ||
265 | if (!test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) && | 271 | if (!test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) && |
@@ -324,12 +330,14 @@ get_anyway: | |||
324 | _debug("USING SERVER: %p{%08x}", | 330 | _debug("USING SERVER: %p{%08x}", |
325 | server, ntohl(server->addr.s_addr)); | 331 | server, ntohl(server->addr.s_addr)); |
326 | 332 | ||
327 | ret = afs_fs_fetch_file_status(server, vnode, NULL, | 333 | ret = afs_fs_fetch_file_status(server, key, vnode, NULL, |
328 | &afs_sync_call); | 334 | &afs_sync_call); |
329 | 335 | ||
330 | } while (!afs_volume_release_fileserver(vnode, server, ret)); | 336 | } while (!afs_volume_release_fileserver(vnode, server, ret)); |
331 | 337 | ||
332 | /* adjust the flags */ | 338 | /* adjust the flags */ |
339 | if (ret == 0 && auth_vnode) | ||
340 | afs_cache_permit(vnode, key, acl_order); | ||
333 | afs_vnode_finalise_status_update(vnode, server, ret); | 341 | afs_vnode_finalise_status_update(vnode, server, ret); |
334 | 342 | ||
335 | _leave(" = %d", ret); | 343 | _leave(" = %d", ret); |
@@ -340,17 +348,18 @@ get_anyway: | |||
340 | * fetch file data from the volume | 348 | * fetch file data from the volume |
341 | * - TODO implement caching and server failover | 349 | * - TODO implement caching and server failover |
342 | */ | 350 | */ |
343 | int afs_vnode_fetch_data(struct afs_vnode *vnode, off_t offset, size_t length, | 351 | int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key, |
344 | struct page *page) | 352 | off_t offset, size_t length, struct page *page) |
345 | { | 353 | { |
346 | struct afs_server *server; | 354 | struct afs_server *server; |
347 | int ret; | 355 | int ret; |
348 | 356 | ||
349 | _enter("%s,{%u,%u,%u}", | 357 | _enter("%s{%u,%u,%u},%x,,,", |
350 | vnode->volume->vlocation->vldb.name, | 358 | vnode->volume->vlocation->vldb.name, |
351 | vnode->fid.vid, | 359 | vnode->fid.vid, |
352 | vnode->fid.vnode, | 360 | vnode->fid.vnode, |
353 | vnode->fid.unique); | 361 | vnode->fid.unique, |
362 | key_serial(key)); | ||
354 | 363 | ||
355 | /* this op will fetch the status */ | 364 | /* this op will fetch the status */ |
356 | spin_lock(&vnode->lock); | 365 | spin_lock(&vnode->lock); |
@@ -367,8 +376,8 @@ int afs_vnode_fetch_data(struct afs_vnode *vnode, off_t offset, size_t length, | |||
367 | 376 | ||
368 | _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); | 377 | _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); |
369 | 378 | ||
370 | ret = afs_fs_fetch_data(server, vnode, offset, length, page, | 379 | ret = afs_fs_fetch_data(server, key, vnode, offset, length, |
371 | NULL, &afs_sync_call); | 380 | page, NULL, &afs_sync_call); |
372 | 381 | ||
373 | } while (!afs_volume_release_fileserver(vnode, server, ret)); | 382 | } while (!afs_volume_release_fileserver(vnode, server, ret)); |
374 | 383 | ||
diff --git a/fs/afs/volume.c b/fs/afs/volume.c index 45491cfd4f4f..15e13678c216 100644 --- a/fs/afs/volume.c +++ b/fs/afs/volume.c | |||
@@ -41,83 +41,20 @@ static const char *afs_voltypes[] = { "R/W", "R/O", "BAK" }; | |||
41 | * - Rule 3: If parent volume is R/W, then only mount R/W volume unless | 41 | * - Rule 3: If parent volume is R/W, then only mount R/W volume unless |
42 | * explicitly told otherwise | 42 | * explicitly told otherwise |
43 | */ | 43 | */ |
44 | struct afs_volume *afs_volume_lookup(const char *name, struct afs_cell *cell, | 44 | struct afs_volume *afs_volume_lookup(struct afs_mount_params *params) |
45 | int rwpath) | ||
46 | { | 45 | { |
47 | struct afs_vlocation *vlocation = NULL; | 46 | struct afs_vlocation *vlocation = NULL; |
48 | struct afs_volume *volume = NULL; | 47 | struct afs_volume *volume = NULL; |
49 | struct afs_server *server = NULL; | 48 | struct afs_server *server = NULL; |
50 | afs_voltype_t type; | ||
51 | const char *cellname, *volname, *suffix; | ||
52 | char srvtmask; | 49 | char srvtmask; |
53 | int force, ret, loop, cellnamesz, volnamesz; | 50 | int ret, loop; |
54 | 51 | ||
55 | _enter("%s,,%d,", name, rwpath); | 52 | _enter("{%*.*s,%d}", |
56 | 53 | params->volnamesz, params->volnamesz, params->volname, params->rwpath); | |
57 | if (!name || (name[0] != '%' && name[0] != '#') || !name[1]) { | ||
58 | printk("kAFS: unparsable volume name\n"); | ||
59 | return ERR_PTR(-EINVAL); | ||
60 | } | ||
61 | |||
62 | /* determine the type of volume we're looking for */ | ||
63 | force = 0; | ||
64 | type = AFSVL_ROVOL; | ||
65 | |||
66 | if (rwpath || name[0] == '%') { | ||
67 | type = AFSVL_RWVOL; | ||
68 | force = 1; | ||
69 | } | ||
70 | |||
71 | suffix = strrchr(name, '.'); | ||
72 | if (suffix) { | ||
73 | if (strcmp(suffix, ".readonly") == 0) { | ||
74 | type = AFSVL_ROVOL; | ||
75 | force = 1; | ||
76 | } else if (strcmp(suffix, ".backup") == 0) { | ||
77 | type = AFSVL_BACKVOL; | ||
78 | force = 1; | ||
79 | } else if (suffix[1] == 0) { | ||
80 | } else { | ||
81 | suffix = NULL; | ||
82 | } | ||
83 | } | ||
84 | |||
85 | /* split the cell and volume names */ | ||
86 | name++; | ||
87 | volname = strchr(name, ':'); | ||
88 | if (volname) { | ||
89 | cellname = name; | ||
90 | cellnamesz = volname - name; | ||
91 | volname++; | ||
92 | } else { | ||
93 | volname = name; | ||
94 | cellname = NULL; | ||
95 | cellnamesz = 0; | ||
96 | } | ||
97 | |||
98 | volnamesz = suffix ? suffix - volname : strlen(volname); | ||
99 | |||
100 | _debug("CELL:%*.*s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s", | ||
101 | cellnamesz, cellnamesz, cellname ?: "", cell, | ||
102 | volnamesz, volnamesz, volname, suffix ?: "-", | ||
103 | type, | ||
104 | force ? " FORCE" : ""); | ||
105 | |||
106 | /* lookup the cell record */ | ||
107 | if (cellname || !cell) { | ||
108 | cell = afs_cell_lookup(cellname, cellnamesz); | ||
109 | if (IS_ERR(cell)) { | ||
110 | ret = PTR_ERR(cell); | ||
111 | printk("kAFS: unable to lookup cell '%s'\n", | ||
112 | cellname ?: ""); | ||
113 | goto error; | ||
114 | } | ||
115 | } else { | ||
116 | afs_get_cell(cell); | ||
117 | } | ||
118 | 54 | ||
119 | /* lookup the volume location record */ | 55 | /* lookup the volume location record */ |
120 | vlocation = afs_vlocation_lookup(cell, volname, volnamesz); | 56 | vlocation = afs_vlocation_lookup(params->cell, params->key, |
57 | params->volname, params->volnamesz); | ||
121 | if (IS_ERR(vlocation)) { | 58 | if (IS_ERR(vlocation)) { |
122 | ret = PTR_ERR(vlocation); | 59 | ret = PTR_ERR(vlocation); |
123 | vlocation = NULL; | 60 | vlocation = NULL; |
@@ -126,30 +63,30 @@ struct afs_volume *afs_volume_lookup(const char *name, struct afs_cell *cell, | |||
126 | 63 | ||
127 | /* make the final decision on the type we want */ | 64 | /* make the final decision on the type we want */ |
128 | ret = -ENOMEDIUM; | 65 | ret = -ENOMEDIUM; |
129 | if (force && !(vlocation->vldb.vidmask & (1 << type))) | 66 | if (params->force && !(vlocation->vldb.vidmask & (1 << params->type))) |
130 | goto error; | 67 | goto error; |
131 | 68 | ||
132 | srvtmask = 0; | 69 | srvtmask = 0; |
133 | for (loop = 0; loop < vlocation->vldb.nservers; loop++) | 70 | for (loop = 0; loop < vlocation->vldb.nservers; loop++) |
134 | srvtmask |= vlocation->vldb.srvtmask[loop]; | 71 | srvtmask |= vlocation->vldb.srvtmask[loop]; |
135 | 72 | ||
136 | if (force) { | 73 | if (params->force) { |
137 | if (!(srvtmask & (1 << type))) | 74 | if (!(srvtmask & (1 << params->type))) |
138 | goto error; | 75 | goto error; |
139 | } else if (srvtmask & AFS_VOL_VTM_RO) { | 76 | } else if (srvtmask & AFS_VOL_VTM_RO) { |
140 | type = AFSVL_ROVOL; | 77 | params->type = AFSVL_ROVOL; |
141 | } else if (srvtmask & AFS_VOL_VTM_RW) { | 78 | } else if (srvtmask & AFS_VOL_VTM_RW) { |
142 | type = AFSVL_RWVOL; | 79 | params->type = AFSVL_RWVOL; |
143 | } else { | 80 | } else { |
144 | goto error; | 81 | goto error; |
145 | } | 82 | } |
146 | 83 | ||
147 | down_write(&cell->vl_sem); | 84 | down_write(¶ms->cell->vl_sem); |
148 | 85 | ||
149 | /* is the volume already active? */ | 86 | /* is the volume already active? */ |
150 | if (vlocation->vols[type]) { | 87 | if (vlocation->vols[params->type]) { |
151 | /* yes - re-use it */ | 88 | /* yes - re-use it */ |
152 | volume = vlocation->vols[type]; | 89 | volume = vlocation->vols[params->type]; |
153 | afs_get_volume(volume); | 90 | afs_get_volume(volume); |
154 | goto success; | 91 | goto success; |
155 | } | 92 | } |
@@ -163,10 +100,10 @@ struct afs_volume *afs_volume_lookup(const char *name, struct afs_cell *cell, | |||
163 | goto error_up; | 100 | goto error_up; |
164 | 101 | ||
165 | atomic_set(&volume->usage, 1); | 102 | atomic_set(&volume->usage, 1); |
166 | volume->type = type; | 103 | volume->type = params->type; |
167 | volume->type_force = force; | 104 | volume->type_force = params->force; |
168 | volume->cell = cell; | 105 | volume->cell = params->cell; |
169 | volume->vid = vlocation->vldb.vid[type]; | 106 | volume->vid = vlocation->vldb.vid[params->type]; |
170 | 107 | ||
171 | init_rwsem(&volume->server_sem); | 108 | init_rwsem(&volume->server_sem); |
172 | 109 | ||
@@ -196,28 +133,26 @@ struct afs_volume *afs_volume_lookup(const char *name, struct afs_cell *cell, | |||
196 | afs_get_vlocation(vlocation); | 133 | afs_get_vlocation(vlocation); |
197 | volume->vlocation = vlocation; | 134 | volume->vlocation = vlocation; |
198 | 135 | ||
199 | vlocation->vols[type] = volume; | 136 | vlocation->vols[volume->type] = volume; |
200 | 137 | ||
201 | success: | 138 | success: |
202 | _debug("kAFS selected %s volume %08x", | 139 | _debug("kAFS selected %s volume %08x", |
203 | afs_voltypes[volume->type], volume->vid); | 140 | afs_voltypes[volume->type], volume->vid); |
204 | up_write(&cell->vl_sem); | 141 | up_write(¶ms->cell->vl_sem); |
205 | afs_put_vlocation(vlocation); | 142 | afs_put_vlocation(vlocation); |
206 | afs_put_cell(cell); | ||
207 | _leave(" = %p", volume); | 143 | _leave(" = %p", volume); |
208 | return volume; | 144 | return volume; |
209 | 145 | ||
210 | /* clean up */ | 146 | /* clean up */ |
211 | error_up: | 147 | error_up: |
212 | up_write(&cell->vl_sem); | 148 | up_write(¶ms->cell->vl_sem); |
213 | error: | 149 | error: |
214 | afs_put_vlocation(vlocation); | 150 | afs_put_vlocation(vlocation); |
215 | afs_put_cell(cell); | ||
216 | _leave(" = %d", ret); | 151 | _leave(" = %d", ret); |
217 | return ERR_PTR(ret); | 152 | return ERR_PTR(ret); |
218 | 153 | ||
219 | error_discard: | 154 | error_discard: |
220 | up_write(&cell->vl_sem); | 155 | up_write(¶ms->cell->vl_sem); |
221 | 156 | ||
222 | for (loop = volume->nservers - 1; loop >= 0; loop--) | 157 | for (loop = volume->nservers - 1; loop >= 0; loop--) |
223 | afs_put_server(volume->servers[loop]); | 158 | afs_put_server(volume->servers[loop]); |