diff options
| author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-11-26 22:42:59 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-11-26 22:42:59 -0500 |
| commit | 423eaf8f00d89ca79bb2c9d4d22e92c9774e2d8a (patch) | |
| tree | e160521a6b059d50045ea47c3f730bf2c83c1f85 /fs | |
| parent | 0685ab4fb8e527639d9867df60d49dccba85d842 (diff) | |
| parent | 02fe494619d525ea803ab1f4f671186dc8a52f7a (diff) | |
Merge git://git.linux-nfs.org/pub/linux/nfs-2.6
* git://git.linux-nfs.org/pub/linux/nfs-2.6:
NFS: Clean up new multi-segment direct I/O changes
NFS: Ensure we return zero if applications attempt to write zero bytes
NFS: Support multiple segment iovecs in the NFS direct I/O path
NFS: Introduce iovec I/O helpers to fs/nfs/direct.c
SUNRPC: Add missing "space" to net/sunrpc/auth_gss.c
SUNRPC: make sunrpc/xprtsock.c:xs_setup_{udp,tcp}() static
NFS: fs/nfs/dir.c should #include "internal.h"
NFS: make nfs_wb_page_priority() static
NFS: mount failure causes bad page state
SUNRPC: remove NFS/RDMA client's binary sysctls
kernel BUG at fs/nfs/namespace.c:108! - can be triggered by bad server
sunrpc: rpc_pipe_poll may miss available data in some cases
sunrpc: return error if unsupported enctype or cksumtype is encountered
sunrpc: gss_pipe_downcall(), don't assume all errors are transient
NFS: Fix the ustat() regression
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/nfs/dir.c | 1 | ||||
| -rw-r--r-- | fs/nfs/direct.c | 142 | ||||
| -rw-r--r-- | fs/nfs/getroot.c | 81 | ||||
| -rw-r--r-- | fs/nfs/super.c | 11 | ||||
| -rw-r--r-- | fs/nfs/write.c | 3 |
5 files changed, 138 insertions, 100 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 35334539d947..f697b5c74b7c 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include "nfs4_fs.h" | 38 | #include "nfs4_fs.h" |
| 39 | #include "delegation.h" | 39 | #include "delegation.h" |
| 40 | #include "iostat.h" | 40 | #include "iostat.h" |
| 41 | #include "internal.h" | ||
| 41 | 42 | ||
| 42 | /* #define NFS_DEBUG_VERBOSE 1 */ | 43 | /* #define NFS_DEBUG_VERBOSE 1 */ |
| 43 | 44 | ||
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index afcab007a22b..5e8d82f6666b 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
| @@ -263,17 +263,19 @@ static const struct rpc_call_ops nfs_read_direct_ops = { | |||
| 263 | * handled automatically by nfs_direct_read_result(). Otherwise, if | 263 | * handled automatically by nfs_direct_read_result(). Otherwise, if |
| 264 | * no requests have been sent, just return an error. | 264 | * no requests have been sent, just return an error. |
| 265 | */ | 265 | */ |
| 266 | static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos) | 266 | static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, |
| 267 | const struct iovec *iov, | ||
| 268 | loff_t pos) | ||
| 267 | { | 269 | { |
| 268 | struct nfs_open_context *ctx = dreq->ctx; | 270 | struct nfs_open_context *ctx = dreq->ctx; |
| 269 | struct inode *inode = ctx->path.dentry->d_inode; | 271 | struct inode *inode = ctx->path.dentry->d_inode; |
| 272 | unsigned long user_addr = (unsigned long)iov->iov_base; | ||
| 273 | size_t count = iov->iov_len; | ||
| 270 | size_t rsize = NFS_SERVER(inode)->rsize; | 274 | size_t rsize = NFS_SERVER(inode)->rsize; |
| 271 | unsigned int pgbase; | 275 | unsigned int pgbase; |
| 272 | int result; | 276 | int result; |
| 273 | ssize_t started = 0; | 277 | ssize_t started = 0; |
| 274 | 278 | ||
| 275 | get_dreq(dreq); | ||
| 276 | |||
| 277 | do { | 279 | do { |
| 278 | struct nfs_read_data *data; | 280 | struct nfs_read_data *data; |
| 279 | size_t bytes; | 281 | size_t bytes; |
| @@ -347,15 +349,46 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo | |||
| 347 | count -= bytes; | 349 | count -= bytes; |
| 348 | } while (count != 0); | 350 | } while (count != 0); |
| 349 | 351 | ||
| 352 | if (started) | ||
| 353 | return started; | ||
| 354 | return result < 0 ? (ssize_t) result : -EFAULT; | ||
| 355 | } | ||
| 356 | |||
| 357 | static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, | ||
| 358 | const struct iovec *iov, | ||
| 359 | unsigned long nr_segs, | ||
| 360 | loff_t pos) | ||
| 361 | { | ||
| 362 | ssize_t result = -EINVAL; | ||
| 363 | size_t requested_bytes = 0; | ||
| 364 | unsigned long seg; | ||
| 365 | |||
| 366 | get_dreq(dreq); | ||
| 367 | |||
| 368 | for (seg = 0; seg < nr_segs; seg++) { | ||
| 369 | const struct iovec *vec = &iov[seg]; | ||
| 370 | result = nfs_direct_read_schedule_segment(dreq, vec, pos); | ||
| 371 | if (result < 0) | ||
| 372 | break; | ||
| 373 | requested_bytes += result; | ||
| 374 | if ((size_t)result < vec->iov_len) | ||
| 375 | break; | ||
| 376 | pos += vec->iov_len; | ||
| 377 | } | ||
| 378 | |||
| 350 | if (put_dreq(dreq)) | 379 | if (put_dreq(dreq)) |
| 351 | nfs_direct_complete(dreq); | 380 | nfs_direct_complete(dreq); |
| 352 | 381 | ||
| 353 | if (started) | 382 | if (requested_bytes != 0) |
| 354 | return 0; | 383 | return 0; |
| 355 | return result < 0 ? (ssize_t) result : -EFAULT; | 384 | |
| 385 | if (result < 0) | ||
| 386 | return result; | ||
| 387 | return -EIO; | ||
| 356 | } | 388 | } |
| 357 | 389 | ||
| 358 | static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos) | 390 | static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov, |
| 391 | unsigned long nr_segs, loff_t pos) | ||
| 359 | { | 392 | { |
| 360 | ssize_t result = 0; | 393 | ssize_t result = 0; |
| 361 | sigset_t oldset; | 394 | sigset_t oldset; |
| @@ -372,9 +405,8 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size | |||
| 372 | if (!is_sync_kiocb(iocb)) | 405 | if (!is_sync_kiocb(iocb)) |
| 373 | dreq->iocb = iocb; | 406 | dreq->iocb = iocb; |
| 374 | 407 | ||
| 375 | nfs_add_stats(inode, NFSIOS_DIRECTREADBYTES, count); | ||
| 376 | rpc_clnt_sigmask(clnt, &oldset); | 408 | rpc_clnt_sigmask(clnt, &oldset); |
| 377 | result = nfs_direct_read_schedule(dreq, user_addr, count, pos); | 409 | result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos); |
| 378 | if (!result) | 410 | if (!result) |
| 379 | result = nfs_direct_wait(dreq); | 411 | result = nfs_direct_wait(dreq); |
| 380 | rpc_clnt_sigunmask(clnt, &oldset); | 412 | rpc_clnt_sigunmask(clnt, &oldset); |
| @@ -601,17 +633,19 @@ static const struct rpc_call_ops nfs_write_direct_ops = { | |||
| 601 | * handled automatically by nfs_direct_write_result(). Otherwise, if | 633 | * handled automatically by nfs_direct_write_result(). Otherwise, if |
| 602 | * no requests have been sent, just return an error. | 634 | * no requests have been sent, just return an error. |
| 603 | */ | 635 | */ |
| 604 | static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos, int sync) | 636 | static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, |
| 637 | const struct iovec *iov, | ||
| 638 | loff_t pos, int sync) | ||
| 605 | { | 639 | { |
| 606 | struct nfs_open_context *ctx = dreq->ctx; | 640 | struct nfs_open_context *ctx = dreq->ctx; |
| 607 | struct inode *inode = ctx->path.dentry->d_inode; | 641 | struct inode *inode = ctx->path.dentry->d_inode; |
| 642 | unsigned long user_addr = (unsigned long)iov->iov_base; | ||
| 643 | size_t count = iov->iov_len; | ||
| 608 | size_t wsize = NFS_SERVER(inode)->wsize; | 644 | size_t wsize = NFS_SERVER(inode)->wsize; |
| 609 | unsigned int pgbase; | 645 | unsigned int pgbase; |
| 610 | int result; | 646 | int result; |
| 611 | ssize_t started = 0; | 647 | ssize_t started = 0; |
| 612 | 648 | ||
| 613 | get_dreq(dreq); | ||
| 614 | |||
| 615 | do { | 649 | do { |
| 616 | struct nfs_write_data *data; | 650 | struct nfs_write_data *data; |
| 617 | size_t bytes; | 651 | size_t bytes; |
| @@ -689,15 +723,48 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l | |||
| 689 | count -= bytes; | 723 | count -= bytes; |
| 690 | } while (count != 0); | 724 | } while (count != 0); |
| 691 | 725 | ||
| 726 | if (started) | ||
| 727 | return started; | ||
| 728 | return result < 0 ? (ssize_t) result : -EFAULT; | ||
| 729 | } | ||
| 730 | |||
| 731 | static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, | ||
| 732 | const struct iovec *iov, | ||
| 733 | unsigned long nr_segs, | ||
| 734 | loff_t pos, int sync) | ||
| 735 | { | ||
| 736 | ssize_t result = 0; | ||
| 737 | size_t requested_bytes = 0; | ||
| 738 | unsigned long seg; | ||
| 739 | |||
| 740 | get_dreq(dreq); | ||
| 741 | |||
| 742 | for (seg = 0; seg < nr_segs; seg++) { | ||
| 743 | const struct iovec *vec = &iov[seg]; | ||
| 744 | result = nfs_direct_write_schedule_segment(dreq, vec, | ||
| 745 | pos, sync); | ||
| 746 | if (result < 0) | ||
| 747 | break; | ||
| 748 | requested_bytes += result; | ||
| 749 | if ((size_t)result < vec->iov_len) | ||
| 750 | break; | ||
| 751 | pos += vec->iov_len; | ||
| 752 | } | ||
| 753 | |||
| 692 | if (put_dreq(dreq)) | 754 | if (put_dreq(dreq)) |
| 693 | nfs_direct_write_complete(dreq, inode); | 755 | nfs_direct_write_complete(dreq, dreq->inode); |
| 694 | 756 | ||
| 695 | if (started) | 757 | if (requested_bytes != 0) |
| 696 | return 0; | 758 | return 0; |
| 697 | return result < 0 ? (ssize_t) result : -EFAULT; | 759 | |
| 760 | if (result < 0) | ||
| 761 | return result; | ||
| 762 | return -EIO; | ||
| 698 | } | 763 | } |
| 699 | 764 | ||
| 700 | static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos) | 765 | static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, |
| 766 | unsigned long nr_segs, loff_t pos, | ||
| 767 | size_t count) | ||
| 701 | { | 768 | { |
| 702 | ssize_t result = 0; | 769 | ssize_t result = 0; |
| 703 | sigset_t oldset; | 770 | sigset_t oldset; |
| @@ -720,10 +787,8 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz | |||
| 720 | if (!is_sync_kiocb(iocb)) | 787 | if (!is_sync_kiocb(iocb)) |
| 721 | dreq->iocb = iocb; | 788 | dreq->iocb = iocb; |
| 722 | 789 | ||
| 723 | nfs_add_stats(inode, NFSIOS_DIRECTWRITTENBYTES, count); | ||
| 724 | |||
| 725 | rpc_clnt_sigmask(clnt, &oldset); | 790 | rpc_clnt_sigmask(clnt, &oldset); |
| 726 | result = nfs_direct_write_schedule(dreq, user_addr, count, pos, sync); | 791 | result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, sync); |
| 727 | if (!result) | 792 | if (!result) |
| 728 | result = nfs_direct_wait(dreq); | 793 | result = nfs_direct_wait(dreq); |
| 729 | rpc_clnt_sigunmask(clnt, &oldset); | 794 | rpc_clnt_sigunmask(clnt, &oldset); |
| @@ -759,21 +824,16 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov, | |||
| 759 | ssize_t retval = -EINVAL; | 824 | ssize_t retval = -EINVAL; |
| 760 | struct file *file = iocb->ki_filp; | 825 | struct file *file = iocb->ki_filp; |
| 761 | struct address_space *mapping = file->f_mapping; | 826 | struct address_space *mapping = file->f_mapping; |
| 762 | /* XXX: temporary */ | 827 | size_t count; |
| 763 | const char __user *buf = iov[0].iov_base; | 828 | |
| 764 | size_t count = iov[0].iov_len; | 829 | count = iov_length(iov, nr_segs); |
| 830 | nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, count); | ||
| 765 | 831 | ||
| 766 | dprintk("nfs: direct read(%s/%s, %lu@%Ld)\n", | 832 | dprintk("nfs: direct read(%s/%s, %zd@%Ld)\n", |
| 767 | file->f_path.dentry->d_parent->d_name.name, | 833 | file->f_path.dentry->d_parent->d_name.name, |
| 768 | file->f_path.dentry->d_name.name, | 834 | file->f_path.dentry->d_name.name, |
| 769 | (unsigned long) count, (long long) pos); | 835 | count, (long long) pos); |
| 770 | |||
| 771 | if (nr_segs != 1) | ||
| 772 | goto out; | ||
| 773 | 836 | ||
| 774 | retval = -EFAULT; | ||
| 775 | if (!access_ok(VERIFY_WRITE, buf, count)) | ||
| 776 | goto out; | ||
| 777 | retval = 0; | 837 | retval = 0; |
| 778 | if (!count) | 838 | if (!count) |
| 779 | goto out; | 839 | goto out; |
| @@ -782,7 +842,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov, | |||
| 782 | if (retval) | 842 | if (retval) |
| 783 | goto out; | 843 | goto out; |
| 784 | 844 | ||
| 785 | retval = nfs_direct_read(iocb, (unsigned long) buf, count, pos); | 845 | retval = nfs_direct_read(iocb, iov, nr_segs, pos); |
| 786 | if (retval > 0) | 846 | if (retval > 0) |
| 787 | iocb->ki_pos = pos + retval; | 847 | iocb->ki_pos = pos + retval; |
| 788 | 848 | ||
| @@ -821,21 +881,21 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 821 | ssize_t retval = -EINVAL; | 881 | ssize_t retval = -EINVAL; |
| 822 | struct file *file = iocb->ki_filp; | 882 | struct file *file = iocb->ki_filp; |
| 823 | struct address_space *mapping = file->f_mapping; | 883 | struct address_space *mapping = file->f_mapping; |
| 824 | /* XXX: temporary */ | 884 | size_t count; |
| 825 | const char __user *buf = iov[0].iov_base; | 885 | |
| 826 | size_t count = iov[0].iov_len; | 886 | count = iov_length(iov, nr_segs); |
| 887 | nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, count); | ||
| 827 | 888 | ||
| 828 | dprintk("nfs: direct write(%s/%s, %lu@%Ld)\n", | 889 | dfprintk(VFS, "nfs: direct write(%s/%s, %zd@%Ld)\n", |
| 829 | file->f_path.dentry->d_parent->d_name.name, | 890 | file->f_path.dentry->d_parent->d_name.name, |
| 830 | file->f_path.dentry->d_name.name, | 891 | file->f_path.dentry->d_name.name, |
| 831 | (unsigned long) count, (long long) pos); | 892 | count, (long long) pos); |
| 832 | |||
| 833 | if (nr_segs != 1) | ||
| 834 | goto out; | ||
| 835 | 893 | ||
| 836 | retval = generic_write_checks(file, &pos, &count, 0); | 894 | retval = generic_write_checks(file, &pos, &count, 0); |
| 837 | if (retval) | 895 | if (retval) |
| 838 | goto out; | 896 | goto out; |
| 897 | if (!count) | ||
| 898 | goto out; /* return 0 */ | ||
| 839 | 899 | ||
| 840 | retval = -EINVAL; | 900 | retval = -EINVAL; |
| 841 | if ((ssize_t) count < 0) | 901 | if ((ssize_t) count < 0) |
| @@ -844,15 +904,11 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 844 | if (!count) | 904 | if (!count) |
| 845 | goto out; | 905 | goto out; |
| 846 | 906 | ||
| 847 | retval = -EFAULT; | ||
| 848 | if (!access_ok(VERIFY_READ, buf, count)) | ||
| 849 | goto out; | ||
| 850 | |||
| 851 | retval = nfs_sync_mapping(mapping); | 907 | retval = nfs_sync_mapping(mapping); |
| 852 | if (retval) | 908 | if (retval) |
| 853 | goto out; | 909 | goto out; |
| 854 | 910 | ||
| 855 | retval = nfs_direct_write(iocb, (unsigned long) buf, count, pos); | 911 | retval = nfs_direct_write(iocb, iov, nr_segs, pos, count); |
| 856 | 912 | ||
| 857 | if (retval > 0) | 913 | if (retval > 0) |
| 858 | iocb->ki_pos = pos + retval; | 914 | iocb->ki_pos = pos + retval; |
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index 522e5ad4d8ad..0ee43843f4ec 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c | |||
| @@ -43,6 +43,25 @@ | |||
| 43 | #define NFSDBG_FACILITY NFSDBG_CLIENT | 43 | #define NFSDBG_FACILITY NFSDBG_CLIENT |
| 44 | 44 | ||
| 45 | /* | 45 | /* |
| 46 | * Set the superblock root dentry. | ||
| 47 | * Note that this function frees the inode in case of error. | ||
| 48 | */ | ||
| 49 | static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *inode) | ||
| 50 | { | ||
| 51 | /* The mntroot acts as the dummy root dentry for this superblock */ | ||
| 52 | if (sb->s_root == NULL) { | ||
| 53 | sb->s_root = d_alloc_root(inode); | ||
| 54 | if (sb->s_root == NULL) { | ||
| 55 | iput(inode); | ||
| 56 | return -ENOMEM; | ||
| 57 | } | ||
| 58 | /* Circumvent igrab(): we know the inode is not being freed */ | ||
| 59 | atomic_inc(&inode->i_count); | ||
| 60 | } | ||
| 61 | return 0; | ||
| 62 | } | ||
| 63 | |||
| 64 | /* | ||
| 46 | * get an NFS2/NFS3 root dentry from the root filehandle | 65 | * get an NFS2/NFS3 root dentry from the root filehandle |
| 47 | */ | 66 | */ |
| 48 | struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) | 67 | struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) |
| @@ -54,33 +73,6 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) | |||
| 54 | struct inode *inode; | 73 | struct inode *inode; |
| 55 | int error; | 74 | int error; |
| 56 | 75 | ||
| 57 | /* create a dummy root dentry with dummy inode for this superblock */ | ||
| 58 | if (!sb->s_root) { | ||
| 59 | struct nfs_fh dummyfh; | ||
| 60 | struct dentry *root; | ||
| 61 | struct inode *iroot; | ||
| 62 | |||
| 63 | memset(&dummyfh, 0, sizeof(dummyfh)); | ||
| 64 | memset(&fattr, 0, sizeof(fattr)); | ||
| 65 | nfs_fattr_init(&fattr); | ||
| 66 | fattr.valid = NFS_ATTR_FATTR; | ||
| 67 | fattr.type = NFDIR; | ||
| 68 | fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR; | ||
| 69 | fattr.nlink = 2; | ||
| 70 | |||
| 71 | iroot = nfs_fhget(sb, &dummyfh, &fattr); | ||
| 72 | if (IS_ERR(iroot)) | ||
| 73 | return ERR_PTR(PTR_ERR(iroot)); | ||
| 74 | |||
| 75 | root = d_alloc_root(iroot); | ||
| 76 | if (!root) { | ||
| 77 | iput(iroot); | ||
| 78 | return ERR_PTR(-ENOMEM); | ||
| 79 | } | ||
| 80 | |||
| 81 | sb->s_root = root; | ||
| 82 | } | ||
| 83 | |||
| 84 | /* get the actual root for this mount */ | 76 | /* get the actual root for this mount */ |
| 85 | fsinfo.fattr = &fattr; | 77 | fsinfo.fattr = &fattr; |
| 86 | 78 | ||
| @@ -96,6 +88,10 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) | |||
| 96 | return ERR_PTR(PTR_ERR(inode)); | 88 | return ERR_PTR(PTR_ERR(inode)); |
| 97 | } | 89 | } |
| 98 | 90 | ||
| 91 | error = nfs_superblock_set_dummy_root(sb, inode); | ||
| 92 | if (error != 0) | ||
| 93 | return ERR_PTR(error); | ||
| 94 | |||
| 99 | /* root dentries normally start off anonymous and get spliced in later | 95 | /* root dentries normally start off anonymous and get spliced in later |
| 100 | * if the dentry tree reaches them; however if the dentry already | 96 | * if the dentry tree reaches them; however if the dentry already |
| 101 | * exists, we'll pick it up at this point and use it as the root | 97 | * exists, we'll pick it up at this point and use it as the root |
| @@ -241,33 +237,6 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) | |||
| 241 | 237 | ||
| 242 | dprintk("--> nfs4_get_root()\n"); | 238 | dprintk("--> nfs4_get_root()\n"); |
| 243 | 239 | ||
| 244 | /* create a dummy root dentry with dummy inode for this superblock */ | ||
| 245 | if (!sb->s_root) { | ||
| 246 | struct nfs_fh dummyfh; | ||
| 247 | struct dentry *root; | ||
| 248 | struct inode *iroot; | ||
| 249 | |||
| 250 | memset(&dummyfh, 0, sizeof(dummyfh)); | ||
| 251 | memset(&fattr, 0, sizeof(fattr)); | ||
| 252 | nfs_fattr_init(&fattr); | ||
| 253 | fattr.valid = NFS_ATTR_FATTR; | ||
| 254 | fattr.type = NFDIR; | ||
| 255 | fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR; | ||
| 256 | fattr.nlink = 2; | ||
| 257 | |||
| 258 | iroot = nfs_fhget(sb, &dummyfh, &fattr); | ||
| 259 | if (IS_ERR(iroot)) | ||
| 260 | return ERR_PTR(PTR_ERR(iroot)); | ||
| 261 | |||
| 262 | root = d_alloc_root(iroot); | ||
| 263 | if (!root) { | ||
| 264 | iput(iroot); | ||
| 265 | return ERR_PTR(-ENOMEM); | ||
| 266 | } | ||
| 267 | |||
| 268 | sb->s_root = root; | ||
| 269 | } | ||
| 270 | |||
| 271 | /* get the info about the server and filesystem */ | 240 | /* get the info about the server and filesystem */ |
| 272 | error = nfs4_server_capabilities(server, mntfh); | 241 | error = nfs4_server_capabilities(server, mntfh); |
| 273 | if (error < 0) { | 242 | if (error < 0) { |
| @@ -289,6 +258,10 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) | |||
| 289 | return ERR_PTR(PTR_ERR(inode)); | 258 | return ERR_PTR(PTR_ERR(inode)); |
| 290 | } | 259 | } |
| 291 | 260 | ||
| 261 | error = nfs_superblock_set_dummy_root(sb, inode); | ||
| 262 | if (error != 0) | ||
| 263 | return ERR_PTR(error); | ||
| 264 | |||
| 292 | /* root dentries normally start off anonymous and get spliced in later | 265 | /* root dentries normally start off anonymous and get spliced in later |
| 293 | * if the dentry tree reaches them; however if the dentry already | 266 | * if the dentry tree reaches them; however if the dentry already |
| 294 | * exists, we'll pick it up at this point and use it as the root | 267 | * exists, we'll pick it up at this point and use it as the root |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index fa517ae9207f..2426e713b77f 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
| @@ -1054,10 +1054,11 @@ static int nfs_validate_mount_data(void *options, | |||
| 1054 | { | 1054 | { |
| 1055 | struct nfs_mount_data *data = (struct nfs_mount_data *)options; | 1055 | struct nfs_mount_data *data = (struct nfs_mount_data *)options; |
| 1056 | 1056 | ||
| 1057 | memset(args, 0, sizeof(*args)); | ||
| 1058 | |||
| 1057 | if (data == NULL) | 1059 | if (data == NULL) |
| 1058 | goto out_no_data; | 1060 | goto out_no_data; |
| 1059 | 1061 | ||
| 1060 | memset(args, 0, sizeof(*args)); | ||
| 1061 | args->flags = (NFS_MOUNT_VER3 | NFS_MOUNT_TCP); | 1062 | args->flags = (NFS_MOUNT_VER3 | NFS_MOUNT_TCP); |
| 1062 | args->rsize = NFS_MAX_FILE_IO_SIZE; | 1063 | args->rsize = NFS_MAX_FILE_IO_SIZE; |
| 1063 | args->wsize = NFS_MAX_FILE_IO_SIZE; | 1064 | args->wsize = NFS_MAX_FILE_IO_SIZE; |
| @@ -1474,6 +1475,11 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags, | |||
| 1474 | error = PTR_ERR(mntroot); | 1475 | error = PTR_ERR(mntroot); |
| 1475 | goto error_splat_super; | 1476 | goto error_splat_super; |
| 1476 | } | 1477 | } |
| 1478 | if (mntroot->d_inode->i_op != &nfs_dir_inode_operations) { | ||
| 1479 | dput(mntroot); | ||
| 1480 | error = -ESTALE; | ||
| 1481 | goto error_splat_super; | ||
| 1482 | } | ||
| 1477 | 1483 | ||
| 1478 | s->s_flags |= MS_ACTIVE; | 1484 | s->s_flags |= MS_ACTIVE; |
| 1479 | mnt->mnt_sb = s; | 1485 | mnt->mnt_sb = s; |
| @@ -1531,10 +1537,11 @@ static int nfs4_validate_mount_data(void *options, | |||
| 1531 | struct nfs4_mount_data *data = (struct nfs4_mount_data *)options; | 1537 | struct nfs4_mount_data *data = (struct nfs4_mount_data *)options; |
| 1532 | char *c; | 1538 | char *c; |
| 1533 | 1539 | ||
| 1540 | memset(args, 0, sizeof(*args)); | ||
| 1541 | |||
| 1534 | if (data == NULL) | 1542 | if (data == NULL) |
| 1535 | goto out_no_data; | 1543 | goto out_no_data; |
| 1536 | 1544 | ||
| 1537 | memset(args, 0, sizeof(*args)); | ||
| 1538 | args->rsize = NFS_MAX_FILE_IO_SIZE; | 1545 | args->rsize = NFS_MAX_FILE_IO_SIZE; |
| 1539 | args->wsize = NFS_MAX_FILE_IO_SIZE; | 1546 | args->wsize = NFS_MAX_FILE_IO_SIZE; |
| 1540 | args->timeo = 600; | 1547 | args->timeo = 600; |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 89527a487ed7..51cc1bd6a116 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
| @@ -1436,7 +1436,8 @@ out: | |||
| 1436 | return ret; | 1436 | return ret; |
| 1437 | } | 1437 | } |
| 1438 | 1438 | ||
| 1439 | int nfs_wb_page_priority(struct inode *inode, struct page *page, int how) | 1439 | static int nfs_wb_page_priority(struct inode *inode, struct page *page, |
| 1440 | int how) | ||
| 1440 | { | 1441 | { |
| 1441 | loff_t range_start = page_offset(page); | 1442 | loff_t range_start = page_offset(page); |
| 1442 | loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); | 1443 | loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); |
