diff options
author | David Woodhouse <dwmw2@shinybook.infradead.org> | 2005-07-02 08:39:09 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@shinybook.infradead.org> | 2005-07-02 08:39:09 -0400 |
commit | d2f6409584e2c62ffad81690562330ff3bf4a458 (patch) | |
tree | 3bdfb97d0b51be2f7f414f2107e97603c1206abb /fs/nfs | |
parent | e1b09eba2686eca94a3a188042b518df6044a3c1 (diff) | |
parent | 4a89a04f1ee21a7c1f4413f1ad7dcfac50ff9b63 (diff) |
Merge with master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/Makefile | 1 | ||||
-rw-r--r-- | fs/nfs/callback.c | 1 | ||||
-rw-r--r-- | fs/nfs/callback_proc.c | 1 | ||||
-rw-r--r-- | fs/nfs/callback_xdr.c | 2 | ||||
-rw-r--r-- | fs/nfs/delegation.c | 1 | ||||
-rw-r--r-- | fs/nfs/dir.c | 160 | ||||
-rw-r--r-- | fs/nfs/direct.c | 7 | ||||
-rw-r--r-- | fs/nfs/file.c | 48 | ||||
-rw-r--r-- | fs/nfs/idmap.c | 1 | ||||
-rw-r--r-- | fs/nfs/inode.c | 427 | ||||
-rw-r--r-- | fs/nfs/mount_clnt.c | 4 | ||||
-rw-r--r-- | fs/nfs/nfs3acl.c | 403 | ||||
-rw-r--r-- | fs/nfs/nfs3proc.c | 43 | ||||
-rw-r--r-- | fs/nfs/nfs3xdr.c | 147 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 253 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 429 | ||||
-rw-r--r-- | fs/nfs/nfs4renewd.c | 1 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 193 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 241 | ||||
-rw-r--r-- | fs/nfs/nfsroot.c | 9 | ||||
-rw-r--r-- | fs/nfs/pagelist.c | 142 | ||||
-rw-r--r-- | fs/nfs/proc.c | 1 | ||||
-rw-r--r-- | fs/nfs/read.c | 3 | ||||
-rw-r--r-- | fs/nfs/write.c | 108 |
24 files changed, 2087 insertions, 539 deletions
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index b4baa031edf4..8b3bb715d177 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile | |||
@@ -8,6 +8,7 @@ nfs-y := dir.o file.o inode.o nfs2xdr.o pagelist.o \ | |||
8 | proc.o read.o symlink.o unlink.o write.o | 8 | proc.o read.o symlink.o unlink.o write.o |
9 | nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o | 9 | nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o |
10 | nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o | 10 | nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o |
11 | nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o | ||
11 | nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ | 12 | nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ |
12 | delegation.o idmap.o \ | 13 | delegation.o idmap.o \ |
13 | callback.o callback_xdr.o callback_proc.o | 14 | callback.o callback_xdr.o callback_proc.o |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 560d6175dd58..f2ca782aba33 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/sunrpc/svc.h> | 14 | #include <linux/sunrpc/svc.h> |
15 | #include <linux/sunrpc/svcsock.h> | 15 | #include <linux/sunrpc/svcsock.h> |
16 | #include <linux/nfs_fs.h> | 16 | #include <linux/nfs_fs.h> |
17 | #include "nfs4_fs.h" | ||
17 | #include "callback.h" | 18 | #include "callback.h" |
18 | 19 | ||
19 | #define NFSDBG_FACILITY NFSDBG_CALLBACK | 20 | #define NFSDBG_FACILITY NFSDBG_CALLBACK |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index ece27e42b93b..65f1e19e4d19 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/config.h> | 8 | #include <linux/config.h> |
9 | #include <linux/nfs4.h> | 9 | #include <linux/nfs4.h> |
10 | #include <linux/nfs_fs.h> | 10 | #include <linux/nfs_fs.h> |
11 | #include "nfs4_fs.h" | ||
11 | #include "callback.h" | 12 | #include "callback.h" |
12 | #include "delegation.h" | 13 | #include "delegation.h" |
13 | 14 | ||
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index d271df9df2b2..7c33b9a81a94 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/sunrpc/svc.h> | 10 | #include <linux/sunrpc/svc.h> |
11 | #include <linux/nfs4.h> | 11 | #include <linux/nfs4.h> |
12 | #include <linux/nfs_fs.h> | 12 | #include <linux/nfs_fs.h> |
13 | #include "nfs4_fs.h" | ||
13 | #include "callback.h" | 14 | #include "callback.h" |
14 | 15 | ||
15 | #define CB_OP_TAGLEN_MAXSZ (512) | 16 | #define CB_OP_TAGLEN_MAXSZ (512) |
@@ -410,7 +411,6 @@ static int nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp | |||
410 | xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base); | 411 | xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base); |
411 | 412 | ||
412 | p = (uint32_t*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len); | 413 | p = (uint32_t*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len); |
413 | rqstp->rq_res.head[0].iov_len = PAGE_SIZE; | ||
414 | xdr_init_encode(&xdr_out, &rqstp->rq_res, p); | 414 | xdr_init_encode(&xdr_out, &rqstp->rq_res, p); |
415 | 415 | ||
416 | decode_compound_hdr_arg(&xdr_in, &hdr_arg); | 416 | decode_compound_hdr_arg(&xdr_in, &hdr_arg); |
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 5b9c60f97791..d7f7eb669d03 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/nfs_fs.h> | 16 | #include <linux/nfs_fs.h> |
17 | #include <linux/nfs_xdr.h> | 17 | #include <linux/nfs_xdr.h> |
18 | 18 | ||
19 | #include "nfs4_fs.h" | ||
19 | #include "delegation.h" | 20 | #include "delegation.h" |
20 | 21 | ||
21 | static struct nfs_delegation *nfs_alloc_delegation(void) | 22 | static struct nfs_delegation *nfs_alloc_delegation(void) |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index ff6155f5e8d9..b38a57e78a63 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/smp_lock.h> | 32 | #include <linux/smp_lock.h> |
33 | #include <linux/namei.h> | 33 | #include <linux/namei.h> |
34 | 34 | ||
35 | #include "nfs4_fs.h" | ||
35 | #include "delegation.h" | 36 | #include "delegation.h" |
36 | 37 | ||
37 | #define NFS_PARANOIA 1 | 38 | #define NFS_PARANOIA 1 |
@@ -50,8 +51,10 @@ static int nfs_mknod(struct inode *, struct dentry *, int, dev_t); | |||
50 | static int nfs_rename(struct inode *, struct dentry *, | 51 | static int nfs_rename(struct inode *, struct dentry *, |
51 | struct inode *, struct dentry *); | 52 | struct inode *, struct dentry *); |
52 | static int nfs_fsync_dir(struct file *, struct dentry *, int); | 53 | static int nfs_fsync_dir(struct file *, struct dentry *, int); |
54 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); | ||
53 | 55 | ||
54 | struct file_operations nfs_dir_operations = { | 56 | struct file_operations nfs_dir_operations = { |
57 | .llseek = nfs_llseek_dir, | ||
55 | .read = generic_read_dir, | 58 | .read = generic_read_dir, |
56 | .readdir = nfs_readdir, | 59 | .readdir = nfs_readdir, |
57 | .open = nfs_opendir, | 60 | .open = nfs_opendir, |
@@ -74,6 +77,27 @@ struct inode_operations nfs_dir_inode_operations = { | |||
74 | .setattr = nfs_setattr, | 77 | .setattr = nfs_setattr, |
75 | }; | 78 | }; |
76 | 79 | ||
80 | #ifdef CONFIG_NFS_V3 | ||
81 | struct inode_operations nfs3_dir_inode_operations = { | ||
82 | .create = nfs_create, | ||
83 | .lookup = nfs_lookup, | ||
84 | .link = nfs_link, | ||
85 | .unlink = nfs_unlink, | ||
86 | .symlink = nfs_symlink, | ||
87 | .mkdir = nfs_mkdir, | ||
88 | .rmdir = nfs_rmdir, | ||
89 | .mknod = nfs_mknod, | ||
90 | .rename = nfs_rename, | ||
91 | .permission = nfs_permission, | ||
92 | .getattr = nfs_getattr, | ||
93 | .setattr = nfs_setattr, | ||
94 | .listxattr = nfs3_listxattr, | ||
95 | .getxattr = nfs3_getxattr, | ||
96 | .setxattr = nfs3_setxattr, | ||
97 | .removexattr = nfs3_removexattr, | ||
98 | }; | ||
99 | #endif /* CONFIG_NFS_V3 */ | ||
100 | |||
77 | #ifdef CONFIG_NFS_V4 | 101 | #ifdef CONFIG_NFS_V4 |
78 | 102 | ||
79 | static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *); | 103 | static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *); |
@@ -90,6 +114,9 @@ struct inode_operations nfs4_dir_inode_operations = { | |||
90 | .permission = nfs_permission, | 114 | .permission = nfs_permission, |
91 | .getattr = nfs_getattr, | 115 | .getattr = nfs_getattr, |
92 | .setattr = nfs_setattr, | 116 | .setattr = nfs_setattr, |
117 | .getxattr = nfs4_getxattr, | ||
118 | .setxattr = nfs4_setxattr, | ||
119 | .listxattr = nfs4_listxattr, | ||
93 | }; | 120 | }; |
94 | 121 | ||
95 | #endif /* CONFIG_NFS_V4 */ | 122 | #endif /* CONFIG_NFS_V4 */ |
@@ -116,7 +143,8 @@ typedef struct { | |||
116 | struct page *page; | 143 | struct page *page; |
117 | unsigned long page_index; | 144 | unsigned long page_index; |
118 | u32 *ptr; | 145 | u32 *ptr; |
119 | u64 target; | 146 | u64 *dir_cookie; |
147 | loff_t current_index; | ||
120 | struct nfs_entry *entry; | 148 | struct nfs_entry *entry; |
121 | decode_dirent_t decode; | 149 | decode_dirent_t decode; |
122 | int plus; | 150 | int plus; |
@@ -164,12 +192,10 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) | |||
164 | NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME; | 192 | NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME; |
165 | /* Ensure consistent page alignment of the data. | 193 | /* Ensure consistent page alignment of the data. |
166 | * Note: assumes we have exclusive access to this mapping either | 194 | * Note: assumes we have exclusive access to this mapping either |
167 | * throught inode->i_sem or some other mechanism. | 195 | * through inode->i_sem or some other mechanism. |
168 | */ | 196 | */ |
169 | if (page->index == 0) { | 197 | if (page->index == 0) |
170 | invalidate_inode_pages(inode->i_mapping); | 198 | invalidate_inode_pages2_range(inode->i_mapping, PAGE_CACHE_SIZE, -1); |
171 | NFS_I(inode)->readdir_timestamp = timestamp; | ||
172 | } | ||
173 | unlock_page(page); | 199 | unlock_page(page); |
174 | return 0; | 200 | return 0; |
175 | error: | 201 | error: |
@@ -202,22 +228,22 @@ void dir_page_release(nfs_readdir_descriptor_t *desc) | |||
202 | 228 | ||
203 | /* | 229 | /* |
204 | * Given a pointer to a buffer that has already been filled by a call | 230 | * Given a pointer to a buffer that has already been filled by a call |
205 | * to readdir, find the next entry. | 231 | * to readdir, find the next entry with cookie '*desc->dir_cookie'. |
206 | * | 232 | * |
207 | * If the end of the buffer has been reached, return -EAGAIN, if not, | 233 | * If the end of the buffer has been reached, return -EAGAIN, if not, |
208 | * return the offset within the buffer of the next entry to be | 234 | * return the offset within the buffer of the next entry to be |
209 | * read. | 235 | * read. |
210 | */ | 236 | */ |
211 | static inline | 237 | static inline |
212 | int find_dirent(nfs_readdir_descriptor_t *desc, struct page *page) | 238 | int find_dirent(nfs_readdir_descriptor_t *desc) |
213 | { | 239 | { |
214 | struct nfs_entry *entry = desc->entry; | 240 | struct nfs_entry *entry = desc->entry; |
215 | int loop_count = 0, | 241 | int loop_count = 0, |
216 | status; | 242 | status; |
217 | 243 | ||
218 | while((status = dir_decode(desc)) == 0) { | 244 | while((status = dir_decode(desc)) == 0) { |
219 | dfprintk(VFS, "NFS: found cookie %Lu\n", (long long)entry->cookie); | 245 | dfprintk(VFS, "NFS: found cookie %Lu\n", (unsigned long long)entry->cookie); |
220 | if (entry->prev_cookie == desc->target) | 246 | if (entry->prev_cookie == *desc->dir_cookie) |
221 | break; | 247 | break; |
222 | if (loop_count++ > 200) { | 248 | if (loop_count++ > 200) { |
223 | loop_count = 0; | 249 | loop_count = 0; |
@@ -229,8 +255,44 @@ int find_dirent(nfs_readdir_descriptor_t *desc, struct page *page) | |||
229 | } | 255 | } |
230 | 256 | ||
231 | /* | 257 | /* |
232 | * Find the given page, and call find_dirent() in order to try to | 258 | * Given a pointer to a buffer that has already been filled by a call |
233 | * return the next entry. | 259 | * to readdir, find the entry at offset 'desc->file->f_pos'. |
260 | * | ||
261 | * If the end of the buffer has been reached, return -EAGAIN, if not, | ||
262 | * return the offset within the buffer of the next entry to be | ||
263 | * read. | ||
264 | */ | ||
265 | static inline | ||
266 | int find_dirent_index(nfs_readdir_descriptor_t *desc) | ||
267 | { | ||
268 | struct nfs_entry *entry = desc->entry; | ||
269 | int loop_count = 0, | ||
270 | status; | ||
271 | |||
272 | for(;;) { | ||
273 | status = dir_decode(desc); | ||
274 | if (status) | ||
275 | break; | ||
276 | |||
277 | dfprintk(VFS, "NFS: found cookie %Lu at index %Ld\n", (unsigned long long)entry->cookie, desc->current_index); | ||
278 | |||
279 | if (desc->file->f_pos == desc->current_index) { | ||
280 | *desc->dir_cookie = entry->cookie; | ||
281 | break; | ||
282 | } | ||
283 | desc->current_index++; | ||
284 | if (loop_count++ > 200) { | ||
285 | loop_count = 0; | ||
286 | schedule(); | ||
287 | } | ||
288 | } | ||
289 | dfprintk(VFS, "NFS: find_dirent_index() returns %d\n", status); | ||
290 | return status; | ||
291 | } | ||
292 | |||
293 | /* | ||
294 | * Find the given page, and call find_dirent() or find_dirent_index in | ||
295 | * order to try to return the next entry. | ||
234 | */ | 296 | */ |
235 | static inline | 297 | static inline |
236 | int find_dirent_page(nfs_readdir_descriptor_t *desc) | 298 | int find_dirent_page(nfs_readdir_descriptor_t *desc) |
@@ -253,7 +315,10 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc) | |||
253 | /* NOTE: Someone else may have changed the READDIRPLUS flag */ | 315 | /* NOTE: Someone else may have changed the READDIRPLUS flag */ |
254 | desc->page = page; | 316 | desc->page = page; |
255 | desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ | 317 | desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ |
256 | status = find_dirent(desc, page); | 318 | if (*desc->dir_cookie != 0) |
319 | status = find_dirent(desc); | ||
320 | else | ||
321 | status = find_dirent_index(desc); | ||
257 | if (status < 0) | 322 | if (status < 0) |
258 | dir_page_release(desc); | 323 | dir_page_release(desc); |
259 | out: | 324 | out: |
@@ -268,7 +333,8 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc) | |||
268 | * Recurse through the page cache pages, and return a | 333 | * Recurse through the page cache pages, and return a |
269 | * filled nfs_entry structure of the next directory entry if possible. | 334 | * filled nfs_entry structure of the next directory entry if possible. |
270 | * | 335 | * |
271 | * The target for the search is 'desc->target'. | 336 | * The target for the search is '*desc->dir_cookie' if non-0, |
337 | * 'desc->file->f_pos' otherwise | ||
272 | */ | 338 | */ |
273 | static inline | 339 | static inline |
274 | int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) | 340 | int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) |
@@ -276,7 +342,16 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) | |||
276 | int loop_count = 0; | 342 | int loop_count = 0; |
277 | int res; | 343 | int res; |
278 | 344 | ||
279 | dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", (long long)desc->target); | 345 | /* Always search-by-index from the beginning of the cache */ |
346 | if (*desc->dir_cookie == 0) { | ||
347 | dfprintk(VFS, "NFS: readdir_search_pagecache() searching for offset %Ld\n", (long long)desc->file->f_pos); | ||
348 | desc->page_index = 0; | ||
349 | desc->entry->cookie = desc->entry->prev_cookie = 0; | ||
350 | desc->entry->eof = 0; | ||
351 | desc->current_index = 0; | ||
352 | } else | ||
353 | dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", (unsigned long long)*desc->dir_cookie); | ||
354 | |||
280 | for (;;) { | 355 | for (;;) { |
281 | res = find_dirent_page(desc); | 356 | res = find_dirent_page(desc); |
282 | if (res != -EAGAIN) | 357 | if (res != -EAGAIN) |
@@ -313,7 +388,7 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
313 | int loop_count = 0, | 388 | int loop_count = 0, |
314 | res; | 389 | res; |
315 | 390 | ||
316 | dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n", (long long)desc->target); | 391 | dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n", (long long)entry->cookie); |
317 | 392 | ||
318 | for(;;) { | 393 | for(;;) { |
319 | unsigned d_type = DT_UNKNOWN; | 394 | unsigned d_type = DT_UNKNOWN; |
@@ -333,10 +408,11 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
333 | } | 408 | } |
334 | 409 | ||
335 | res = filldir(dirent, entry->name, entry->len, | 410 | res = filldir(dirent, entry->name, entry->len, |
336 | entry->prev_cookie, fileid, d_type); | 411 | file->f_pos, fileid, d_type); |
337 | if (res < 0) | 412 | if (res < 0) |
338 | break; | 413 | break; |
339 | file->f_pos = desc->target = entry->cookie; | 414 | file->f_pos++; |
415 | *desc->dir_cookie = entry->cookie; | ||
340 | if (dir_decode(desc) != 0) { | 416 | if (dir_decode(desc) != 0) { |
341 | desc->page_index ++; | 417 | desc->page_index ++; |
342 | break; | 418 | break; |
@@ -349,7 +425,7 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
349 | dir_page_release(desc); | 425 | dir_page_release(desc); |
350 | if (dentry != NULL) | 426 | if (dentry != NULL) |
351 | dput(dentry); | 427 | dput(dentry); |
352 | dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (long long)desc->target, res); | 428 | dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (unsigned long long)*desc->dir_cookie, res); |
353 | return res; | 429 | return res; |
354 | } | 430 | } |
355 | 431 | ||
@@ -375,14 +451,14 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
375 | struct page *page = NULL; | 451 | struct page *page = NULL; |
376 | int status; | 452 | int status; |
377 | 453 | ||
378 | dfprintk(VFS, "NFS: uncached_readdir() searching for cookie %Lu\n", (long long)desc->target); | 454 | dfprintk(VFS, "NFS: uncached_readdir() searching for cookie %Lu\n", (unsigned long long)*desc->dir_cookie); |
379 | 455 | ||
380 | page = alloc_page(GFP_HIGHUSER); | 456 | page = alloc_page(GFP_HIGHUSER); |
381 | if (!page) { | 457 | if (!page) { |
382 | status = -ENOMEM; | 458 | status = -ENOMEM; |
383 | goto out; | 459 | goto out; |
384 | } | 460 | } |
385 | desc->error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, desc->target, | 461 | desc->error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, *desc->dir_cookie, |
386 | page, | 462 | page, |
387 | NFS_SERVER(inode)->dtsize, | 463 | NFS_SERVER(inode)->dtsize, |
388 | desc->plus); | 464 | desc->plus); |
@@ -391,7 +467,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
391 | desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ | 467 | desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ |
392 | if (desc->error >= 0) { | 468 | if (desc->error >= 0) { |
393 | if ((status = dir_decode(desc)) == 0) | 469 | if ((status = dir_decode(desc)) == 0) |
394 | desc->entry->prev_cookie = desc->target; | 470 | desc->entry->prev_cookie = *desc->dir_cookie; |
395 | } else | 471 | } else |
396 | status = -EIO; | 472 | status = -EIO; |
397 | if (status < 0) | 473 | if (status < 0) |
@@ -412,8 +488,9 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
412 | goto out; | 488 | goto out; |
413 | } | 489 | } |
414 | 490 | ||
415 | /* The file offset position is now represented as a true offset into the | 491 | /* The file offset position represents the dirent entry number. A |
416 | * page cache as is the case in most of the other filesystems. | 492 | last cookie cache takes care of the common case of reading the |
493 | whole directory. | ||
417 | */ | 494 | */ |
418 | static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | 495 | static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) |
419 | { | 496 | { |
@@ -435,15 +512,15 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
435 | } | 512 | } |
436 | 513 | ||
437 | /* | 514 | /* |
438 | * filp->f_pos points to the file offset in the page cache. | 515 | * filp->f_pos points to the dirent entry number. |
439 | * but if the cache has meanwhile been zapped, we need to | 516 | * *desc->dir_cookie has the cookie for the next entry. We have |
440 | * read from the last dirent to revalidate f_pos | 517 | * to either find the entry with the appropriate number or |
441 | * itself. | 518 | * revalidate the cookie. |
442 | */ | 519 | */ |
443 | memset(desc, 0, sizeof(*desc)); | 520 | memset(desc, 0, sizeof(*desc)); |
444 | 521 | ||
445 | desc->file = filp; | 522 | desc->file = filp; |
446 | desc->target = filp->f_pos; | 523 | desc->dir_cookie = &((struct nfs_open_context *)filp->private_data)->dir_cookie; |
447 | desc->decode = NFS_PROTO(inode)->decode_dirent; | 524 | desc->decode = NFS_PROTO(inode)->decode_dirent; |
448 | desc->plus = NFS_USE_READDIRPLUS(inode); | 525 | desc->plus = NFS_USE_READDIRPLUS(inode); |
449 | 526 | ||
@@ -455,9 +532,10 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
455 | 532 | ||
456 | while(!desc->entry->eof) { | 533 | while(!desc->entry->eof) { |
457 | res = readdir_search_pagecache(desc); | 534 | res = readdir_search_pagecache(desc); |
535 | |||
458 | if (res == -EBADCOOKIE) { | 536 | if (res == -EBADCOOKIE) { |
459 | /* This means either end of directory */ | 537 | /* This means either end of directory */ |
460 | if (desc->entry->cookie != desc->target) { | 538 | if (*desc->dir_cookie && desc->entry->cookie != *desc->dir_cookie) { |
461 | /* Or that the server has 'lost' a cookie */ | 539 | /* Or that the server has 'lost' a cookie */ |
462 | res = uncached_readdir(desc, dirent, filldir); | 540 | res = uncached_readdir(desc, dirent, filldir); |
463 | if (res >= 0) | 541 | if (res >= 0) |
@@ -490,6 +568,28 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
490 | return 0; | 568 | return 0; |
491 | } | 569 | } |
492 | 570 | ||
571 | loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin) | ||
572 | { | ||
573 | down(&filp->f_dentry->d_inode->i_sem); | ||
574 | switch (origin) { | ||
575 | case 1: | ||
576 | offset += filp->f_pos; | ||
577 | case 0: | ||
578 | if (offset >= 0) | ||
579 | break; | ||
580 | default: | ||
581 | offset = -EINVAL; | ||
582 | goto out; | ||
583 | } | ||
584 | if (offset != filp->f_pos) { | ||
585 | filp->f_pos = offset; | ||
586 | ((struct nfs_open_context *)filp->private_data)->dir_cookie = 0; | ||
587 | } | ||
588 | out: | ||
589 | up(&filp->f_dentry->d_inode->i_sem); | ||
590 | return offset; | ||
591 | } | ||
592 | |||
493 | /* | 593 | /* |
494 | * All directory operations under NFS are synchronous, so fsync() | 594 | * All directory operations under NFS are synchronous, so fsync() |
495 | * is a dummy operation. | 595 | * is a dummy operation. |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 68df803f27ca..6537f2c4ae44 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -517,7 +517,7 @@ retry: | |||
517 | result = tot_bytes; | 517 | result = tot_bytes; |
518 | 518 | ||
519 | out: | 519 | out: |
520 | nfs_end_data_update_defer(inode); | 520 | nfs_end_data_update(inode); |
521 | nfs_writedata_free(wdata); | 521 | nfs_writedata_free(wdata); |
522 | return result; | 522 | return result; |
523 | 523 | ||
@@ -751,11 +751,6 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, | |||
751 | retval = -EFAULT; | 751 | retval = -EFAULT; |
752 | if (!access_ok(VERIFY_READ, iov.iov_base, iov.iov_len)) | 752 | if (!access_ok(VERIFY_READ, iov.iov_base, iov.iov_len)) |
753 | goto out; | 753 | goto out; |
754 | if (file->f_error) { | ||
755 | retval = file->f_error; | ||
756 | file->f_error = 0; | ||
757 | goto out; | ||
758 | } | ||
759 | retval = -EFBIG; | 754 | retval = -EFBIG; |
760 | if (limit != RLIM_INFINITY) { | 755 | if (limit != RLIM_INFINITY) { |
761 | if (pos >= limit) { | 756 | if (pos >= limit) { |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 55c907592490..5621ba9885f4 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -71,6 +71,18 @@ struct inode_operations nfs_file_inode_operations = { | |||
71 | .setattr = nfs_setattr, | 71 | .setattr = nfs_setattr, |
72 | }; | 72 | }; |
73 | 73 | ||
74 | #ifdef CONFIG_NFS_V3 | ||
75 | struct inode_operations nfs3_file_inode_operations = { | ||
76 | .permission = nfs_permission, | ||
77 | .getattr = nfs_getattr, | ||
78 | .setattr = nfs_setattr, | ||
79 | .listxattr = nfs3_listxattr, | ||
80 | .getxattr = nfs3_getxattr, | ||
81 | .setxattr = nfs3_setxattr, | ||
82 | .removexattr = nfs3_removexattr, | ||
83 | }; | ||
84 | #endif /* CONFIG_NFS_v3 */ | ||
85 | |||
74 | /* Hack for future NFS swap support */ | 86 | /* Hack for future NFS swap support */ |
75 | #ifndef IS_SWAPFILE | 87 | #ifndef IS_SWAPFILE |
76 | # define IS_SWAPFILE(inode) (0) | 88 | # define IS_SWAPFILE(inode) (0) |
@@ -116,6 +128,21 @@ nfs_file_release(struct inode *inode, struct file *filp) | |||
116 | } | 128 | } |
117 | 129 | ||
118 | /** | 130 | /** |
131 | * nfs_revalidate_file - Revalidate the page cache & related metadata | ||
132 | * @inode - pointer to inode struct | ||
133 | * @file - pointer to file | ||
134 | */ | ||
135 | static int nfs_revalidate_file(struct inode *inode, struct file *filp) | ||
136 | { | ||
137 | int retval = 0; | ||
138 | |||
139 | if ((NFS_FLAGS(inode) & NFS_INO_REVAL_PAGECACHE) || nfs_attribute_timeout(inode)) | ||
140 | retval = __nfs_revalidate_inode(NFS_SERVER(inode), inode); | ||
141 | nfs_revalidate_mapping(inode, filp->f_mapping); | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | /** | ||
119 | * nfs_revalidate_size - Revalidate the file size | 146 | * nfs_revalidate_size - Revalidate the file size |
120 | * @inode - pointer to inode struct | 147 | * @inode - pointer to inode struct |
121 | * @file - pointer to struct file | 148 | * @file - pointer to struct file |
@@ -137,7 +164,8 @@ static int nfs_revalidate_file_size(struct inode *inode, struct file *filp) | |||
137 | goto force_reval; | 164 | goto force_reval; |
138 | if (nfsi->npages != 0) | 165 | if (nfsi->npages != 0) |
139 | return 0; | 166 | return 0; |
140 | return nfs_revalidate_inode(server, inode); | 167 | if (!(NFS_FLAGS(inode) & NFS_INO_REVAL_PAGECACHE) && !nfs_attribute_timeout(inode)) |
168 | return 0; | ||
141 | force_reval: | 169 | force_reval: |
142 | return __nfs_revalidate_inode(server, inode); | 170 | return __nfs_revalidate_inode(server, inode); |
143 | } | 171 | } |
@@ -198,7 +226,7 @@ nfs_file_read(struct kiocb *iocb, char __user * buf, size_t count, loff_t pos) | |||
198 | dentry->d_parent->d_name.name, dentry->d_name.name, | 226 | dentry->d_parent->d_name.name, dentry->d_name.name, |
199 | (unsigned long) count, (unsigned long) pos); | 227 | (unsigned long) count, (unsigned long) pos); |
200 | 228 | ||
201 | result = nfs_revalidate_inode(NFS_SERVER(inode), inode); | 229 | result = nfs_revalidate_file(inode, iocb->ki_filp); |
202 | if (!result) | 230 | if (!result) |
203 | result = generic_file_aio_read(iocb, buf, count, pos); | 231 | result = generic_file_aio_read(iocb, buf, count, pos); |
204 | return result; | 232 | return result; |
@@ -216,7 +244,7 @@ nfs_file_sendfile(struct file *filp, loff_t *ppos, size_t count, | |||
216 | dentry->d_parent->d_name.name, dentry->d_name.name, | 244 | dentry->d_parent->d_name.name, dentry->d_name.name, |
217 | (unsigned long) count, (unsigned long long) *ppos); | 245 | (unsigned long) count, (unsigned long long) *ppos); |
218 | 246 | ||
219 | res = nfs_revalidate_inode(NFS_SERVER(inode), inode); | 247 | res = nfs_revalidate_file(inode, filp); |
220 | if (!res) | 248 | if (!res) |
221 | res = generic_file_sendfile(filp, ppos, count, actor, target); | 249 | res = generic_file_sendfile(filp, ppos, count, actor, target); |
222 | return res; | 250 | return res; |
@@ -232,7 +260,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) | |||
232 | dfprintk(VFS, "nfs: mmap(%s/%s)\n", | 260 | dfprintk(VFS, "nfs: mmap(%s/%s)\n", |
233 | dentry->d_parent->d_name.name, dentry->d_name.name); | 261 | dentry->d_parent->d_name.name, dentry->d_name.name); |
234 | 262 | ||
235 | status = nfs_revalidate_inode(NFS_SERVER(inode), inode); | 263 | status = nfs_revalidate_file(inode, file); |
236 | if (!status) | 264 | if (!status) |
237 | status = generic_file_mmap(file, vma); | 265 | status = generic_file_mmap(file, vma); |
238 | return status; | 266 | return status; |
@@ -321,9 +349,15 @@ nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t | |||
321 | result = -EBUSY; | 349 | result = -EBUSY; |
322 | if (IS_SWAPFILE(inode)) | 350 | if (IS_SWAPFILE(inode)) |
323 | goto out_swapfile; | 351 | goto out_swapfile; |
324 | result = nfs_revalidate_inode(NFS_SERVER(inode), inode); | 352 | /* |
325 | if (result) | 353 | * O_APPEND implies that we must revalidate the file length. |
326 | goto out; | 354 | */ |
355 | if (iocb->ki_filp->f_flags & O_APPEND) { | ||
356 | result = nfs_revalidate_file_size(inode, iocb->ki_filp); | ||
357 | if (result) | ||
358 | goto out; | ||
359 | } | ||
360 | nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping); | ||
327 | 361 | ||
328 | result = count; | 362 | result = count; |
329 | if (!count) | 363 | if (!count) |
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 87f4f9aeac86..ffb8df91dc34 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include <linux/nfs_fs.h> | 50 | #include <linux/nfs_fs.h> |
51 | 51 | ||
52 | #include <linux/nfs_idmap.h> | 52 | #include <linux/nfs_idmap.h> |
53 | #include "nfs4_fs.h" | ||
53 | 54 | ||
54 | #define IDMAP_HASH_SZ 128 | 55 | #define IDMAP_HASH_SZ 128 |
55 | 56 | ||
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index f2317f3e29f9..4845911f1c63 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <asm/system.h> | 39 | #include <asm/system.h> |
40 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
41 | 41 | ||
42 | #include "nfs4_fs.h" | ||
42 | #include "delegation.h" | 43 | #include "delegation.h" |
43 | 44 | ||
44 | #define NFSDBG_FACILITY NFSDBG_VFS | 45 | #define NFSDBG_FACILITY NFSDBG_VFS |
@@ -63,6 +64,7 @@ static void nfs_clear_inode(struct inode *); | |||
63 | static void nfs_umount_begin(struct super_block *); | 64 | static void nfs_umount_begin(struct super_block *); |
64 | static int nfs_statfs(struct super_block *, struct kstatfs *); | 65 | static int nfs_statfs(struct super_block *, struct kstatfs *); |
65 | static int nfs_show_options(struct seq_file *, struct vfsmount *); | 66 | static int nfs_show_options(struct seq_file *, struct vfsmount *); |
67 | static void nfs_zap_acl_cache(struct inode *); | ||
66 | 68 | ||
67 | static struct rpc_program nfs_program; | 69 | static struct rpc_program nfs_program; |
68 | 70 | ||
@@ -106,6 +108,21 @@ static struct rpc_program nfs_program = { | |||
106 | .pipe_dir_name = "/nfs", | 108 | .pipe_dir_name = "/nfs", |
107 | }; | 109 | }; |
108 | 110 | ||
111 | #ifdef CONFIG_NFS_V3_ACL | ||
112 | static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program }; | ||
113 | static struct rpc_version * nfsacl_version[] = { | ||
114 | [3] = &nfsacl_version3, | ||
115 | }; | ||
116 | |||
117 | struct rpc_program nfsacl_program = { | ||
118 | .name = "nfsacl", | ||
119 | .number = NFS_ACL_PROGRAM, | ||
120 | .nrvers = sizeof(nfsacl_version) / sizeof(nfsacl_version[0]), | ||
121 | .version = nfsacl_version, | ||
122 | .stats = &nfsacl_rpcstat, | ||
123 | }; | ||
124 | #endif /* CONFIG_NFS_V3_ACL */ | ||
125 | |||
109 | static inline unsigned long | 126 | static inline unsigned long |
110 | nfs_fattr_to_ino_t(struct nfs_fattr *fattr) | 127 | nfs_fattr_to_ino_t(struct nfs_fattr *fattr) |
111 | { | 128 | { |
@@ -118,7 +135,7 @@ nfs_write_inode(struct inode *inode, int sync) | |||
118 | int flags = sync ? FLUSH_WAIT : 0; | 135 | int flags = sync ? FLUSH_WAIT : 0; |
119 | int ret; | 136 | int ret; |
120 | 137 | ||
121 | ret = nfs_commit_inode(inode, 0, 0, flags); | 138 | ret = nfs_commit_inode(inode, flags); |
122 | if (ret < 0) | 139 | if (ret < 0) |
123 | return ret; | 140 | return ret; |
124 | return 0; | 141 | return 0; |
@@ -140,10 +157,6 @@ nfs_delete_inode(struct inode * inode) | |||
140 | clear_inode(inode); | 157 | clear_inode(inode); |
141 | } | 158 | } |
142 | 159 | ||
143 | /* | ||
144 | * For the moment, the only task for the NFS clear_inode method is to | ||
145 | * release the mmap credential | ||
146 | */ | ||
147 | static void | 160 | static void |
148 | nfs_clear_inode(struct inode *inode) | 161 | nfs_clear_inode(struct inode *inode) |
149 | { | 162 | { |
@@ -152,6 +165,7 @@ nfs_clear_inode(struct inode *inode) | |||
152 | 165 | ||
153 | nfs_wb_all(inode); | 166 | nfs_wb_all(inode); |
154 | BUG_ON (!list_empty(&nfsi->open_files)); | 167 | BUG_ON (!list_empty(&nfsi->open_files)); |
168 | nfs_zap_acl_cache(inode); | ||
155 | cred = nfsi->cache_access.cred; | 169 | cred = nfsi->cache_access.cred; |
156 | if (cred) | 170 | if (cred) |
157 | put_rpccred(cred); | 171 | put_rpccred(cred); |
@@ -161,11 +175,13 @@ nfs_clear_inode(struct inode *inode) | |||
161 | void | 175 | void |
162 | nfs_umount_begin(struct super_block *sb) | 176 | nfs_umount_begin(struct super_block *sb) |
163 | { | 177 | { |
164 | struct nfs_server *server = NFS_SB(sb); | 178 | struct rpc_clnt *rpc = NFS_SB(sb)->client; |
165 | struct rpc_clnt *rpc; | ||
166 | 179 | ||
167 | /* -EIO all pending I/O */ | 180 | /* -EIO all pending I/O */ |
168 | if ((rpc = server->client) != NULL) | 181 | if (!IS_ERR(rpc)) |
182 | rpc_killall_tasks(rpc); | ||
183 | rpc = NFS_SB(sb)->client_acl; | ||
184 | if (!IS_ERR(rpc)) | ||
169 | rpc_killall_tasks(rpc); | 185 | rpc_killall_tasks(rpc); |
170 | } | 186 | } |
171 | 187 | ||
@@ -366,13 +382,15 @@ nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data) | |||
366 | xprt = xprt_create_proto(tcp ? IPPROTO_TCP : IPPROTO_UDP, | 382 | xprt = xprt_create_proto(tcp ? IPPROTO_TCP : IPPROTO_UDP, |
367 | &server->addr, &timeparms); | 383 | &server->addr, &timeparms); |
368 | if (IS_ERR(xprt)) { | 384 | if (IS_ERR(xprt)) { |
369 | printk(KERN_WARNING "NFS: cannot create RPC transport.\n"); | 385 | dprintk("%s: cannot create RPC transport. Error = %ld\n", |
386 | __FUNCTION__, PTR_ERR(xprt)); | ||
370 | return (struct rpc_clnt *)xprt; | 387 | return (struct rpc_clnt *)xprt; |
371 | } | 388 | } |
372 | clnt = rpc_create_client(xprt, server->hostname, &nfs_program, | 389 | clnt = rpc_create_client(xprt, server->hostname, &nfs_program, |
373 | server->rpc_ops->version, data->pseudoflavor); | 390 | server->rpc_ops->version, data->pseudoflavor); |
374 | if (IS_ERR(clnt)) { | 391 | if (IS_ERR(clnt)) { |
375 | printk(KERN_WARNING "NFS: cannot create RPC client.\n"); | 392 | dprintk("%s: cannot create RPC client. Error = %ld\n", |
393 | __FUNCTION__, PTR_ERR(xprt)); | ||
376 | goto out_fail; | 394 | goto out_fail; |
377 | } | 395 | } |
378 | 396 | ||
@@ -383,7 +401,6 @@ nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data) | |||
383 | return clnt; | 401 | return clnt; |
384 | 402 | ||
385 | out_fail: | 403 | out_fail: |
386 | xprt_destroy(xprt); | ||
387 | return clnt; | 404 | return clnt; |
388 | } | 405 | } |
389 | 406 | ||
@@ -427,21 +444,16 @@ nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent) | |||
427 | 444 | ||
428 | /* Check NFS protocol revision and initialize RPC op vector | 445 | /* Check NFS protocol revision and initialize RPC op vector |
429 | * and file handle pool. */ | 446 | * and file handle pool. */ |
430 | if (server->flags & NFS_MOUNT_VER3) { | ||
431 | #ifdef CONFIG_NFS_V3 | 447 | #ifdef CONFIG_NFS_V3 |
448 | if (server->flags & NFS_MOUNT_VER3) { | ||
432 | server->rpc_ops = &nfs_v3_clientops; | 449 | server->rpc_ops = &nfs_v3_clientops; |
433 | server->caps |= NFS_CAP_READDIRPLUS; | 450 | server->caps |= NFS_CAP_READDIRPLUS; |
434 | if (data->version < 4) { | ||
435 | printk(KERN_NOTICE "NFS: NFSv3 not supported by mount program.\n"); | ||
436 | return -EIO; | ||
437 | } | ||
438 | #else | ||
439 | printk(KERN_NOTICE "NFS: NFSv3 not supported.\n"); | ||
440 | return -EIO; | ||
441 | #endif | ||
442 | } else { | 451 | } else { |
443 | server->rpc_ops = &nfs_v2_clientops; | 452 | server->rpc_ops = &nfs_v2_clientops; |
444 | } | 453 | } |
454 | #else | ||
455 | server->rpc_ops = &nfs_v2_clientops; | ||
456 | #endif | ||
445 | 457 | ||
446 | /* Fill in pseudoflavor for mount version < 5 */ | 458 | /* Fill in pseudoflavor for mount version < 5 */ |
447 | if (!(data->flags & NFS_MOUNT_SECFLAVOUR)) | 459 | if (!(data->flags & NFS_MOUNT_SECFLAVOUR)) |
@@ -455,17 +467,34 @@ nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent) | |||
455 | return PTR_ERR(server->client); | 467 | return PTR_ERR(server->client); |
456 | /* RFC 2623, sec 2.3.2 */ | 468 | /* RFC 2623, sec 2.3.2 */ |
457 | if (authflavor != RPC_AUTH_UNIX) { | 469 | if (authflavor != RPC_AUTH_UNIX) { |
470 | struct rpc_auth *auth; | ||
471 | |||
458 | server->client_sys = rpc_clone_client(server->client); | 472 | server->client_sys = rpc_clone_client(server->client); |
459 | if (IS_ERR(server->client_sys)) | 473 | if (IS_ERR(server->client_sys)) |
460 | return PTR_ERR(server->client_sys); | 474 | return PTR_ERR(server->client_sys); |
461 | if (!rpcauth_create(RPC_AUTH_UNIX, server->client_sys)) | 475 | auth = rpcauth_create(RPC_AUTH_UNIX, server->client_sys); |
462 | return -ENOMEM; | 476 | if (IS_ERR(auth)) |
477 | return PTR_ERR(auth); | ||
463 | } else { | 478 | } else { |
464 | atomic_inc(&server->client->cl_count); | 479 | atomic_inc(&server->client->cl_count); |
465 | server->client_sys = server->client; | 480 | server->client_sys = server->client; |
466 | } | 481 | } |
467 | |||
468 | if (server->flags & NFS_MOUNT_VER3) { | 482 | if (server->flags & NFS_MOUNT_VER3) { |
483 | #ifdef CONFIG_NFS_V3_ACL | ||
484 | if (!(server->flags & NFS_MOUNT_NOACL)) { | ||
485 | server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3); | ||
486 | /* No errors! Assume that Sun nfsacls are supported */ | ||
487 | if (!IS_ERR(server->client_acl)) | ||
488 | server->caps |= NFS_CAP_ACLS; | ||
489 | } | ||
490 | #else | ||
491 | server->flags &= ~NFS_MOUNT_NOACL; | ||
492 | #endif /* CONFIG_NFS_V3_ACL */ | ||
493 | /* | ||
494 | * The VFS shouldn't apply the umask to mode bits. We will | ||
495 | * do so ourselves when necessary. | ||
496 | */ | ||
497 | sb->s_flags |= MS_POSIXACL; | ||
469 | if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN) | 498 | if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN) |
470 | server->namelen = NFS3_MAXNAMLEN; | 499 | server->namelen = NFS3_MAXNAMLEN; |
471 | sb->s_time_gran = 1; | 500 | sb->s_time_gran = 1; |
@@ -549,6 +578,7 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
549 | { NFS_MOUNT_NOCTO, ",nocto", "" }, | 578 | { NFS_MOUNT_NOCTO, ",nocto", "" }, |
550 | { NFS_MOUNT_NOAC, ",noac", "" }, | 579 | { NFS_MOUNT_NOAC, ",noac", "" }, |
551 | { NFS_MOUNT_NONLM, ",nolock", ",lock" }, | 580 | { NFS_MOUNT_NONLM, ",nolock", ",lock" }, |
581 | { NFS_MOUNT_NOACL, ",noacl", "" }, | ||
552 | { 0, NULL, NULL } | 582 | { 0, NULL, NULL } |
553 | }; | 583 | }; |
554 | struct proc_nfs_info *nfs_infop; | 584 | struct proc_nfs_info *nfs_infop; |
@@ -590,9 +620,19 @@ nfs_zap_caches(struct inode *inode) | |||
590 | 620 | ||
591 | memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); | 621 | memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); |
592 | if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) | 622 | if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) |
593 | nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS; | 623 | nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; |
594 | else | 624 | else |
595 | nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS; | 625 | nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; |
626 | } | ||
627 | |||
628 | static void nfs_zap_acl_cache(struct inode *inode) | ||
629 | { | ||
630 | void (*clear_acl_cache)(struct inode *); | ||
631 | |||
632 | clear_acl_cache = NFS_PROTO(inode)->clear_acl_cache; | ||
633 | if (clear_acl_cache != NULL) | ||
634 | clear_acl_cache(inode); | ||
635 | NFS_I(inode)->flags &= ~NFS_INO_INVALID_ACL; | ||
596 | } | 636 | } |
597 | 637 | ||
598 | /* | 638 | /* |
@@ -689,7 +729,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
689 | /* Why so? Because we want revalidate for devices/FIFOs, and | 729 | /* Why so? Because we want revalidate for devices/FIFOs, and |
690 | * that's precisely what we have in nfs_file_inode_operations. | 730 | * that's precisely what we have in nfs_file_inode_operations. |
691 | */ | 731 | */ |
692 | inode->i_op = &nfs_file_inode_operations; | 732 | inode->i_op = NFS_SB(sb)->rpc_ops->file_inode_ops; |
693 | if (S_ISREG(inode->i_mode)) { | 733 | if (S_ISREG(inode->i_mode)) { |
694 | inode->i_fop = &nfs_file_operations; | 734 | inode->i_fop = &nfs_file_operations; |
695 | inode->i_data.a_ops = &nfs_file_aops; | 735 | inode->i_data.a_ops = &nfs_file_aops; |
@@ -792,7 +832,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
792 | } | 832 | } |
793 | } | 833 | } |
794 | if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) | 834 | if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) |
795 | NFS_FLAGS(inode) |= NFS_INO_INVALID_ACCESS; | 835 | NFS_FLAGS(inode) |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
796 | nfs_end_data_update(inode); | 836 | nfs_end_data_update(inode); |
797 | unlock_kernel(); | 837 | unlock_kernel(); |
798 | return error; | 838 | return error; |
@@ -851,7 +891,7 @@ struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rp | |||
851 | ctx->state = NULL; | 891 | ctx->state = NULL; |
852 | ctx->lockowner = current->files; | 892 | ctx->lockowner = current->files; |
853 | ctx->error = 0; | 893 | ctx->error = 0; |
854 | init_waitqueue_head(&ctx->waitq); | 894 | ctx->dir_cookie = 0; |
855 | } | 895 | } |
856 | return ctx; | 896 | return ctx; |
857 | } | 897 | } |
@@ -1015,6 +1055,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
1015 | goto out; | 1055 | goto out; |
1016 | } | 1056 | } |
1017 | flags = nfsi->flags; | 1057 | flags = nfsi->flags; |
1058 | nfsi->flags &= ~NFS_INO_REVAL_PAGECACHE; | ||
1018 | /* | 1059 | /* |
1019 | * We may need to keep the attributes marked as invalid if | 1060 | * We may need to keep the attributes marked as invalid if |
1020 | * we raced with nfs_end_attr_update(). | 1061 | * we raced with nfs_end_attr_update(). |
@@ -1022,21 +1063,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
1022 | if (verifier == nfsi->cache_change_attribute) | 1063 | if (verifier == nfsi->cache_change_attribute) |
1023 | nfsi->flags &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME); | 1064 | nfsi->flags &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME); |
1024 | /* Do the page cache invalidation */ | 1065 | /* Do the page cache invalidation */ |
1025 | if (flags & NFS_INO_INVALID_DATA) { | 1066 | nfs_revalidate_mapping(inode, inode->i_mapping); |
1026 | if (S_ISREG(inode->i_mode)) { | 1067 | if (flags & NFS_INO_INVALID_ACL) |
1027 | if (filemap_fdatawrite(inode->i_mapping) == 0) | 1068 | nfs_zap_acl_cache(inode); |
1028 | filemap_fdatawait(inode->i_mapping); | ||
1029 | nfs_wb_all(inode); | ||
1030 | } | ||
1031 | nfsi->flags &= ~NFS_INO_INVALID_DATA; | ||
1032 | invalidate_inode_pages2(inode->i_mapping); | ||
1033 | memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); | ||
1034 | dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", | ||
1035 | inode->i_sb->s_id, | ||
1036 | (long long)NFS_FILEID(inode)); | ||
1037 | /* This ensures we revalidate dentries */ | ||
1038 | nfsi->cache_change_attribute++; | ||
1039 | } | ||
1040 | dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n", | 1069 | dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n", |
1041 | inode->i_sb->s_id, | 1070 | inode->i_sb->s_id, |
1042 | (long long)NFS_FILEID(inode)); | 1071 | (long long)NFS_FILEID(inode)); |
@@ -1074,6 +1103,34 @@ int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
1074 | } | 1103 | } |
1075 | 1104 | ||
1076 | /** | 1105 | /** |
1106 | * nfs_revalidate_mapping - Revalidate the pagecache | ||
1107 | * @inode - pointer to host inode | ||
1108 | * @mapping - pointer to mapping | ||
1109 | */ | ||
1110 | void nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) | ||
1111 | { | ||
1112 | struct nfs_inode *nfsi = NFS_I(inode); | ||
1113 | |||
1114 | if (nfsi->flags & NFS_INO_INVALID_DATA) { | ||
1115 | if (S_ISREG(inode->i_mode)) { | ||
1116 | if (filemap_fdatawrite(mapping) == 0) | ||
1117 | filemap_fdatawait(mapping); | ||
1118 | nfs_wb_all(inode); | ||
1119 | } | ||
1120 | invalidate_inode_pages2(mapping); | ||
1121 | nfsi->flags &= ~NFS_INO_INVALID_DATA; | ||
1122 | if (S_ISDIR(inode->i_mode)) { | ||
1123 | memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); | ||
1124 | /* This ensures we revalidate child dentries */ | ||
1125 | nfsi->cache_change_attribute++; | ||
1126 | } | ||
1127 | dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", | ||
1128 | inode->i_sb->s_id, | ||
1129 | (long long)NFS_FILEID(inode)); | ||
1130 | } | ||
1131 | } | ||
1132 | |||
1133 | /** | ||
1077 | * nfs_begin_data_update | 1134 | * nfs_begin_data_update |
1078 | * @inode - pointer to inode | 1135 | * @inode - pointer to inode |
1079 | * Declare that a set of operations will update file data on the server | 1136 | * Declare that a set of operations will update file data on the server |
@@ -1106,27 +1163,6 @@ void nfs_end_data_update(struct inode *inode) | |||
1106 | } | 1163 | } |
1107 | 1164 | ||
1108 | /** | 1165 | /** |
1109 | * nfs_end_data_update_defer | ||
1110 | * @inode - pointer to inode | ||
1111 | * Declare end of the operations that will update file data | ||
1112 | * This will defer marking the inode as needing revalidation | ||
1113 | * unless there are no other pending updates. | ||
1114 | */ | ||
1115 | void nfs_end_data_update_defer(struct inode *inode) | ||
1116 | { | ||
1117 | struct nfs_inode *nfsi = NFS_I(inode); | ||
1118 | |||
1119 | if (atomic_dec_and_test(&nfsi->data_updates)) { | ||
1120 | /* Mark the attribute cache for revalidation */ | ||
1121 | nfsi->flags |= NFS_INO_INVALID_ATTR; | ||
1122 | /* Directories and symlinks: invalidate page cache too */ | ||
1123 | if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) | ||
1124 | nfsi->flags |= NFS_INO_INVALID_DATA; | ||
1125 | nfsi->cache_change_attribute ++; | ||
1126 | } | ||
1127 | } | ||
1128 | |||
1129 | /** | ||
1130 | * nfs_refresh_inode - verify consistency of the inode attribute cache | 1166 | * nfs_refresh_inode - verify consistency of the inode attribute cache |
1131 | * @inode - pointer to inode | 1167 | * @inode - pointer to inode |
1132 | * @fattr - updated attributes | 1168 | * @fattr - updated attributes |
@@ -1152,8 +1188,11 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1152 | if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0 | 1188 | if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0 |
1153 | && nfsi->change_attr == fattr->pre_change_attr) | 1189 | && nfsi->change_attr == fattr->pre_change_attr) |
1154 | nfsi->change_attr = fattr->change_attr; | 1190 | nfsi->change_attr = fattr->change_attr; |
1155 | if (!data_unstable && nfsi->change_attr != fattr->change_attr) | 1191 | if (nfsi->change_attr != fattr->change_attr) { |
1156 | nfsi->flags |= NFS_INO_INVALID_ATTR; | 1192 | nfsi->flags |= NFS_INO_INVALID_ATTR; |
1193 | if (!data_unstable) | ||
1194 | nfsi->flags |= NFS_INO_REVAL_PAGECACHE; | ||
1195 | } | ||
1157 | } | 1196 | } |
1158 | 1197 | ||
1159 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) | 1198 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) |
@@ -1176,18 +1215,22 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1176 | } | 1215 | } |
1177 | 1216 | ||
1178 | /* Verify a few of the more important attributes */ | 1217 | /* Verify a few of the more important attributes */ |
1179 | if (!data_unstable) { | 1218 | if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { |
1180 | if (!timespec_equal(&inode->i_mtime, &fattr->mtime) | 1219 | nfsi->flags |= NFS_INO_INVALID_ATTR; |
1181 | || cur_size != new_isize) | 1220 | if (!data_unstable) |
1182 | nfsi->flags |= NFS_INO_INVALID_ATTR; | 1221 | nfsi->flags |= NFS_INO_REVAL_PAGECACHE; |
1183 | } else if (S_ISREG(inode->i_mode) && new_isize > cur_size) | 1222 | } |
1184 | nfsi->flags |= NFS_INO_INVALID_ATTR; | 1223 | if (cur_size != new_isize) { |
1224 | nfsi->flags |= NFS_INO_INVALID_ATTR; | ||
1225 | if (nfsi->npages == 0) | ||
1226 | nfsi->flags |= NFS_INO_REVAL_PAGECACHE; | ||
1227 | } | ||
1185 | 1228 | ||
1186 | /* Have any file permissions changed? */ | 1229 | /* Have any file permissions changed? */ |
1187 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) | 1230 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) |
1188 | || inode->i_uid != fattr->uid | 1231 | || inode->i_uid != fattr->uid |
1189 | || inode->i_gid != fattr->gid) | 1232 | || inode->i_gid != fattr->gid) |
1190 | nfsi->flags |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS; | 1233 | nfsi->flags |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL; |
1191 | 1234 | ||
1192 | /* Has the link count changed? */ | 1235 | /* Has the link count changed? */ |
1193 | if (inode->i_nlink != fattr->nlink) | 1236 | if (inode->i_nlink != fattr->nlink) |
@@ -1215,10 +1258,8 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1215 | static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsigned long verifier) | 1258 | static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsigned long verifier) |
1216 | { | 1259 | { |
1217 | struct nfs_inode *nfsi = NFS_I(inode); | 1260 | struct nfs_inode *nfsi = NFS_I(inode); |
1218 | __u64 new_size; | 1261 | loff_t cur_isize, new_isize; |
1219 | loff_t new_isize; | ||
1220 | unsigned int invalid = 0; | 1262 | unsigned int invalid = 0; |
1221 | loff_t cur_isize; | ||
1222 | int data_unstable; | 1263 | int data_unstable; |
1223 | 1264 | ||
1224 | dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", | 1265 | dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", |
@@ -1251,61 +1292,56 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign | |||
1251 | /* Are we racing with known updates of the metadata on the server? */ | 1292 | /* Are we racing with known updates of the metadata on the server? */ |
1252 | data_unstable = ! nfs_verify_change_attribute(inode, verifier); | 1293 | data_unstable = ! nfs_verify_change_attribute(inode, verifier); |
1253 | 1294 | ||
1254 | /* Check if the file size agrees */ | 1295 | /* Check if our cached file size is stale */ |
1255 | new_size = fattr->size; | ||
1256 | new_isize = nfs_size_to_loff_t(fattr->size); | 1296 | new_isize = nfs_size_to_loff_t(fattr->size); |
1257 | cur_isize = i_size_read(inode); | 1297 | cur_isize = i_size_read(inode); |
1258 | if (cur_isize != new_size) { | 1298 | if (new_isize != cur_isize) { |
1259 | #ifdef NFS_DEBUG_VERBOSE | 1299 | /* Do we perhaps have any outstanding writes? */ |
1260 | printk(KERN_DEBUG "NFS: isize change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino); | 1300 | if (nfsi->npages == 0) { |
1261 | #endif | 1301 | /* No, but did we race with nfs_end_data_update()? */ |
1262 | /* | 1302 | if (verifier == nfsi->cache_change_attribute) { |
1263 | * If we have pending writebacks, things can get | ||
1264 | * messy. | ||
1265 | */ | ||
1266 | if (S_ISREG(inode->i_mode) && data_unstable) { | ||
1267 | if (new_isize > cur_isize) { | ||
1268 | inode->i_size = new_isize; | 1303 | inode->i_size = new_isize; |
1269 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; | 1304 | invalid |= NFS_INO_INVALID_DATA; |
1270 | } | 1305 | } |
1271 | } else { | 1306 | invalid |= NFS_INO_INVALID_ATTR; |
1307 | } else if (new_isize > cur_isize) { | ||
1272 | inode->i_size = new_isize; | 1308 | inode->i_size = new_isize; |
1273 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; | 1309 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; |
1274 | } | 1310 | } |
1311 | dprintk("NFS: isize change on server for file %s/%ld\n", | ||
1312 | inode->i_sb->s_id, inode->i_ino); | ||
1275 | } | 1313 | } |
1276 | 1314 | ||
1277 | /* | 1315 | /* Check if the mtime agrees */ |
1278 | * Note: we don't check inode->i_mtime since pipes etc. | ||
1279 | * can change this value in VFS without requiring a | ||
1280 | * cache revalidation. | ||
1281 | */ | ||
1282 | if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { | 1316 | if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { |
1283 | memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); | 1317 | memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); |
1284 | #ifdef NFS_DEBUG_VERBOSE | 1318 | dprintk("NFS: mtime change on server for file %s/%ld\n", |
1285 | printk(KERN_DEBUG "NFS: mtime change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino); | 1319 | inode->i_sb->s_id, inode->i_ino); |
1286 | #endif | ||
1287 | if (!data_unstable) | 1320 | if (!data_unstable) |
1288 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; | 1321 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; |
1289 | } | 1322 | } |
1290 | 1323 | ||
1291 | if ((fattr->valid & NFS_ATTR_FATTR_V4) | 1324 | if ((fattr->valid & NFS_ATTR_FATTR_V4) |
1292 | && nfsi->change_attr != fattr->change_attr) { | 1325 | && nfsi->change_attr != fattr->change_attr) { |
1293 | #ifdef NFS_DEBUG_VERBOSE | 1326 | dprintk("NFS: change_attr change on server for file %s/%ld\n", |
1294 | printk(KERN_DEBUG "NFS: change_attr change on %s/%ld\n", | ||
1295 | inode->i_sb->s_id, inode->i_ino); | 1327 | inode->i_sb->s_id, inode->i_ino); |
1296 | #endif | ||
1297 | nfsi->change_attr = fattr->change_attr; | 1328 | nfsi->change_attr = fattr->change_attr; |
1298 | if (!data_unstable) | 1329 | if (!data_unstable) |
1299 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS; | 1330 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
1300 | } | 1331 | } |
1301 | 1332 | ||
1302 | memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); | 1333 | /* If ctime has changed we should definitely clear access+acl caches */ |
1334 | if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) { | ||
1335 | if (!data_unstable) | ||
1336 | invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | ||
1337 | memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); | ||
1338 | } | ||
1303 | memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); | 1339 | memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); |
1304 | 1340 | ||
1305 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) || | 1341 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) || |
1306 | inode->i_uid != fattr->uid || | 1342 | inode->i_uid != fattr->uid || |
1307 | inode->i_gid != fattr->gid) | 1343 | inode->i_gid != fattr->gid) |
1308 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS; | 1344 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
1309 | 1345 | ||
1310 | inode->i_mode = fattr->mode; | 1346 | inode->i_mode = fattr->mode; |
1311 | inode->i_nlink = fattr->nlink; | 1347 | inode->i_nlink = fattr->nlink; |
@@ -1385,74 +1421,95 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type, | |||
1385 | int flags, const char *dev_name, void *raw_data) | 1421 | int flags, const char *dev_name, void *raw_data) |
1386 | { | 1422 | { |
1387 | int error; | 1423 | int error; |
1388 | struct nfs_server *server; | 1424 | struct nfs_server *server = NULL; |
1389 | struct super_block *s; | 1425 | struct super_block *s; |
1390 | struct nfs_fh *root; | 1426 | struct nfs_fh *root; |
1391 | struct nfs_mount_data *data = raw_data; | 1427 | struct nfs_mount_data *data = raw_data; |
1392 | 1428 | ||
1393 | if (!data) { | 1429 | s = ERR_PTR(-EINVAL); |
1394 | printk("nfs_read_super: missing data argument\n"); | 1430 | if (data == NULL) { |
1395 | return ERR_PTR(-EINVAL); | 1431 | dprintk("%s: missing data argument\n", __FUNCTION__); |
1432 | goto out_err; | ||
1433 | } | ||
1434 | if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) { | ||
1435 | dprintk("%s: bad mount version\n", __FUNCTION__); | ||
1436 | goto out_err; | ||
1396 | } | 1437 | } |
1438 | switch (data->version) { | ||
1439 | case 1: | ||
1440 | data->namlen = 0; | ||
1441 | case 2: | ||
1442 | data->bsize = 0; | ||
1443 | case 3: | ||
1444 | if (data->flags & NFS_MOUNT_VER3) { | ||
1445 | dprintk("%s: mount structure version %d does not support NFSv3\n", | ||
1446 | __FUNCTION__, | ||
1447 | data->version); | ||
1448 | goto out_err; | ||
1449 | } | ||
1450 | data->root.size = NFS2_FHSIZE; | ||
1451 | memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); | ||
1452 | case 4: | ||
1453 | if (data->flags & NFS_MOUNT_SECFLAVOUR) { | ||
1454 | dprintk("%s: mount structure version %d does not support strong security\n", | ||
1455 | __FUNCTION__, | ||
1456 | data->version); | ||
1457 | goto out_err; | ||
1458 | } | ||
1459 | case 5: | ||
1460 | memset(data->context, 0, sizeof(data->context)); | ||
1461 | } | ||
1462 | #ifndef CONFIG_NFS_V3 | ||
1463 | /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */ | ||
1464 | s = ERR_PTR(-EPROTONOSUPPORT); | ||
1465 | if (data->flags & NFS_MOUNT_VER3) { | ||
1466 | dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__); | ||
1467 | goto out_err; | ||
1468 | } | ||
1469 | #endif /* CONFIG_NFS_V3 */ | ||
1397 | 1470 | ||
1471 | s = ERR_PTR(-ENOMEM); | ||
1398 | server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL); | 1472 | server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL); |
1399 | if (!server) | 1473 | if (!server) |
1400 | return ERR_PTR(-ENOMEM); | 1474 | goto out_err; |
1401 | memset(server, 0, sizeof(struct nfs_server)); | 1475 | memset(server, 0, sizeof(struct nfs_server)); |
1402 | /* Zero out the NFS state stuff */ | 1476 | /* Zero out the NFS state stuff */ |
1403 | init_nfsv4_state(server); | 1477 | init_nfsv4_state(server); |
1404 | 1478 | server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); | |
1405 | if (data->version != NFS_MOUNT_VERSION) { | ||
1406 | printk("nfs warning: mount version %s than kernel\n", | ||
1407 | data->version < NFS_MOUNT_VERSION ? "older" : "newer"); | ||
1408 | if (data->version < 2) | ||
1409 | data->namlen = 0; | ||
1410 | if (data->version < 3) | ||
1411 | data->bsize = 0; | ||
1412 | if (data->version < 4) { | ||
1413 | data->flags &= ~NFS_MOUNT_VER3; | ||
1414 | data->root.size = NFS2_FHSIZE; | ||
1415 | memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); | ||
1416 | } | ||
1417 | if (data->version < 5) | ||
1418 | data->flags &= ~NFS_MOUNT_SECFLAVOUR; | ||
1419 | } | ||
1420 | 1479 | ||
1421 | root = &server->fh; | 1480 | root = &server->fh; |
1422 | if (data->flags & NFS_MOUNT_VER3) | 1481 | if (data->flags & NFS_MOUNT_VER3) |
1423 | root->size = data->root.size; | 1482 | root->size = data->root.size; |
1424 | else | 1483 | else |
1425 | root->size = NFS2_FHSIZE; | 1484 | root->size = NFS2_FHSIZE; |
1485 | s = ERR_PTR(-EINVAL); | ||
1426 | if (root->size > sizeof(root->data)) { | 1486 | if (root->size > sizeof(root->data)) { |
1427 | printk("nfs_get_sb: invalid root filehandle\n"); | 1487 | dprintk("%s: invalid root filehandle\n", __FUNCTION__); |
1428 | kfree(server); | 1488 | goto out_err; |
1429 | return ERR_PTR(-EINVAL); | ||
1430 | } | 1489 | } |
1431 | memcpy(root->data, data->root.data, root->size); | 1490 | memcpy(root->data, data->root.data, root->size); |
1432 | 1491 | ||
1433 | /* We now require that the mount process passes the remote address */ | 1492 | /* We now require that the mount process passes the remote address */ |
1434 | memcpy(&server->addr, &data->addr, sizeof(server->addr)); | 1493 | memcpy(&server->addr, &data->addr, sizeof(server->addr)); |
1435 | if (server->addr.sin_addr.s_addr == INADDR_ANY) { | 1494 | if (server->addr.sin_addr.s_addr == INADDR_ANY) { |
1436 | printk("NFS: mount program didn't pass remote address!\n"); | 1495 | dprintk("%s: mount program didn't pass remote address!\n", |
1437 | kfree(server); | 1496 | __FUNCTION__); |
1438 | return ERR_PTR(-EINVAL); | 1497 | goto out_err; |
1439 | } | 1498 | } |
1440 | 1499 | ||
1441 | s = sget(fs_type, nfs_compare_super, nfs_set_super, server); | 1500 | /* Fire up rpciod if not yet running */ |
1442 | 1501 | s = ERR_PTR(rpciod_up()); | |
1443 | if (IS_ERR(s) || s->s_root) { | 1502 | if (IS_ERR(s)) { |
1444 | kfree(server); | 1503 | dprintk("%s: couldn't start rpciod! Error = %ld\n", |
1445 | return s; | 1504 | __FUNCTION__, PTR_ERR(s)); |
1505 | goto out_err; | ||
1446 | } | 1506 | } |
1447 | 1507 | ||
1448 | s->s_flags = flags; | 1508 | s = sget(fs_type, nfs_compare_super, nfs_set_super, server); |
1509 | if (IS_ERR(s) || s->s_root) | ||
1510 | goto out_rpciod_down; | ||
1449 | 1511 | ||
1450 | /* Fire up rpciod if not yet running */ | 1512 | s->s_flags = flags; |
1451 | if (rpciod_up() != 0) { | ||
1452 | printk(KERN_WARNING "NFS: couldn't start rpciod!\n"); | ||
1453 | kfree(server); | ||
1454 | return ERR_PTR(-EIO); | ||
1455 | } | ||
1456 | 1513 | ||
1457 | error = nfs_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0); | 1514 | error = nfs_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0); |
1458 | if (error) { | 1515 | if (error) { |
@@ -1462,6 +1519,11 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type, | |||
1462 | } | 1519 | } |
1463 | s->s_flags |= MS_ACTIVE; | 1520 | s->s_flags |= MS_ACTIVE; |
1464 | return s; | 1521 | return s; |
1522 | out_rpciod_down: | ||
1523 | rpciod_down(); | ||
1524 | out_err: | ||
1525 | kfree(server); | ||
1526 | return s; | ||
1465 | } | 1527 | } |
1466 | 1528 | ||
1467 | static void nfs_kill_super(struct super_block *s) | 1529 | static void nfs_kill_super(struct super_block *s) |
@@ -1470,10 +1532,12 @@ static void nfs_kill_super(struct super_block *s) | |||
1470 | 1532 | ||
1471 | kill_anon_super(s); | 1533 | kill_anon_super(s); |
1472 | 1534 | ||
1473 | if (server->client != NULL && !IS_ERR(server->client)) | 1535 | if (!IS_ERR(server->client)) |
1474 | rpc_shutdown_client(server->client); | 1536 | rpc_shutdown_client(server->client); |
1475 | if (server->client_sys != NULL && !IS_ERR(server->client_sys)) | 1537 | if (!IS_ERR(server->client_sys)) |
1476 | rpc_shutdown_client(server->client_sys); | 1538 | rpc_shutdown_client(server->client_sys); |
1539 | if (!IS_ERR(server->client_acl)) | ||
1540 | rpc_shutdown_client(server->client_acl); | ||
1477 | 1541 | ||
1478 | if (!(server->flags & NFS_MOUNT_NONLM)) | 1542 | if (!(server->flags & NFS_MOUNT_NONLM)) |
1479 | lockd_down(); /* release rpc.lockd */ | 1543 | lockd_down(); /* release rpc.lockd */ |
@@ -1594,15 +1658,19 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, | |||
1594 | 1658 | ||
1595 | clp = nfs4_get_client(&server->addr.sin_addr); | 1659 | clp = nfs4_get_client(&server->addr.sin_addr); |
1596 | if (!clp) { | 1660 | if (!clp) { |
1597 | printk(KERN_WARNING "NFS: failed to create NFS4 client.\n"); | 1661 | dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__); |
1598 | return -EIO; | 1662 | return -EIO; |
1599 | } | 1663 | } |
1600 | 1664 | ||
1601 | /* Now create transport and client */ | 1665 | /* Now create transport and client */ |
1602 | authflavour = RPC_AUTH_UNIX; | 1666 | authflavour = RPC_AUTH_UNIX; |
1603 | if (data->auth_flavourlen != 0) { | 1667 | if (data->auth_flavourlen != 0) { |
1604 | if (data->auth_flavourlen > 1) | 1668 | if (data->auth_flavourlen != 1) { |
1605 | printk(KERN_INFO "NFS: cannot yet deal with multiple auth flavours.\n"); | 1669 | dprintk("%s: Invalid number of RPC auth flavours %d.\n", |
1670 | __FUNCTION__, data->auth_flavourlen); | ||
1671 | err = -EINVAL; | ||
1672 | goto out_fail; | ||
1673 | } | ||
1606 | if (copy_from_user(&authflavour, data->auth_flavours, sizeof(authflavour))) { | 1674 | if (copy_from_user(&authflavour, data->auth_flavours, sizeof(authflavour))) { |
1607 | err = -EFAULT; | 1675 | err = -EFAULT; |
1608 | goto out_fail; | 1676 | goto out_fail; |
@@ -1610,21 +1678,22 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, | |||
1610 | } | 1678 | } |
1611 | 1679 | ||
1612 | down_write(&clp->cl_sem); | 1680 | down_write(&clp->cl_sem); |
1613 | if (clp->cl_rpcclient == NULL) { | 1681 | if (IS_ERR(clp->cl_rpcclient)) { |
1614 | xprt = xprt_create_proto(proto, &server->addr, &timeparms); | 1682 | xprt = xprt_create_proto(proto, &server->addr, &timeparms); |
1615 | if (IS_ERR(xprt)) { | 1683 | if (IS_ERR(xprt)) { |
1616 | up_write(&clp->cl_sem); | 1684 | up_write(&clp->cl_sem); |
1617 | printk(KERN_WARNING "NFS: cannot create RPC transport.\n"); | ||
1618 | err = PTR_ERR(xprt); | 1685 | err = PTR_ERR(xprt); |
1686 | dprintk("%s: cannot create RPC transport. Error = %d\n", | ||
1687 | __FUNCTION__, err); | ||
1619 | goto out_fail; | 1688 | goto out_fail; |
1620 | } | 1689 | } |
1621 | clnt = rpc_create_client(xprt, server->hostname, &nfs_program, | 1690 | clnt = rpc_create_client(xprt, server->hostname, &nfs_program, |
1622 | server->rpc_ops->version, authflavour); | 1691 | server->rpc_ops->version, authflavour); |
1623 | if (IS_ERR(clnt)) { | 1692 | if (IS_ERR(clnt)) { |
1624 | up_write(&clp->cl_sem); | 1693 | up_write(&clp->cl_sem); |
1625 | printk(KERN_WARNING "NFS: cannot create RPC client.\n"); | ||
1626 | xprt_destroy(xprt); | ||
1627 | err = PTR_ERR(clnt); | 1694 | err = PTR_ERR(clnt); |
1695 | dprintk("%s: cannot create RPC client. Error = %d\n", | ||
1696 | __FUNCTION__, err); | ||
1628 | goto out_fail; | 1697 | goto out_fail; |
1629 | } | 1698 | } |
1630 | clnt->cl_intr = 1; | 1699 | clnt->cl_intr = 1; |
@@ -1656,21 +1725,26 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, | |||
1656 | clp = NULL; | 1725 | clp = NULL; |
1657 | 1726 | ||
1658 | if (IS_ERR(clnt)) { | 1727 | if (IS_ERR(clnt)) { |
1659 | printk(KERN_WARNING "NFS: cannot create RPC client.\n"); | 1728 | err = PTR_ERR(clnt); |
1660 | return PTR_ERR(clnt); | 1729 | dprintk("%s: cannot create RPC client. Error = %d\n", |
1730 | __FUNCTION__, err); | ||
1731 | return err; | ||
1661 | } | 1732 | } |
1662 | 1733 | ||
1663 | server->client = clnt; | 1734 | server->client = clnt; |
1664 | 1735 | ||
1665 | if (server->nfs4_state->cl_idmap == NULL) { | 1736 | if (server->nfs4_state->cl_idmap == NULL) { |
1666 | printk(KERN_WARNING "NFS: failed to create idmapper.\n"); | 1737 | dprintk("%s: failed to create idmapper.\n", __FUNCTION__); |
1667 | return -ENOMEM; | 1738 | return -ENOMEM; |
1668 | } | 1739 | } |
1669 | 1740 | ||
1670 | if (clnt->cl_auth->au_flavor != authflavour) { | 1741 | if (clnt->cl_auth->au_flavor != authflavour) { |
1671 | if (rpcauth_create(authflavour, clnt) == NULL) { | 1742 | struct rpc_auth *auth; |
1672 | printk(KERN_WARNING "NFS: couldn't create credcache!\n"); | 1743 | |
1673 | return -ENOMEM; | 1744 | auth = rpcauth_create(authflavour, clnt); |
1745 | if (IS_ERR(auth)) { | ||
1746 | dprintk("%s: couldn't create credcache!\n", __FUNCTION__); | ||
1747 | return PTR_ERR(auth); | ||
1674 | } | 1748 | } |
1675 | } | 1749 | } |
1676 | 1750 | ||
@@ -1730,8 +1804,12 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, | |||
1730 | struct nfs4_mount_data *data = raw_data; | 1804 | struct nfs4_mount_data *data = raw_data; |
1731 | void *p; | 1805 | void *p; |
1732 | 1806 | ||
1733 | if (!data) { | 1807 | if (data == NULL) { |
1734 | printk("nfs_read_super: missing data argument\n"); | 1808 | dprintk("%s: missing data argument\n", __FUNCTION__); |
1809 | return ERR_PTR(-EINVAL); | ||
1810 | } | ||
1811 | if (data->version <= 0 || data->version > NFS4_MOUNT_VERSION) { | ||
1812 | dprintk("%s: bad mount version\n", __FUNCTION__); | ||
1735 | return ERR_PTR(-EINVAL); | 1813 | return ERR_PTR(-EINVAL); |
1736 | } | 1814 | } |
1737 | 1815 | ||
@@ -1741,11 +1819,7 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, | |||
1741 | memset(server, 0, sizeof(struct nfs_server)); | 1819 | memset(server, 0, sizeof(struct nfs_server)); |
1742 | /* Zero out the NFS state stuff */ | 1820 | /* Zero out the NFS state stuff */ |
1743 | init_nfsv4_state(server); | 1821 | init_nfsv4_state(server); |
1744 | 1822 | server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); | |
1745 | if (data->version != NFS4_MOUNT_VERSION) { | ||
1746 | printk("nfs warning: mount version %s than kernel\n", | ||
1747 | data->version < NFS4_MOUNT_VERSION ? "older" : "newer"); | ||
1748 | } | ||
1749 | 1823 | ||
1750 | p = nfs_copy_user_string(NULL, &data->hostname, 256); | 1824 | p = nfs_copy_user_string(NULL, &data->hostname, 256); |
1751 | if (IS_ERR(p)) | 1825 | if (IS_ERR(p)) |
@@ -1773,11 +1847,20 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, | |||
1773 | } | 1847 | } |
1774 | if (server->addr.sin_family != AF_INET || | 1848 | if (server->addr.sin_family != AF_INET || |
1775 | server->addr.sin_addr.s_addr == INADDR_ANY) { | 1849 | server->addr.sin_addr.s_addr == INADDR_ANY) { |
1776 | printk("NFS: mount program didn't pass remote IP address!\n"); | 1850 | dprintk("%s: mount program didn't pass remote IP address!\n", |
1851 | __FUNCTION__); | ||
1777 | s = ERR_PTR(-EINVAL); | 1852 | s = ERR_PTR(-EINVAL); |
1778 | goto out_free; | 1853 | goto out_free; |
1779 | } | 1854 | } |
1780 | 1855 | ||
1856 | /* Fire up rpciod if not yet running */ | ||
1857 | s = ERR_PTR(rpciod_up()); | ||
1858 | if (IS_ERR(s)) { | ||
1859 | dprintk("%s: couldn't start rpciod! Error = %ld\n", | ||
1860 | __FUNCTION__, PTR_ERR(s)); | ||
1861 | goto out_free; | ||
1862 | } | ||
1863 | |||
1781 | s = sget(fs_type, nfs4_compare_super, nfs_set_super, server); | 1864 | s = sget(fs_type, nfs4_compare_super, nfs_set_super, server); |
1782 | 1865 | ||
1783 | if (IS_ERR(s) || s->s_root) | 1866 | if (IS_ERR(s) || s->s_root) |
@@ -1785,13 +1868,6 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, | |||
1785 | 1868 | ||
1786 | s->s_flags = flags; | 1869 | s->s_flags = flags; |
1787 | 1870 | ||
1788 | /* Fire up rpciod if not yet running */ | ||
1789 | if (rpciod_up() != 0) { | ||
1790 | printk(KERN_WARNING "NFS: couldn't start rpciod!\n"); | ||
1791 | s = ERR_PTR(-EIO); | ||
1792 | goto out_free; | ||
1793 | } | ||
1794 | |||
1795 | error = nfs4_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0); | 1871 | error = nfs4_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0); |
1796 | if (error) { | 1872 | if (error) { |
1797 | up_write(&s->s_umount); | 1873 | up_write(&s->s_umount); |
@@ -1875,6 +1951,13 @@ static struct inode *nfs_alloc_inode(struct super_block *sb) | |||
1875 | if (!nfsi) | 1951 | if (!nfsi) |
1876 | return NULL; | 1952 | return NULL; |
1877 | nfsi->flags = 0; | 1953 | nfsi->flags = 0; |
1954 | #ifdef CONFIG_NFS_V3_ACL | ||
1955 | nfsi->acl_access = ERR_PTR(-EAGAIN); | ||
1956 | nfsi->acl_default = ERR_PTR(-EAGAIN); | ||
1957 | #endif | ||
1958 | #ifdef CONFIG_NFS_V4 | ||
1959 | nfsi->nfs4_acl = NULL; | ||
1960 | #endif /* CONFIG_NFS_V4 */ | ||
1878 | return &nfsi->vfs_inode; | 1961 | return &nfsi->vfs_inode; |
1879 | } | 1962 | } |
1880 | 1963 | ||
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 9d3ddad96d9e..0e82617f2de0 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
@@ -80,9 +80,7 @@ mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version, | |||
80 | clnt = rpc_create_client(xprt, hostname, | 80 | clnt = rpc_create_client(xprt, hostname, |
81 | &mnt_program, version, | 81 | &mnt_program, version, |
82 | RPC_AUTH_UNIX); | 82 | RPC_AUTH_UNIX); |
83 | if (IS_ERR(clnt)) { | 83 | if (!IS_ERR(clnt)) { |
84 | xprt_destroy(xprt); | ||
85 | } else { | ||
86 | clnt->cl_softrtry = 1; | 84 | clnt->cl_softrtry = 1; |
87 | clnt->cl_chatty = 1; | 85 | clnt->cl_chatty = 1; |
88 | clnt->cl_oneshot = 1; | 86 | clnt->cl_oneshot = 1; |
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c new file mode 100644 index 000000000000..1b7a3ef2f813 --- /dev/null +++ b/fs/nfs/nfs3acl.c | |||
@@ -0,0 +1,403 @@ | |||
1 | #include <linux/fs.h> | ||
2 | #include <linux/nfs.h> | ||
3 | #include <linux/nfs3.h> | ||
4 | #include <linux/nfs_fs.h> | ||
5 | #include <linux/posix_acl_xattr.h> | ||
6 | #include <linux/nfsacl.h> | ||
7 | |||
8 | #define NFSDBG_FACILITY NFSDBG_PROC | ||
9 | |||
10 | ssize_t nfs3_listxattr(struct dentry *dentry, char *buffer, size_t size) | ||
11 | { | ||
12 | struct inode *inode = dentry->d_inode; | ||
13 | struct posix_acl *acl; | ||
14 | int pos=0, len=0; | ||
15 | |||
16 | # define output(s) do { \ | ||
17 | if (pos + sizeof(s) <= size) { \ | ||
18 | memcpy(buffer + pos, s, sizeof(s)); \ | ||
19 | pos += sizeof(s); \ | ||
20 | } \ | ||
21 | len += sizeof(s); \ | ||
22 | } while(0) | ||
23 | |||
24 | acl = nfs3_proc_getacl(inode, ACL_TYPE_ACCESS); | ||
25 | if (IS_ERR(acl)) | ||
26 | return PTR_ERR(acl); | ||
27 | if (acl) { | ||
28 | output("system.posix_acl_access"); | ||
29 | posix_acl_release(acl); | ||
30 | } | ||
31 | |||
32 | if (S_ISDIR(inode->i_mode)) { | ||
33 | acl = nfs3_proc_getacl(inode, ACL_TYPE_DEFAULT); | ||
34 | if (IS_ERR(acl)) | ||
35 | return PTR_ERR(acl); | ||
36 | if (acl) { | ||
37 | output("system.posix_acl_default"); | ||
38 | posix_acl_release(acl); | ||
39 | } | ||
40 | } | ||
41 | |||
42 | # undef output | ||
43 | |||
44 | if (!buffer || len <= size) | ||
45 | return len; | ||
46 | return -ERANGE; | ||
47 | } | ||
48 | |||
49 | ssize_t nfs3_getxattr(struct dentry *dentry, const char *name, | ||
50 | void *buffer, size_t size) | ||
51 | { | ||
52 | struct inode *inode = dentry->d_inode; | ||
53 | struct posix_acl *acl; | ||
54 | int type, error = 0; | ||
55 | |||
56 | if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) | ||
57 | type = ACL_TYPE_ACCESS; | ||
58 | else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) | ||
59 | type = ACL_TYPE_DEFAULT; | ||
60 | else | ||
61 | return -EOPNOTSUPP; | ||
62 | |||
63 | acl = nfs3_proc_getacl(inode, type); | ||
64 | if (IS_ERR(acl)) | ||
65 | return PTR_ERR(acl); | ||
66 | else if (acl) { | ||
67 | if (type == ACL_TYPE_ACCESS && acl->a_count == 0) | ||
68 | error = -ENODATA; | ||
69 | else | ||
70 | error = posix_acl_to_xattr(acl, buffer, size); | ||
71 | posix_acl_release(acl); | ||
72 | } else | ||
73 | error = -ENODATA; | ||
74 | |||
75 | return error; | ||
76 | } | ||
77 | |||
78 | int nfs3_setxattr(struct dentry *dentry, const char *name, | ||
79 | const void *value, size_t size, int flags) | ||
80 | { | ||
81 | struct inode *inode = dentry->d_inode; | ||
82 | struct posix_acl *acl; | ||
83 | int type, error; | ||
84 | |||
85 | if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) | ||
86 | type = ACL_TYPE_ACCESS; | ||
87 | else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) | ||
88 | type = ACL_TYPE_DEFAULT; | ||
89 | else | ||
90 | return -EOPNOTSUPP; | ||
91 | |||
92 | acl = posix_acl_from_xattr(value, size); | ||
93 | if (IS_ERR(acl)) | ||
94 | return PTR_ERR(acl); | ||
95 | error = nfs3_proc_setacl(inode, type, acl); | ||
96 | posix_acl_release(acl); | ||
97 | |||
98 | return error; | ||
99 | } | ||
100 | |||
101 | int nfs3_removexattr(struct dentry *dentry, const char *name) | ||
102 | { | ||
103 | struct inode *inode = dentry->d_inode; | ||
104 | int type; | ||
105 | |||
106 | if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) | ||
107 | type = ACL_TYPE_ACCESS; | ||
108 | else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) | ||
109 | type = ACL_TYPE_DEFAULT; | ||
110 | else | ||
111 | return -EOPNOTSUPP; | ||
112 | |||
113 | return nfs3_proc_setacl(inode, type, NULL); | ||
114 | } | ||
115 | |||
116 | static void __nfs3_forget_cached_acls(struct nfs_inode *nfsi) | ||
117 | { | ||
118 | if (!IS_ERR(nfsi->acl_access)) { | ||
119 | posix_acl_release(nfsi->acl_access); | ||
120 | nfsi->acl_access = ERR_PTR(-EAGAIN); | ||
121 | } | ||
122 | if (!IS_ERR(nfsi->acl_default)) { | ||
123 | posix_acl_release(nfsi->acl_default); | ||
124 | nfsi->acl_default = ERR_PTR(-EAGAIN); | ||
125 | } | ||
126 | } | ||
127 | |||
128 | void nfs3_forget_cached_acls(struct inode *inode) | ||
129 | { | ||
130 | dprintk("NFS: nfs3_forget_cached_acls(%s/%ld)\n", inode->i_sb->s_id, | ||
131 | inode->i_ino); | ||
132 | spin_lock(&inode->i_lock); | ||
133 | __nfs3_forget_cached_acls(NFS_I(inode)); | ||
134 | spin_unlock(&inode->i_lock); | ||
135 | } | ||
136 | |||
137 | static struct posix_acl *nfs3_get_cached_acl(struct inode *inode, int type) | ||
138 | { | ||
139 | struct nfs_inode *nfsi = NFS_I(inode); | ||
140 | struct posix_acl *acl = ERR_PTR(-EINVAL); | ||
141 | |||
142 | spin_lock(&inode->i_lock); | ||
143 | switch(type) { | ||
144 | case ACL_TYPE_ACCESS: | ||
145 | acl = nfsi->acl_access; | ||
146 | break; | ||
147 | |||
148 | case ACL_TYPE_DEFAULT: | ||
149 | acl = nfsi->acl_default; | ||
150 | break; | ||
151 | |||
152 | default: | ||
153 | goto out; | ||
154 | } | ||
155 | if (IS_ERR(acl)) | ||
156 | acl = ERR_PTR(-EAGAIN); | ||
157 | else | ||
158 | acl = posix_acl_dup(acl); | ||
159 | out: | ||
160 | spin_unlock(&inode->i_lock); | ||
161 | dprintk("NFS: nfs3_get_cached_acl(%s/%ld, %d) = %p\n", inode->i_sb->s_id, | ||
162 | inode->i_ino, type, acl); | ||
163 | return acl; | ||
164 | } | ||
165 | |||
166 | static void nfs3_cache_acls(struct inode *inode, struct posix_acl *acl, | ||
167 | struct posix_acl *dfacl) | ||
168 | { | ||
169 | struct nfs_inode *nfsi = NFS_I(inode); | ||
170 | |||
171 | dprintk("nfs3_cache_acls(%s/%ld, %p, %p)\n", inode->i_sb->s_id, | ||
172 | inode->i_ino, acl, dfacl); | ||
173 | spin_lock(&inode->i_lock); | ||
174 | __nfs3_forget_cached_acls(NFS_I(inode)); | ||
175 | nfsi->acl_access = posix_acl_dup(acl); | ||
176 | nfsi->acl_default = posix_acl_dup(dfacl); | ||
177 | spin_unlock(&inode->i_lock); | ||
178 | } | ||
179 | |||
180 | struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | ||
181 | { | ||
182 | struct nfs_server *server = NFS_SERVER(inode); | ||
183 | struct nfs_fattr fattr; | ||
184 | struct page *pages[NFSACL_MAXPAGES] = { }; | ||
185 | struct nfs3_getaclargs args = { | ||
186 | .fh = NFS_FH(inode), | ||
187 | /* The xdr layer may allocate pages here. */ | ||
188 | .pages = pages, | ||
189 | }; | ||
190 | struct nfs3_getaclres res = { | ||
191 | .fattr = &fattr, | ||
192 | }; | ||
193 | struct posix_acl *acl; | ||
194 | int status, count; | ||
195 | |||
196 | if (!nfs_server_capable(inode, NFS_CAP_ACLS)) | ||
197 | return ERR_PTR(-EOPNOTSUPP); | ||
198 | |||
199 | status = nfs_revalidate_inode(server, inode); | ||
200 | if (status < 0) | ||
201 | return ERR_PTR(status); | ||
202 | acl = nfs3_get_cached_acl(inode, type); | ||
203 | if (acl != ERR_PTR(-EAGAIN)) | ||
204 | return acl; | ||
205 | acl = NULL; | ||
206 | |||
207 | /* | ||
208 | * Only get the access acl when explicitly requested: We don't | ||
209 | * need it for access decisions, and only some applications use | ||
210 | * it. Applications which request the access acl first are not | ||
211 | * penalized from this optimization. | ||
212 | */ | ||
213 | if (type == ACL_TYPE_ACCESS) | ||
214 | args.mask |= NFS_ACLCNT|NFS_ACL; | ||
215 | if (S_ISDIR(inode->i_mode)) | ||
216 | args.mask |= NFS_DFACLCNT|NFS_DFACL; | ||
217 | if (args.mask == 0) | ||
218 | return NULL; | ||
219 | |||
220 | dprintk("NFS call getacl\n"); | ||
221 | status = rpc_call(server->client_acl, ACLPROC3_GETACL, | ||
222 | &args, &res, 0); | ||
223 | dprintk("NFS reply getacl: %d\n", status); | ||
224 | |||
225 | /* pages may have been allocated at the xdr layer. */ | ||
226 | for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++) | ||
227 | __free_page(args.pages[count]); | ||
228 | |||
229 | switch (status) { | ||
230 | case 0: | ||
231 | status = nfs_refresh_inode(inode, &fattr); | ||
232 | break; | ||
233 | case -EPFNOSUPPORT: | ||
234 | case -EPROTONOSUPPORT: | ||
235 | dprintk("NFS_V3_ACL extension not supported; disabling\n"); | ||
236 | server->caps &= ~NFS_CAP_ACLS; | ||
237 | case -ENOTSUPP: | ||
238 | status = -EOPNOTSUPP; | ||
239 | default: | ||
240 | goto getout; | ||
241 | } | ||
242 | if ((args.mask & res.mask) != args.mask) { | ||
243 | status = -EIO; | ||
244 | goto getout; | ||
245 | } | ||
246 | |||
247 | if (res.acl_access != NULL) { | ||
248 | if (posix_acl_equiv_mode(res.acl_access, NULL) == 0) { | ||
249 | posix_acl_release(res.acl_access); | ||
250 | res.acl_access = NULL; | ||
251 | } | ||
252 | } | ||
253 | nfs3_cache_acls(inode, res.acl_access, res.acl_default); | ||
254 | |||
255 | switch(type) { | ||
256 | case ACL_TYPE_ACCESS: | ||
257 | acl = res.acl_access; | ||
258 | res.acl_access = NULL; | ||
259 | break; | ||
260 | |||
261 | case ACL_TYPE_DEFAULT: | ||
262 | acl = res.acl_default; | ||
263 | res.acl_default = NULL; | ||
264 | } | ||
265 | |||
266 | getout: | ||
267 | posix_acl_release(res.acl_access); | ||
268 | posix_acl_release(res.acl_default); | ||
269 | |||
270 | if (status != 0) { | ||
271 | posix_acl_release(acl); | ||
272 | acl = ERR_PTR(status); | ||
273 | } | ||
274 | return acl; | ||
275 | } | ||
276 | |||
277 | static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, | ||
278 | struct posix_acl *dfacl) | ||
279 | { | ||
280 | struct nfs_server *server = NFS_SERVER(inode); | ||
281 | struct nfs_fattr fattr; | ||
282 | struct page *pages[NFSACL_MAXPAGES] = { }; | ||
283 | struct nfs3_setaclargs args = { | ||
284 | .inode = inode, | ||
285 | .mask = NFS_ACL, | ||
286 | .acl_access = acl, | ||
287 | .pages = pages, | ||
288 | }; | ||
289 | int status, count; | ||
290 | |||
291 | status = -EOPNOTSUPP; | ||
292 | if (!nfs_server_capable(inode, NFS_CAP_ACLS)) | ||
293 | goto out; | ||
294 | |||
295 | /* We are doing this here, because XDR marshalling can only | ||
296 | return -ENOMEM. */ | ||
297 | status = -ENOSPC; | ||
298 | if (acl != NULL && acl->a_count > NFS_ACL_MAX_ENTRIES) | ||
299 | goto out; | ||
300 | if (dfacl != NULL && dfacl->a_count > NFS_ACL_MAX_ENTRIES) | ||
301 | goto out; | ||
302 | if (S_ISDIR(inode->i_mode)) { | ||
303 | args.mask |= NFS_DFACL; | ||
304 | args.acl_default = dfacl; | ||
305 | } | ||
306 | |||
307 | dprintk("NFS call setacl\n"); | ||
308 | nfs_begin_data_update(inode); | ||
309 | status = rpc_call(server->client_acl, ACLPROC3_SETACL, | ||
310 | &args, &fattr, 0); | ||
311 | NFS_FLAGS(inode) |= NFS_INO_INVALID_ACCESS; | ||
312 | nfs_end_data_update(inode); | ||
313 | dprintk("NFS reply setacl: %d\n", status); | ||
314 | |||
315 | /* pages may have been allocated at the xdr layer. */ | ||
316 | for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++) | ||
317 | __free_page(args.pages[count]); | ||
318 | |||
319 | switch (status) { | ||
320 | case 0: | ||
321 | status = nfs_refresh_inode(inode, &fattr); | ||
322 | break; | ||
323 | case -EPFNOSUPPORT: | ||
324 | case -EPROTONOSUPPORT: | ||
325 | dprintk("NFS_V3_ACL SETACL RPC not supported" | ||
326 | "(will not retry)\n"); | ||
327 | server->caps &= ~NFS_CAP_ACLS; | ||
328 | case -ENOTSUPP: | ||
329 | status = -EOPNOTSUPP; | ||
330 | } | ||
331 | out: | ||
332 | return status; | ||
333 | } | ||
334 | |||
335 | int nfs3_proc_setacl(struct inode *inode, int type, struct posix_acl *acl) | ||
336 | { | ||
337 | struct posix_acl *alloc = NULL, *dfacl = NULL; | ||
338 | int status; | ||
339 | |||
340 | if (S_ISDIR(inode->i_mode)) { | ||
341 | switch(type) { | ||
342 | case ACL_TYPE_ACCESS: | ||
343 | alloc = dfacl = nfs3_proc_getacl(inode, | ||
344 | ACL_TYPE_DEFAULT); | ||
345 | if (IS_ERR(alloc)) | ||
346 | goto fail; | ||
347 | break; | ||
348 | |||
349 | case ACL_TYPE_DEFAULT: | ||
350 | dfacl = acl; | ||
351 | alloc = acl = nfs3_proc_getacl(inode, | ||
352 | ACL_TYPE_ACCESS); | ||
353 | if (IS_ERR(alloc)) | ||
354 | goto fail; | ||
355 | break; | ||
356 | |||
357 | default: | ||
358 | return -EINVAL; | ||
359 | } | ||
360 | } else if (type != ACL_TYPE_ACCESS) | ||
361 | return -EINVAL; | ||
362 | |||
363 | if (acl == NULL) { | ||
364 | alloc = acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); | ||
365 | if (IS_ERR(alloc)) | ||
366 | goto fail; | ||
367 | } | ||
368 | status = nfs3_proc_setacls(inode, acl, dfacl); | ||
369 | posix_acl_release(alloc); | ||
370 | return status; | ||
371 | |||
372 | fail: | ||
373 | return PTR_ERR(alloc); | ||
374 | } | ||
375 | |||
376 | int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode, | ||
377 | mode_t mode) | ||
378 | { | ||
379 | struct posix_acl *dfacl, *acl; | ||
380 | int error = 0; | ||
381 | |||
382 | dfacl = nfs3_proc_getacl(dir, ACL_TYPE_DEFAULT); | ||
383 | if (IS_ERR(dfacl)) { | ||
384 | error = PTR_ERR(dfacl); | ||
385 | return (error == -EOPNOTSUPP) ? 0 : error; | ||
386 | } | ||
387 | if (!dfacl) | ||
388 | return 0; | ||
389 | acl = posix_acl_clone(dfacl, GFP_KERNEL); | ||
390 | error = -ENOMEM; | ||
391 | if (!acl) | ||
392 | goto out_release_dfacl; | ||
393 | error = posix_acl_create_masq(acl, &mode); | ||
394 | if (error < 0) | ||
395 | goto out_release_acl; | ||
396 | error = nfs3_proc_setacls(inode, acl, S_ISDIR(inode->i_mode) ? | ||
397 | dfacl : NULL); | ||
398 | out_release_acl: | ||
399 | posix_acl_release(acl); | ||
400 | out_release_dfacl: | ||
401 | posix_acl_release(dfacl); | ||
402 | return error; | ||
403 | } | ||
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 3878494dfc2c..7851569b31c6 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/nfs_page.h> | 17 | #include <linux/nfs_page.h> |
18 | #include <linux/lockd/bind.h> | 18 | #include <linux/lockd/bind.h> |
19 | #include <linux/smp_lock.h> | 19 | #include <linux/smp_lock.h> |
20 | #include <linux/nfs_mount.h> | ||
20 | 21 | ||
21 | #define NFSDBG_FACILITY NFSDBG_PROC | 22 | #define NFSDBG_FACILITY NFSDBG_PROC |
22 | 23 | ||
@@ -45,7 +46,7 @@ static inline int | |||
45 | nfs3_rpc_call_wrapper(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags) | 46 | nfs3_rpc_call_wrapper(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags) |
46 | { | 47 | { |
47 | struct rpc_message msg = { | 48 | struct rpc_message msg = { |
48 | .rpc_proc = &nfs3_procedures[proc], | 49 | .rpc_proc = &clnt->cl_procinfo[proc], |
49 | .rpc_argp = argp, | 50 | .rpc_argp = argp, |
50 | .rpc_resp = resp, | 51 | .rpc_resp = resp, |
51 | }; | 52 | }; |
@@ -313,7 +314,8 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
313 | .fh = &fhandle, | 314 | .fh = &fhandle, |
314 | .fattr = &fattr | 315 | .fattr = &fattr |
315 | }; | 316 | }; |
316 | int status; | 317 | mode_t mode = sattr->ia_mode; |
318 | int status; | ||
317 | 319 | ||
318 | dprintk("NFS call create %s\n", dentry->d_name.name); | 320 | dprintk("NFS call create %s\n", dentry->d_name.name); |
319 | arg.createmode = NFS3_CREATE_UNCHECKED; | 321 | arg.createmode = NFS3_CREATE_UNCHECKED; |
@@ -323,6 +325,8 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
323 | arg.verifier[1] = current->pid; | 325 | arg.verifier[1] = current->pid; |
324 | } | 326 | } |
325 | 327 | ||
328 | sattr->ia_mode &= ~current->fs->umask; | ||
329 | |||
326 | again: | 330 | again: |
327 | dir_attr.valid = 0; | 331 | dir_attr.valid = 0; |
328 | fattr.valid = 0; | 332 | fattr.valid = 0; |
@@ -369,6 +373,9 @@ again: | |||
369 | nfs_refresh_inode(dentry->d_inode, &fattr); | 373 | nfs_refresh_inode(dentry->d_inode, &fattr); |
370 | dprintk("NFS reply setattr (post-create): %d\n", status); | 374 | dprintk("NFS reply setattr (post-create): %d\n", status); |
371 | } | 375 | } |
376 | if (status != 0) | ||
377 | goto out; | ||
378 | status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); | ||
372 | out: | 379 | out: |
373 | dprintk("NFS reply create: %d\n", status); | 380 | dprintk("NFS reply create: %d\n", status); |
374 | return status; | 381 | return status; |
@@ -538,15 +545,24 @@ nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) | |||
538 | .fh = &fhandle, | 545 | .fh = &fhandle, |
539 | .fattr = &fattr | 546 | .fattr = &fattr |
540 | }; | 547 | }; |
541 | int status; | 548 | int mode = sattr->ia_mode; |
549 | int status; | ||
542 | 550 | ||
543 | dprintk("NFS call mkdir %s\n", dentry->d_name.name); | 551 | dprintk("NFS call mkdir %s\n", dentry->d_name.name); |
544 | dir_attr.valid = 0; | 552 | dir_attr.valid = 0; |
545 | fattr.valid = 0; | 553 | fattr.valid = 0; |
554 | |||
555 | sattr->ia_mode &= ~current->fs->umask; | ||
556 | |||
546 | status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, 0); | 557 | status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, 0); |
547 | nfs_refresh_inode(dir, &dir_attr); | 558 | nfs_refresh_inode(dir, &dir_attr); |
548 | if (status == 0) | 559 | if (status != 0) |
549 | status = nfs_instantiate(dentry, &fhandle, &fattr); | 560 | goto out; |
561 | status = nfs_instantiate(dentry, &fhandle, &fattr); | ||
562 | if (status != 0) | ||
563 | goto out; | ||
564 | status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); | ||
565 | out: | ||
550 | dprintk("NFS reply mkdir: %d\n", status); | 566 | dprintk("NFS reply mkdir: %d\n", status); |
551 | return status; | 567 | return status; |
552 | } | 568 | } |
@@ -641,6 +657,7 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
641 | .fh = &fh, | 657 | .fh = &fh, |
642 | .fattr = &fattr | 658 | .fattr = &fattr |
643 | }; | 659 | }; |
660 | mode_t mode = sattr->ia_mode; | ||
644 | int status; | 661 | int status; |
645 | 662 | ||
646 | switch (sattr->ia_mode & S_IFMT) { | 663 | switch (sattr->ia_mode & S_IFMT) { |
@@ -653,12 +670,20 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
653 | 670 | ||
654 | dprintk("NFS call mknod %s %u:%u\n", dentry->d_name.name, | 671 | dprintk("NFS call mknod %s %u:%u\n", dentry->d_name.name, |
655 | MAJOR(rdev), MINOR(rdev)); | 672 | MAJOR(rdev), MINOR(rdev)); |
673 | |||
674 | sattr->ia_mode &= ~current->fs->umask; | ||
675 | |||
656 | dir_attr.valid = 0; | 676 | dir_attr.valid = 0; |
657 | fattr.valid = 0; | 677 | fattr.valid = 0; |
658 | status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0); | 678 | status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0); |
659 | nfs_refresh_inode(dir, &dir_attr); | 679 | nfs_refresh_inode(dir, &dir_attr); |
660 | if (status == 0) | 680 | if (status != 0) |
661 | status = nfs_instantiate(dentry, &fh, &fattr); | 681 | goto out; |
682 | status = nfs_instantiate(dentry, &fh, &fattr); | ||
683 | if (status != 0) | ||
684 | goto out; | ||
685 | status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); | ||
686 | out: | ||
662 | dprintk("NFS reply mknod: %d\n", status); | 687 | dprintk("NFS reply mknod: %d\n", status); |
663 | return status; | 688 | return status; |
664 | } | 689 | } |
@@ -825,7 +850,8 @@ nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl) | |||
825 | struct nfs_rpc_ops nfs_v3_clientops = { | 850 | struct nfs_rpc_ops nfs_v3_clientops = { |
826 | .version = 3, /* protocol version */ | 851 | .version = 3, /* protocol version */ |
827 | .dentry_ops = &nfs_dentry_operations, | 852 | .dentry_ops = &nfs_dentry_operations, |
828 | .dir_inode_ops = &nfs_dir_inode_operations, | 853 | .dir_inode_ops = &nfs3_dir_inode_operations, |
854 | .file_inode_ops = &nfs3_file_inode_operations, | ||
829 | .getroot = nfs3_proc_get_root, | 855 | .getroot = nfs3_proc_get_root, |
830 | .getattr = nfs3_proc_getattr, | 856 | .getattr = nfs3_proc_getattr, |
831 | .setattr = nfs3_proc_setattr, | 857 | .setattr = nfs3_proc_setattr, |
@@ -856,4 +882,5 @@ struct nfs_rpc_ops nfs_v3_clientops = { | |||
856 | .file_open = nfs_open, | 882 | .file_open = nfs_open, |
857 | .file_release = nfs_release, | 883 | .file_release = nfs_release, |
858 | .lock = nfs3_proc_lock, | 884 | .lock = nfs3_proc_lock, |
885 | .clear_acl_cache = nfs3_forget_cached_acls, | ||
859 | }; | 886 | }; |
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index a3593d47e5ab..db4a904810a4 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/nfs.h> | 21 | #include <linux/nfs.h> |
22 | #include <linux/nfs3.h> | 22 | #include <linux/nfs3.h> |
23 | #include <linux/nfs_fs.h> | 23 | #include <linux/nfs_fs.h> |
24 | #include <linux/nfsacl.h> | ||
24 | 25 | ||
25 | #define NFSDBG_FACILITY NFSDBG_XDR | 26 | #define NFSDBG_FACILITY NFSDBG_XDR |
26 | 27 | ||
@@ -79,6 +80,11 @@ extern int nfs_stat_to_errno(int); | |||
79 | #define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6) | 80 | #define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6) |
80 | #define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2) | 81 | #define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2) |
81 | 82 | ||
83 | #define ACL3_getaclargs_sz (NFS3_fh_sz+1) | ||
84 | #define ACL3_setaclargs_sz (NFS3_fh_sz+1+2*(2+5*3)) | ||
85 | #define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+2*(2+5*3)) | ||
86 | #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz) | ||
87 | |||
82 | /* | 88 | /* |
83 | * Map file type to S_IFMT bits | 89 | * Map file type to S_IFMT bits |
84 | */ | 90 | */ |
@@ -627,6 +633,74 @@ nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args) | |||
627 | return 0; | 633 | return 0; |
628 | } | 634 | } |
629 | 635 | ||
636 | #ifdef CONFIG_NFS_V3_ACL | ||
637 | /* | ||
638 | * Encode GETACL arguments | ||
639 | */ | ||
640 | static int | ||
641 | nfs3_xdr_getaclargs(struct rpc_rqst *req, u32 *p, | ||
642 | struct nfs3_getaclargs *args) | ||
643 | { | ||
644 | struct rpc_auth *auth = req->rq_task->tk_auth; | ||
645 | unsigned int replen; | ||
646 | |||
647 | p = xdr_encode_fhandle(p, args->fh); | ||
648 | *p++ = htonl(args->mask); | ||
649 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); | ||
650 | |||
651 | if (args->mask & (NFS_ACL | NFS_DFACL)) { | ||
652 | /* Inline the page array */ | ||
653 | replen = (RPC_REPHDRSIZE + auth->au_rslack + | ||
654 | ACL3_getaclres_sz) << 2; | ||
655 | xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, | ||
656 | NFSACL_MAXPAGES << PAGE_SHIFT); | ||
657 | } | ||
658 | return 0; | ||
659 | } | ||
660 | |||
661 | /* | ||
662 | * Encode SETACL arguments | ||
663 | */ | ||
664 | static int | ||
665 | nfs3_xdr_setaclargs(struct rpc_rqst *req, u32 *p, | ||
666 | struct nfs3_setaclargs *args) | ||
667 | { | ||
668 | struct xdr_buf *buf = &req->rq_snd_buf; | ||
669 | unsigned int base, len_in_head, len = nfsacl_size( | ||
670 | (args->mask & NFS_ACL) ? args->acl_access : NULL, | ||
671 | (args->mask & NFS_DFACL) ? args->acl_default : NULL); | ||
672 | int count, err; | ||
673 | |||
674 | p = xdr_encode_fhandle(p, NFS_FH(args->inode)); | ||
675 | *p++ = htonl(args->mask); | ||
676 | base = (char *)p - (char *)buf->head->iov_base; | ||
677 | /* put as much of the acls into head as possible. */ | ||
678 | len_in_head = min_t(unsigned int, buf->head->iov_len - base, len); | ||
679 | len -= len_in_head; | ||
680 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + (len_in_head >> 2)); | ||
681 | |||
682 | for (count = 0; (count << PAGE_SHIFT) < len; count++) { | ||
683 | args->pages[count] = alloc_page(GFP_KERNEL); | ||
684 | if (!args->pages[count]) { | ||
685 | while (count) | ||
686 | __free_page(args->pages[--count]); | ||
687 | return -ENOMEM; | ||
688 | } | ||
689 | } | ||
690 | xdr_encode_pages(buf, args->pages, 0, len); | ||
691 | |||
692 | err = nfsacl_encode(buf, base, args->inode, | ||
693 | (args->mask & NFS_ACL) ? | ||
694 | args->acl_access : NULL, 1, 0); | ||
695 | if (err > 0) | ||
696 | err = nfsacl_encode(buf, base + err, args->inode, | ||
697 | (args->mask & NFS_DFACL) ? | ||
698 | args->acl_default : NULL, 1, | ||
699 | NFS_ACL_DEFAULT); | ||
700 | return (err > 0) ? 0 : err; | ||
701 | } | ||
702 | #endif /* CONFIG_NFS_V3_ACL */ | ||
703 | |||
630 | /* | 704 | /* |
631 | * NFS XDR decode functions | 705 | * NFS XDR decode functions |
632 | */ | 706 | */ |
@@ -978,6 +1052,54 @@ nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res) | |||
978 | return 0; | 1052 | return 0; |
979 | } | 1053 | } |
980 | 1054 | ||
1055 | #ifdef CONFIG_NFS_V3_ACL | ||
1056 | /* | ||
1057 | * Decode GETACL reply | ||
1058 | */ | ||
1059 | static int | ||
1060 | nfs3_xdr_getaclres(struct rpc_rqst *req, u32 *p, | ||
1061 | struct nfs3_getaclres *res) | ||
1062 | { | ||
1063 | struct xdr_buf *buf = &req->rq_rcv_buf; | ||
1064 | int status = ntohl(*p++); | ||
1065 | struct posix_acl **acl; | ||
1066 | unsigned int *aclcnt; | ||
1067 | int err, base; | ||
1068 | |||
1069 | if (status != 0) | ||
1070 | return -nfs_stat_to_errno(status); | ||
1071 | p = xdr_decode_post_op_attr(p, res->fattr); | ||
1072 | res->mask = ntohl(*p++); | ||
1073 | if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) | ||
1074 | return -EINVAL; | ||
1075 | base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base; | ||
1076 | |||
1077 | acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL; | ||
1078 | aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL; | ||
1079 | err = nfsacl_decode(buf, base, aclcnt, acl); | ||
1080 | |||
1081 | acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL; | ||
1082 | aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL; | ||
1083 | if (err > 0) | ||
1084 | err = nfsacl_decode(buf, base + err, aclcnt, acl); | ||
1085 | return (err > 0) ? 0 : err; | ||
1086 | } | ||
1087 | |||
1088 | /* | ||
1089 | * Decode setacl reply. | ||
1090 | */ | ||
1091 | static int | ||
1092 | nfs3_xdr_setaclres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr) | ||
1093 | { | ||
1094 | int status = ntohl(*p++); | ||
1095 | |||
1096 | if (status) | ||
1097 | return -nfs_stat_to_errno(status); | ||
1098 | xdr_decode_post_op_attr(p, fattr); | ||
1099 | return 0; | ||
1100 | } | ||
1101 | #endif /* CONFIG_NFS_V3_ACL */ | ||
1102 | |||
981 | #ifndef MAX | 1103 | #ifndef MAX |
982 | # define MAX(a, b) (((a) > (b))? (a) : (b)) | 1104 | # define MAX(a, b) (((a) > (b))? (a) : (b)) |
983 | #endif | 1105 | #endif |
@@ -1021,3 +1143,28 @@ struct rpc_version nfs_version3 = { | |||
1021 | .procs = nfs3_procedures | 1143 | .procs = nfs3_procedures |
1022 | }; | 1144 | }; |
1023 | 1145 | ||
1146 | #ifdef CONFIG_NFS_V3_ACL | ||
1147 | static struct rpc_procinfo nfs3_acl_procedures[] = { | ||
1148 | [ACLPROC3_GETACL] = { | ||
1149 | .p_proc = ACLPROC3_GETACL, | ||
1150 | .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs, | ||
1151 | .p_decode = (kxdrproc_t) nfs3_xdr_getaclres, | ||
1152 | .p_bufsiz = MAX(ACL3_getaclargs_sz, ACL3_getaclres_sz) << 2, | ||
1153 | .p_timer = 1, | ||
1154 | }, | ||
1155 | [ACLPROC3_SETACL] = { | ||
1156 | .p_proc = ACLPROC3_SETACL, | ||
1157 | .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs, | ||
1158 | .p_decode = (kxdrproc_t) nfs3_xdr_setaclres, | ||
1159 | .p_bufsiz = MAX(ACL3_setaclargs_sz, ACL3_setaclres_sz) << 2, | ||
1160 | .p_timer = 0, | ||
1161 | }, | ||
1162 | }; | ||
1163 | |||
1164 | struct rpc_version nfsacl_version3 = { | ||
1165 | .number = 3, | ||
1166 | .nrprocs = sizeof(nfs3_acl_procedures)/ | ||
1167 | sizeof(nfs3_acl_procedures[0]), | ||
1168 | .procs = nfs3_acl_procedures, | ||
1169 | }; | ||
1170 | #endif /* CONFIG_NFS_V3_ACL */ | ||
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h new file mode 100644 index 000000000000..ec1a22d7b876 --- /dev/null +++ b/fs/nfs/nfs4_fs.h | |||
@@ -0,0 +1,253 @@ | |||
1 | /* | ||
2 | * linux/fs/nfs/nfs4_fs.h | ||
3 | * | ||
4 | * Copyright (C) 2005 Trond Myklebust | ||
5 | * | ||
6 | * NFSv4-specific filesystem definitions and declarations | ||
7 | */ | ||
8 | |||
9 | #ifndef __LINUX_FS_NFS_NFS4_FS_H | ||
10 | #define __LINUX_FS_NFS_NFS4_FS_H | ||
11 | |||
12 | #ifdef CONFIG_NFS_V4 | ||
13 | |||
14 | struct idmap; | ||
15 | |||
16 | /* | ||
17 | * In a seqid-mutating op, this macro controls which error return | ||
18 | * values trigger incrementation of the seqid. | ||
19 | * | ||
20 | * from rfc 3010: | ||
21 | * The client MUST monotonically increment the sequence number for the | ||
22 | * CLOSE, LOCK, LOCKU, OPEN, OPEN_CONFIRM, and OPEN_DOWNGRADE | ||
23 | * operations. This is true even in the event that the previous | ||
24 | * operation that used the sequence number received an error. The only | ||
25 | * exception to this rule is if the previous operation received one of | ||
26 | * the following errors: NFSERR_STALE_CLIENTID, NFSERR_STALE_STATEID, | ||
27 | * NFSERR_BAD_STATEID, NFSERR_BAD_SEQID, NFSERR_BADXDR, | ||
28 | * NFSERR_RESOURCE, NFSERR_NOFILEHANDLE. | ||
29 | * | ||
30 | */ | ||
31 | #define seqid_mutating_err(err) \ | ||
32 | (((err) != NFSERR_STALE_CLIENTID) && \ | ||
33 | ((err) != NFSERR_STALE_STATEID) && \ | ||
34 | ((err) != NFSERR_BAD_STATEID) && \ | ||
35 | ((err) != NFSERR_BAD_SEQID) && \ | ||
36 | ((err) != NFSERR_BAD_XDR) && \ | ||
37 | ((err) != NFSERR_RESOURCE) && \ | ||
38 | ((err) != NFSERR_NOFILEHANDLE)) | ||
39 | |||
40 | enum nfs4_client_state { | ||
41 | NFS4CLNT_OK = 0, | ||
42 | }; | ||
43 | |||
44 | /* | ||
45 | * The nfs4_client identifies our client state to the server. | ||
46 | */ | ||
47 | struct nfs4_client { | ||
48 | struct list_head cl_servers; /* Global list of servers */ | ||
49 | struct in_addr cl_addr; /* Server identifier */ | ||
50 | u64 cl_clientid; /* constant */ | ||
51 | nfs4_verifier cl_confirm; | ||
52 | unsigned long cl_state; | ||
53 | |||
54 | u32 cl_lockowner_id; | ||
55 | |||
56 | /* | ||
57 | * The following rwsem ensures exclusive access to the server | ||
58 | * while we recover the state following a lease expiration. | ||
59 | */ | ||
60 | struct rw_semaphore cl_sem; | ||
61 | |||
62 | struct list_head cl_delegations; | ||
63 | struct list_head cl_state_owners; | ||
64 | struct list_head cl_unused; | ||
65 | int cl_nunused; | ||
66 | spinlock_t cl_lock; | ||
67 | atomic_t cl_count; | ||
68 | |||
69 | struct rpc_clnt * cl_rpcclient; | ||
70 | struct rpc_cred * cl_cred; | ||
71 | |||
72 | struct list_head cl_superblocks; /* List of nfs_server structs */ | ||
73 | |||
74 | unsigned long cl_lease_time; | ||
75 | unsigned long cl_last_renewal; | ||
76 | struct work_struct cl_renewd; | ||
77 | struct work_struct cl_recoverd; | ||
78 | |||
79 | wait_queue_head_t cl_waitq; | ||
80 | struct rpc_wait_queue cl_rpcwaitq; | ||
81 | |||
82 | /* used for the setclientid verifier */ | ||
83 | struct timespec cl_boot_time; | ||
84 | |||
85 | /* idmapper */ | ||
86 | struct idmap * cl_idmap; | ||
87 | |||
88 | /* Our own IP address, as a null-terminated string. | ||
89 | * This is used to generate the clientid, and the callback address. | ||
90 | */ | ||
91 | char cl_ipaddr[16]; | ||
92 | unsigned char cl_id_uniquifier; | ||
93 | }; | ||
94 | |||
95 | /* | ||
96 | * NFS4 state_owners and lock_owners are simply labels for ordered | ||
97 | * sequences of RPC calls. Their sole purpose is to provide once-only | ||
98 | * semantics by allowing the server to identify replayed requests. | ||
99 | * | ||
100 | * The ->so_sema is held during all state_owner seqid-mutating operations: | ||
101 | * OPEN, OPEN_DOWNGRADE, and CLOSE. Its purpose is to properly serialize | ||
102 | * so_seqid. | ||
103 | */ | ||
104 | struct nfs4_state_owner { | ||
105 | struct list_head so_list; /* per-clientid list of state_owners */ | ||
106 | struct nfs4_client *so_client; | ||
107 | u32 so_id; /* 32-bit identifier, unique */ | ||
108 | struct semaphore so_sema; | ||
109 | u32 so_seqid; /* protected by so_sema */ | ||
110 | atomic_t so_count; | ||
111 | |||
112 | struct rpc_cred *so_cred; /* Associated cred */ | ||
113 | struct list_head so_states; | ||
114 | struct list_head so_delegations; | ||
115 | }; | ||
116 | |||
117 | /* | ||
118 | * struct nfs4_state maintains the client-side state for a given | ||
119 | * (state_owner,inode) tuple (OPEN) or state_owner (LOCK). | ||
120 | * | ||
121 | * OPEN: | ||
122 | * In order to know when to OPEN_DOWNGRADE or CLOSE the state on the server, | ||
123 | * we need to know how many files are open for reading or writing on a | ||
124 | * given inode. This information too is stored here. | ||
125 | * | ||
126 | * LOCK: one nfs4_state (LOCK) to hold the lock stateid nfs4_state(OPEN) | ||
127 | */ | ||
128 | |||
129 | struct nfs4_lock_state { | ||
130 | struct list_head ls_locks; /* Other lock stateids */ | ||
131 | struct nfs4_state * ls_state; /* Pointer to open state */ | ||
132 | fl_owner_t ls_owner; /* POSIX lock owner */ | ||
133 | #define NFS_LOCK_INITIALIZED 1 | ||
134 | int ls_flags; | ||
135 | u32 ls_seqid; | ||
136 | u32 ls_id; | ||
137 | nfs4_stateid ls_stateid; | ||
138 | atomic_t ls_count; | ||
139 | }; | ||
140 | |||
141 | /* bits for nfs4_state->flags */ | ||
142 | enum { | ||
143 | LK_STATE_IN_USE, | ||
144 | NFS_DELEGATED_STATE, | ||
145 | }; | ||
146 | |||
147 | struct nfs4_state { | ||
148 | struct list_head open_states; /* List of states for the same state_owner */ | ||
149 | struct list_head inode_states; /* List of states for the same inode */ | ||
150 | struct list_head lock_states; /* List of subservient lock stateids */ | ||
151 | |||
152 | struct nfs4_state_owner *owner; /* Pointer to the open owner */ | ||
153 | struct inode *inode; /* Pointer to the inode */ | ||
154 | |||
155 | unsigned long flags; /* Do we hold any locks? */ | ||
156 | struct semaphore lock_sema; /* Serializes file locking operations */ | ||
157 | spinlock_t state_lock; /* Protects the lock_states list */ | ||
158 | |||
159 | nfs4_stateid stateid; | ||
160 | |||
161 | unsigned int nreaders; | ||
162 | unsigned int nwriters; | ||
163 | int state; /* State on the server (R,W, or RW) */ | ||
164 | atomic_t count; | ||
165 | }; | ||
166 | |||
167 | |||
168 | struct nfs4_exception { | ||
169 | long timeout; | ||
170 | int retry; | ||
171 | }; | ||
172 | |||
173 | struct nfs4_state_recovery_ops { | ||
174 | int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *); | ||
175 | int (*recover_lock)(struct nfs4_state *, struct file_lock *); | ||
176 | }; | ||
177 | |||
178 | extern struct dentry_operations nfs4_dentry_operations; | ||
179 | extern struct inode_operations nfs4_dir_inode_operations; | ||
180 | |||
181 | /* inode.c */ | ||
182 | extern ssize_t nfs4_getxattr(struct dentry *, const char *, void *, size_t); | ||
183 | extern int nfs4_setxattr(struct dentry *, const char *, const void *, size_t, int); | ||
184 | extern ssize_t nfs4_listxattr(struct dentry *, char *, size_t); | ||
185 | |||
186 | |||
187 | /* nfs4proc.c */ | ||
188 | extern int nfs4_map_errors(int err); | ||
189 | extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short); | ||
190 | extern int nfs4_proc_setclientid_confirm(struct nfs4_client *); | ||
191 | extern int nfs4_proc_async_renew(struct nfs4_client *); | ||
192 | extern int nfs4_proc_renew(struct nfs4_client *); | ||
193 | extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state, mode_t mode); | ||
194 | extern struct inode *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); | ||
195 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int); | ||
196 | |||
197 | extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; | ||
198 | extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops; | ||
199 | |||
200 | extern const u32 nfs4_fattr_bitmap[2]; | ||
201 | extern const u32 nfs4_statfs_bitmap[2]; | ||
202 | extern const u32 nfs4_pathconf_bitmap[2]; | ||
203 | extern const u32 nfs4_fsinfo_bitmap[2]; | ||
204 | |||
205 | /* nfs4renewd.c */ | ||
206 | extern void nfs4_schedule_state_renewal(struct nfs4_client *); | ||
207 | extern void nfs4_renewd_prepare_shutdown(struct nfs_server *); | ||
208 | extern void nfs4_kill_renewd(struct nfs4_client *); | ||
209 | extern void nfs4_renew_state(void *); | ||
210 | |||
211 | /* nfs4state.c */ | ||
212 | extern void init_nfsv4_state(struct nfs_server *); | ||
213 | extern void destroy_nfsv4_state(struct nfs_server *); | ||
214 | extern struct nfs4_client *nfs4_get_client(struct in_addr *); | ||
215 | extern void nfs4_put_client(struct nfs4_client *clp); | ||
216 | extern int nfs4_init_client(struct nfs4_client *clp); | ||
217 | extern struct nfs4_client *nfs4_find_client(struct in_addr *); | ||
218 | extern u32 nfs4_alloc_lockowner_id(struct nfs4_client *); | ||
219 | |||
220 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); | ||
221 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); | ||
222 | extern void nfs4_drop_state_owner(struct nfs4_state_owner *); | ||
223 | extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *); | ||
224 | extern void nfs4_put_open_state(struct nfs4_state *); | ||
225 | extern void nfs4_close_state(struct nfs4_state *, mode_t); | ||
226 | extern struct nfs4_state *nfs4_find_state(struct inode *, struct rpc_cred *, mode_t mode); | ||
227 | extern void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp); | ||
228 | extern void nfs4_schedule_state_recovery(struct nfs4_client *); | ||
229 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); | ||
230 | extern void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *ls); | ||
231 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); | ||
232 | |||
233 | extern const nfs4_stateid zero_stateid; | ||
234 | |||
235 | /* nfs4xdr.c */ | ||
236 | extern uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus); | ||
237 | extern struct rpc_procinfo nfs4_procedures[]; | ||
238 | |||
239 | struct nfs4_mount_data; | ||
240 | |||
241 | /* callback_xdr.c */ | ||
242 | extern struct svc_version nfs4_callback_version1; | ||
243 | |||
244 | #else | ||
245 | |||
246 | #define init_nfsv4_state(server) do { } while (0) | ||
247 | #define destroy_nfsv4_state(server) do { } while (0) | ||
248 | #define nfs4_put_state_owner(inode, owner) do { } while (0) | ||
249 | #define nfs4_put_open_state(state) do { } while (0) | ||
250 | #define nfs4_close_state(a, b) do { } while (0) | ||
251 | |||
252 | #endif /* CONFIG_NFS_V4 */ | ||
253 | #endif /* __LINUX_FS_NFS_NFS4_FS.H */ | ||
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 1d5cb3e80c3e..1b76f80aedb9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <linux/smp_lock.h> | 48 | #include <linux/smp_lock.h> |
49 | #include <linux/namei.h> | 49 | #include <linux/namei.h> |
50 | 50 | ||
51 | #include "nfs4_fs.h" | ||
51 | #include "delegation.h" | 52 | #include "delegation.h" |
52 | 53 | ||
53 | #define NFSDBG_FACILITY NFSDBG_PROC | 54 | #define NFSDBG_FACILITY NFSDBG_PROC |
@@ -62,8 +63,6 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc | |||
62 | extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); | 63 | extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); |
63 | extern struct rpc_procinfo nfs4_procedures[]; | 64 | extern struct rpc_procinfo nfs4_procedures[]; |
64 | 65 | ||
65 | extern nfs4_stateid zero_stateid; | ||
66 | |||
67 | /* Prevent leaks of NFSv4 errors into userland */ | 66 | /* Prevent leaks of NFSv4 errors into userland */ |
68 | int nfs4_map_errors(int err) | 67 | int nfs4_map_errors(int err) |
69 | { | 68 | { |
@@ -104,7 +103,7 @@ const u32 nfs4_statfs_bitmap[2] = { | |||
104 | | FATTR4_WORD1_SPACE_TOTAL | 103 | | FATTR4_WORD1_SPACE_TOTAL |
105 | }; | 104 | }; |
106 | 105 | ||
107 | u32 nfs4_pathconf_bitmap[2] = { | 106 | const u32 nfs4_pathconf_bitmap[2] = { |
108 | FATTR4_WORD0_MAXLINK | 107 | FATTR4_WORD0_MAXLINK |
109 | | FATTR4_WORD0_MAXNAME, | 108 | | FATTR4_WORD0_MAXNAME, |
110 | 0 | 109 | 0 |
@@ -124,7 +123,7 @@ static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry, | |||
124 | 123 | ||
125 | BUG_ON(readdir->count < 80); | 124 | BUG_ON(readdir->count < 80); |
126 | if (cookie > 2) { | 125 | if (cookie > 2) { |
127 | readdir->cookie = (cookie > 2) ? cookie : 0; | 126 | readdir->cookie = cookie; |
128 | memcpy(&readdir->verifier, verifier, sizeof(readdir->verifier)); | 127 | memcpy(&readdir->verifier, verifier, sizeof(readdir->verifier)); |
129 | return; | 128 | return; |
130 | } | 129 | } |
@@ -270,14 +269,9 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta | |||
270 | int err; | 269 | int err; |
271 | do { | 270 | do { |
272 | err = _nfs4_open_reclaim(sp, state); | 271 | err = _nfs4_open_reclaim(sp, state); |
273 | switch (err) { | 272 | if (err != -NFS4ERR_DELAY) |
274 | case 0: | 273 | break; |
275 | case -NFS4ERR_STALE_CLIENTID: | 274 | nfs4_handle_exception(server, err, &exception); |
276 | case -NFS4ERR_STALE_STATEID: | ||
277 | case -NFS4ERR_EXPIRED: | ||
278 | return err; | ||
279 | } | ||
280 | err = nfs4_handle_exception(server, err, &exception); | ||
281 | } while (exception.retry); | 275 | } while (exception.retry); |
282 | return err; | 276 | return err; |
283 | } | 277 | } |
@@ -509,6 +503,20 @@ out_stale: | |||
509 | goto out_nodeleg; | 503 | goto out_nodeleg; |
510 | } | 504 | } |
511 | 505 | ||
506 | static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) | ||
507 | { | ||
508 | struct nfs_server *server = NFS_SERVER(dentry->d_inode); | ||
509 | struct nfs4_exception exception = { }; | ||
510 | int err; | ||
511 | |||
512 | do { | ||
513 | err = _nfs4_open_expired(sp, state, dentry); | ||
514 | if (err == -NFS4ERR_DELAY) | ||
515 | nfs4_handle_exception(server, err, &exception); | ||
516 | } while (exception.retry); | ||
517 | return err; | ||
518 | } | ||
519 | |||
512 | static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) | 520 | static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) |
513 | { | 521 | { |
514 | struct nfs_inode *nfsi = NFS_I(state->inode); | 522 | struct nfs_inode *nfsi = NFS_I(state->inode); |
@@ -521,7 +529,7 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta | |||
521 | continue; | 529 | continue; |
522 | get_nfs_open_context(ctx); | 530 | get_nfs_open_context(ctx); |
523 | spin_unlock(&state->inode->i_lock); | 531 | spin_unlock(&state->inode->i_lock); |
524 | status = _nfs4_open_expired(sp, state, ctx->dentry); | 532 | status = nfs4_do_open_expired(sp, state, ctx->dentry); |
525 | put_nfs_open_context(ctx); | 533 | put_nfs_open_context(ctx); |
526 | return status; | 534 | return status; |
527 | } | 535 | } |
@@ -748,11 +756,10 @@ static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, | |||
748 | 756 | ||
749 | fattr->valid = 0; | 757 | fattr->valid = 0; |
750 | 758 | ||
751 | if (state != NULL) | 759 | if (state != NULL) { |
752 | msg.rpc_cred = state->owner->so_cred; | 760 | msg.rpc_cred = state->owner->so_cred; |
753 | if (sattr->ia_valid & ATTR_SIZE) | 761 | nfs4_copy_stateid(&arg.stateid, state, current->files); |
754 | nfs4_copy_stateid(&arg.stateid, state, NULL); | 762 | } else |
755 | else | ||
756 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); | 763 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); |
757 | 764 | ||
758 | return rpc_call_sync(server->client, &msg, 0); | 765 | return rpc_call_sync(server->client, &msg, 0); |
@@ -1116,47 +1123,31 @@ static int | |||
1116 | nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | 1123 | nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, |
1117 | struct iattr *sattr) | 1124 | struct iattr *sattr) |
1118 | { | 1125 | { |
1119 | struct inode * inode = dentry->d_inode; | 1126 | struct rpc_cred *cred; |
1120 | int size_change = sattr->ia_valid & ATTR_SIZE; | 1127 | struct inode *inode = dentry->d_inode; |
1121 | struct nfs4_state *state = NULL; | 1128 | struct nfs4_state *state; |
1122 | int need_iput = 0; | ||
1123 | int status; | 1129 | int status; |
1124 | 1130 | ||
1125 | fattr->valid = 0; | 1131 | fattr->valid = 0; |
1126 | 1132 | ||
1127 | if (size_change) { | 1133 | cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); |
1128 | struct rpc_cred *cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); | 1134 | if (IS_ERR(cred)) |
1129 | if (IS_ERR(cred)) | 1135 | return PTR_ERR(cred); |
1130 | return PTR_ERR(cred); | 1136 | /* Search for an existing WRITE delegation first */ |
1137 | state = nfs4_open_delegated(inode, FMODE_WRITE, cred); | ||
1138 | if (!IS_ERR(state)) { | ||
1139 | /* NB: nfs4_open_delegated() bumps the inode->i_count */ | ||
1140 | iput(inode); | ||
1141 | } else { | ||
1142 | /* Search for an existing open(O_WRITE) stateid */ | ||
1131 | state = nfs4_find_state(inode, cred, FMODE_WRITE); | 1143 | state = nfs4_find_state(inode, cred, FMODE_WRITE); |
1132 | if (state == NULL) { | ||
1133 | state = nfs4_open_delegated(dentry->d_inode, | ||
1134 | FMODE_WRITE, cred); | ||
1135 | if (IS_ERR(state)) | ||
1136 | state = nfs4_do_open(dentry->d_parent->d_inode, | ||
1137 | dentry, FMODE_WRITE, | ||
1138 | NULL, cred); | ||
1139 | need_iput = 1; | ||
1140 | } | ||
1141 | put_rpccred(cred); | ||
1142 | if (IS_ERR(state)) | ||
1143 | return PTR_ERR(state); | ||
1144 | |||
1145 | if (state->inode != inode) { | ||
1146 | printk(KERN_WARNING "nfs: raced in setattr (%p != %p), returning -EIO\n", inode, state->inode); | ||
1147 | status = -EIO; | ||
1148 | goto out; | ||
1149 | } | ||
1150 | } | 1144 | } |
1145 | |||
1151 | status = nfs4_do_setattr(NFS_SERVER(inode), fattr, | 1146 | status = nfs4_do_setattr(NFS_SERVER(inode), fattr, |
1152 | NFS_FH(inode), sattr, state); | 1147 | NFS_FH(inode), sattr, state); |
1153 | out: | 1148 | if (state != NULL) |
1154 | if (state) { | ||
1155 | inode = state->inode; | ||
1156 | nfs4_close_state(state, FMODE_WRITE); | 1149 | nfs4_close_state(state, FMODE_WRITE); |
1157 | if (need_iput) | 1150 | put_rpccred(cred); |
1158 | iput(inode); | ||
1159 | } | ||
1160 | return status; | 1151 | return status; |
1161 | } | 1152 | } |
1162 | 1153 | ||
@@ -1731,6 +1722,10 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
1731 | }; | 1722 | }; |
1732 | int status; | 1723 | int status; |
1733 | 1724 | ||
1725 | dprintk("%s: dentry = %s/%s, cookie = %Lu\n", __FUNCTION__, | ||
1726 | dentry->d_parent->d_name.name, | ||
1727 | dentry->d_name.name, | ||
1728 | (unsigned long long)cookie); | ||
1734 | lock_kernel(); | 1729 | lock_kernel(); |
1735 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); | 1730 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); |
1736 | res.pgbase = args.pgbase; | 1731 | res.pgbase = args.pgbase; |
@@ -1738,6 +1733,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
1738 | if (status == 0) | 1733 | if (status == 0) |
1739 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); | 1734 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); |
1740 | unlock_kernel(); | 1735 | unlock_kernel(); |
1736 | dprintk("%s: returns %d\n", __FUNCTION__, status); | ||
1741 | return status; | 1737 | return status; |
1742 | } | 1738 | } |
1743 | 1739 | ||
@@ -2163,6 +2159,193 @@ nfs4_proc_file_release(struct inode *inode, struct file *filp) | |||
2163 | return 0; | 2159 | return 0; |
2164 | } | 2160 | } |
2165 | 2161 | ||
2162 | static inline int nfs4_server_supports_acls(struct nfs_server *server) | ||
2163 | { | ||
2164 | return (server->caps & NFS_CAP_ACLS) | ||
2165 | && (server->acl_bitmask & ACL4_SUPPORT_ALLOW_ACL) | ||
2166 | && (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL); | ||
2167 | } | ||
2168 | |||
2169 | /* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_CACHE_SIZE, and that | ||
2170 | * it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_CACHE_SIZE) bytes on | ||
2171 | * the stack. | ||
2172 | */ | ||
2173 | #define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT) | ||
2174 | |||
2175 | static void buf_to_pages(const void *buf, size_t buflen, | ||
2176 | struct page **pages, unsigned int *pgbase) | ||
2177 | { | ||
2178 | const void *p = buf; | ||
2179 | |||
2180 | *pgbase = offset_in_page(buf); | ||
2181 | p -= *pgbase; | ||
2182 | while (p < buf + buflen) { | ||
2183 | *(pages++) = virt_to_page(p); | ||
2184 | p += PAGE_CACHE_SIZE; | ||
2185 | } | ||
2186 | } | ||
2187 | |||
2188 | struct nfs4_cached_acl { | ||
2189 | int cached; | ||
2190 | size_t len; | ||
2191 | char data[0]; | ||
2192 | }; | ||
2193 | |||
2194 | static void nfs4_set_cached_acl(struct inode *inode, struct nfs4_cached_acl *acl) | ||
2195 | { | ||
2196 | struct nfs_inode *nfsi = NFS_I(inode); | ||
2197 | |||
2198 | spin_lock(&inode->i_lock); | ||
2199 | kfree(nfsi->nfs4_acl); | ||
2200 | nfsi->nfs4_acl = acl; | ||
2201 | spin_unlock(&inode->i_lock); | ||
2202 | } | ||
2203 | |||
2204 | static void nfs4_zap_acl_attr(struct inode *inode) | ||
2205 | { | ||
2206 | nfs4_set_cached_acl(inode, NULL); | ||
2207 | } | ||
2208 | |||
2209 | static inline ssize_t nfs4_read_cached_acl(struct inode *inode, char *buf, size_t buflen) | ||
2210 | { | ||
2211 | struct nfs_inode *nfsi = NFS_I(inode); | ||
2212 | struct nfs4_cached_acl *acl; | ||
2213 | int ret = -ENOENT; | ||
2214 | |||
2215 | spin_lock(&inode->i_lock); | ||
2216 | acl = nfsi->nfs4_acl; | ||
2217 | if (acl == NULL) | ||
2218 | goto out; | ||
2219 | if (buf == NULL) /* user is just asking for length */ | ||
2220 | goto out_len; | ||
2221 | if (acl->cached == 0) | ||
2222 | goto out; | ||
2223 | ret = -ERANGE; /* see getxattr(2) man page */ | ||
2224 | if (acl->len > buflen) | ||
2225 | goto out; | ||
2226 | memcpy(buf, acl->data, acl->len); | ||
2227 | out_len: | ||
2228 | ret = acl->len; | ||
2229 | out: | ||
2230 | spin_unlock(&inode->i_lock); | ||
2231 | return ret; | ||
2232 | } | ||
2233 | |||
2234 | static void nfs4_write_cached_acl(struct inode *inode, const char *buf, size_t acl_len) | ||
2235 | { | ||
2236 | struct nfs4_cached_acl *acl; | ||
2237 | |||
2238 | if (buf && acl_len <= PAGE_SIZE) { | ||
2239 | acl = kmalloc(sizeof(*acl) + acl_len, GFP_KERNEL); | ||
2240 | if (acl == NULL) | ||
2241 | goto out; | ||
2242 | acl->cached = 1; | ||
2243 | memcpy(acl->data, buf, acl_len); | ||
2244 | } else { | ||
2245 | acl = kmalloc(sizeof(*acl), GFP_KERNEL); | ||
2246 | if (acl == NULL) | ||
2247 | goto out; | ||
2248 | acl->cached = 0; | ||
2249 | } | ||
2250 | acl->len = acl_len; | ||
2251 | out: | ||
2252 | nfs4_set_cached_acl(inode, acl); | ||
2253 | } | ||
2254 | |||
2255 | static inline ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) | ||
2256 | { | ||
2257 | struct page *pages[NFS4ACL_MAXPAGES]; | ||
2258 | struct nfs_getaclargs args = { | ||
2259 | .fh = NFS_FH(inode), | ||
2260 | .acl_pages = pages, | ||
2261 | .acl_len = buflen, | ||
2262 | }; | ||
2263 | size_t resp_len = buflen; | ||
2264 | void *resp_buf; | ||
2265 | struct rpc_message msg = { | ||
2266 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], | ||
2267 | .rpc_argp = &args, | ||
2268 | .rpc_resp = &resp_len, | ||
2269 | }; | ||
2270 | struct page *localpage = NULL; | ||
2271 | int ret; | ||
2272 | |||
2273 | if (buflen < PAGE_SIZE) { | ||
2274 | /* As long as we're doing a round trip to the server anyway, | ||
2275 | * let's be prepared for a page of acl data. */ | ||
2276 | localpage = alloc_page(GFP_KERNEL); | ||
2277 | resp_buf = page_address(localpage); | ||
2278 | if (localpage == NULL) | ||
2279 | return -ENOMEM; | ||
2280 | args.acl_pages[0] = localpage; | ||
2281 | args.acl_pgbase = 0; | ||
2282 | args.acl_len = PAGE_SIZE; | ||
2283 | } else { | ||
2284 | resp_buf = buf; | ||
2285 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); | ||
2286 | } | ||
2287 | ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | ||
2288 | if (ret) | ||
2289 | goto out_free; | ||
2290 | if (resp_len > args.acl_len) | ||
2291 | nfs4_write_cached_acl(inode, NULL, resp_len); | ||
2292 | else | ||
2293 | nfs4_write_cached_acl(inode, resp_buf, resp_len); | ||
2294 | if (buf) { | ||
2295 | ret = -ERANGE; | ||
2296 | if (resp_len > buflen) | ||
2297 | goto out_free; | ||
2298 | if (localpage) | ||
2299 | memcpy(buf, resp_buf, resp_len); | ||
2300 | } | ||
2301 | ret = resp_len; | ||
2302 | out_free: | ||
2303 | if (localpage) | ||
2304 | __free_page(localpage); | ||
2305 | return ret; | ||
2306 | } | ||
2307 | |||
2308 | static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) | ||
2309 | { | ||
2310 | struct nfs_server *server = NFS_SERVER(inode); | ||
2311 | int ret; | ||
2312 | |||
2313 | if (!nfs4_server_supports_acls(server)) | ||
2314 | return -EOPNOTSUPP; | ||
2315 | ret = nfs_revalidate_inode(server, inode); | ||
2316 | if (ret < 0) | ||
2317 | return ret; | ||
2318 | ret = nfs4_read_cached_acl(inode, buf, buflen); | ||
2319 | if (ret != -ENOENT) | ||
2320 | return ret; | ||
2321 | return nfs4_get_acl_uncached(inode, buf, buflen); | ||
2322 | } | ||
2323 | |||
2324 | static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen) | ||
2325 | { | ||
2326 | struct nfs_server *server = NFS_SERVER(inode); | ||
2327 | struct page *pages[NFS4ACL_MAXPAGES]; | ||
2328 | struct nfs_setaclargs arg = { | ||
2329 | .fh = NFS_FH(inode), | ||
2330 | .acl_pages = pages, | ||
2331 | .acl_len = buflen, | ||
2332 | }; | ||
2333 | struct rpc_message msg = { | ||
2334 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETACL], | ||
2335 | .rpc_argp = &arg, | ||
2336 | .rpc_resp = NULL, | ||
2337 | }; | ||
2338 | int ret; | ||
2339 | |||
2340 | if (!nfs4_server_supports_acls(server)) | ||
2341 | return -EOPNOTSUPP; | ||
2342 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); | ||
2343 | ret = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0); | ||
2344 | if (ret == 0) | ||
2345 | nfs4_write_cached_acl(inode, buf, buflen); | ||
2346 | return ret; | ||
2347 | } | ||
2348 | |||
2166 | static int | 2349 | static int |
2167 | nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server) | 2350 | nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server) |
2168 | { | 2351 | { |
@@ -2448,14 +2631,11 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
2448 | down_read(&clp->cl_sem); | 2631 | down_read(&clp->cl_sem); |
2449 | nlo.clientid = clp->cl_clientid; | 2632 | nlo.clientid = clp->cl_clientid; |
2450 | down(&state->lock_sema); | 2633 | down(&state->lock_sema); |
2451 | lsp = nfs4_find_lock_state(state, request->fl_owner); | 2634 | status = nfs4_set_lock_state(state, request); |
2452 | if (lsp) | 2635 | if (status != 0) |
2453 | nlo.id = lsp->ls_id; | 2636 | goto out; |
2454 | else { | 2637 | lsp = request->fl_u.nfs4_fl.owner; |
2455 | spin_lock(&clp->cl_lock); | 2638 | nlo.id = lsp->ls_id; |
2456 | nlo.id = nfs4_alloc_lockowner_id(clp); | ||
2457 | spin_unlock(&clp->cl_lock); | ||
2458 | } | ||
2459 | arg.u.lockt = &nlo; | 2639 | arg.u.lockt = &nlo; |
2460 | status = rpc_call_sync(server->client, &msg, 0); | 2640 | status = rpc_call_sync(server->client, &msg, 0); |
2461 | if (!status) { | 2641 | if (!status) { |
@@ -2476,8 +2656,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
2476 | request->fl_pid = 0; | 2656 | request->fl_pid = 0; |
2477 | status = 0; | 2657 | status = 0; |
2478 | } | 2658 | } |
2479 | if (lsp) | 2659 | out: |
2480 | nfs4_put_lock_state(lsp); | ||
2481 | up(&state->lock_sema); | 2660 | up(&state->lock_sema); |
2482 | up_read(&clp->cl_sem); | 2661 | up_read(&clp->cl_sem); |
2483 | return status; | 2662 | return status; |
@@ -2537,28 +2716,26 @@ static int _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock | |||
2537 | }; | 2716 | }; |
2538 | struct nfs4_lock_state *lsp; | 2717 | struct nfs4_lock_state *lsp; |
2539 | struct nfs_locku_opargs luargs; | 2718 | struct nfs_locku_opargs luargs; |
2540 | int status = 0; | 2719 | int status; |
2541 | 2720 | ||
2542 | down_read(&clp->cl_sem); | 2721 | down_read(&clp->cl_sem); |
2543 | down(&state->lock_sema); | 2722 | down(&state->lock_sema); |
2544 | lsp = nfs4_find_lock_state(state, request->fl_owner); | 2723 | status = nfs4_set_lock_state(state, request); |
2545 | if (!lsp) | 2724 | if (status != 0) |
2546 | goto out; | 2725 | goto out; |
2726 | lsp = request->fl_u.nfs4_fl.owner; | ||
2547 | /* We might have lost the locks! */ | 2727 | /* We might have lost the locks! */ |
2548 | if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) { | 2728 | if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) |
2549 | luargs.seqid = lsp->ls_seqid; | 2729 | goto out; |
2550 | memcpy(&luargs.stateid, &lsp->ls_stateid, sizeof(luargs.stateid)); | 2730 | luargs.seqid = lsp->ls_seqid; |
2551 | arg.u.locku = &luargs; | 2731 | memcpy(&luargs.stateid, &lsp->ls_stateid, sizeof(luargs.stateid)); |
2552 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 2732 | arg.u.locku = &luargs; |
2553 | nfs4_increment_lock_seqid(status, lsp); | 2733 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); |
2554 | } | 2734 | nfs4_increment_lock_seqid(status, lsp); |
2555 | 2735 | ||
2556 | if (status == 0) { | 2736 | if (status == 0) |
2557 | memcpy(&lsp->ls_stateid, &res.u.stateid, | 2737 | memcpy(&lsp->ls_stateid, &res.u.stateid, |
2558 | sizeof(lsp->ls_stateid)); | 2738 | sizeof(lsp->ls_stateid)); |
2559 | nfs4_notify_unlck(state, request, lsp); | ||
2560 | } | ||
2561 | nfs4_put_lock_state(lsp); | ||
2562 | out: | 2739 | out: |
2563 | up(&state->lock_sema); | 2740 | up(&state->lock_sema); |
2564 | if (status == 0) | 2741 | if (status == 0) |
@@ -2584,7 +2761,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r | |||
2584 | { | 2761 | { |
2585 | struct inode *inode = state->inode; | 2762 | struct inode *inode = state->inode; |
2586 | struct nfs_server *server = NFS_SERVER(inode); | 2763 | struct nfs_server *server = NFS_SERVER(inode); |
2587 | struct nfs4_lock_state *lsp; | 2764 | struct nfs4_lock_state *lsp = request->fl_u.nfs4_fl.owner; |
2588 | struct nfs_lockargs arg = { | 2765 | struct nfs_lockargs arg = { |
2589 | .fh = NFS_FH(inode), | 2766 | .fh = NFS_FH(inode), |
2590 | .type = nfs4_lck_type(cmd, request), | 2767 | .type = nfs4_lck_type(cmd, request), |
@@ -2606,9 +2783,6 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r | |||
2606 | }; | 2783 | }; |
2607 | int status; | 2784 | int status; |
2608 | 2785 | ||
2609 | lsp = nfs4_get_lock_state(state, request->fl_owner); | ||
2610 | if (lsp == NULL) | ||
2611 | return -ENOMEM; | ||
2612 | if (!(lsp->ls_flags & NFS_LOCK_INITIALIZED)) { | 2786 | if (!(lsp->ls_flags & NFS_LOCK_INITIALIZED)) { |
2613 | struct nfs4_state_owner *owner = state->owner; | 2787 | struct nfs4_state_owner *owner = state->owner; |
2614 | struct nfs_open_to_lock otl = { | 2788 | struct nfs_open_to_lock otl = { |
@@ -2630,38 +2804,57 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r | |||
2630 | * seqid mutating errors */ | 2804 | * seqid mutating errors */ |
2631 | nfs4_increment_seqid(status, owner); | 2805 | nfs4_increment_seqid(status, owner); |
2632 | up(&owner->so_sema); | 2806 | up(&owner->so_sema); |
2807 | if (status == 0) { | ||
2808 | lsp->ls_flags |= NFS_LOCK_INITIALIZED; | ||
2809 | lsp->ls_seqid++; | ||
2810 | } | ||
2633 | } else { | 2811 | } else { |
2634 | struct nfs_exist_lock el = { | 2812 | struct nfs_exist_lock el = { |
2635 | .seqid = lsp->ls_seqid, | 2813 | .seqid = lsp->ls_seqid, |
2636 | }; | 2814 | }; |
2637 | memcpy(&el.stateid, &lsp->ls_stateid, sizeof(el.stateid)); | 2815 | memcpy(&el.stateid, &lsp->ls_stateid, sizeof(el.stateid)); |
2638 | largs.u.exist_lock = ⪙ | 2816 | largs.u.exist_lock = ⪙ |
2639 | largs.new_lock_owner = 0; | ||
2640 | arg.u.lock = &largs; | 2817 | arg.u.lock = &largs; |
2641 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 2818 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); |
2819 | /* increment seqid on success, and * seqid mutating errors*/ | ||
2820 | nfs4_increment_lock_seqid(status, lsp); | ||
2642 | } | 2821 | } |
2643 | /* increment seqid on success, and * seqid mutating errors*/ | ||
2644 | nfs4_increment_lock_seqid(status, lsp); | ||
2645 | /* save the returned stateid. */ | 2822 | /* save the returned stateid. */ |
2646 | if (status == 0) { | 2823 | if (status == 0) |
2647 | memcpy(&lsp->ls_stateid, &res.u.stateid, sizeof(nfs4_stateid)); | 2824 | memcpy(&lsp->ls_stateid, &res.u.stateid, sizeof(nfs4_stateid)); |
2648 | lsp->ls_flags |= NFS_LOCK_INITIALIZED; | 2825 | else if (status == -NFS4ERR_DENIED) |
2649 | if (!reclaim) | ||
2650 | nfs4_notify_setlk(state, request, lsp); | ||
2651 | } else if (status == -NFS4ERR_DENIED) | ||
2652 | status = -EAGAIN; | 2826 | status = -EAGAIN; |
2653 | nfs4_put_lock_state(lsp); | ||
2654 | return status; | 2827 | return status; |
2655 | } | 2828 | } |
2656 | 2829 | ||
2657 | static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request) | 2830 | static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request) |
2658 | { | 2831 | { |
2659 | return _nfs4_do_setlk(state, F_SETLK, request, 1); | 2832 | struct nfs_server *server = NFS_SERVER(state->inode); |
2833 | struct nfs4_exception exception = { }; | ||
2834 | int err; | ||
2835 | |||
2836 | do { | ||
2837 | err = _nfs4_do_setlk(state, F_SETLK, request, 1); | ||
2838 | if (err != -NFS4ERR_DELAY) | ||
2839 | break; | ||
2840 | nfs4_handle_exception(server, err, &exception); | ||
2841 | } while (exception.retry); | ||
2842 | return err; | ||
2660 | } | 2843 | } |
2661 | 2844 | ||
2662 | static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request) | 2845 | static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request) |
2663 | { | 2846 | { |
2664 | return _nfs4_do_setlk(state, F_SETLK, request, 0); | 2847 | struct nfs_server *server = NFS_SERVER(state->inode); |
2848 | struct nfs4_exception exception = { }; | ||
2849 | int err; | ||
2850 | |||
2851 | do { | ||
2852 | err = _nfs4_do_setlk(state, F_SETLK, request, 0); | ||
2853 | if (err != -NFS4ERR_DELAY) | ||
2854 | break; | ||
2855 | nfs4_handle_exception(server, err, &exception); | ||
2856 | } while (exception.retry); | ||
2857 | return err; | ||
2665 | } | 2858 | } |
2666 | 2859 | ||
2667 | static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) | 2860 | static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) |
@@ -2671,7 +2864,9 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock | |||
2671 | 2864 | ||
2672 | down_read(&clp->cl_sem); | 2865 | down_read(&clp->cl_sem); |
2673 | down(&state->lock_sema); | 2866 | down(&state->lock_sema); |
2674 | status = _nfs4_do_setlk(state, cmd, request, 0); | 2867 | status = nfs4_set_lock_state(state, request); |
2868 | if (status == 0) | ||
2869 | status = _nfs4_do_setlk(state, cmd, request, 0); | ||
2675 | up(&state->lock_sema); | 2870 | up(&state->lock_sema); |
2676 | if (status == 0) { | 2871 | if (status == 0) { |
2677 | /* Note: we always want to sleep here! */ | 2872 | /* Note: we always want to sleep here! */ |
@@ -2729,10 +2924,53 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request) | |||
2729 | if (signalled()) | 2924 | if (signalled()) |
2730 | break; | 2925 | break; |
2731 | } while(status < 0); | 2926 | } while(status < 0); |
2732 | |||
2733 | return status; | 2927 | return status; |
2734 | } | 2928 | } |
2735 | 2929 | ||
2930 | |||
2931 | #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl" | ||
2932 | |||
2933 | int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf, | ||
2934 | size_t buflen, int flags) | ||
2935 | { | ||
2936 | struct inode *inode = dentry->d_inode; | ||
2937 | |||
2938 | if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0) | ||
2939 | return -EOPNOTSUPP; | ||
2940 | |||
2941 | if (!S_ISREG(inode->i_mode) && | ||
2942 | (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX)) | ||
2943 | return -EPERM; | ||
2944 | |||
2945 | return nfs4_proc_set_acl(inode, buf, buflen); | ||
2946 | } | ||
2947 | |||
2948 | /* The getxattr man page suggests returning -ENODATA for unknown attributes, | ||
2949 | * and that's what we'll do for e.g. user attributes that haven't been set. | ||
2950 | * But we'll follow ext2/ext3's lead by returning -EOPNOTSUPP for unsupported | ||
2951 | * attributes in kernel-managed attribute namespaces. */ | ||
2952 | ssize_t nfs4_getxattr(struct dentry *dentry, const char *key, void *buf, | ||
2953 | size_t buflen) | ||
2954 | { | ||
2955 | struct inode *inode = dentry->d_inode; | ||
2956 | |||
2957 | if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0) | ||
2958 | return -EOPNOTSUPP; | ||
2959 | |||
2960 | return nfs4_proc_get_acl(inode, buf, buflen); | ||
2961 | } | ||
2962 | |||
2963 | ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen) | ||
2964 | { | ||
2965 | size_t len = strlen(XATTR_NAME_NFSV4_ACL) + 1; | ||
2966 | |||
2967 | if (buf && buflen < len) | ||
2968 | return -ERANGE; | ||
2969 | if (buf) | ||
2970 | memcpy(buf, XATTR_NAME_NFSV4_ACL, len); | ||
2971 | return len; | ||
2972 | } | ||
2973 | |||
2736 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { | 2974 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { |
2737 | .recover_open = nfs4_open_reclaim, | 2975 | .recover_open = nfs4_open_reclaim, |
2738 | .recover_lock = nfs4_lock_reclaim, | 2976 | .recover_lock = nfs4_lock_reclaim, |
@@ -2743,10 +2981,20 @@ struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops = { | |||
2743 | .recover_lock = nfs4_lock_expired, | 2981 | .recover_lock = nfs4_lock_expired, |
2744 | }; | 2982 | }; |
2745 | 2983 | ||
2984 | static struct inode_operations nfs4_file_inode_operations = { | ||
2985 | .permission = nfs_permission, | ||
2986 | .getattr = nfs_getattr, | ||
2987 | .setattr = nfs_setattr, | ||
2988 | .getxattr = nfs4_getxattr, | ||
2989 | .setxattr = nfs4_setxattr, | ||
2990 | .listxattr = nfs4_listxattr, | ||
2991 | }; | ||
2992 | |||
2746 | struct nfs_rpc_ops nfs_v4_clientops = { | 2993 | struct nfs_rpc_ops nfs_v4_clientops = { |
2747 | .version = 4, /* protocol version */ | 2994 | .version = 4, /* protocol version */ |
2748 | .dentry_ops = &nfs4_dentry_operations, | 2995 | .dentry_ops = &nfs4_dentry_operations, |
2749 | .dir_inode_ops = &nfs4_dir_inode_operations, | 2996 | .dir_inode_ops = &nfs4_dir_inode_operations, |
2997 | .file_inode_ops = &nfs4_file_inode_operations, | ||
2750 | .getroot = nfs4_proc_get_root, | 2998 | .getroot = nfs4_proc_get_root, |
2751 | .getattr = nfs4_proc_getattr, | 2999 | .getattr = nfs4_proc_getattr, |
2752 | .setattr = nfs4_proc_setattr, | 3000 | .setattr = nfs4_proc_setattr, |
@@ -2777,6 +3025,7 @@ struct nfs_rpc_ops nfs_v4_clientops = { | |||
2777 | .file_open = nfs4_proc_file_open, | 3025 | .file_open = nfs4_proc_file_open, |
2778 | .file_release = nfs4_proc_file_release, | 3026 | .file_release = nfs4_proc_file_release, |
2779 | .lock = nfs4_proc_lock, | 3027 | .lock = nfs4_proc_lock, |
3028 | .clear_acl_cache = nfs4_zap_acl_attr, | ||
2780 | }; | 3029 | }; |
2781 | 3030 | ||
2782 | /* | 3031 | /* |
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index 667e06f1c647..a3001628ad32 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c | |||
@@ -53,6 +53,7 @@ | |||
53 | #include <linux/nfs.h> | 53 | #include <linux/nfs.h> |
54 | #include <linux/nfs4.h> | 54 | #include <linux/nfs4.h> |
55 | #include <linux/nfs_fs.h> | 55 | #include <linux/nfs_fs.h> |
56 | #include "nfs4_fs.h" | ||
56 | 57 | ||
57 | #define NFSDBG_FACILITY NFSDBG_PROC | 58 | #define NFSDBG_FACILITY NFSDBG_PROC |
58 | 59 | ||
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 231cebce3c87..afe587d82f1e 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -46,24 +46,18 @@ | |||
46 | #include <linux/workqueue.h> | 46 | #include <linux/workqueue.h> |
47 | #include <linux/bitops.h> | 47 | #include <linux/bitops.h> |
48 | 48 | ||
49 | #include "nfs4_fs.h" | ||
49 | #include "callback.h" | 50 | #include "callback.h" |
50 | #include "delegation.h" | 51 | #include "delegation.h" |
51 | 52 | ||
52 | #define OPENOWNER_POOL_SIZE 8 | 53 | #define OPENOWNER_POOL_SIZE 8 |
53 | 54 | ||
54 | static DEFINE_SPINLOCK(state_spinlock); | 55 | const nfs4_stateid zero_stateid; |
55 | |||
56 | nfs4_stateid zero_stateid; | ||
57 | |||
58 | #if 0 | ||
59 | nfs4_stateid one_stateid = | ||
60 | { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | ||
61 | #endif | ||
62 | 56 | ||
57 | static DEFINE_SPINLOCK(state_spinlock); | ||
63 | static LIST_HEAD(nfs4_clientid_list); | 58 | static LIST_HEAD(nfs4_clientid_list); |
64 | 59 | ||
65 | static void nfs4_recover_state(void *); | 60 | static void nfs4_recover_state(void *); |
66 | extern void nfs4_renew_state(void *); | ||
67 | 61 | ||
68 | void | 62 | void |
69 | init_nfsv4_state(struct nfs_server *server) | 63 | init_nfsv4_state(struct nfs_server *server) |
@@ -116,6 +110,7 @@ nfs4_alloc_client(struct in_addr *addr) | |||
116 | INIT_LIST_HEAD(&clp->cl_superblocks); | 110 | INIT_LIST_HEAD(&clp->cl_superblocks); |
117 | init_waitqueue_head(&clp->cl_waitq); | 111 | init_waitqueue_head(&clp->cl_waitq); |
118 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client"); | 112 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client"); |
113 | clp->cl_rpcclient = ERR_PTR(-EINVAL); | ||
119 | clp->cl_boot_time = CURRENT_TIME; | 114 | clp->cl_boot_time = CURRENT_TIME; |
120 | clp->cl_state = 1 << NFS4CLNT_OK; | 115 | clp->cl_state = 1 << NFS4CLNT_OK; |
121 | return clp; | 116 | return clp; |
@@ -137,7 +132,7 @@ nfs4_free_client(struct nfs4_client *clp) | |||
137 | if (clp->cl_cred) | 132 | if (clp->cl_cred) |
138 | put_rpccred(clp->cl_cred); | 133 | put_rpccred(clp->cl_cred); |
139 | nfs_idmap_delete(clp); | 134 | nfs_idmap_delete(clp); |
140 | if (clp->cl_rpcclient) | 135 | if (!IS_ERR(clp->cl_rpcclient)) |
141 | rpc_shutdown_client(clp->cl_rpcclient); | 136 | rpc_shutdown_client(clp->cl_rpcclient); |
142 | kfree(clp); | 137 | kfree(clp); |
143 | nfs_callback_down(); | 138 | nfs_callback_down(); |
@@ -365,7 +360,7 @@ nfs4_alloc_open_state(void) | |||
365 | atomic_set(&state->count, 1); | 360 | atomic_set(&state->count, 1); |
366 | INIT_LIST_HEAD(&state->lock_states); | 361 | INIT_LIST_HEAD(&state->lock_states); |
367 | init_MUTEX(&state->lock_sema); | 362 | init_MUTEX(&state->lock_sema); |
368 | rwlock_init(&state->state_lock); | 363 | spin_lock_init(&state->state_lock); |
369 | return state; | 364 | return state; |
370 | } | 365 | } |
371 | 366 | ||
@@ -547,16 +542,6 @@ __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) | |||
547 | return NULL; | 542 | return NULL; |
548 | } | 543 | } |
549 | 544 | ||
550 | struct nfs4_lock_state * | ||
551 | nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) | ||
552 | { | ||
553 | struct nfs4_lock_state *lsp; | ||
554 | read_lock(&state->state_lock); | ||
555 | lsp = __nfs4_find_lock_state(state, fl_owner); | ||
556 | read_unlock(&state->state_lock); | ||
557 | return lsp; | ||
558 | } | ||
559 | |||
560 | /* | 545 | /* |
561 | * Return a compatible lock_state. If no initialized lock_state structure | 546 | * Return a compatible lock_state. If no initialized lock_state structure |
562 | * exists, return an uninitialized one. | 547 | * exists, return an uninitialized one. |
@@ -573,14 +558,13 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f | |||
573 | return NULL; | 558 | return NULL; |
574 | lsp->ls_flags = 0; | 559 | lsp->ls_flags = 0; |
575 | lsp->ls_seqid = 0; /* arbitrary */ | 560 | lsp->ls_seqid = 0; /* arbitrary */ |
576 | lsp->ls_id = -1; | ||
577 | memset(lsp->ls_stateid.data, 0, sizeof(lsp->ls_stateid.data)); | 561 | memset(lsp->ls_stateid.data, 0, sizeof(lsp->ls_stateid.data)); |
578 | atomic_set(&lsp->ls_count, 1); | 562 | atomic_set(&lsp->ls_count, 1); |
579 | lsp->ls_owner = fl_owner; | 563 | lsp->ls_owner = fl_owner; |
580 | INIT_LIST_HEAD(&lsp->ls_locks); | ||
581 | spin_lock(&clp->cl_lock); | 564 | spin_lock(&clp->cl_lock); |
582 | lsp->ls_id = nfs4_alloc_lockowner_id(clp); | 565 | lsp->ls_id = nfs4_alloc_lockowner_id(clp); |
583 | spin_unlock(&clp->cl_lock); | 566 | spin_unlock(&clp->cl_lock); |
567 | INIT_LIST_HEAD(&lsp->ls_locks); | ||
584 | return lsp; | 568 | return lsp; |
585 | } | 569 | } |
586 | 570 | ||
@@ -590,121 +574,112 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f | |||
590 | * | 574 | * |
591 | * The caller must be holding state->lock_sema and clp->cl_sem | 575 | * The caller must be holding state->lock_sema and clp->cl_sem |
592 | */ | 576 | */ |
593 | struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner) | 577 | static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner) |
594 | { | 578 | { |
595 | struct nfs4_lock_state * lsp; | 579 | struct nfs4_lock_state *lsp, *new = NULL; |
596 | 580 | ||
597 | lsp = nfs4_find_lock_state(state, owner); | 581 | for(;;) { |
598 | if (lsp == NULL) | 582 | spin_lock(&state->state_lock); |
599 | lsp = nfs4_alloc_lock_state(state, owner); | 583 | lsp = __nfs4_find_lock_state(state, owner); |
584 | if (lsp != NULL) | ||
585 | break; | ||
586 | if (new != NULL) { | ||
587 | new->ls_state = state; | ||
588 | list_add(&new->ls_locks, &state->lock_states); | ||
589 | set_bit(LK_STATE_IN_USE, &state->flags); | ||
590 | lsp = new; | ||
591 | new = NULL; | ||
592 | break; | ||
593 | } | ||
594 | spin_unlock(&state->state_lock); | ||
595 | new = nfs4_alloc_lock_state(state, owner); | ||
596 | if (new == NULL) | ||
597 | return NULL; | ||
598 | } | ||
599 | spin_unlock(&state->state_lock); | ||
600 | kfree(new); | ||
600 | return lsp; | 601 | return lsp; |
601 | } | 602 | } |
602 | 603 | ||
603 | /* | 604 | /* |
604 | * Byte-range lock aware utility to initialize the stateid of read/write | 605 | * Release reference to lock_state, and free it if we see that |
605 | * requests. | 606 | * it is no longer in use |
606 | */ | 607 | */ |
607 | void | 608 | static void nfs4_put_lock_state(struct nfs4_lock_state *lsp) |
608 | nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner) | ||
609 | { | 609 | { |
610 | if (test_bit(LK_STATE_IN_USE, &state->flags)) { | 610 | struct nfs4_state *state; |
611 | struct nfs4_lock_state *lsp; | ||
612 | 611 | ||
613 | lsp = nfs4_find_lock_state(state, fl_owner); | 612 | if (lsp == NULL) |
614 | if (lsp) { | 613 | return; |
615 | memcpy(dst, &lsp->ls_stateid, sizeof(*dst)); | 614 | state = lsp->ls_state; |
616 | nfs4_put_lock_state(lsp); | 615 | if (!atomic_dec_and_lock(&lsp->ls_count, &state->state_lock)) |
617 | return; | 616 | return; |
618 | } | 617 | list_del(&lsp->ls_locks); |
619 | } | 618 | if (list_empty(&state->lock_states)) |
620 | memcpy(dst, &state->stateid, sizeof(*dst)); | 619 | clear_bit(LK_STATE_IN_USE, &state->flags); |
620 | spin_unlock(&state->state_lock); | ||
621 | kfree(lsp); | ||
621 | } | 622 | } |
622 | 623 | ||
623 | /* | 624 | static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src) |
624 | * Called with state->lock_sema and clp->cl_sem held. | ||
625 | */ | ||
626 | void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *lsp) | ||
627 | { | 625 | { |
628 | if (status == NFS_OK || seqid_mutating_err(-status)) | 626 | struct nfs4_lock_state *lsp = src->fl_u.nfs4_fl.owner; |
629 | lsp->ls_seqid++; | ||
630 | } | ||
631 | 627 | ||
632 | /* | 628 | dst->fl_u.nfs4_fl.owner = lsp; |
633 | * Check to see if the request lock (type FL_UNLK) effects the fl lock. | 629 | atomic_inc(&lsp->ls_count); |
634 | * | 630 | } |
635 | * fl and request must have the same posix owner | ||
636 | * | ||
637 | * return: | ||
638 | * 0 -> fl not effected by request | ||
639 | * 1 -> fl consumed by request | ||
640 | */ | ||
641 | 631 | ||
642 | static int | 632 | static void nfs4_fl_release_lock(struct file_lock *fl) |
643 | nfs4_check_unlock(struct file_lock *fl, struct file_lock *request) | ||
644 | { | 633 | { |
645 | if (fl->fl_start >= request->fl_start && fl->fl_end <= request->fl_end) | 634 | nfs4_put_lock_state(fl->fl_u.nfs4_fl.owner); |
646 | return 1; | ||
647 | return 0; | ||
648 | } | 635 | } |
649 | 636 | ||
650 | /* | 637 | static struct file_lock_operations nfs4_fl_lock_ops = { |
651 | * Post an initialized lock_state on the state->lock_states list. | 638 | .fl_copy_lock = nfs4_fl_copy_lock, |
652 | */ | 639 | .fl_release_private = nfs4_fl_release_lock, |
653 | void nfs4_notify_setlk(struct nfs4_state *state, struct file_lock *request, struct nfs4_lock_state *lsp) | 640 | }; |
641 | |||
642 | int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl) | ||
654 | { | 643 | { |
655 | if (!list_empty(&lsp->ls_locks)) | 644 | struct nfs4_lock_state *lsp; |
656 | return; | 645 | |
657 | atomic_inc(&lsp->ls_count); | 646 | if (fl->fl_ops != NULL) |
658 | write_lock(&state->state_lock); | 647 | return 0; |
659 | list_add(&lsp->ls_locks, &state->lock_states); | 648 | lsp = nfs4_get_lock_state(state, fl->fl_owner); |
660 | set_bit(LK_STATE_IN_USE, &state->flags); | 649 | if (lsp == NULL) |
661 | write_unlock(&state->state_lock); | 650 | return -ENOMEM; |
651 | fl->fl_u.nfs4_fl.owner = lsp; | ||
652 | fl->fl_ops = &nfs4_fl_lock_ops; | ||
653 | return 0; | ||
662 | } | 654 | } |
663 | 655 | ||
664 | /* | 656 | /* |
665 | * to decide to 'reap' lock state: | 657 | * Byte-range lock aware utility to initialize the stateid of read/write |
666 | * 1) search i_flock for file_locks with fl.lock_state = to ls. | 658 | * requests. |
667 | * 2) determine if unlock will consume found lock. | ||
668 | * if so, reap | ||
669 | * | ||
670 | * else, don't reap. | ||
671 | * | ||
672 | */ | 659 | */ |
673 | void | 660 | void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner) |
674 | nfs4_notify_unlck(struct nfs4_state *state, struct file_lock *request, struct nfs4_lock_state *lsp) | ||
675 | { | 661 | { |
676 | struct inode *inode = state->inode; | 662 | struct nfs4_lock_state *lsp; |
677 | struct file_lock *fl; | ||
678 | 663 | ||
679 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { | 664 | memcpy(dst, &state->stateid, sizeof(*dst)); |
680 | if (!(fl->fl_flags & FL_POSIX)) | 665 | if (test_bit(LK_STATE_IN_USE, &state->flags) == 0) |
681 | continue; | 666 | return; |
682 | if (fl->fl_owner != lsp->ls_owner) | ||
683 | continue; | ||
684 | /* Exit if we find at least one lock which is not consumed */ | ||
685 | if (nfs4_check_unlock(fl,request) == 0) | ||
686 | return; | ||
687 | } | ||
688 | 667 | ||
689 | write_lock(&state->state_lock); | 668 | spin_lock(&state->state_lock); |
690 | list_del_init(&lsp->ls_locks); | 669 | lsp = __nfs4_find_lock_state(state, fl_owner); |
691 | if (list_empty(&state->lock_states)) | 670 | if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) |
692 | clear_bit(LK_STATE_IN_USE, &state->flags); | 671 | memcpy(dst, &lsp->ls_stateid, sizeof(*dst)); |
693 | write_unlock(&state->state_lock); | 672 | spin_unlock(&state->state_lock); |
694 | nfs4_put_lock_state(lsp); | 673 | nfs4_put_lock_state(lsp); |
695 | } | 674 | } |
696 | 675 | ||
697 | /* | 676 | /* |
698 | * Release reference to lock_state, and free it if we see that | 677 | * Called with state->lock_sema and clp->cl_sem held. |
699 | * it is no longer in use | 678 | */ |
700 | */ | 679 | void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *lsp) |
701 | void | ||
702 | nfs4_put_lock_state(struct nfs4_lock_state *lsp) | ||
703 | { | 680 | { |
704 | if (!atomic_dec_and_test(&lsp->ls_count)) | 681 | if (status == NFS_OK || seqid_mutating_err(-status)) |
705 | return; | 682 | lsp->ls_seqid++; |
706 | BUG_ON (!list_empty(&lsp->ls_locks)); | ||
707 | kfree(lsp); | ||
708 | } | 683 | } |
709 | 684 | ||
710 | /* | 685 | /* |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 5f4de05763c9..6c564ef9489e 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -51,6 +51,7 @@ | |||
51 | #include <linux/nfs4.h> | 51 | #include <linux/nfs4.h> |
52 | #include <linux/nfs_fs.h> | 52 | #include <linux/nfs_fs.h> |
53 | #include <linux/nfs_idmap.h> | 53 | #include <linux/nfs_idmap.h> |
54 | #include "nfs4_fs.h" | ||
54 | 55 | ||
55 | #define NFSDBG_FACILITY NFSDBG_XDR | 56 | #define NFSDBG_FACILITY NFSDBG_XDR |
56 | 57 | ||
@@ -82,12 +83,16 @@ static int nfs_stat_to_errno(int); | |||
82 | #define encode_getfh_maxsz (op_encode_hdr_maxsz) | 83 | #define encode_getfh_maxsz (op_encode_hdr_maxsz) |
83 | #define decode_getfh_maxsz (op_decode_hdr_maxsz + 1 + \ | 84 | #define decode_getfh_maxsz (op_decode_hdr_maxsz + 1 + \ |
84 | ((3+NFS4_FHSIZE) >> 2)) | 85 | ((3+NFS4_FHSIZE) >> 2)) |
85 | #define encode_getattr_maxsz (op_encode_hdr_maxsz + 3) | 86 | #define nfs4_fattr_bitmap_maxsz 3 |
87 | #define encode_getattr_maxsz (op_encode_hdr_maxsz + nfs4_fattr_bitmap_maxsz) | ||
86 | #define nfs4_name_maxsz (1 + ((3 + NFS4_MAXNAMLEN) >> 2)) | 88 | #define nfs4_name_maxsz (1 + ((3 + NFS4_MAXNAMLEN) >> 2)) |
87 | #define nfs4_path_maxsz (1 + ((3 + NFS4_MAXPATHLEN) >> 2)) | 89 | #define nfs4_path_maxsz (1 + ((3 + NFS4_MAXPATHLEN) >> 2)) |
88 | #define nfs4_fattr_bitmap_maxsz (36 + 2 * nfs4_name_maxsz) | 90 | /* This is based on getfattr, which uses the most attributes: */ |
89 | #define decode_getattr_maxsz (op_decode_hdr_maxsz + 3 + \ | 91 | #define nfs4_fattr_value_maxsz (1 + (1 + 2 + 2 + 4 + 2 + 1 + 1 + 2 + 2 + \ |
90 | nfs4_fattr_bitmap_maxsz) | 92 | 3 + 3 + 3 + 2 * nfs4_name_maxsz)) |
93 | #define nfs4_fattr_maxsz (nfs4_fattr_bitmap_maxsz + \ | ||
94 | nfs4_fattr_value_maxsz) | ||
95 | #define decode_getattr_maxsz (op_decode_hdr_maxsz + nfs4_fattr_maxsz) | ||
91 | #define encode_savefh_maxsz (op_encode_hdr_maxsz) | 96 | #define encode_savefh_maxsz (op_encode_hdr_maxsz) |
92 | #define decode_savefh_maxsz (op_decode_hdr_maxsz) | 97 | #define decode_savefh_maxsz (op_decode_hdr_maxsz) |
93 | #define encode_fsinfo_maxsz (op_encode_hdr_maxsz + 2) | 98 | #define encode_fsinfo_maxsz (op_encode_hdr_maxsz + 2) |
@@ -122,11 +127,11 @@ static int nfs_stat_to_errno(int); | |||
122 | #define encode_symlink_maxsz (op_encode_hdr_maxsz + \ | 127 | #define encode_symlink_maxsz (op_encode_hdr_maxsz + \ |
123 | 1 + nfs4_name_maxsz + \ | 128 | 1 + nfs4_name_maxsz + \ |
124 | nfs4_path_maxsz + \ | 129 | nfs4_path_maxsz + \ |
125 | nfs4_fattr_bitmap_maxsz) | 130 | nfs4_fattr_maxsz) |
126 | #define decode_symlink_maxsz (op_decode_hdr_maxsz + 8) | 131 | #define decode_symlink_maxsz (op_decode_hdr_maxsz + 8) |
127 | #define encode_create_maxsz (op_encode_hdr_maxsz + \ | 132 | #define encode_create_maxsz (op_encode_hdr_maxsz + \ |
128 | 2 + nfs4_name_maxsz + \ | 133 | 2 + nfs4_name_maxsz + \ |
129 | nfs4_fattr_bitmap_maxsz) | 134 | nfs4_fattr_maxsz) |
130 | #define decode_create_maxsz (op_decode_hdr_maxsz + 8) | 135 | #define decode_create_maxsz (op_decode_hdr_maxsz + 8) |
131 | #define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4) | 136 | #define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4) |
132 | #define decode_delegreturn_maxsz (op_decode_hdr_maxsz) | 137 | #define decode_delegreturn_maxsz (op_decode_hdr_maxsz) |
@@ -205,7 +210,7 @@ static int nfs_stat_to_errno(int); | |||
205 | #define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \ | 210 | #define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \ |
206 | encode_putfh_maxsz + \ | 211 | encode_putfh_maxsz + \ |
207 | op_encode_hdr_maxsz + 4 + \ | 212 | op_encode_hdr_maxsz + 4 + \ |
208 | nfs4_fattr_bitmap_maxsz + \ | 213 | nfs4_fattr_maxsz + \ |
209 | encode_getattr_maxsz) | 214 | encode_getattr_maxsz) |
210 | #define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \ | 215 | #define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \ |
211 | decode_putfh_maxsz + \ | 216 | decode_putfh_maxsz + \ |
@@ -360,6 +365,20 @@ static int nfs_stat_to_errno(int); | |||
360 | encode_delegreturn_maxsz) | 365 | encode_delegreturn_maxsz) |
361 | #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \ | 366 | #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \ |
362 | decode_delegreturn_maxsz) | 367 | decode_delegreturn_maxsz) |
368 | #define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \ | ||
369 | encode_putfh_maxsz + \ | ||
370 | encode_getattr_maxsz) | ||
371 | #define NFS4_dec_getacl_sz (compound_decode_hdr_maxsz + \ | ||
372 | decode_putfh_maxsz + \ | ||
373 | op_decode_hdr_maxsz + \ | ||
374 | nfs4_fattr_bitmap_maxsz + 1) | ||
375 | #define NFS4_enc_setacl_sz (compound_encode_hdr_maxsz + \ | ||
376 | encode_putfh_maxsz + \ | ||
377 | op_encode_hdr_maxsz + 4 + \ | ||
378 | nfs4_fattr_bitmap_maxsz + 1) | ||
379 | #define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \ | ||
380 | decode_putfh_maxsz + \ | ||
381 | op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz) | ||
363 | 382 | ||
364 | static struct { | 383 | static struct { |
365 | unsigned int mode; | 384 | unsigned int mode; |
@@ -459,7 +478,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s | |||
459 | * In the worst-case, this would be | 478 | * In the worst-case, this would be |
460 | * 12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime) | 479 | * 12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime) |
461 | * = 36 bytes, plus any contribution from variable-length fields | 480 | * = 36 bytes, plus any contribution from variable-length fields |
462 | * such as owner/group/acl's. | 481 | * such as owner/group. |
463 | */ | 482 | */ |
464 | len = 16; | 483 | len = 16; |
465 | 484 | ||
@@ -660,8 +679,6 @@ static int encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1 | |||
660 | 679 | ||
661 | static int encode_getfattr(struct xdr_stream *xdr, const u32* bitmask) | 680 | static int encode_getfattr(struct xdr_stream *xdr, const u32* bitmask) |
662 | { | 681 | { |
663 | extern u32 nfs4_fattr_bitmap[]; | ||
664 | |||
665 | return encode_getattr_two(xdr, | 682 | return encode_getattr_two(xdr, |
666 | bitmask[0] & nfs4_fattr_bitmap[0], | 683 | bitmask[0] & nfs4_fattr_bitmap[0], |
667 | bitmask[1] & nfs4_fattr_bitmap[1]); | 684 | bitmask[1] & nfs4_fattr_bitmap[1]); |
@@ -669,8 +686,6 @@ static int encode_getfattr(struct xdr_stream *xdr, const u32* bitmask) | |||
669 | 686 | ||
670 | static int encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask) | 687 | static int encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask) |
671 | { | 688 | { |
672 | extern u32 nfs4_fsinfo_bitmap[]; | ||
673 | |||
674 | return encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0], | 689 | return encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0], |
675 | bitmask[1] & nfs4_fsinfo_bitmap[1]); | 690 | bitmask[1] & nfs4_fsinfo_bitmap[1]); |
676 | } | 691 | } |
@@ -969,7 +984,6 @@ static int encode_putrootfh(struct xdr_stream *xdr) | |||
969 | 984 | ||
970 | static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) | 985 | static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) |
971 | { | 986 | { |
972 | extern nfs4_stateid zero_stateid; | ||
973 | nfs4_stateid stateid; | 987 | nfs4_stateid stateid; |
974 | uint32_t *p; | 988 | uint32_t *p; |
975 | 989 | ||
@@ -1000,6 +1014,10 @@ static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args) | |||
1000 | static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req) | 1014 | static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req) |
1001 | { | 1015 | { |
1002 | struct rpc_auth *auth = req->rq_task->tk_auth; | 1016 | struct rpc_auth *auth = req->rq_task->tk_auth; |
1017 | uint32_t attrs[2] = { | ||
1018 | FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID, | ||
1019 | FATTR4_WORD1_MOUNTED_ON_FILEID, | ||
1020 | }; | ||
1003 | int replen; | 1021 | int replen; |
1004 | uint32_t *p; | 1022 | uint32_t *p; |
1005 | 1023 | ||
@@ -1010,13 +1028,20 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
1010 | WRITE32(readdir->count >> 1); /* We're not doing readdirplus */ | 1028 | WRITE32(readdir->count >> 1); /* We're not doing readdirplus */ |
1011 | WRITE32(readdir->count); | 1029 | WRITE32(readdir->count); |
1012 | WRITE32(2); | 1030 | WRITE32(2); |
1013 | if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID) { | 1031 | /* Switch to mounted_on_fileid if the server supports it */ |
1014 | WRITE32(0); | 1032 | if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID) |
1015 | WRITE32(FATTR4_WORD1_MOUNTED_ON_FILEID); | 1033 | attrs[0] &= ~FATTR4_WORD0_FILEID; |
1016 | } else { | 1034 | else |
1017 | WRITE32(FATTR4_WORD0_FILEID); | 1035 | attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; |
1018 | WRITE32(0); | 1036 | WRITE32(attrs[0] & readdir->bitmask[0]); |
1019 | } | 1037 | WRITE32(attrs[1] & readdir->bitmask[1]); |
1038 | dprintk("%s: cookie = %Lu, verifier = 0x%x%x, bitmap = 0x%x%x\n", | ||
1039 | __FUNCTION__, | ||
1040 | (unsigned long long)readdir->cookie, | ||
1041 | ((u32 *)readdir->verifier.data)[0], | ||
1042 | ((u32 *)readdir->verifier.data)[1], | ||
1043 | attrs[0] & readdir->bitmask[0], | ||
1044 | attrs[1] & readdir->bitmask[1]); | ||
1020 | 1045 | ||
1021 | /* set up reply kvec | 1046 | /* set up reply kvec |
1022 | * toplevel_status + taglen + rescount + OP_PUTFH + status | 1047 | * toplevel_status + taglen + rescount + OP_PUTFH + status |
@@ -1025,6 +1050,9 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
1025 | replen = (RPC_REPHDRSIZE + auth->au_rslack + 9) << 2; | 1050 | replen = (RPC_REPHDRSIZE + auth->au_rslack + 9) << 2; |
1026 | xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->pages, | 1051 | xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->pages, |
1027 | readdir->pgbase, readdir->count); | 1052 | readdir->pgbase, readdir->count); |
1053 | dprintk("%s: inlined page args = (%u, %p, %u, %u)\n", | ||
1054 | __FUNCTION__, replen, readdir->pages, | ||
1055 | readdir->pgbase, readdir->count); | ||
1028 | 1056 | ||
1029 | return 0; | 1057 | return 0; |
1030 | } | 1058 | } |
@@ -1089,6 +1117,25 @@ static int encode_renew(struct xdr_stream *xdr, const struct nfs4_client *client | |||
1089 | } | 1117 | } |
1090 | 1118 | ||
1091 | static int | 1119 | static int |
1120 | encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg) | ||
1121 | { | ||
1122 | uint32_t *p; | ||
1123 | |||
1124 | RESERVE_SPACE(4+sizeof(zero_stateid.data)); | ||
1125 | WRITE32(OP_SETATTR); | ||
1126 | WRITEMEM(zero_stateid.data, sizeof(zero_stateid.data)); | ||
1127 | RESERVE_SPACE(2*4); | ||
1128 | WRITE32(1); | ||
1129 | WRITE32(FATTR4_WORD0_ACL); | ||
1130 | if (arg->acl_len % 4) | ||
1131 | return -EINVAL; | ||
1132 | RESERVE_SPACE(4); | ||
1133 | WRITE32(arg->acl_len); | ||
1134 | xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); | ||
1135 | return 0; | ||
1136 | } | ||
1137 | |||
1138 | static int | ||
1092 | encode_savefh(struct xdr_stream *xdr) | 1139 | encode_savefh(struct xdr_stream *xdr) |
1093 | { | 1140 | { |
1094 | uint32_t *p; | 1141 | uint32_t *p; |
@@ -1632,6 +1679,34 @@ out: | |||
1632 | } | 1679 | } |
1633 | 1680 | ||
1634 | /* | 1681 | /* |
1682 | * Encode a GETACL request | ||
1683 | */ | ||
1684 | static int | ||
1685 | nfs4_xdr_enc_getacl(struct rpc_rqst *req, uint32_t *p, | ||
1686 | struct nfs_getaclargs *args) | ||
1687 | { | ||
1688 | struct xdr_stream xdr; | ||
1689 | struct rpc_auth *auth = req->rq_task->tk_auth; | ||
1690 | struct compound_hdr hdr = { | ||
1691 | .nops = 2, | ||
1692 | }; | ||
1693 | int replen, status; | ||
1694 | |||
1695 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
1696 | encode_compound_hdr(&xdr, &hdr); | ||
1697 | status = encode_putfh(&xdr, args->fh); | ||
1698 | if (status) | ||
1699 | goto out; | ||
1700 | status = encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0); | ||
1701 | /* set up reply buffer: */ | ||
1702 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_getacl_sz) << 2; | ||
1703 | xdr_inline_pages(&req->rq_rcv_buf, replen, | ||
1704 | args->acl_pages, args->acl_pgbase, args->acl_len); | ||
1705 | out: | ||
1706 | return status; | ||
1707 | } | ||
1708 | |||
1709 | /* | ||
1635 | * Encode a WRITE request | 1710 | * Encode a WRITE request |
1636 | */ | 1711 | */ |
1637 | static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args) | 1712 | static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args) |
@@ -1697,7 +1772,6 @@ static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs4_fs | |||
1697 | */ | 1772 | */ |
1698 | static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct nfs4_pathconf_arg *args) | 1773 | static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct nfs4_pathconf_arg *args) |
1699 | { | 1774 | { |
1700 | extern u32 nfs4_pathconf_bitmap[2]; | ||
1701 | struct xdr_stream xdr; | 1775 | struct xdr_stream xdr; |
1702 | struct compound_hdr hdr = { | 1776 | struct compound_hdr hdr = { |
1703 | .nops = 2, | 1777 | .nops = 2, |
@@ -1718,7 +1792,6 @@ static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct | |||
1718 | */ | 1792 | */ |
1719 | static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, const struct nfs4_statfs_arg *args) | 1793 | static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, const struct nfs4_statfs_arg *args) |
1720 | { | 1794 | { |
1721 | extern u32 nfs4_statfs_bitmap[]; | ||
1722 | struct xdr_stream xdr; | 1795 | struct xdr_stream xdr; |
1723 | struct compound_hdr hdr = { | 1796 | struct compound_hdr hdr = { |
1724 | .nops = 2, | 1797 | .nops = 2, |
@@ -3003,6 +3076,11 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
3003 | return status; | 3076 | return status; |
3004 | READ_BUF(8); | 3077 | READ_BUF(8); |
3005 | COPYMEM(readdir->verifier.data, 8); | 3078 | COPYMEM(readdir->verifier.data, 8); |
3079 | dprintk("%s: verifier = 0x%x%x\n", | ||
3080 | __FUNCTION__, | ||
3081 | ((u32 *)readdir->verifier.data)[0], | ||
3082 | ((u32 *)readdir->verifier.data)[1]); | ||
3083 | |||
3006 | 3084 | ||
3007 | hdrlen = (char *) p - (char *) iov->iov_base; | 3085 | hdrlen = (char *) p - (char *) iov->iov_base; |
3008 | recvd = rcvbuf->len - hdrlen; | 3086 | recvd = rcvbuf->len - hdrlen; |
@@ -3017,12 +3095,14 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
3017 | for (nr = 0; *p++; nr++) { | 3095 | for (nr = 0; *p++; nr++) { |
3018 | if (p + 3 > end) | 3096 | if (p + 3 > end) |
3019 | goto short_pkt; | 3097 | goto short_pkt; |
3098 | dprintk("cookie = %Lu, ", *((unsigned long long *)p)); | ||
3020 | p += 2; /* cookie */ | 3099 | p += 2; /* cookie */ |
3021 | len = ntohl(*p++); /* filename length */ | 3100 | len = ntohl(*p++); /* filename length */ |
3022 | if (len > NFS4_MAXNAMLEN) { | 3101 | if (len > NFS4_MAXNAMLEN) { |
3023 | printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len); | 3102 | printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len); |
3024 | goto err_unmap; | 3103 | goto err_unmap; |
3025 | } | 3104 | } |
3105 | dprintk("filename = %*s\n", len, (char *)p); | ||
3026 | p += XDR_QUADLEN(len); | 3106 | p += XDR_QUADLEN(len); |
3027 | if (p + 1 > end) | 3107 | if (p + 1 > end) |
3028 | goto short_pkt; | 3108 | goto short_pkt; |
@@ -3042,6 +3122,7 @@ out: | |||
3042 | kunmap_atomic(kaddr, KM_USER0); | 3122 | kunmap_atomic(kaddr, KM_USER0); |
3043 | return 0; | 3123 | return 0; |
3044 | short_pkt: | 3124 | short_pkt: |
3125 | dprintk("%s: short packet at entry %d\n", __FUNCTION__, nr); | ||
3045 | entry[0] = entry[1] = 0; | 3126 | entry[0] = entry[1] = 0; |
3046 | /* truncate listing ? */ | 3127 | /* truncate listing ? */ |
3047 | if (!nr) { | 3128 | if (!nr) { |
@@ -3127,6 +3208,47 @@ static int decode_renew(struct xdr_stream *xdr) | |||
3127 | return decode_op_hdr(xdr, OP_RENEW); | 3208 | return decode_op_hdr(xdr, OP_RENEW); |
3128 | } | 3209 | } |
3129 | 3210 | ||
3211 | static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, | ||
3212 | size_t *acl_len) | ||
3213 | { | ||
3214 | uint32_t *savep; | ||
3215 | uint32_t attrlen, | ||
3216 | bitmap[2] = {0}; | ||
3217 | struct kvec *iov = req->rq_rcv_buf.head; | ||
3218 | int status; | ||
3219 | |||
3220 | *acl_len = 0; | ||
3221 | if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) | ||
3222 | goto out; | ||
3223 | if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) | ||
3224 | goto out; | ||
3225 | if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) | ||
3226 | goto out; | ||
3227 | |||
3228 | if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U))) | ||
3229 | return -EIO; | ||
3230 | if (likely(bitmap[0] & FATTR4_WORD0_ACL)) { | ||
3231 | int hdrlen, recvd; | ||
3232 | |||
3233 | /* We ignore &savep and don't do consistency checks on | ||
3234 | * the attr length. Let userspace figure it out.... */ | ||
3235 | hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base; | ||
3236 | recvd = req->rq_rcv_buf.len - hdrlen; | ||
3237 | if (attrlen > recvd) { | ||
3238 | printk(KERN_WARNING "NFS: server cheating in getattr" | ||
3239 | " acl reply: attrlen %u > recvd %u\n", | ||
3240 | attrlen, recvd); | ||
3241 | return -EINVAL; | ||
3242 | } | ||
3243 | if (attrlen <= *acl_len) | ||
3244 | xdr_read_pages(xdr, attrlen); | ||
3245 | *acl_len = attrlen; | ||
3246 | } | ||
3247 | |||
3248 | out: | ||
3249 | return status; | ||
3250 | } | ||
3251 | |||
3130 | static int | 3252 | static int |
3131 | decode_savefh(struct xdr_stream *xdr) | 3253 | decode_savefh(struct xdr_stream *xdr) |
3132 | { | 3254 | { |
@@ -3418,6 +3540,71 @@ out: | |||
3418 | 3540 | ||
3419 | } | 3541 | } |
3420 | 3542 | ||
3543 | /* | ||
3544 | * Encode an SETACL request | ||
3545 | */ | ||
3546 | static int | ||
3547 | nfs4_xdr_enc_setacl(struct rpc_rqst *req, uint32_t *p, struct nfs_setaclargs *args) | ||
3548 | { | ||
3549 | struct xdr_stream xdr; | ||
3550 | struct compound_hdr hdr = { | ||
3551 | .nops = 2, | ||
3552 | }; | ||
3553 | int status; | ||
3554 | |||
3555 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
3556 | encode_compound_hdr(&xdr, &hdr); | ||
3557 | status = encode_putfh(&xdr, args->fh); | ||
3558 | if (status) | ||
3559 | goto out; | ||
3560 | status = encode_setacl(&xdr, args); | ||
3561 | out: | ||
3562 | return status; | ||
3563 | } | ||
3564 | /* | ||
3565 | * Decode SETACL response | ||
3566 | */ | ||
3567 | static int | ||
3568 | nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, uint32_t *p, void *res) | ||
3569 | { | ||
3570 | struct xdr_stream xdr; | ||
3571 | struct compound_hdr hdr; | ||
3572 | int status; | ||
3573 | |||
3574 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
3575 | status = decode_compound_hdr(&xdr, &hdr); | ||
3576 | if (status) | ||
3577 | goto out; | ||
3578 | status = decode_putfh(&xdr); | ||
3579 | if (status) | ||
3580 | goto out; | ||
3581 | status = decode_setattr(&xdr, res); | ||
3582 | out: | ||
3583 | return status; | ||
3584 | } | ||
3585 | |||
3586 | /* | ||
3587 | * Decode GETACL response | ||
3588 | */ | ||
3589 | static int | ||
3590 | nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, uint32_t *p, size_t *acl_len) | ||
3591 | { | ||
3592 | struct xdr_stream xdr; | ||
3593 | struct compound_hdr hdr; | ||
3594 | int status; | ||
3595 | |||
3596 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
3597 | status = decode_compound_hdr(&xdr, &hdr); | ||
3598 | if (status) | ||
3599 | goto out; | ||
3600 | status = decode_putfh(&xdr); | ||
3601 | if (status) | ||
3602 | goto out; | ||
3603 | status = decode_getacl(&xdr, rqstp, acl_len); | ||
3604 | |||
3605 | out: | ||
3606 | return status; | ||
3607 | } | ||
3421 | 3608 | ||
3422 | /* | 3609 | /* |
3423 | * Decode CLOSE response | 3610 | * Decode CLOSE response |
@@ -3895,6 +4082,12 @@ uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus) | |||
3895 | } | 4082 | } |
3896 | len = XDR_QUADLEN(ntohl(*p++)); /* attribute buffer length */ | 4083 | len = XDR_QUADLEN(ntohl(*p++)); /* attribute buffer length */ |
3897 | if (len > 0) { | 4084 | if (len > 0) { |
4085 | if (bitmap[0] & FATTR4_WORD0_RDATTR_ERROR) { | ||
4086 | bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR; | ||
4087 | /* Ignore the return value of rdattr_error for now */ | ||
4088 | p++; | ||
4089 | len--; | ||
4090 | } | ||
3898 | if (bitmap[0] == 0 && bitmap[1] == FATTR4_WORD1_MOUNTED_ON_FILEID) | 4091 | if (bitmap[0] == 0 && bitmap[1] == FATTR4_WORD1_MOUNTED_ON_FILEID) |
3899 | xdr_decode_hyper(p, &entry->ino); | 4092 | xdr_decode_hyper(p, &entry->ino); |
3900 | else if (bitmap[0] == FATTR4_WORD0_FILEID) | 4093 | else if (bitmap[0] == FATTR4_WORD0_FILEID) |
@@ -3934,6 +4127,8 @@ static struct { | |||
3934 | { NFS4ERR_DQUOT, EDQUOT }, | 4127 | { NFS4ERR_DQUOT, EDQUOT }, |
3935 | { NFS4ERR_STALE, ESTALE }, | 4128 | { NFS4ERR_STALE, ESTALE }, |
3936 | { NFS4ERR_BADHANDLE, EBADHANDLE }, | 4129 | { NFS4ERR_BADHANDLE, EBADHANDLE }, |
4130 | { NFS4ERR_BADOWNER, EINVAL }, | ||
4131 | { NFS4ERR_BADNAME, EINVAL }, | ||
3937 | { NFS4ERR_BAD_COOKIE, EBADCOOKIE }, | 4132 | { NFS4ERR_BAD_COOKIE, EBADCOOKIE }, |
3938 | { NFS4ERR_NOTSUPP, ENOTSUPP }, | 4133 | { NFS4ERR_NOTSUPP, ENOTSUPP }, |
3939 | { NFS4ERR_TOOSMALL, ETOOSMALL }, | 4134 | { NFS4ERR_TOOSMALL, ETOOSMALL }, |
@@ -4019,6 +4214,8 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
4019 | PROC(READDIR, enc_readdir, dec_readdir), | 4214 | PROC(READDIR, enc_readdir, dec_readdir), |
4020 | PROC(SERVER_CAPS, enc_server_caps, dec_server_caps), | 4215 | PROC(SERVER_CAPS, enc_server_caps, dec_server_caps), |
4021 | PROC(DELEGRETURN, enc_delegreturn, dec_delegreturn), | 4216 | PROC(DELEGRETURN, enc_delegreturn, dec_delegreturn), |
4217 | PROC(GETACL, enc_getacl, dec_getacl), | ||
4218 | PROC(SETACL, enc_setacl, dec_setacl), | ||
4022 | }; | 4219 | }; |
4023 | 4220 | ||
4024 | struct rpc_version nfs_version4 = { | 4221 | struct rpc_version nfs_version4 = { |
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index fd5bc596fe8a..1b272a135a31 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c | |||
@@ -124,6 +124,7 @@ enum { | |||
124 | Opt_soft, Opt_hard, Opt_intr, | 124 | Opt_soft, Opt_hard, Opt_intr, |
125 | Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac, | 125 | Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac, |
126 | Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp, | 126 | Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp, |
127 | Opt_acl, Opt_noacl, | ||
127 | /* Error token */ | 128 | /* Error token */ |
128 | Opt_err | 129 | Opt_err |
129 | }; | 130 | }; |
@@ -158,6 +159,8 @@ static match_table_t __initdata tokens = { | |||
158 | {Opt_udp, "udp"}, | 159 | {Opt_udp, "udp"}, |
159 | {Opt_tcp, "proto=tcp"}, | 160 | {Opt_tcp, "proto=tcp"}, |
160 | {Opt_tcp, "tcp"}, | 161 | {Opt_tcp, "tcp"}, |
162 | {Opt_acl, "acl"}, | ||
163 | {Opt_noacl, "noacl"}, | ||
161 | {Opt_err, NULL} | 164 | {Opt_err, NULL} |
162 | 165 | ||
163 | }; | 166 | }; |
@@ -266,6 +269,12 @@ static int __init root_nfs_parse(char *name, char *buf) | |||
266 | case Opt_tcp: | 269 | case Opt_tcp: |
267 | nfs_data.flags |= NFS_MOUNT_TCP; | 270 | nfs_data.flags |= NFS_MOUNT_TCP; |
268 | break; | 271 | break; |
272 | case Opt_acl: | ||
273 | nfs_data.flags &= ~NFS_MOUNT_NOACL; | ||
274 | break; | ||
275 | case Opt_noacl: | ||
276 | nfs_data.flags |= NFS_MOUNT_NOACL; | ||
277 | break; | ||
269 | default : | 278 | default : |
270 | return 0; | 279 | return 0; |
271 | } | 280 | } |
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 4f1ba723848d..d53857b148e2 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -107,11 +107,38 @@ void nfs_unlock_request(struct nfs_page *req) | |||
107 | smp_mb__before_clear_bit(); | 107 | smp_mb__before_clear_bit(); |
108 | clear_bit(PG_BUSY, &req->wb_flags); | 108 | clear_bit(PG_BUSY, &req->wb_flags); |
109 | smp_mb__after_clear_bit(); | 109 | smp_mb__after_clear_bit(); |
110 | wake_up_all(&req->wb_context->waitq); | 110 | wake_up_bit(&req->wb_flags, PG_BUSY); |
111 | nfs_release_request(req); | 111 | nfs_release_request(req); |
112 | } | 112 | } |
113 | 113 | ||
114 | /** | 114 | /** |
115 | * nfs_set_page_writeback_locked - Lock a request for writeback | ||
116 | * @req: | ||
117 | */ | ||
118 | int nfs_set_page_writeback_locked(struct nfs_page *req) | ||
119 | { | ||
120 | struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); | ||
121 | |||
122 | if (!nfs_lock_request(req)) | ||
123 | return 0; | ||
124 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); | ||
125 | return 1; | ||
126 | } | ||
127 | |||
128 | /** | ||
129 | * nfs_clear_page_writeback - Unlock request and wake up sleepers | ||
130 | */ | ||
131 | void nfs_clear_page_writeback(struct nfs_page *req) | ||
132 | { | ||
133 | struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); | ||
134 | |||
135 | spin_lock(&nfsi->req_lock); | ||
136 | radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); | ||
137 | spin_unlock(&nfsi->req_lock); | ||
138 | nfs_unlock_request(req); | ||
139 | } | ||
140 | |||
141 | /** | ||
115 | * nfs_clear_request - Free up all resources allocated to the request | 142 | * nfs_clear_request - Free up all resources allocated to the request |
116 | * @req: | 143 | * @req: |
117 | * | 144 | * |
@@ -150,34 +177,15 @@ nfs_release_request(struct nfs_page *req) | |||
150 | nfs_page_free(req); | 177 | nfs_page_free(req); |
151 | } | 178 | } |
152 | 179 | ||
153 | /** | 180 | static int nfs_wait_bit_interruptible(void *word) |
154 | * nfs_list_add_request - Insert a request into a sorted list | ||
155 | * @req: request | ||
156 | * @head: head of list into which to insert the request. | ||
157 | * | ||
158 | * Note that the wb_list is sorted by page index in order to facilitate | ||
159 | * coalescing of requests. | ||
160 | * We use an insertion sort that is optimized for the case of appended | ||
161 | * writes. | ||
162 | */ | ||
163 | void | ||
164 | nfs_list_add_request(struct nfs_page *req, struct list_head *head) | ||
165 | { | 181 | { |
166 | struct list_head *pos; | 182 | int ret = 0; |
167 | 183 | ||
168 | #ifdef NFS_PARANOIA | 184 | if (signal_pending(current)) |
169 | if (!list_empty(&req->wb_list)) { | 185 | ret = -ERESTARTSYS; |
170 | printk(KERN_ERR "NFS: Add to list failed!\n"); | 186 | else |
171 | BUG(); | 187 | schedule(); |
172 | } | 188 | return ret; |
173 | #endif | ||
174 | list_for_each_prev(pos, head) { | ||
175 | struct nfs_page *p = nfs_list_entry(pos); | ||
176 | if (p->wb_index < req->wb_index) | ||
177 | break; | ||
178 | } | ||
179 | list_add(&req->wb_list, pos); | ||
180 | req->wb_list_head = head; | ||
181 | } | 189 | } |
182 | 190 | ||
183 | /** | 191 | /** |
@@ -190,12 +198,22 @@ nfs_list_add_request(struct nfs_page *req, struct list_head *head) | |||
190 | int | 198 | int |
191 | nfs_wait_on_request(struct nfs_page *req) | 199 | nfs_wait_on_request(struct nfs_page *req) |
192 | { | 200 | { |
193 | struct inode *inode = req->wb_context->dentry->d_inode; | 201 | struct rpc_clnt *clnt = NFS_CLIENT(req->wb_context->dentry->d_inode); |
194 | struct rpc_clnt *clnt = NFS_CLIENT(inode); | 202 | sigset_t oldmask; |
195 | 203 | int ret = 0; | |
196 | if (!NFS_WBACK_BUSY(req)) | 204 | |
197 | return 0; | 205 | if (!test_bit(PG_BUSY, &req->wb_flags)) |
198 | return nfs_wait_event(clnt, req->wb_context->waitq, !NFS_WBACK_BUSY(req)); | 206 | goto out; |
207 | /* | ||
208 | * Note: the call to rpc_clnt_sigmask() suffices to ensure that we | ||
209 | * are not interrupted if intr flag is not set | ||
210 | */ | ||
211 | rpc_clnt_sigmask(clnt, &oldmask); | ||
212 | ret = out_of_line_wait_on_bit(&req->wb_flags, PG_BUSY, | ||
213 | nfs_wait_bit_interruptible, TASK_INTERRUPTIBLE); | ||
214 | rpc_clnt_sigunmask(clnt, &oldmask); | ||
215 | out: | ||
216 | return ret; | ||
199 | } | 217 | } |
200 | 218 | ||
201 | /** | 219 | /** |
@@ -243,6 +261,62 @@ nfs_coalesce_requests(struct list_head *head, struct list_head *dst, | |||
243 | return npages; | 261 | return npages; |
244 | } | 262 | } |
245 | 263 | ||
264 | #define NFS_SCAN_MAXENTRIES 16 | ||
265 | /** | ||
266 | * nfs_scan_lock_dirty - Scan the radix tree for dirty requests | ||
267 | * @nfsi: NFS inode | ||
268 | * @dst: Destination list | ||
269 | * @idx_start: lower bound of page->index to scan | ||
270 | * @npages: idx_start + npages sets the upper bound to scan. | ||
271 | * | ||
272 | * Moves elements from one of the inode request lists. | ||
273 | * If the number of requests is set to 0, the entire address_space | ||
274 | * starting at index idx_start, is scanned. | ||
275 | * The requests are *not* checked to ensure that they form a contiguous set. | ||
276 | * You must be holding the inode's req_lock when calling this function | ||
277 | */ | ||
278 | int | ||
279 | nfs_scan_lock_dirty(struct nfs_inode *nfsi, struct list_head *dst, | ||
280 | unsigned long idx_start, unsigned int npages) | ||
281 | { | ||
282 | struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES]; | ||
283 | struct nfs_page *req; | ||
284 | unsigned long idx_end; | ||
285 | int found, i; | ||
286 | int res; | ||
287 | |||
288 | res = 0; | ||
289 | if (npages == 0) | ||
290 | idx_end = ~0; | ||
291 | else | ||
292 | idx_end = idx_start + npages - 1; | ||
293 | |||
294 | for (;;) { | ||
295 | found = radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, | ||
296 | (void **)&pgvec[0], idx_start, NFS_SCAN_MAXENTRIES, | ||
297 | NFS_PAGE_TAG_DIRTY); | ||
298 | if (found <= 0) | ||
299 | break; | ||
300 | for (i = 0; i < found; i++) { | ||
301 | req = pgvec[i]; | ||
302 | if (req->wb_index > idx_end) | ||
303 | goto out; | ||
304 | |||
305 | idx_start = req->wb_index + 1; | ||
306 | |||
307 | if (nfs_set_page_writeback_locked(req)) { | ||
308 | radix_tree_tag_clear(&nfsi->nfs_page_tree, | ||
309 | req->wb_index, NFS_PAGE_TAG_DIRTY); | ||
310 | nfs_list_remove_request(req); | ||
311 | nfs_list_add_request(req, dst); | ||
312 | res++; | ||
313 | } | ||
314 | } | ||
315 | } | ||
316 | out: | ||
317 | return res; | ||
318 | } | ||
319 | |||
246 | /** | 320 | /** |
247 | * nfs_scan_list - Scan a list for matching requests | 321 | * nfs_scan_list - Scan a list for matching requests |
248 | * @head: One of the NFS inode request lists | 322 | * @head: One of the NFS inode request lists |
@@ -280,7 +354,7 @@ nfs_scan_list(struct list_head *head, struct list_head *dst, | |||
280 | if (req->wb_index > idx_end) | 354 | if (req->wb_index > idx_end) |
281 | break; | 355 | break; |
282 | 356 | ||
283 | if (!nfs_lock_request(req)) | 357 | if (!nfs_set_page_writeback_locked(req)) |
284 | continue; | 358 | continue; |
285 | nfs_list_remove_request(req); | 359 | nfs_list_remove_request(req); |
286 | nfs_list_add_request(req, dst); | 360 | nfs_list_add_request(req, dst); |
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index d31b4d6e5a5e..cedf636bcf3c 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
@@ -622,6 +622,7 @@ struct nfs_rpc_ops nfs_v2_clientops = { | |||
622 | .version = 2, /* protocol version */ | 622 | .version = 2, /* protocol version */ |
623 | .dentry_ops = &nfs_dentry_operations, | 623 | .dentry_ops = &nfs_dentry_operations, |
624 | .dir_inode_ops = &nfs_dir_inode_operations, | 624 | .dir_inode_ops = &nfs_dir_inode_operations, |
625 | .file_inode_ops = &nfs_file_inode_operations, | ||
625 | .getroot = nfs_proc_get_root, | 626 | .getroot = nfs_proc_get_root, |
626 | .getattr = nfs_proc_getattr, | 627 | .getattr = nfs_proc_getattr, |
627 | .setattr = nfs_proc_setattr, | 628 | .setattr = nfs_proc_setattr, |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index a0042fb58634..6f866b8aa2d5 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -173,7 +173,6 @@ static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, | |||
173 | if (len < PAGE_CACHE_SIZE) | 173 | if (len < PAGE_CACHE_SIZE) |
174 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); | 174 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); |
175 | 175 | ||
176 | nfs_lock_request(new); | ||
177 | nfs_list_add_request(new, &one_request); | 176 | nfs_list_add_request(new, &one_request); |
178 | nfs_pagein_one(&one_request, inode); | 177 | nfs_pagein_one(&one_request, inode); |
179 | return 0; | 178 | return 0; |
@@ -185,7 +184,6 @@ static void nfs_readpage_release(struct nfs_page *req) | |||
185 | 184 | ||
186 | nfs_clear_request(req); | 185 | nfs_clear_request(req); |
187 | nfs_release_request(req); | 186 | nfs_release_request(req); |
188 | nfs_unlock_request(req); | ||
189 | 187 | ||
190 | dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", | 188 | dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", |
191 | req->wb_context->dentry->d_inode->i_sb->s_id, | 189 | req->wb_context->dentry->d_inode->i_sb->s_id, |
@@ -553,7 +551,6 @@ readpage_async_filler(void *data, struct page *page) | |||
553 | } | 551 | } |
554 | if (len < PAGE_CACHE_SIZE) | 552 | if (len < PAGE_CACHE_SIZE) |
555 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); | 553 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); |
556 | nfs_lock_request(new); | ||
557 | nfs_list_add_request(new, desc->head); | 554 | nfs_list_add_request(new, desc->head); |
558 | return 0; | 555 | return 0; |
559 | } | 556 | } |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 6f7a4af3bc46..5130eda231d7 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -220,7 +220,7 @@ static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode, | |||
220 | ClearPageError(page); | 220 | ClearPageError(page); |
221 | 221 | ||
222 | io_error: | 222 | io_error: |
223 | nfs_end_data_update_defer(inode); | 223 | nfs_end_data_update(inode); |
224 | nfs_writedata_free(wdata); | 224 | nfs_writedata_free(wdata); |
225 | return written ? written : result; | 225 | return written ? written : result; |
226 | } | 226 | } |
@@ -352,7 +352,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) | |||
352 | if (err < 0) | 352 | if (err < 0) |
353 | goto out; | 353 | goto out; |
354 | } | 354 | } |
355 | err = nfs_commit_inode(inode, 0, 0, wb_priority(wbc)); | 355 | err = nfs_commit_inode(inode, wb_priority(wbc)); |
356 | if (err > 0) { | 356 | if (err > 0) { |
357 | wbc->nr_to_write -= err; | 357 | wbc->nr_to_write -= err; |
358 | err = 0; | 358 | err = 0; |
@@ -401,7 +401,7 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |||
401 | nfsi->npages--; | 401 | nfsi->npages--; |
402 | if (!nfsi->npages) { | 402 | if (!nfsi->npages) { |
403 | spin_unlock(&nfsi->req_lock); | 403 | spin_unlock(&nfsi->req_lock); |
404 | nfs_end_data_update_defer(inode); | 404 | nfs_end_data_update(inode); |
405 | iput(inode); | 405 | iput(inode); |
406 | } else | 406 | } else |
407 | spin_unlock(&nfsi->req_lock); | 407 | spin_unlock(&nfsi->req_lock); |
@@ -446,6 +446,8 @@ nfs_mark_request_dirty(struct nfs_page *req) | |||
446 | struct nfs_inode *nfsi = NFS_I(inode); | 446 | struct nfs_inode *nfsi = NFS_I(inode); |
447 | 447 | ||
448 | spin_lock(&nfsi->req_lock); | 448 | spin_lock(&nfsi->req_lock); |
449 | radix_tree_tag_set(&nfsi->nfs_page_tree, | ||
450 | req->wb_index, NFS_PAGE_TAG_DIRTY); | ||
449 | nfs_list_add_request(req, &nfsi->dirty); | 451 | nfs_list_add_request(req, &nfsi->dirty); |
450 | nfsi->ndirty++; | 452 | nfsi->ndirty++; |
451 | spin_unlock(&nfsi->req_lock); | 453 | spin_unlock(&nfsi->req_lock); |
@@ -503,13 +505,12 @@ nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, unsigned int | |||
503 | 505 | ||
504 | spin_lock(&nfsi->req_lock); | 506 | spin_lock(&nfsi->req_lock); |
505 | next = idx_start; | 507 | next = idx_start; |
506 | while (radix_tree_gang_lookup(&nfsi->nfs_page_tree, (void **)&req, next, 1)) { | 508 | while (radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, (void **)&req, next, 1, NFS_PAGE_TAG_WRITEBACK)) { |
507 | if (req->wb_index > idx_end) | 509 | if (req->wb_index > idx_end) |
508 | break; | 510 | break; |
509 | 511 | ||
510 | next = req->wb_index + 1; | 512 | next = req->wb_index + 1; |
511 | if (!NFS_WBACK_BUSY(req)) | 513 | BUG_ON(!NFS_WBACK_BUSY(req)); |
512 | continue; | ||
513 | 514 | ||
514 | atomic_inc(&req->wb_count); | 515 | atomic_inc(&req->wb_count); |
515 | spin_unlock(&nfsi->req_lock); | 516 | spin_unlock(&nfsi->req_lock); |
@@ -538,12 +539,15 @@ static int | |||
538 | nfs_scan_dirty(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) | 539 | nfs_scan_dirty(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) |
539 | { | 540 | { |
540 | struct nfs_inode *nfsi = NFS_I(inode); | 541 | struct nfs_inode *nfsi = NFS_I(inode); |
541 | int res; | 542 | int res = 0; |
542 | res = nfs_scan_list(&nfsi->dirty, dst, idx_start, npages); | 543 | |
543 | nfsi->ndirty -= res; | 544 | if (nfsi->ndirty != 0) { |
544 | sub_page_state(nr_dirty,res); | 545 | res = nfs_scan_lock_dirty(nfsi, dst, idx_start, npages); |
545 | if ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty)) | 546 | nfsi->ndirty -= res; |
546 | printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n"); | 547 | sub_page_state(nr_dirty,res); |
548 | if ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty)) | ||
549 | printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n"); | ||
550 | } | ||
547 | return res; | 551 | return res; |
548 | } | 552 | } |
549 | 553 | ||
@@ -562,11 +566,14 @@ static int | |||
562 | nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) | 566 | nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) |
563 | { | 567 | { |
564 | struct nfs_inode *nfsi = NFS_I(inode); | 568 | struct nfs_inode *nfsi = NFS_I(inode); |
565 | int res; | 569 | int res = 0; |
566 | res = nfs_scan_list(&nfsi->commit, dst, idx_start, npages); | 570 | |
567 | nfsi->ncommit -= res; | 571 | if (nfsi->ncommit != 0) { |
568 | if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit)) | 572 | res = nfs_scan_list(&nfsi->commit, dst, idx_start, npages); |
569 | printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n"); | 573 | nfsi->ncommit -= res; |
574 | if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit)) | ||
575 | printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n"); | ||
576 | } | ||
570 | return res; | 577 | return res; |
571 | } | 578 | } |
572 | #endif | 579 | #endif |
@@ -750,7 +757,7 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
750 | * is entirely in cache, it may be more efficient to avoid | 757 | * is entirely in cache, it may be more efficient to avoid |
751 | * fragmenting write requests. | 758 | * fragmenting write requests. |
752 | */ | 759 | */ |
753 | if (PageUptodate(page) && inode->i_flock == NULL) { | 760 | if (PageUptodate(page) && inode->i_flock == NULL && !(file->f_mode & O_SYNC)) { |
754 | loff_t end_offs = i_size_read(inode) - 1; | 761 | loff_t end_offs = i_size_read(inode) - 1; |
755 | unsigned long end_index = end_offs >> PAGE_CACHE_SHIFT; | 762 | unsigned long end_index = end_offs >> PAGE_CACHE_SHIFT; |
756 | 763 | ||
@@ -821,7 +828,7 @@ out: | |||
821 | #else | 828 | #else |
822 | nfs_inode_remove_request(req); | 829 | nfs_inode_remove_request(req); |
823 | #endif | 830 | #endif |
824 | nfs_unlock_request(req); | 831 | nfs_clear_page_writeback(req); |
825 | } | 832 | } |
826 | 833 | ||
827 | static inline int flush_task_priority(int how) | 834 | static inline int flush_task_priority(int how) |
@@ -952,7 +959,7 @@ out_bad: | |||
952 | nfs_writedata_free(data); | 959 | nfs_writedata_free(data); |
953 | } | 960 | } |
954 | nfs_mark_request_dirty(req); | 961 | nfs_mark_request_dirty(req); |
955 | nfs_unlock_request(req); | 962 | nfs_clear_page_writeback(req); |
956 | return -ENOMEM; | 963 | return -ENOMEM; |
957 | } | 964 | } |
958 | 965 | ||
@@ -1002,7 +1009,7 @@ static int nfs_flush_one(struct list_head *head, struct inode *inode, int how) | |||
1002 | struct nfs_page *req = nfs_list_entry(head->next); | 1009 | struct nfs_page *req = nfs_list_entry(head->next); |
1003 | nfs_list_remove_request(req); | 1010 | nfs_list_remove_request(req); |
1004 | nfs_mark_request_dirty(req); | 1011 | nfs_mark_request_dirty(req); |
1005 | nfs_unlock_request(req); | 1012 | nfs_clear_page_writeback(req); |
1006 | } | 1013 | } |
1007 | return -ENOMEM; | 1014 | return -ENOMEM; |
1008 | } | 1015 | } |
@@ -1029,7 +1036,7 @@ nfs_flush_list(struct list_head *head, int wpages, int how) | |||
1029 | req = nfs_list_entry(head->next); | 1036 | req = nfs_list_entry(head->next); |
1030 | nfs_list_remove_request(req); | 1037 | nfs_list_remove_request(req); |
1031 | nfs_mark_request_dirty(req); | 1038 | nfs_mark_request_dirty(req); |
1032 | nfs_unlock_request(req); | 1039 | nfs_clear_page_writeback(req); |
1033 | } | 1040 | } |
1034 | return error; | 1041 | return error; |
1035 | } | 1042 | } |
@@ -1121,7 +1128,7 @@ static void nfs_writeback_done_full(struct nfs_write_data *data, int status) | |||
1121 | nfs_inode_remove_request(req); | 1128 | nfs_inode_remove_request(req); |
1122 | #endif | 1129 | #endif |
1123 | next: | 1130 | next: |
1124 | nfs_unlock_request(req); | 1131 | nfs_clear_page_writeback(req); |
1125 | } | 1132 | } |
1126 | } | 1133 | } |
1127 | 1134 | ||
@@ -1210,36 +1217,24 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1210 | struct nfs_write_data *data, int how) | 1217 | struct nfs_write_data *data, int how) |
1211 | { | 1218 | { |
1212 | struct rpc_task *task = &data->task; | 1219 | struct rpc_task *task = &data->task; |
1213 | struct nfs_page *first, *last; | 1220 | struct nfs_page *first; |
1214 | struct inode *inode; | 1221 | struct inode *inode; |
1215 | loff_t start, end, len; | ||
1216 | 1222 | ||
1217 | /* Set up the RPC argument and reply structs | 1223 | /* Set up the RPC argument and reply structs |
1218 | * NB: take care not to mess about with data->commit et al. */ | 1224 | * NB: take care not to mess about with data->commit et al. */ |
1219 | 1225 | ||
1220 | list_splice_init(head, &data->pages); | 1226 | list_splice_init(head, &data->pages); |
1221 | first = nfs_list_entry(data->pages.next); | 1227 | first = nfs_list_entry(data->pages.next); |
1222 | last = nfs_list_entry(data->pages.prev); | ||
1223 | inode = first->wb_context->dentry->d_inode; | 1228 | inode = first->wb_context->dentry->d_inode; |
1224 | 1229 | ||
1225 | /* | ||
1226 | * Determine the offset range of requests in the COMMIT call. | ||
1227 | * We rely on the fact that data->pages is an ordered list... | ||
1228 | */ | ||
1229 | start = req_offset(first); | ||
1230 | end = req_offset(last) + last->wb_bytes; | ||
1231 | len = end - start; | ||
1232 | /* If 'len' is not a 32-bit quantity, pass '0' in the COMMIT call */ | ||
1233 | if (end >= i_size_read(inode) || len < 0 || len > (~((u32)0) >> 1)) | ||
1234 | len = 0; | ||
1235 | |||
1236 | data->inode = inode; | 1230 | data->inode = inode; |
1237 | data->cred = first->wb_context->cred; | 1231 | data->cred = first->wb_context->cred; |
1238 | 1232 | ||
1239 | data->args.fh = NFS_FH(data->inode); | 1233 | data->args.fh = NFS_FH(data->inode); |
1240 | data->args.offset = start; | 1234 | /* Note: we always request a commit of the entire inode */ |
1241 | data->args.count = len; | 1235 | data->args.offset = 0; |
1242 | data->res.count = len; | 1236 | data->args.count = 0; |
1237 | data->res.count = 0; | ||
1243 | data->res.fattr = &data->fattr; | 1238 | data->res.fattr = &data->fattr; |
1244 | data->res.verf = &data->verf; | 1239 | data->res.verf = &data->verf; |
1245 | 1240 | ||
@@ -1278,7 +1273,7 @@ nfs_commit_list(struct list_head *head, int how) | |||
1278 | req = nfs_list_entry(head->next); | 1273 | req = nfs_list_entry(head->next); |
1279 | nfs_list_remove_request(req); | 1274 | nfs_list_remove_request(req); |
1280 | nfs_mark_request_commit(req); | 1275 | nfs_mark_request_commit(req); |
1281 | nfs_unlock_request(req); | 1276 | nfs_clear_page_writeback(req); |
1282 | } | 1277 | } |
1283 | return -ENOMEM; | 1278 | return -ENOMEM; |
1284 | } | 1279 | } |
@@ -1324,7 +1319,7 @@ nfs_commit_done(struct rpc_task *task) | |||
1324 | dprintk(" mismatch\n"); | 1319 | dprintk(" mismatch\n"); |
1325 | nfs_mark_request_dirty(req); | 1320 | nfs_mark_request_dirty(req); |
1326 | next: | 1321 | next: |
1327 | nfs_unlock_request(req); | 1322 | nfs_clear_page_writeback(req); |
1328 | res++; | 1323 | res++; |
1329 | } | 1324 | } |
1330 | sub_page_state(nr_unstable,res); | 1325 | sub_page_state(nr_unstable,res); |
@@ -1342,16 +1337,23 @@ static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, | |||
1342 | spin_lock(&nfsi->req_lock); | 1337 | spin_lock(&nfsi->req_lock); |
1343 | res = nfs_scan_dirty(inode, &head, idx_start, npages); | 1338 | res = nfs_scan_dirty(inode, &head, idx_start, npages); |
1344 | spin_unlock(&nfsi->req_lock); | 1339 | spin_unlock(&nfsi->req_lock); |
1345 | if (res) | 1340 | if (res) { |
1346 | error = nfs_flush_list(&head, NFS_SERVER(inode)->wpages, how); | 1341 | struct nfs_server *server = NFS_SERVER(inode); |
1342 | |||
1343 | /* For single writes, FLUSH_STABLE is more efficient */ | ||
1344 | if (res == nfsi->npages && nfsi->npages <= server->wpages) { | ||
1345 | if (res > 1 || nfs_list_entry(head.next)->wb_bytes <= server->wsize) | ||
1346 | how |= FLUSH_STABLE; | ||
1347 | } | ||
1348 | error = nfs_flush_list(&head, server->wpages, how); | ||
1349 | } | ||
1347 | if (error < 0) | 1350 | if (error < 0) |
1348 | return error; | 1351 | return error; |
1349 | return res; | 1352 | return res; |
1350 | } | 1353 | } |
1351 | 1354 | ||
1352 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1355 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
1353 | int nfs_commit_inode(struct inode *inode, unsigned long idx_start, | 1356 | int nfs_commit_inode(struct inode *inode, int how) |
1354 | unsigned int npages, int how) | ||
1355 | { | 1357 | { |
1356 | struct nfs_inode *nfsi = NFS_I(inode); | 1358 | struct nfs_inode *nfsi = NFS_I(inode); |
1357 | LIST_HEAD(head); | 1359 | LIST_HEAD(head); |
@@ -1359,15 +1361,13 @@ int nfs_commit_inode(struct inode *inode, unsigned long idx_start, | |||
1359 | error = 0; | 1361 | error = 0; |
1360 | 1362 | ||
1361 | spin_lock(&nfsi->req_lock); | 1363 | spin_lock(&nfsi->req_lock); |
1362 | res = nfs_scan_commit(inode, &head, idx_start, npages); | 1364 | res = nfs_scan_commit(inode, &head, 0, 0); |
1365 | spin_unlock(&nfsi->req_lock); | ||
1363 | if (res) { | 1366 | if (res) { |
1364 | res += nfs_scan_commit(inode, &head, 0, 0); | ||
1365 | spin_unlock(&nfsi->req_lock); | ||
1366 | error = nfs_commit_list(&head, how); | 1367 | error = nfs_commit_list(&head, how); |
1367 | } else | 1368 | if (error < 0) |
1368 | spin_unlock(&nfsi->req_lock); | 1369 | return error; |
1369 | if (error < 0) | 1370 | } |
1370 | return error; | ||
1371 | return res; | 1371 | return res; |
1372 | } | 1372 | } |
1373 | #endif | 1373 | #endif |
@@ -1389,7 +1389,7 @@ int nfs_sync_inode(struct inode *inode, unsigned long idx_start, | |||
1389 | error = nfs_flush_inode(inode, idx_start, npages, how); | 1389 | error = nfs_flush_inode(inode, idx_start, npages, how); |
1390 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1390 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
1391 | if (error == 0) | 1391 | if (error == 0) |
1392 | error = nfs_commit_inode(inode, idx_start, npages, how); | 1392 | error = nfs_commit_inode(inode, how); |
1393 | #endif | 1393 | #endif |
1394 | } while (error > 0); | 1394 | } while (error > 0); |
1395 | return error; | 1395 | return error; |