diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-25 12:18:27 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-25 12:18:27 -0500 |
commit | 53846a21c1766326bb14ce8ab6e997a0c120675d (patch) | |
tree | 37b04485e29844b4e734479181276a2f4d2447e4 /fs/nfs/inode.c | |
parent | 2e9abdd9bad485970b37cd53a82f92702054984c (diff) | |
parent | 1ebbe2b20091d306453a5cf480a87e6cd28ae76f (diff) |
Merge git://git.linux-nfs.org/pub/linux/nfs-2.6
* git://git.linux-nfs.org/pub/linux/nfs-2.6: (103 commits)
SUNRPC,RPCSEC_GSS: spkm3--fix config dependencies
SUNRPC,RPCSEC_GSS: spkm3: import contexts using NID_cast5_cbc
LOCKD: Make nlmsvc_traverse_shares return void
LOCKD: nlmsvc_traverse_blocks return is unused
SUNRPC,RPCSEC_GSS: fix krb5 sequence numbers.
NFSv4: Dont list system.nfs4_acl for filesystems that don't support it.
SUNRPC,RPCSEC_GSS: remove unnecessary kmalloc of a checksum
SUNRPC: Ensure rpc_call_async() always calls tk_ops->rpc_release()
SUNRPC: Fix memory barriers for req->rq_received
NFS: Fix a race in nfs_sync_inode()
NFS: Clean up nfs_flush_list()
NFS: Fix a race with PG_private and nfs_release_page()
NFSv4: Ensure the callback daemon flushes signals
SUNRPC: Fix a 'Busy inodes' error in rpc_pipefs
NFS, NLM: Allow blocking locks to respect signals
NFS: Make nfs_fhget() return appropriate error values
NFSv4: Fix an oops in nfs4_fill_super
lockd: blocks should hold a reference to the nlm_file
NFSv4: SETCLIENTID_CONFIRM should handle NFS4ERR_DELAY/NFS4ERR_RESOURCE
NFSv4: Send the delegation stateid for SETATTR calls
...
Diffstat (limited to 'fs/nfs/inode.c')
-rw-r--r-- | fs/nfs/inode.c | 229 |
1 files changed, 171 insertions, 58 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 3413996f9a86..2f7656b911b6 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/unistd.h> | 26 | #include <linux/unistd.h> |
27 | #include <linux/sunrpc/clnt.h> | 27 | #include <linux/sunrpc/clnt.h> |
28 | #include <linux/sunrpc/stats.h> | 28 | #include <linux/sunrpc/stats.h> |
29 | #include <linux/sunrpc/metrics.h> | ||
29 | #include <linux/nfs_fs.h> | 30 | #include <linux/nfs_fs.h> |
30 | #include <linux/nfs_mount.h> | 31 | #include <linux/nfs_mount.h> |
31 | #include <linux/nfs4_mount.h> | 32 | #include <linux/nfs4_mount.h> |
@@ -42,6 +43,7 @@ | |||
42 | #include "nfs4_fs.h" | 43 | #include "nfs4_fs.h" |
43 | #include "callback.h" | 44 | #include "callback.h" |
44 | #include "delegation.h" | 45 | #include "delegation.h" |
46 | #include "iostat.h" | ||
45 | 47 | ||
46 | #define NFSDBG_FACILITY NFSDBG_VFS | 48 | #define NFSDBG_FACILITY NFSDBG_VFS |
47 | #define NFS_PARANOIA 1 | 49 | #define NFS_PARANOIA 1 |
@@ -65,6 +67,7 @@ static void nfs_clear_inode(struct inode *); | |||
65 | static void nfs_umount_begin(struct super_block *); | 67 | static void nfs_umount_begin(struct super_block *); |
66 | static int nfs_statfs(struct super_block *, struct kstatfs *); | 68 | static int nfs_statfs(struct super_block *, struct kstatfs *); |
67 | static int nfs_show_options(struct seq_file *, struct vfsmount *); | 69 | static int nfs_show_options(struct seq_file *, struct vfsmount *); |
70 | static int nfs_show_stats(struct seq_file *, struct vfsmount *); | ||
68 | static void nfs_zap_acl_cache(struct inode *); | 71 | static void nfs_zap_acl_cache(struct inode *); |
69 | 72 | ||
70 | static struct rpc_program nfs_program; | 73 | static struct rpc_program nfs_program; |
@@ -78,6 +81,7 @@ static struct super_operations nfs_sops = { | |||
78 | .clear_inode = nfs_clear_inode, | 81 | .clear_inode = nfs_clear_inode, |
79 | .umount_begin = nfs_umount_begin, | 82 | .umount_begin = nfs_umount_begin, |
80 | .show_options = nfs_show_options, | 83 | .show_options = nfs_show_options, |
84 | .show_stats = nfs_show_stats, | ||
81 | }; | 85 | }; |
82 | 86 | ||
83 | /* | 87 | /* |
@@ -133,7 +137,7 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr) | |||
133 | static int | 137 | static int |
134 | nfs_write_inode(struct inode *inode, int sync) | 138 | nfs_write_inode(struct inode *inode, int sync) |
135 | { | 139 | { |
136 | int flags = sync ? FLUSH_WAIT : 0; | 140 | int flags = sync ? FLUSH_SYNC : 0; |
137 | int ret; | 141 | int ret; |
138 | 142 | ||
139 | ret = nfs_commit_inode(inode, flags); | 143 | ret = nfs_commit_inode(inode, flags); |
@@ -237,7 +241,6 @@ static struct inode * | |||
237 | nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo) | 241 | nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo) |
238 | { | 242 | { |
239 | struct nfs_server *server = NFS_SB(sb); | 243 | struct nfs_server *server = NFS_SB(sb); |
240 | struct inode *rooti; | ||
241 | int error; | 244 | int error; |
242 | 245 | ||
243 | error = server->rpc_ops->getroot(server, rootfh, fsinfo); | 246 | error = server->rpc_ops->getroot(server, rootfh, fsinfo); |
@@ -246,10 +249,7 @@ nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *f | |||
246 | return ERR_PTR(error); | 249 | return ERR_PTR(error); |
247 | } | 250 | } |
248 | 251 | ||
249 | rooti = nfs_fhget(sb, rootfh, fsinfo->fattr); | 252 | return nfs_fhget(sb, rootfh, fsinfo->fattr); |
250 | if (!rooti) | ||
251 | return ERR_PTR(-ENOMEM); | ||
252 | return rooti; | ||
253 | } | 253 | } |
254 | 254 | ||
255 | /* | 255 | /* |
@@ -277,6 +277,10 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor) | |||
277 | 277 | ||
278 | sb->s_magic = NFS_SUPER_MAGIC; | 278 | sb->s_magic = NFS_SUPER_MAGIC; |
279 | 279 | ||
280 | server->io_stats = nfs_alloc_iostats(); | ||
281 | if (server->io_stats == NULL) | ||
282 | return -ENOMEM; | ||
283 | |||
280 | root_inode = nfs_get_root(sb, &server->fh, &fsinfo); | 284 | root_inode = nfs_get_root(sb, &server->fh, &fsinfo); |
281 | /* Did getting the root inode fail? */ | 285 | /* Did getting the root inode fail? */ |
282 | if (IS_ERR(root_inode)) { | 286 | if (IS_ERR(root_inode)) { |
@@ -290,6 +294,9 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor) | |||
290 | } | 294 | } |
291 | sb->s_root->d_op = server->rpc_ops->dentry_ops; | 295 | sb->s_root->d_op = server->rpc_ops->dentry_ops; |
292 | 296 | ||
297 | /* mount time stamp, in seconds */ | ||
298 | server->mount_time = jiffies; | ||
299 | |||
293 | /* Get some general file system info */ | 300 | /* Get some general file system info */ |
294 | if (server->namelen == 0 && | 301 | if (server->namelen == 0 && |
295 | server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0) | 302 | server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0) |
@@ -396,6 +403,9 @@ nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data) | |||
396 | 403 | ||
397 | nfs_init_timeout_values(&timeparms, proto, data->timeo, data->retrans); | 404 | nfs_init_timeout_values(&timeparms, proto, data->timeo, data->retrans); |
398 | 405 | ||
406 | server->retrans_timeo = timeparms.to_initval; | ||
407 | server->retrans_count = timeparms.to_retries; | ||
408 | |||
399 | /* create transport and client */ | 409 | /* create transport and client */ |
400 | xprt = xprt_create_proto(proto, &server->addr, &timeparms); | 410 | xprt = xprt_create_proto(proto, &server->addr, &timeparms); |
401 | if (IS_ERR(xprt)) { | 411 | if (IS_ERR(xprt)) { |
@@ -579,7 +589,7 @@ nfs_statfs(struct super_block *sb, struct kstatfs *buf) | |||
579 | 589 | ||
580 | } | 590 | } |
581 | 591 | ||
582 | static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) | 592 | static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, int showdefaults) |
583 | { | 593 | { |
584 | static struct proc_nfs_info { | 594 | static struct proc_nfs_info { |
585 | int flag; | 595 | int flag; |
@@ -588,28 +598,26 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
588 | } nfs_info[] = { | 598 | } nfs_info[] = { |
589 | { NFS_MOUNT_SOFT, ",soft", ",hard" }, | 599 | { NFS_MOUNT_SOFT, ",soft", ",hard" }, |
590 | { NFS_MOUNT_INTR, ",intr", "" }, | 600 | { NFS_MOUNT_INTR, ",intr", "" }, |
591 | { NFS_MOUNT_POSIX, ",posix", "" }, | ||
592 | { NFS_MOUNT_NOCTO, ",nocto", "" }, | 601 | { NFS_MOUNT_NOCTO, ",nocto", "" }, |
593 | { NFS_MOUNT_NOAC, ",noac", "" }, | 602 | { NFS_MOUNT_NOAC, ",noac", "" }, |
594 | { NFS_MOUNT_NONLM, ",nolock", ",lock" }, | 603 | { NFS_MOUNT_NONLM, ",nolock", "" }, |
595 | { NFS_MOUNT_NOACL, ",noacl", "" }, | 604 | { NFS_MOUNT_NOACL, ",noacl", "" }, |
596 | { 0, NULL, NULL } | 605 | { 0, NULL, NULL } |
597 | }; | 606 | }; |
598 | struct proc_nfs_info *nfs_infop; | 607 | struct proc_nfs_info *nfs_infop; |
599 | struct nfs_server *nfss = NFS_SB(mnt->mnt_sb); | ||
600 | char buf[12]; | 608 | char buf[12]; |
601 | char *proto; | 609 | char *proto; |
602 | 610 | ||
603 | seq_printf(m, ",v%d", nfss->rpc_ops->version); | 611 | seq_printf(m, ",vers=%d", nfss->rpc_ops->version); |
604 | seq_printf(m, ",rsize=%d", nfss->rsize); | 612 | seq_printf(m, ",rsize=%d", nfss->rsize); |
605 | seq_printf(m, ",wsize=%d", nfss->wsize); | 613 | seq_printf(m, ",wsize=%d", nfss->wsize); |
606 | if (nfss->acregmin != 3*HZ) | 614 | if (nfss->acregmin != 3*HZ || showdefaults) |
607 | seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ); | 615 | seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ); |
608 | if (nfss->acregmax != 60*HZ) | 616 | if (nfss->acregmax != 60*HZ || showdefaults) |
609 | seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ); | 617 | seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ); |
610 | if (nfss->acdirmin != 30*HZ) | 618 | if (nfss->acdirmin != 30*HZ || showdefaults) |
611 | seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ); | 619 | seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ); |
612 | if (nfss->acdirmax != 60*HZ) | 620 | if (nfss->acdirmax != 60*HZ || showdefaults) |
613 | seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ); | 621 | seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ); |
614 | for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) { | 622 | for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) { |
615 | if (nfss->flags & nfs_infop->flag) | 623 | if (nfss->flags & nfs_infop->flag) |
@@ -629,8 +637,96 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
629 | proto = buf; | 637 | proto = buf; |
630 | } | 638 | } |
631 | seq_printf(m, ",proto=%s", proto); | 639 | seq_printf(m, ",proto=%s", proto); |
640 | seq_printf(m, ",timeo=%lu", 10U * nfss->retrans_timeo / HZ); | ||
641 | seq_printf(m, ",retrans=%u", nfss->retrans_count); | ||
642 | } | ||
643 | |||
644 | static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) | ||
645 | { | ||
646 | struct nfs_server *nfss = NFS_SB(mnt->mnt_sb); | ||
647 | |||
648 | nfs_show_mount_options(m, nfss, 0); | ||
649 | |||
632 | seq_puts(m, ",addr="); | 650 | seq_puts(m, ",addr="); |
633 | seq_escape(m, nfss->hostname, " \t\n\\"); | 651 | seq_escape(m, nfss->hostname, " \t\n\\"); |
652 | |||
653 | return 0; | ||
654 | } | ||
655 | |||
656 | static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) | ||
657 | { | ||
658 | int i, cpu; | ||
659 | struct nfs_server *nfss = NFS_SB(mnt->mnt_sb); | ||
660 | struct rpc_auth *auth = nfss->client->cl_auth; | ||
661 | struct nfs_iostats totals = { }; | ||
662 | |||
663 | seq_printf(m, "statvers=%s", NFS_IOSTAT_VERS); | ||
664 | |||
665 | /* | ||
666 | * Display all mount option settings | ||
667 | */ | ||
668 | seq_printf(m, "\n\topts:\t"); | ||
669 | seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? "ro" : "rw"); | ||
670 | seq_puts(m, mnt->mnt_sb->s_flags & MS_SYNCHRONOUS ? ",sync" : ""); | ||
671 | seq_puts(m, mnt->mnt_sb->s_flags & MS_NOATIME ? ",noatime" : ""); | ||
672 | seq_puts(m, mnt->mnt_sb->s_flags & MS_NODIRATIME ? ",nodiratime" : ""); | ||
673 | nfs_show_mount_options(m, nfss, 1); | ||
674 | |||
675 | seq_printf(m, "\n\tage:\t%lu", (jiffies - nfss->mount_time) / HZ); | ||
676 | |||
677 | seq_printf(m, "\n\tcaps:\t"); | ||
678 | seq_printf(m, "caps=0x%x", nfss->caps); | ||
679 | seq_printf(m, ",wtmult=%d", nfss->wtmult); | ||
680 | seq_printf(m, ",dtsize=%d", nfss->dtsize); | ||
681 | seq_printf(m, ",bsize=%d", nfss->bsize); | ||
682 | seq_printf(m, ",namelen=%d", nfss->namelen); | ||
683 | |||
684 | #ifdef CONFIG_NFS_V4 | ||
685 | if (nfss->rpc_ops->version == 4) { | ||
686 | seq_printf(m, "\n\tnfsv4:\t"); | ||
687 | seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]); | ||
688 | seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]); | ||
689 | seq_printf(m, ",acl=0x%x", nfss->acl_bitmask); | ||
690 | } | ||
691 | #endif | ||
692 | |||
693 | /* | ||
694 | * Display security flavor in effect for this mount | ||
695 | */ | ||
696 | seq_printf(m, "\n\tsec:\tflavor=%d", auth->au_ops->au_flavor); | ||
697 | if (auth->au_flavor) | ||
698 | seq_printf(m, ",pseudoflavor=%d", auth->au_flavor); | ||
699 | |||
700 | /* | ||
701 | * Display superblock I/O counters | ||
702 | */ | ||
703 | for (cpu = 0; cpu < NR_CPUS; cpu++) { | ||
704 | struct nfs_iostats *stats; | ||
705 | |||
706 | if (!cpu_possible(cpu)) | ||
707 | continue; | ||
708 | |||
709 | preempt_disable(); | ||
710 | stats = per_cpu_ptr(nfss->io_stats, cpu); | ||
711 | |||
712 | for (i = 0; i < __NFSIOS_COUNTSMAX; i++) | ||
713 | totals.events[i] += stats->events[i]; | ||
714 | for (i = 0; i < __NFSIOS_BYTESMAX; i++) | ||
715 | totals.bytes[i] += stats->bytes[i]; | ||
716 | |||
717 | preempt_enable(); | ||
718 | } | ||
719 | |||
720 | seq_printf(m, "\n\tevents:\t"); | ||
721 | for (i = 0; i < __NFSIOS_COUNTSMAX; i++) | ||
722 | seq_printf(m, "%lu ", totals.events[i]); | ||
723 | seq_printf(m, "\n\tbytes:\t"); | ||
724 | for (i = 0; i < __NFSIOS_BYTESMAX; i++) | ||
725 | seq_printf(m, "%Lu ", totals.bytes[i]); | ||
726 | seq_printf(m, "\n"); | ||
727 | |||
728 | rpc_print_iostats(m, nfss->client); | ||
729 | |||
634 | return 0; | 730 | return 0; |
635 | } | 731 | } |
636 | 732 | ||
@@ -660,6 +756,8 @@ static void nfs_zap_caches_locked(struct inode *inode) | |||
660 | struct nfs_inode *nfsi = NFS_I(inode); | 756 | struct nfs_inode *nfsi = NFS_I(inode); |
661 | int mode = inode->i_mode; | 757 | int mode = inode->i_mode; |
662 | 758 | ||
759 | nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); | ||
760 | |||
663 | NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); | 761 | NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); |
664 | NFS_ATTRTIMEO_UPDATE(inode) = jiffies; | 762 | NFS_ATTRTIMEO_UPDATE(inode) = jiffies; |
665 | 763 | ||
@@ -751,7 +849,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
751 | .fh = fh, | 849 | .fh = fh, |
752 | .fattr = fattr | 850 | .fattr = fattr |
753 | }; | 851 | }; |
754 | struct inode *inode = NULL; | 852 | struct inode *inode = ERR_PTR(-ENOENT); |
755 | unsigned long hash; | 853 | unsigned long hash; |
756 | 854 | ||
757 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) | 855 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) |
@@ -764,8 +862,11 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
764 | 862 | ||
765 | hash = nfs_fattr_to_ino_t(fattr); | 863 | hash = nfs_fattr_to_ino_t(fattr); |
766 | 864 | ||
767 | if (!(inode = iget5_locked(sb, hash, nfs_find_actor, nfs_init_locked, &desc))) | 865 | inode = iget5_locked(sb, hash, nfs_find_actor, nfs_init_locked, &desc); |
866 | if (inode == NULL) { | ||
867 | inode = ERR_PTR(-ENOMEM); | ||
768 | goto out_no_inode; | 868 | goto out_no_inode; |
869 | } | ||
769 | 870 | ||
770 | if (inode->i_state & I_NEW) { | 871 | if (inode->i_state & I_NEW) { |
771 | struct nfs_inode *nfsi = NFS_I(inode); | 872 | struct nfs_inode *nfsi = NFS_I(inode); |
@@ -834,7 +935,7 @@ out: | |||
834 | return inode; | 935 | return inode; |
835 | 936 | ||
836 | out_no_inode: | 937 | out_no_inode: |
837 | printk("nfs_fhget: iget failed\n"); | 938 | dprintk("nfs_fhget: iget failed with error %ld\n", PTR_ERR(inode)); |
838 | goto out; | 939 | goto out; |
839 | } | 940 | } |
840 | 941 | ||
@@ -847,6 +948,8 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
847 | struct nfs_fattr fattr; | 948 | struct nfs_fattr fattr; |
848 | int error; | 949 | int error; |
849 | 950 | ||
951 | nfs_inc_stats(inode, NFSIOS_VFSSETATTR); | ||
952 | |||
850 | if (attr->ia_valid & ATTR_SIZE) { | 953 | if (attr->ia_valid & ATTR_SIZE) { |
851 | if (!S_ISREG(inode->i_mode) || attr->ia_size == i_size_read(inode)) | 954 | if (!S_ISREG(inode->i_mode) || attr->ia_size == i_size_read(inode)) |
852 | attr->ia_valid &= ~ATTR_SIZE; | 955 | attr->ia_valid &= ~ATTR_SIZE; |
@@ -859,11 +962,9 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
859 | 962 | ||
860 | lock_kernel(); | 963 | lock_kernel(); |
861 | nfs_begin_data_update(inode); | 964 | nfs_begin_data_update(inode); |
862 | /* Write all dirty data if we're changing file permissions or size */ | 965 | /* Write all dirty data */ |
863 | if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE)) != 0) { | 966 | filemap_write_and_wait(inode->i_mapping); |
864 | filemap_write_and_wait(inode->i_mapping); | 967 | nfs_wb_all(inode); |
865 | nfs_wb_all(inode); | ||
866 | } | ||
867 | /* | 968 | /* |
868 | * Return any delegations if we're going to change ACLs | 969 | * Return any delegations if we're going to change ACLs |
869 | */ | 970 | */ |
@@ -902,6 +1003,7 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr) | |||
902 | spin_unlock(&inode->i_lock); | 1003 | spin_unlock(&inode->i_lock); |
903 | } | 1004 | } |
904 | if ((attr->ia_valid & ATTR_SIZE) != 0) { | 1005 | if ((attr->ia_valid & ATTR_SIZE) != 0) { |
1006 | nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC); | ||
905 | inode->i_size = attr->ia_size; | 1007 | inode->i_size = attr->ia_size; |
906 | vmtruncate(inode, attr->ia_size); | 1008 | vmtruncate(inode, attr->ia_size); |
907 | } | 1009 | } |
@@ -949,7 +1051,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
949 | int err; | 1051 | int err; |
950 | 1052 | ||
951 | /* Flush out writes to the server in order to update c/mtime */ | 1053 | /* Flush out writes to the server in order to update c/mtime */ |
952 | nfs_sync_inode(inode, 0, 0, FLUSH_WAIT|FLUSH_NOCOMMIT); | 1054 | nfs_sync_inode_wait(inode, 0, 0, FLUSH_NOCOMMIT); |
953 | 1055 | ||
954 | /* | 1056 | /* |
955 | * We may force a getattr if the user cares about atime. | 1057 | * We may force a getattr if the user cares about atime. |
@@ -973,7 +1075,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
973 | return err; | 1075 | return err; |
974 | } | 1076 | } |
975 | 1077 | ||
976 | struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rpc_cred *cred) | 1078 | static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, struct dentry *dentry, struct rpc_cred *cred) |
977 | { | 1079 | { |
978 | struct nfs_open_context *ctx; | 1080 | struct nfs_open_context *ctx; |
979 | 1081 | ||
@@ -981,6 +1083,7 @@ struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rp | |||
981 | if (ctx != NULL) { | 1083 | if (ctx != NULL) { |
982 | atomic_set(&ctx->count, 1); | 1084 | atomic_set(&ctx->count, 1); |
983 | ctx->dentry = dget(dentry); | 1085 | ctx->dentry = dget(dentry); |
1086 | ctx->vfsmnt = mntget(mnt); | ||
984 | ctx->cred = get_rpccred(cred); | 1087 | ctx->cred = get_rpccred(cred); |
985 | ctx->state = NULL; | 1088 | ctx->state = NULL; |
986 | ctx->lockowner = current->files; | 1089 | ctx->lockowner = current->files; |
@@ -1011,6 +1114,7 @@ void put_nfs_open_context(struct nfs_open_context *ctx) | |||
1011 | if (ctx->cred != NULL) | 1114 | if (ctx->cred != NULL) |
1012 | put_rpccred(ctx->cred); | 1115 | put_rpccred(ctx->cred); |
1013 | dput(ctx->dentry); | 1116 | dput(ctx->dentry); |
1117 | mntput(ctx->vfsmnt); | ||
1014 | kfree(ctx); | 1118 | kfree(ctx); |
1015 | } | 1119 | } |
1016 | } | 1120 | } |
@@ -1019,7 +1123,7 @@ void put_nfs_open_context(struct nfs_open_context *ctx) | |||
1019 | * Ensure that mmap has a recent RPC credential for use when writing out | 1123 | * Ensure that mmap has a recent RPC credential for use when writing out |
1020 | * shared pages | 1124 | * shared pages |
1021 | */ | 1125 | */ |
1022 | void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx) | 1126 | static void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx) |
1023 | { | 1127 | { |
1024 | struct inode *inode = filp->f_dentry->d_inode; | 1128 | struct inode *inode = filp->f_dentry->d_inode; |
1025 | struct nfs_inode *nfsi = NFS_I(inode); | 1129 | struct nfs_inode *nfsi = NFS_I(inode); |
@@ -1051,7 +1155,7 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_c | |||
1051 | return ctx; | 1155 | return ctx; |
1052 | } | 1156 | } |
1053 | 1157 | ||
1054 | void nfs_file_clear_open_context(struct file *filp) | 1158 | static void nfs_file_clear_open_context(struct file *filp) |
1055 | { | 1159 | { |
1056 | struct inode *inode = filp->f_dentry->d_inode; | 1160 | struct inode *inode = filp->f_dentry->d_inode; |
1057 | struct nfs_open_context *ctx = (struct nfs_open_context *)filp->private_data; | 1161 | struct nfs_open_context *ctx = (struct nfs_open_context *)filp->private_data; |
@@ -1076,7 +1180,7 @@ int nfs_open(struct inode *inode, struct file *filp) | |||
1076 | cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); | 1180 | cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); |
1077 | if (IS_ERR(cred)) | 1181 | if (IS_ERR(cred)) |
1078 | return PTR_ERR(cred); | 1182 | return PTR_ERR(cred); |
1079 | ctx = alloc_nfs_open_context(filp->f_dentry, cred); | 1183 | ctx = alloc_nfs_open_context(filp->f_vfsmnt, filp->f_dentry, cred); |
1080 | put_rpccred(cred); | 1184 | put_rpccred(cred); |
1081 | if (ctx == NULL) | 1185 | if (ctx == NULL) |
1082 | return -ENOMEM; | 1186 | return -ENOMEM; |
@@ -1185,6 +1289,7 @@ int nfs_attribute_timeout(struct inode *inode) | |||
1185 | */ | 1289 | */ |
1186 | int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | 1290 | int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) |
1187 | { | 1291 | { |
1292 | nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE); | ||
1188 | if (!(NFS_I(inode)->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA)) | 1293 | if (!(NFS_I(inode)->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA)) |
1189 | && !nfs_attribute_timeout(inode)) | 1294 | && !nfs_attribute_timeout(inode)) |
1190 | return NFS_STALE(inode) ? -ESTALE : 0; | 1295 | return NFS_STALE(inode) ? -ESTALE : 0; |
@@ -1201,6 +1306,7 @@ void nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) | |||
1201 | struct nfs_inode *nfsi = NFS_I(inode); | 1306 | struct nfs_inode *nfsi = NFS_I(inode); |
1202 | 1307 | ||
1203 | if (nfsi->cache_validity & NFS_INO_INVALID_DATA) { | 1308 | if (nfsi->cache_validity & NFS_INO_INVALID_DATA) { |
1309 | nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE); | ||
1204 | if (S_ISREG(inode->i_mode)) | 1310 | if (S_ISREG(inode->i_mode)) |
1205 | nfs_sync_mapping(mapping); | 1311 | nfs_sync_mapping(mapping); |
1206 | invalidate_inode_pages2(mapping); | 1312 | invalidate_inode_pages2(mapping); |
@@ -1299,39 +1405,37 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat | |||
1299 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) | 1405 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) |
1300 | return 0; | 1406 | return 0; |
1301 | 1407 | ||
1408 | /* Has the inode gone and changed behind our back? */ | ||
1409 | if (nfsi->fileid != fattr->fileid | ||
1410 | || (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) { | ||
1411 | return -EIO; | ||
1412 | } | ||
1413 | |||
1302 | /* Are we in the process of updating data on the server? */ | 1414 | /* Are we in the process of updating data on the server? */ |
1303 | data_unstable = nfs_caches_unstable(inode); | 1415 | data_unstable = nfs_caches_unstable(inode); |
1304 | 1416 | ||
1305 | /* Do atomic weak cache consistency updates */ | 1417 | /* Do atomic weak cache consistency updates */ |
1306 | nfs_wcc_update_inode(inode, fattr); | 1418 | nfs_wcc_update_inode(inode, fattr); |
1307 | 1419 | ||
1308 | if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 && | 1420 | if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0) { |
1309 | nfsi->change_attr != fattr->change_attr) { | 1421 | if (nfsi->change_attr == fattr->change_attr) |
1422 | goto out; | ||
1310 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; | 1423 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; |
1311 | if (!data_unstable) | 1424 | if (!data_unstable) |
1312 | nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE; | 1425 | nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE; |
1313 | } | 1426 | } |
1314 | 1427 | ||
1315 | /* Has the inode gone and changed behind our back? */ | ||
1316 | if (nfsi->fileid != fattr->fileid | ||
1317 | || (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) { | ||
1318 | return -EIO; | ||
1319 | } | ||
1320 | |||
1321 | cur_size = i_size_read(inode); | ||
1322 | new_isize = nfs_size_to_loff_t(fattr->size); | ||
1323 | |||
1324 | /* Verify a few of the more important attributes */ | 1428 | /* Verify a few of the more important attributes */ |
1325 | if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { | 1429 | if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { |
1326 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; | 1430 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; |
1327 | if (!data_unstable) | 1431 | if (!data_unstable) |
1328 | nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE; | 1432 | nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE; |
1329 | } | 1433 | } |
1330 | if (cur_size != new_isize) { | 1434 | |
1331 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; | 1435 | cur_size = i_size_read(inode); |
1332 | if (nfsi->npages == 0) | 1436 | new_isize = nfs_size_to_loff_t(fattr->size); |
1333 | nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE; | 1437 | if (cur_size != new_isize && nfsi->npages == 0) |
1334 | } | 1438 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; |
1335 | 1439 | ||
1336 | /* Have any file permissions changed? */ | 1440 | /* Have any file permissions changed? */ |
1337 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) | 1441 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) |
@@ -1343,6 +1447,7 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat | |||
1343 | if (inode->i_nlink != fattr->nlink) | 1447 | if (inode->i_nlink != fattr->nlink) |
1344 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; | 1448 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; |
1345 | 1449 | ||
1450 | out: | ||
1346 | if (!timespec_equal(&inode->i_atime, &fattr->atime)) | 1451 | if (!timespec_equal(&inode->i_atime, &fattr->atime)) |
1347 | nfsi->cache_validity |= NFS_INO_INVALID_ATIME; | 1452 | nfsi->cache_validity |= NFS_INO_INVALID_ATIME; |
1348 | 1453 | ||
@@ -1481,15 +1586,6 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1481 | nfsi->cache_change_attribute = jiffies; | 1586 | nfsi->cache_change_attribute = jiffies; |
1482 | } | 1587 | } |
1483 | 1588 | ||
1484 | if ((fattr->valid & NFS_ATTR_FATTR_V4) | ||
1485 | && nfsi->change_attr != fattr->change_attr) { | ||
1486 | dprintk("NFS: change_attr change on server for file %s/%ld\n", | ||
1487 | inode->i_sb->s_id, inode->i_ino); | ||
1488 | nfsi->change_attr = fattr->change_attr; | ||
1489 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | ||
1490 | nfsi->cache_change_attribute = jiffies; | ||
1491 | } | ||
1492 | |||
1493 | /* If ctime has changed we should definitely clear access+acl caches */ | 1589 | /* If ctime has changed we should definitely clear access+acl caches */ |
1494 | if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) { | 1590 | if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) { |
1495 | invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | 1591 | invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
@@ -1519,8 +1615,20 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1519 | inode->i_blksize = fattr->du.nfs2.blocksize; | 1615 | inode->i_blksize = fattr->du.nfs2.blocksize; |
1520 | } | 1616 | } |
1521 | 1617 | ||
1618 | if ((fattr->valid & NFS_ATTR_FATTR_V4)) { | ||
1619 | if (nfsi->change_attr != fattr->change_attr) { | ||
1620 | dprintk("NFS: change_attr change on server for file %s/%ld\n", | ||
1621 | inode->i_sb->s_id, inode->i_ino); | ||
1622 | nfsi->change_attr = fattr->change_attr; | ||
1623 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | ||
1624 | nfsi->cache_change_attribute = jiffies; | ||
1625 | } else | ||
1626 | invalid &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA); | ||
1627 | } | ||
1628 | |||
1522 | /* Update attrtimeo value if we're out of the unstable period */ | 1629 | /* Update attrtimeo value if we're out of the unstable period */ |
1523 | if (invalid & NFS_INO_INVALID_ATTR) { | 1630 | if (invalid & NFS_INO_INVALID_ATTR) { |
1631 | nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); | ||
1524 | nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); | 1632 | nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); |
1525 | nfsi->attrtimeo_timestamp = jiffies; | 1633 | nfsi->attrtimeo_timestamp = jiffies; |
1526 | } else if (time_after(jiffies, nfsi->attrtimeo_timestamp+nfsi->attrtimeo)) { | 1634 | } else if (time_after(jiffies, nfsi->attrtimeo_timestamp+nfsi->attrtimeo)) { |
@@ -1637,10 +1745,9 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type, | |||
1637 | #endif /* CONFIG_NFS_V3 */ | 1745 | #endif /* CONFIG_NFS_V3 */ |
1638 | 1746 | ||
1639 | s = ERR_PTR(-ENOMEM); | 1747 | s = ERR_PTR(-ENOMEM); |
1640 | server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL); | 1748 | server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL); |
1641 | if (!server) | 1749 | if (!server) |
1642 | goto out_err; | 1750 | goto out_err; |
1643 | memset(server, 0, sizeof(struct nfs_server)); | ||
1644 | /* Zero out the NFS state stuff */ | 1751 | /* Zero out the NFS state stuff */ |
1645 | init_nfsv4_state(server); | 1752 | init_nfsv4_state(server); |
1646 | server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); | 1753 | server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); |
@@ -1712,6 +1819,7 @@ static void nfs_kill_super(struct super_block *s) | |||
1712 | 1819 | ||
1713 | rpciod_down(); /* release rpciod */ | 1820 | rpciod_down(); /* release rpciod */ |
1714 | 1821 | ||
1822 | nfs_free_iostats(server->io_stats); | ||
1715 | kfree(server->hostname); | 1823 | kfree(server->hostname); |
1716 | kfree(server); | 1824 | kfree(server); |
1717 | } | 1825 | } |
@@ -1738,6 +1846,7 @@ static struct super_operations nfs4_sops = { | |||
1738 | .clear_inode = nfs4_clear_inode, | 1846 | .clear_inode = nfs4_clear_inode, |
1739 | .umount_begin = nfs_umount_begin, | 1847 | .umount_begin = nfs_umount_begin, |
1740 | .show_options = nfs_show_options, | 1848 | .show_options = nfs_show_options, |
1849 | .show_stats = nfs_show_stats, | ||
1741 | }; | 1850 | }; |
1742 | 1851 | ||
1743 | /* | 1852 | /* |
@@ -1800,6 +1909,9 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, | |||
1800 | 1909 | ||
1801 | nfs_init_timeout_values(&timeparms, data->proto, data->timeo, data->retrans); | 1910 | nfs_init_timeout_values(&timeparms, data->proto, data->timeo, data->retrans); |
1802 | 1911 | ||
1912 | server->retrans_timeo = timeparms.to_initval; | ||
1913 | server->retrans_count = timeparms.to_retries; | ||
1914 | |||
1803 | clp = nfs4_get_client(&server->addr.sin_addr); | 1915 | clp = nfs4_get_client(&server->addr.sin_addr); |
1804 | if (!clp) { | 1916 | if (!clp) { |
1805 | dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__); | 1917 | dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__); |
@@ -1941,10 +2053,9 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, | |||
1941 | return ERR_PTR(-EINVAL); | 2053 | return ERR_PTR(-EINVAL); |
1942 | } | 2054 | } |
1943 | 2055 | ||
1944 | server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL); | 2056 | server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL); |
1945 | if (!server) | 2057 | if (!server) |
1946 | return ERR_PTR(-ENOMEM); | 2058 | return ERR_PTR(-ENOMEM); |
1947 | memset(server, 0, sizeof(struct nfs_server)); | ||
1948 | /* Zero out the NFS state stuff */ | 2059 | /* Zero out the NFS state stuff */ |
1949 | init_nfsv4_state(server); | 2060 | init_nfsv4_state(server); |
1950 | server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); | 2061 | server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); |
@@ -2024,10 +2135,12 @@ static void nfs4_kill_super(struct super_block *sb) | |||
2024 | 2135 | ||
2025 | if (server->client != NULL && !IS_ERR(server->client)) | 2136 | if (server->client != NULL && !IS_ERR(server->client)) |
2026 | rpc_shutdown_client(server->client); | 2137 | rpc_shutdown_client(server->client); |
2027 | rpciod_down(); /* release rpciod */ | ||
2028 | 2138 | ||
2029 | destroy_nfsv4_state(server); | 2139 | destroy_nfsv4_state(server); |
2030 | 2140 | ||
2141 | rpciod_down(); | ||
2142 | |||
2143 | nfs_free_iostats(server->io_stats); | ||
2031 | kfree(server->hostname); | 2144 | kfree(server->hostname); |
2032 | kfree(server); | 2145 | kfree(server); |
2033 | } | 2146 | } |