diff options
Diffstat (limited to 'fs/nfs/dir.c')
-rw-r--r-- | fs/nfs/dir.c | 92 |
1 files changed, 49 insertions, 43 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index d33da530097a..2c3eb33b904d 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -33,8 +33,8 @@ | |||
33 | #include <linux/namei.h> | 33 | #include <linux/namei.h> |
34 | #include <linux/mount.h> | 34 | #include <linux/mount.h> |
35 | #include <linux/sched.h> | 35 | #include <linux/sched.h> |
36 | #include <linux/vmalloc.h> | ||
37 | #include <linux/kmemleak.h> | 36 | #include <linux/kmemleak.h> |
37 | #include <linux/xattr.h> | ||
38 | 38 | ||
39 | #include "delegation.h" | 39 | #include "delegation.h" |
40 | #include "iostat.h" | 40 | #include "iostat.h" |
@@ -125,9 +125,10 @@ const struct inode_operations nfs4_dir_inode_operations = { | |||
125 | .permission = nfs_permission, | 125 | .permission = nfs_permission, |
126 | .getattr = nfs_getattr, | 126 | .getattr = nfs_getattr, |
127 | .setattr = nfs_setattr, | 127 | .setattr = nfs_setattr, |
128 | .getxattr = nfs4_getxattr, | 128 | .getxattr = generic_getxattr, |
129 | .setxattr = nfs4_setxattr, | 129 | .setxattr = generic_setxattr, |
130 | .listxattr = nfs4_listxattr, | 130 | .listxattr = generic_listxattr, |
131 | .removexattr = generic_removexattr, | ||
131 | }; | 132 | }; |
132 | 133 | ||
133 | #endif /* CONFIG_NFS_V4 */ | 134 | #endif /* CONFIG_NFS_V4 */ |
@@ -172,7 +173,7 @@ struct nfs_cache_array { | |||
172 | struct nfs_cache_array_entry array[0]; | 173 | struct nfs_cache_array_entry array[0]; |
173 | }; | 174 | }; |
174 | 175 | ||
175 | typedef __be32 * (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int); | 176 | typedef int (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, int); |
176 | typedef struct { | 177 | typedef struct { |
177 | struct file *file; | 178 | struct file *file; |
178 | struct page *page; | 179 | struct page *page; |
@@ -378,14 +379,14 @@ error: | |||
378 | return error; | 379 | return error; |
379 | } | 380 | } |
380 | 381 | ||
381 | /* Fill in an entry based on the xdr code stored in desc->page */ | 382 | static int xdr_decode(nfs_readdir_descriptor_t *desc, |
382 | static | 383 | struct nfs_entry *entry, struct xdr_stream *xdr) |
383 | int xdr_decode(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, struct xdr_stream *stream) | ||
384 | { | 384 | { |
385 | __be32 *p = desc->decode(stream, entry, NFS_SERVER(desc->file->f_path.dentry->d_inode), desc->plus); | 385 | int error; |
386 | if (IS_ERR(p)) | ||
387 | return PTR_ERR(p); | ||
388 | 386 | ||
387 | error = desc->decode(xdr, entry, desc->plus); | ||
388 | if (error) | ||
389 | return error; | ||
389 | entry->fattr->time_start = desc->timestamp; | 390 | entry->fattr->time_start = desc->timestamp; |
390 | entry->fattr->gencount = desc->gencount; | 391 | entry->fattr->gencount = desc->gencount; |
391 | return 0; | 392 | return 0; |
@@ -438,7 +439,6 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) | |||
438 | if (dentry == NULL) | 439 | if (dentry == NULL) |
439 | return; | 440 | return; |
440 | 441 | ||
441 | d_set_d_op(dentry, NFS_PROTO(dir)->dentry_ops); | ||
442 | inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr); | 442 | inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr); |
443 | if (IS_ERR(inode)) | 443 | if (IS_ERR(inode)) |
444 | goto out; | 444 | goto out; |
@@ -459,25 +459,26 @@ out: | |||
459 | /* Perform conversion from xdr to cache array */ | 459 | /* Perform conversion from xdr to cache array */ |
460 | static | 460 | static |
461 | int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, | 461 | int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, |
462 | void *xdr_page, struct page *page, unsigned int buflen) | 462 | struct page **xdr_pages, struct page *page, unsigned int buflen) |
463 | { | 463 | { |
464 | struct xdr_stream stream; | 464 | struct xdr_stream stream; |
465 | struct xdr_buf buf; | 465 | struct xdr_buf buf = { |
466 | __be32 *ptr = xdr_page; | 466 | .pages = xdr_pages, |
467 | .page_len = buflen, | ||
468 | .buflen = buflen, | ||
469 | .len = buflen, | ||
470 | }; | ||
471 | struct page *scratch; | ||
467 | struct nfs_cache_array *array; | 472 | struct nfs_cache_array *array; |
468 | unsigned int count = 0; | 473 | unsigned int count = 0; |
469 | int status; | 474 | int status; |
470 | 475 | ||
471 | buf.head->iov_base = xdr_page; | 476 | scratch = alloc_page(GFP_KERNEL); |
472 | buf.head->iov_len = buflen; | 477 | if (scratch == NULL) |
473 | buf.tail->iov_len = 0; | 478 | return -ENOMEM; |
474 | buf.page_base = 0; | ||
475 | buf.page_len = 0; | ||
476 | buf.buflen = buf.head->iov_len; | ||
477 | buf.len = buf.head->iov_len; | ||
478 | |||
479 | xdr_init_decode(&stream, &buf, ptr); | ||
480 | 479 | ||
480 | xdr_init_decode(&stream, &buf, NULL); | ||
481 | xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE); | ||
481 | 482 | ||
482 | do { | 483 | do { |
483 | status = xdr_decode(desc, entry, &stream); | 484 | status = xdr_decode(desc, entry, &stream); |
@@ -506,6 +507,8 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en | |||
506 | } else | 507 | } else |
507 | status = PTR_ERR(array); | 508 | status = PTR_ERR(array); |
508 | } | 509 | } |
510 | |||
511 | put_page(scratch); | ||
509 | return status; | 512 | return status; |
510 | } | 513 | } |
511 | 514 | ||
@@ -521,7 +524,6 @@ static | |||
521 | void nfs_readdir_free_large_page(void *ptr, struct page **pages, | 524 | void nfs_readdir_free_large_page(void *ptr, struct page **pages, |
522 | unsigned int npages) | 525 | unsigned int npages) |
523 | { | 526 | { |
524 | vm_unmap_ram(ptr, npages); | ||
525 | nfs_readdir_free_pagearray(pages, npages); | 527 | nfs_readdir_free_pagearray(pages, npages); |
526 | } | 528 | } |
527 | 529 | ||
@@ -530,9 +532,8 @@ void nfs_readdir_free_large_page(void *ptr, struct page **pages, | |||
530 | * to nfs_readdir_free_large_page | 532 | * to nfs_readdir_free_large_page |
531 | */ | 533 | */ |
532 | static | 534 | static |
533 | void *nfs_readdir_large_page(struct page **pages, unsigned int npages) | 535 | int nfs_readdir_large_page(struct page **pages, unsigned int npages) |
534 | { | 536 | { |
535 | void *ptr; | ||
536 | unsigned int i; | 537 | unsigned int i; |
537 | 538 | ||
538 | for (i = 0; i < npages; i++) { | 539 | for (i = 0; i < npages; i++) { |
@@ -541,13 +542,11 @@ void *nfs_readdir_large_page(struct page **pages, unsigned int npages) | |||
541 | goto out_freepages; | 542 | goto out_freepages; |
542 | pages[i] = page; | 543 | pages[i] = page; |
543 | } | 544 | } |
545 | return 0; | ||
544 | 546 | ||
545 | ptr = vm_map_ram(pages, npages, 0, PAGE_KERNEL); | ||
546 | if (!IS_ERR_OR_NULL(ptr)) | ||
547 | return ptr; | ||
548 | out_freepages: | 547 | out_freepages: |
549 | nfs_readdir_free_pagearray(pages, i); | 548 | nfs_readdir_free_pagearray(pages, i); |
550 | return NULL; | 549 | return -ENOMEM; |
551 | } | 550 | } |
552 | 551 | ||
553 | static | 552 | static |
@@ -566,6 +565,7 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, | |||
566 | entry.eof = 0; | 565 | entry.eof = 0; |
567 | entry.fh = nfs_alloc_fhandle(); | 566 | entry.fh = nfs_alloc_fhandle(); |
568 | entry.fattr = nfs_alloc_fattr(); | 567 | entry.fattr = nfs_alloc_fattr(); |
568 | entry.server = NFS_SERVER(inode); | ||
569 | if (entry.fh == NULL || entry.fattr == NULL) | 569 | if (entry.fh == NULL || entry.fattr == NULL) |
570 | goto out; | 570 | goto out; |
571 | 571 | ||
@@ -577,8 +577,8 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, | |||
577 | memset(array, 0, sizeof(struct nfs_cache_array)); | 577 | memset(array, 0, sizeof(struct nfs_cache_array)); |
578 | array->eof_index = -1; | 578 | array->eof_index = -1; |
579 | 579 | ||
580 | pages_ptr = nfs_readdir_large_page(pages, array_size); | 580 | status = nfs_readdir_large_page(pages, array_size); |
581 | if (!pages_ptr) | 581 | if (status < 0) |
582 | goto out_release_array; | 582 | goto out_release_array; |
583 | do { | 583 | do { |
584 | unsigned int pglen; | 584 | unsigned int pglen; |
@@ -587,7 +587,7 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, | |||
587 | if (status < 0) | 587 | if (status < 0) |
588 | break; | 588 | break; |
589 | pglen = status; | 589 | pglen = status; |
590 | status = nfs_readdir_page_filler(desc, &entry, pages_ptr, page, pglen); | 590 | status = nfs_readdir_page_filler(desc, &entry, pages, page, pglen); |
591 | if (status < 0) { | 591 | if (status < 0) { |
592 | if (status == -ENOSPC) | 592 | if (status == -ENOSPC) |
593 | status = 0; | 593 | status = 0; |
@@ -970,7 +970,7 @@ int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd) | |||
970 | { | 970 | { |
971 | struct nfs_server *server = NFS_SERVER(inode); | 971 | struct nfs_server *server = NFS_SERVER(inode); |
972 | 972 | ||
973 | if (test_bit(NFS_INO_MOUNTPOINT, &NFS_I(inode)->flags)) | 973 | if (IS_AUTOMOUNT(inode)) |
974 | return 0; | 974 | return 0; |
975 | if (nd != NULL) { | 975 | if (nd != NULL) { |
976 | /* VFS wants an on-the-wire revalidation */ | 976 | /* VFS wants an on-the-wire revalidation */ |
@@ -1173,6 +1173,7 @@ const struct dentry_operations nfs_dentry_operations = { | |||
1173 | .d_revalidate = nfs_lookup_revalidate, | 1173 | .d_revalidate = nfs_lookup_revalidate, |
1174 | .d_delete = nfs_dentry_delete, | 1174 | .d_delete = nfs_dentry_delete, |
1175 | .d_iput = nfs_dentry_iput, | 1175 | .d_iput = nfs_dentry_iput, |
1176 | .d_automount = nfs_d_automount, | ||
1176 | }; | 1177 | }; |
1177 | 1178 | ||
1178 | static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) | 1179 | static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) |
@@ -1192,8 +1193,6 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
1192 | if (dentry->d_name.len > NFS_SERVER(dir)->namelen) | 1193 | if (dentry->d_name.len > NFS_SERVER(dir)->namelen) |
1193 | goto out; | 1194 | goto out; |
1194 | 1195 | ||
1195 | d_set_d_op(dentry, NFS_PROTO(dir)->dentry_ops); | ||
1196 | |||
1197 | /* | 1196 | /* |
1198 | * If we're doing an exclusive create, optimize away the lookup | 1197 | * If we're doing an exclusive create, optimize away the lookup |
1199 | * but don't hash the dentry. | 1198 | * but don't hash the dentry. |
@@ -1221,7 +1220,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
1221 | goto out_unblock_sillyrename; | 1220 | goto out_unblock_sillyrename; |
1222 | } | 1221 | } |
1223 | inode = nfs_fhget(dentry->d_sb, fhandle, fattr); | 1222 | inode = nfs_fhget(dentry->d_sb, fhandle, fattr); |
1224 | res = (struct dentry *)inode; | 1223 | res = ERR_CAST(inode); |
1225 | if (IS_ERR(res)) | 1224 | if (IS_ERR(res)) |
1226 | goto out_unblock_sillyrename; | 1225 | goto out_unblock_sillyrename; |
1227 | 1226 | ||
@@ -1248,6 +1247,7 @@ const struct dentry_operations nfs4_dentry_operations = { | |||
1248 | .d_revalidate = nfs_open_revalidate, | 1247 | .d_revalidate = nfs_open_revalidate, |
1249 | .d_delete = nfs_dentry_delete, | 1248 | .d_delete = nfs_dentry_delete, |
1250 | .d_iput = nfs_dentry_iput, | 1249 | .d_iput = nfs_dentry_iput, |
1250 | .d_automount = nfs_d_automount, | ||
1251 | }; | 1251 | }; |
1252 | 1252 | ||
1253 | /* | 1253 | /* |
@@ -1337,7 +1337,6 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry | |||
1337 | res = ERR_PTR(-ENAMETOOLONG); | 1337 | res = ERR_PTR(-ENAMETOOLONG); |
1338 | goto out; | 1338 | goto out; |
1339 | } | 1339 | } |
1340 | d_set_d_op(dentry, NFS_PROTO(dir)->dentry_ops); | ||
1341 | 1340 | ||
1342 | /* Let vfs_create() deal with O_EXCL. Instantiate, but don't hash | 1341 | /* Let vfs_create() deal with O_EXCL. Instantiate, but don't hash |
1343 | * the dentry. */ | 1342 | * the dentry. */ |
@@ -1355,8 +1354,7 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry | |||
1355 | if (nd->flags & LOOKUP_CREATE) { | 1354 | if (nd->flags & LOOKUP_CREATE) { |
1356 | attr.ia_mode = nd->intent.open.create_mode; | 1355 | attr.ia_mode = nd->intent.open.create_mode; |
1357 | attr.ia_valid = ATTR_MODE; | 1356 | attr.ia_valid = ATTR_MODE; |
1358 | if (!IS_POSIXACL(dir)) | 1357 | attr.ia_mode &= ~current_umask(); |
1359 | attr.ia_mode &= ~current_umask(); | ||
1360 | } else { | 1358 | } else { |
1361 | open_flags &= ~(O_EXCL | O_CREAT); | 1359 | open_flags &= ~(O_EXCL | O_CREAT); |
1362 | attr.ia_valid = 0; | 1360 | attr.ia_valid = 0; |
@@ -1410,11 +1408,15 @@ no_open: | |||
1410 | static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) | 1408 | static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) |
1411 | { | 1409 | { |
1412 | struct dentry *parent = NULL; | 1410 | struct dentry *parent = NULL; |
1413 | struct inode *inode = dentry->d_inode; | 1411 | struct inode *inode; |
1414 | struct inode *dir; | 1412 | struct inode *dir; |
1415 | struct nfs_open_context *ctx; | 1413 | struct nfs_open_context *ctx; |
1416 | int openflags, ret = 0; | 1414 | int openflags, ret = 0; |
1417 | 1415 | ||
1416 | if (nd->flags & LOOKUP_RCU) | ||
1417 | return -ECHILD; | ||
1418 | |||
1419 | inode = dentry->d_inode; | ||
1418 | if (!is_atomic_open(nd) || d_mountpoint(dentry)) | 1420 | if (!is_atomic_open(nd) || d_mountpoint(dentry)) |
1419 | goto no_open; | 1421 | goto no_open; |
1420 | 1422 | ||
@@ -1583,6 +1585,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
1583 | { | 1585 | { |
1584 | struct iattr attr; | 1586 | struct iattr attr; |
1585 | int error; | 1587 | int error; |
1588 | int open_flags = 0; | ||
1586 | 1589 | ||
1587 | dfprintk(VFS, "NFS: create(%s/%ld), %s\n", | 1590 | dfprintk(VFS, "NFS: create(%s/%ld), %s\n", |
1588 | dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); | 1591 | dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); |
@@ -1590,7 +1593,10 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
1590 | attr.ia_mode = mode; | 1593 | attr.ia_mode = mode; |
1591 | attr.ia_valid = ATTR_MODE; | 1594 | attr.ia_valid = ATTR_MODE; |
1592 | 1595 | ||
1593 | error = NFS_PROTO(dir)->create(dir, dentry, &attr, 0, NULL); | 1596 | if ((nd->flags & LOOKUP_CREATE) != 0) |
1597 | open_flags = nd->intent.open.flags; | ||
1598 | |||
1599 | error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, NULL); | ||
1594 | if (error != 0) | 1600 | if (error != 0) |
1595 | goto out_err; | 1601 | goto out_err; |
1596 | return 0; | 1602 | return 0; |