aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2009-03-11 14:10:24 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2009-03-11 14:10:24 -0400
commit9e6e70f8d8b6698e0017c56b86525aabe9c7cd4c (patch)
tree3364c61dc3fdb1cc69b18e0cf16947abc49c0be5
parent78f945f88ef83dcc7c962614a080e0a9a2db5889 (diff)
NFSv4: Support NFSv4 optional attributes in the struct nfs_fattr
Currently, filling struct nfs_fattr is more or less an all or nothing operation, since NFSv2 and NFSv3 have only mandatory attributes. In NFSv4, some attributes are optional, and so we may simply not be able to fill in those fields. Furthermore, NFSv4 allows you to specify which attributes you are interested in retrieving, thus permitting you to optimise away retrieval of attributes that you know will no change... Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/inode.c243
-rw-r--r--fs/nfs/nfs2xdr.c2
-rw-r--r--fs/nfs/nfs3xdr.c6
-rw-r--r--fs/nfs/nfs4xdr.c6
-rw-r--r--include/linux/nfs_xdr.h48
5 files changed, 202 insertions, 103 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 268ce3a46220..b7656bd3706f 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -249,13 +249,10 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
249 struct inode *inode = ERR_PTR(-ENOENT); 249 struct inode *inode = ERR_PTR(-ENOENT);
250 unsigned long hash; 250 unsigned long hash;
251 251
252 if ((fattr->valid & NFS_ATTR_FATTR) == 0) 252 if ((fattr->valid & NFS_ATTR_FATTR_FILEID) == 0)
253 goto out_no_inode; 253 goto out_no_inode;
254 254 if ((fattr->valid & NFS_ATTR_FATTR_TYPE) == 0)
255 if (!fattr->nlink) {
256 printk("NFS: Buggy server - nlink == 0!\n");
257 goto out_no_inode; 255 goto out_no_inode;
258 }
259 256
260 hash = nfs_fattr_to_ino_t(fattr); 257 hash = nfs_fattr_to_ino_t(fattr);
261 258
@@ -291,7 +288,8 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
291 && fattr->size <= NFS_LIMIT_READDIRPLUS) 288 && fattr->size <= NFS_LIMIT_READDIRPLUS)
292 set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); 289 set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags);
293 /* Deal with crossing mountpoints */ 290 /* Deal with crossing mountpoints */
294 if (!nfs_fsid_equal(&NFS_SB(sb)->fsid, &fattr->fsid)) { 291 if ((fattr->valid & NFS_ATTR_FATTR_FSID)
292 && !nfs_fsid_equal(&NFS_SB(sb)->fsid, &fattr->fsid)) {
295 if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) 293 if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
296 inode->i_op = &nfs_referral_inode_operations; 294 inode->i_op = &nfs_referral_inode_operations;
297 else 295 else
@@ -304,28 +302,45 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
304 else 302 else
305 init_special_inode(inode, inode->i_mode, fattr->rdev); 303 init_special_inode(inode, inode->i_mode, fattr->rdev);
306 304
305 memset(&inode->i_atime, 0, sizeof(inode->i_atime));
306 memset(&inode->i_mtime, 0, sizeof(inode->i_mtime));
307 memset(&inode->i_ctime, 0, sizeof(inode->i_ctime));
308 nfsi->change_attr = 0;
309 inode->i_size = 0;
310 inode->i_nlink = 0;
311 inode->i_uid = -2;
312 inode->i_gid = -2;
313 inode->i_blocks = 0;
314 memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
315
307 nfsi->read_cache_jiffies = fattr->time_start; 316 nfsi->read_cache_jiffies = fattr->time_start;
308 nfsi->attr_gencount = fattr->gencount; 317 nfsi->attr_gencount = fattr->gencount;
309 inode->i_atime = fattr->atime; 318 if (fattr->valid & NFS_ATTR_FATTR_ATIME)
310 inode->i_mtime = fattr->mtime; 319 inode->i_atime = fattr->atime;
311 inode->i_ctime = fattr->ctime; 320 if (fattr->valid & NFS_ATTR_FATTR_MTIME)
312 if (fattr->valid & NFS_ATTR_FATTR_V4) 321 inode->i_mtime = fattr->mtime;
322 if (fattr->valid & NFS_ATTR_FATTR_CTIME)
323 inode->i_ctime = fattr->ctime;
324 if (fattr->valid & NFS_ATTR_FATTR_CHANGE)
313 nfsi->change_attr = fattr->change_attr; 325 nfsi->change_attr = fattr->change_attr;
314 inode->i_size = nfs_size_to_loff_t(fattr->size); 326 if (fattr->valid & NFS_ATTR_FATTR_SIZE)
315 inode->i_nlink = fattr->nlink; 327 inode->i_size = nfs_size_to_loff_t(fattr->size);
316 inode->i_uid = fattr->uid; 328 if (fattr->valid & NFS_ATTR_FATTR_NLINK)
317 inode->i_gid = fattr->gid; 329 inode->i_nlink = fattr->nlink;
318 if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) { 330 if (fattr->valid & NFS_ATTR_FATTR_OWNER)
331 inode->i_uid = fattr->uid;
332 if (fattr->valid & NFS_ATTR_FATTR_GROUP)
333 inode->i_gid = fattr->gid;
334 if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
335 inode->i_blocks = fattr->du.nfs2.blocks;
336 if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
319 /* 337 /*
320 * report the blocks in 512byte units 338 * report the blocks in 512byte units
321 */ 339 */
322 inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used); 340 inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
323 } else {
324 inode->i_blocks = fattr->du.nfs2.blocks;
325 } 341 }
326 nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); 342 nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
327 nfsi->attrtimeo_timestamp = now; 343 nfsi->attrtimeo_timestamp = now;
328 memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
329 nfsi->access_cache = RB_ROOT; 344 nfsi->access_cache = RB_ROOT;
330 345
331 unlock_new_inode(inode); 346 unlock_new_inode(inode);
@@ -812,25 +827,31 @@ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
812{ 827{
813 struct nfs_inode *nfsi = NFS_I(inode); 828 struct nfs_inode *nfsi = NFS_I(inode);
814 829
815 if ((fattr->valid & NFS_ATTR_WCC_V4) != 0 && 830 if ((fattr->valid & NFS_ATTR_FATTR_PRECHANGE)
816 nfsi->change_attr == fattr->pre_change_attr) { 831 && (fattr->valid & NFS_ATTR_FATTR_CHANGE)
832 && nfsi->change_attr == fattr->pre_change_attr) {
817 nfsi->change_attr = fattr->change_attr; 833 nfsi->change_attr = fattr->change_attr;
818 if (S_ISDIR(inode->i_mode)) 834 if (S_ISDIR(inode->i_mode))
819 nfsi->cache_validity |= NFS_INO_INVALID_DATA; 835 nfsi->cache_validity |= NFS_INO_INVALID_DATA;
820 } 836 }
821 /* If we have atomic WCC data, we may update some attributes */ 837 /* If we have atomic WCC data, we may update some attributes */
822 if ((fattr->valid & NFS_ATTR_WCC) != 0) { 838 if ((fattr->valid & NFS_ATTR_FATTR_PRECTIME)
823 if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) 839 && (fattr->valid & NFS_ATTR_FATTR_CTIME)
840 && timespec_equal(&inode->i_ctime, &fattr->pre_ctime))
824 memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); 841 memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
825 if (timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) { 842
843 if ((fattr->valid & NFS_ATTR_FATTR_PREMTIME)
844 && (fattr->valid & NFS_ATTR_FATTR_MTIME)
845 && timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) {
826 memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); 846 memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
827 if (S_ISDIR(inode->i_mode)) 847 if (S_ISDIR(inode->i_mode))
828 nfsi->cache_validity |= NFS_INO_INVALID_DATA; 848 nfsi->cache_validity |= NFS_INO_INVALID_DATA;
829 }
830 if (i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size) &&
831 nfsi->npages == 0)
832 i_size_write(inode, nfs_size_to_loff_t(fattr->size));
833 } 849 }
850 if ((fattr->valid & NFS_ATTR_FATTR_PRESIZE)
851 && (fattr->valid & NFS_ATTR_FATTR_SIZE)
852 && i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size)
853 && nfsi->npages == 0)
854 i_size_write(inode, nfs_size_to_loff_t(fattr->size));
834} 855}
835 856
836/** 857/**
@@ -850,35 +871,39 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
850 871
851 872
852 /* Has the inode gone and changed behind our back? */ 873 /* Has the inode gone and changed behind our back? */
853 if (nfsi->fileid != fattr->fileid 874 if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid)
854 || (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) { 875 return -EIO;
876 if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
855 return -EIO; 877 return -EIO;
856 }
857 878
858 if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 && 879 if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 &&
859 nfsi->change_attr != fattr->change_attr) 880 nfsi->change_attr != fattr->change_attr)
860 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; 881 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
861 882
862 /* Verify a few of the more important attributes */ 883 /* Verify a few of the more important attributes */
863 if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) 884 if ((fattr->valid & NFS_ATTR_FATTR_MTIME) && !timespec_equal(&inode->i_mtime, &fattr->mtime))
864 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; 885 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
865 886
866 cur_size = i_size_read(inode); 887 if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
867 new_isize = nfs_size_to_loff_t(fattr->size); 888 cur_size = i_size_read(inode);
868 if (cur_size != new_isize && nfsi->npages == 0) 889 new_isize = nfs_size_to_loff_t(fattr->size);
869 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; 890 if (cur_size != new_isize && nfsi->npages == 0)
891 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
892 }
870 893
871 /* Have any file permissions changed? */ 894 /* Have any file permissions changed? */
872 if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) 895 if ((fattr->valid & NFS_ATTR_FATTR_MODE) && (inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO))
873 || inode->i_uid != fattr->uid 896 invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
874 || inode->i_gid != fattr->gid) 897 if ((fattr->valid & NFS_ATTR_FATTR_OWNER) && inode->i_uid != fattr->uid)
898 invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
899 if ((fattr->valid & NFS_ATTR_FATTR_GROUP) && inode->i_gid != fattr->gid)
875 invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL; 900 invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
876 901
877 /* Has the link count changed? */ 902 /* Has the link count changed? */
878 if (inode->i_nlink != fattr->nlink) 903 if ((fattr->valid & NFS_ATTR_FATTR_NLINK) && inode->i_nlink != fattr->nlink)
879 invalid |= NFS_INO_INVALID_ATTR; 904 invalid |= NFS_INO_INVALID_ATTR;
880 905
881 if (!timespec_equal(&inode->i_atime, &fattr->atime)) 906 if ((fattr->valid & NFS_ATTR_FATTR_ATIME) && !timespec_equal(&inode->i_atime, &fattr->atime))
882 invalid |= NFS_INO_INVALID_ATIME; 907 invalid |= NFS_INO_INVALID_ATIME;
883 908
884 if (invalid != 0) 909 if (invalid != 0)
@@ -890,11 +915,15 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
890 915
891static int nfs_ctime_need_update(const struct inode *inode, const struct nfs_fattr *fattr) 916static int nfs_ctime_need_update(const struct inode *inode, const struct nfs_fattr *fattr)
892{ 917{
918 if (!(fattr->valid & NFS_ATTR_FATTR_CTIME))
919 return 0;
893 return timespec_compare(&fattr->ctime, &inode->i_ctime) > 0; 920 return timespec_compare(&fattr->ctime, &inode->i_ctime) > 0;
894} 921}
895 922
896static int nfs_size_need_update(const struct inode *inode, const struct nfs_fattr *fattr) 923static int nfs_size_need_update(const struct inode *inode, const struct nfs_fattr *fattr)
897{ 924{
925 if (!(fattr->valid & NFS_ATTR_FATTR_SIZE))
926 return 0;
898 return nfs_size_to_loff_t(fattr->size) > i_size_read(inode); 927 return nfs_size_to_loff_t(fattr->size) > i_size_read(inode);
899} 928}
900 929
@@ -1030,20 +1059,31 @@ int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fa
1030 /* Don't do a WCC update if these attributes are already stale */ 1059 /* Don't do a WCC update if these attributes are already stale */
1031 if ((fattr->valid & NFS_ATTR_FATTR) == 0 || 1060 if ((fattr->valid & NFS_ATTR_FATTR) == 0 ||
1032 !nfs_inode_attrs_need_update(inode, fattr)) { 1061 !nfs_inode_attrs_need_update(inode, fattr)) {
1033 fattr->valid &= ~(NFS_ATTR_WCC_V4|NFS_ATTR_WCC); 1062 fattr->valid &= ~(NFS_ATTR_FATTR_PRECHANGE
1063 | NFS_ATTR_FATTR_PRESIZE
1064 | NFS_ATTR_FATTR_PREMTIME
1065 | NFS_ATTR_FATTR_PRECTIME);
1034 goto out_noforce; 1066 goto out_noforce;
1035 } 1067 }
1036 if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 && 1068 if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 &&
1037 (fattr->valid & NFS_ATTR_WCC_V4) == 0) { 1069 (fattr->valid & NFS_ATTR_FATTR_PRECHANGE) == 0) {
1038 fattr->pre_change_attr = NFS_I(inode)->change_attr; 1070 fattr->pre_change_attr = NFS_I(inode)->change_attr;
1039 fattr->valid |= NFS_ATTR_WCC_V4; 1071 fattr->valid |= NFS_ATTR_FATTR_PRECHANGE;
1040 } 1072 }
1041 if ((fattr->valid & NFS_ATTR_FATTR) != 0 && 1073 if ((fattr->valid & NFS_ATTR_FATTR_CTIME) != 0 &&
1042 (fattr->valid & NFS_ATTR_WCC) == 0) { 1074 (fattr->valid & NFS_ATTR_FATTR_PRECTIME) == 0) {
1043 memcpy(&fattr->pre_ctime, &inode->i_ctime, sizeof(fattr->pre_ctime)); 1075 memcpy(&fattr->pre_ctime, &inode->i_ctime, sizeof(fattr->pre_ctime));
1076 fattr->valid |= NFS_ATTR_FATTR_PRECTIME;
1077 }
1078 if ((fattr->valid & NFS_ATTR_FATTR_MTIME) != 0 &&
1079 (fattr->valid & NFS_ATTR_FATTR_PREMTIME) == 0) {
1044 memcpy(&fattr->pre_mtime, &inode->i_mtime, sizeof(fattr->pre_mtime)); 1080 memcpy(&fattr->pre_mtime, &inode->i_mtime, sizeof(fattr->pre_mtime));
1081 fattr->valid |= NFS_ATTR_FATTR_PREMTIME;
1082 }
1083 if ((fattr->valid & NFS_ATTR_FATTR_SIZE) != 0 &&
1084 (fattr->valid & NFS_ATTR_FATTR_PRESIZE) == 0) {
1045 fattr->pre_size = i_size_read(inode); 1085 fattr->pre_size = i_size_read(inode);
1046 fattr->valid |= NFS_ATTR_WCC; 1086 fattr->valid |= NFS_ATTR_FATTR_PRESIZE;
1047 } 1087 }
1048out_noforce: 1088out_noforce:
1049 status = nfs_post_op_update_inode_locked(inode, fattr); 1089 status = nfs_post_op_update_inode_locked(inode, fattr);
@@ -1075,18 +1115,18 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
1075 __func__, inode->i_sb->s_id, inode->i_ino, 1115 __func__, inode->i_sb->s_id, inode->i_ino,
1076 atomic_read(&inode->i_count), fattr->valid); 1116 atomic_read(&inode->i_count), fattr->valid);
1077 1117
1078 if (nfsi->fileid != fattr->fileid) 1118 if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid)
1079 goto out_fileid; 1119 goto out_fileid;
1080 1120
1081 /* 1121 /*
1082 * Make sure the inode's type hasn't changed. 1122 * Make sure the inode's type hasn't changed.
1083 */ 1123 */
1084 if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) 1124 if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
1085 goto out_changed; 1125 goto out_changed;
1086 1126
1087 server = NFS_SERVER(inode); 1127 server = NFS_SERVER(inode);
1088 /* Update the fsid? */ 1128 /* Update the fsid? */
1089 if (S_ISDIR(inode->i_mode) && 1129 if (S_ISDIR(inode->i_mode) && (fattr->valid & NFS_ATTR_FATTR_FSID) &&
1090 !nfs_fsid_equal(&server->fsid, &fattr->fsid) && 1130 !nfs_fsid_equal(&server->fsid, &fattr->fsid) &&
1091 !test_bit(NFS_INO_MOUNTPOINT, &nfsi->flags)) 1131 !test_bit(NFS_INO_MOUNTPOINT, &nfsi->flags))
1092 server->fsid = fattr->fsid; 1132 server->fsid = fattr->fsid;
@@ -1096,14 +1136,27 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
1096 */ 1136 */
1097 nfsi->read_cache_jiffies = fattr->time_start; 1137 nfsi->read_cache_jiffies = fattr->time_start;
1098 1138
1099 nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ATIME 1139 if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) || (fattr->valid & (NFS_ATTR_FATTR_MTIME|NFS_ATTR_FATTR_CTIME)))
1100 | NFS_INO_REVAL_PAGECACHE); 1140 nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR
1141 | NFS_INO_INVALID_ATIME
1142 | NFS_INO_REVAL_PAGECACHE);
1101 1143
1102 /* Do atomic weak cache consistency updates */ 1144 /* Do atomic weak cache consistency updates */
1103 nfs_wcc_update_inode(inode, fattr); 1145 nfs_wcc_update_inode(inode, fattr);
1104 1146
1105 /* More cache consistency checks */ 1147 /* More cache consistency checks */
1106 if (!(fattr->valid & NFS_ATTR_FATTR_V4)) { 1148 if (fattr->valid & NFS_ATTR_FATTR_CHANGE) {
1149 if (nfsi->change_attr != fattr->change_attr) {
1150 dprintk("NFS: change_attr change on server for file %s/%ld\n",
1151 inode->i_sb->s_id, inode->i_ino);
1152 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
1153 if (S_ISDIR(inode->i_mode))
1154 nfs_force_lookup_revalidate(inode);
1155 nfsi->change_attr = fattr->change_attr;
1156 }
1157 }
1158
1159 if (fattr->valid & NFS_ATTR_FATTR_MTIME) {
1107 /* NFSv2/v3: Check if the mtime agrees */ 1160 /* NFSv2/v3: Check if the mtime agrees */
1108 if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { 1161 if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) {
1109 dprintk("NFS: mtime change on server for file %s/%ld\n", 1162 dprintk("NFS: mtime change on server for file %s/%ld\n",
@@ -1111,7 +1164,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
1111 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; 1164 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
1112 if (S_ISDIR(inode->i_mode)) 1165 if (S_ISDIR(inode->i_mode))
1113 nfs_force_lookup_revalidate(inode); 1166 nfs_force_lookup_revalidate(inode);
1167 memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
1114 } 1168 }
1169 }
1170 if (fattr->valid & NFS_ATTR_FATTR_CTIME) {
1115 /* If ctime has changed we should definitely clear access+acl caches */ 1171 /* If ctime has changed we should definitely clear access+acl caches */
1116 if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) { 1172 if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) {
1117 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; 1173 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
@@ -1122,59 +1178,66 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
1122 invalid |= NFS_INO_INVALID_DATA; 1178 invalid |= NFS_INO_INVALID_DATA;
1123 nfs_force_lookup_revalidate(inode); 1179 nfs_force_lookup_revalidate(inode);
1124 } 1180 }
1181 memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
1125 } 1182 }
1126 } else if (nfsi->change_attr != fattr->change_attr) {
1127 dprintk("NFS: change_attr change on server for file %s/%ld\n",
1128 inode->i_sb->s_id, inode->i_ino);
1129 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
1130 if (S_ISDIR(inode->i_mode))
1131 nfs_force_lookup_revalidate(inode);
1132 } 1183 }
1133 1184
1134 /* Check if our cached file size is stale */ 1185 /* Check if our cached file size is stale */
1135 new_isize = nfs_size_to_loff_t(fattr->size); 1186 if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
1136 cur_isize = i_size_read(inode); 1187 new_isize = nfs_size_to_loff_t(fattr->size);
1137 if (new_isize != cur_isize) { 1188 cur_isize = i_size_read(inode);
1138 /* Do we perhaps have any outstanding writes, or has 1189 if (new_isize != cur_isize) {
1139 * the file grown beyond our last write? */ 1190 /* Do we perhaps have any outstanding writes, or has
1140 if (nfsi->npages == 0 || new_isize > cur_isize) { 1191 * the file grown beyond our last write? */
1141 i_size_write(inode, new_isize); 1192 if (nfsi->npages == 0 || new_isize > cur_isize) {
1142 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; 1193 i_size_write(inode, new_isize);
1194 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
1195 }
1196 dprintk("NFS: isize change on server for file %s/%ld\n",
1197 inode->i_sb->s_id, inode->i_ino);
1143 } 1198 }
1144 dprintk("NFS: isize change on server for file %s/%ld\n",
1145 inode->i_sb->s_id, inode->i_ino);
1146 } 1199 }
1147 1200
1148 1201
1149 memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); 1202 if (fattr->valid & NFS_ATTR_FATTR_ATIME)
1150 memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); 1203 memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
1151 memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
1152 nfsi->change_attr = fattr->change_attr;
1153 1204
1154 if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) || 1205 if (fattr->valid & NFS_ATTR_FATTR_MODE) {
1155 inode->i_uid != fattr->uid || 1206 if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) {
1156 inode->i_gid != fattr->gid) 1207 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
1157 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; 1208 inode->i_mode = fattr->mode;
1158 1209 }
1159 if (inode->i_nlink != fattr->nlink) { 1210 }
1160 invalid |= NFS_INO_INVALID_ATTR; 1211 if (fattr->valid & NFS_ATTR_FATTR_OWNER) {
1161 if (S_ISDIR(inode->i_mode)) 1212 if (inode->i_uid != fattr->uid) {
1162 invalid |= NFS_INO_INVALID_DATA; 1213 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
1214 inode->i_uid = fattr->uid;
1215 }
1216 }
1217 if (fattr->valid & NFS_ATTR_FATTR_GROUP) {
1218 if (inode->i_gid != fattr->gid) {
1219 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
1220 inode->i_gid = fattr->gid;
1221 }
1163 } 1222 }
1164 1223
1165 inode->i_mode = fattr->mode; 1224 if (fattr->valid & NFS_ATTR_FATTR_NLINK) {
1166 inode->i_nlink = fattr->nlink; 1225 if (inode->i_nlink != fattr->nlink) {
1167 inode->i_uid = fattr->uid; 1226 invalid |= NFS_INO_INVALID_ATTR;
1168 inode->i_gid = fattr->gid; 1227 if (S_ISDIR(inode->i_mode))
1228 invalid |= NFS_INO_INVALID_DATA;
1229 inode->i_nlink = fattr->nlink;
1230 }
1231 }
1169 1232
1170 if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) { 1233 if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
1171 /* 1234 /*
1172 * report the blocks in 512byte units 1235 * report the blocks in 512byte units
1173 */ 1236 */
1174 inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used); 1237 inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
1175 } else {
1176 inode->i_blocks = fattr->du.nfs2.blocks;
1177 } 1238 }
1239 if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
1240 inode->i_blocks = fattr->du.nfs2.blocks;
1178 1241
1179 /* Update attrtimeo value if we're out of the unstable period */ 1242 /* Update attrtimeo value if we're out of the unstable period */
1180 if (invalid & NFS_INO_INVALID_ATTR) { 1243 if (invalid & NFS_INO_INVALID_ATTR) {
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 28bab67d1519..bea99992c302 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -136,7 +136,7 @@ xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
136 p = xdr_decode_time(p, &fattr->atime); 136 p = xdr_decode_time(p, &fattr->atime);
137 p = xdr_decode_time(p, &fattr->mtime); 137 p = xdr_decode_time(p, &fattr->mtime);
138 p = xdr_decode_time(p, &fattr->ctime); 138 p = xdr_decode_time(p, &fattr->ctime);
139 fattr->valid |= NFS_ATTR_FATTR; 139 fattr->valid |= NFS_ATTR_FATTR_V2;
140 fattr->rdev = new_decode_dev(rdev); 140 fattr->rdev = new_decode_dev(rdev);
141 if (fattr->type == NFCHR && rdev == NFS2_FIFO_DEV) { 141 if (fattr->type == NFCHR && rdev == NFS2_FIFO_DEV) {
142 fattr->type = NFFIFO; 142 fattr->type = NFFIFO;
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index 6cdeacffde46..c0f7d02aced9 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -177,7 +177,7 @@ xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
177 p = xdr_decode_time3(p, &fattr->ctime); 177 p = xdr_decode_time3(p, &fattr->ctime);
178 178
179 /* Update the mode bits */ 179 /* Update the mode bits */
180 fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3); 180 fattr->valid |= NFS_ATTR_FATTR_V3;
181 return p; 181 return p;
182} 182}
183 183
@@ -233,7 +233,9 @@ xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
233 p = xdr_decode_hyper(p, &fattr->pre_size); 233 p = xdr_decode_hyper(p, &fattr->pre_size);
234 p = xdr_decode_time3(p, &fattr->pre_mtime); 234 p = xdr_decode_time3(p, &fattr->pre_mtime);
235 p = xdr_decode_time3(p, &fattr->pre_ctime); 235 p = xdr_decode_time3(p, &fattr->pre_ctime);
236 fattr->valid |= NFS_ATTR_WCC; 236 fattr->valid |= NFS_ATTR_FATTR_PRESIZE
237 | NFS_ATTR_FATTR_PREMTIME
238 | NFS_ATTR_FATTR_PRECTIME;
237 return p; 239 return p;
238} 240}
239 241
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 5f0ee3e2bd84..7d220da3db36 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -3012,7 +3012,7 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
3012 if ((status = decode_attr_type(xdr, bitmap, &type)) != 0) 3012 if ((status = decode_attr_type(xdr, bitmap, &type)) != 0)
3013 goto xdr_error; 3013 goto xdr_error;
3014 fattr->type = nfs_type2fmt[type].nfs2type; 3014 fattr->type = nfs_type2fmt[type].nfs2type;
3015 fmode = nfs_type2fmt[type].mode; 3015 fattr->mode = nfs_type2fmt[type].mode;
3016 3016
3017 if ((status = decode_attr_change(xdr, bitmap, &fattr->change_attr)) != 0) 3017 if ((status = decode_attr_change(xdr, bitmap, &fattr->change_attr)) != 0)
3018 goto xdr_error; 3018 goto xdr_error;
@@ -3026,7 +3026,7 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
3026 struct nfs4_fs_locations, 3026 struct nfs4_fs_locations,
3027 fattr))) != 0) 3027 fattr))) != 0)
3028 goto xdr_error; 3028 goto xdr_error;
3029 if ((status = decode_attr_mode(xdr, bitmap, &fattr->mode)) != 0) 3029 if ((status = decode_attr_mode(xdr, bitmap, &fmode)) != 0)
3030 goto xdr_error; 3030 goto xdr_error;
3031 fattr->mode |= fmode; 3031 fattr->mode |= fmode;
3032 if ((status = decode_attr_nlink(xdr, bitmap, &fattr->nlink)) != 0) 3032 if ((status = decode_attr_nlink(xdr, bitmap, &fattr->nlink)) != 0)
@@ -3050,7 +3050,7 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
3050 if (fattr->fileid == 0 && fileid != 0) 3050 if (fattr->fileid == 0 && fileid != 0)
3051 fattr->fileid = fileid; 3051 fattr->fileid = fileid;
3052 if ((status = verify_attr_len(xdr, savep, attrlen)) == 0) 3052 if ((status = verify_attr_len(xdr, savep, attrlen)) == 0)
3053 fattr->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4; 3053 fattr->valid = NFS_ATTR_FATTR_V4;
3054xdr_error: 3054xdr_error:
3055 dprintk("%s: xdr returned %d\n", __func__, -status); 3055 dprintk("%s: xdr returned %d\n", __func__, -status);
3056 return status; 3056 return status;
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 2e5f00066afd..b99295e07cdf 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -27,7 +27,7 @@ static inline int nfs_fsid_equal(const struct nfs_fsid *a, const struct nfs_fsid
27} 27}
28 28
29struct nfs_fattr { 29struct nfs_fattr {
30 unsigned short valid; /* which fields are valid */ 30 unsigned int valid; /* which fields are valid */
31 __u64 pre_size; /* pre_op_attr.size */ 31 __u64 pre_size; /* pre_op_attr.size */
32 struct timespec pre_mtime; /* pre_op_attr.mtime */ 32 struct timespec pre_mtime; /* pre_op_attr.mtime */
33 struct timespec pre_ctime; /* pre_op_attr.ctime */ 33 struct timespec pre_ctime; /* pre_op_attr.ctime */
@@ -59,12 +59,46 @@ struct nfs_fattr {
59 unsigned long gencount; 59 unsigned long gencount;
60}; 60};
61 61
62#define NFS_ATTR_WCC 0x0001 /* pre-op WCC data */ 62#define NFS_ATTR_FATTR_TYPE (1U << 0)
63#define NFS_ATTR_FATTR 0x0002 /* post-op attributes */ 63#define NFS_ATTR_FATTR_MODE (1U << 1)
64#define NFS_ATTR_FATTR_V3 0x0004 /* NFSv3 attributes */ 64#define NFS_ATTR_FATTR_NLINK (1U << 2)
65#define NFS_ATTR_FATTR_V4 0x0008 /* NFSv4 change attribute */ 65#define NFS_ATTR_FATTR_OWNER (1U << 3)
66#define NFS_ATTR_WCC_V4 0x0010 /* pre-op change attribute */ 66#define NFS_ATTR_FATTR_GROUP (1U << 4)
67#define NFS_ATTR_FATTR_V4_REFERRAL 0x0020 /* NFSv4 referral */ 67#define NFS_ATTR_FATTR_RDEV (1U << 5)
68#define NFS_ATTR_FATTR_SIZE (1U << 6)
69#define NFS_ATTR_FATTR_PRESIZE (1U << 7)
70#define NFS_ATTR_FATTR_BLOCKS_USED (1U << 8)
71#define NFS_ATTR_FATTR_SPACE_USED (1U << 9)
72#define NFS_ATTR_FATTR_FSID (1U << 10)
73#define NFS_ATTR_FATTR_FILEID (1U << 11)
74#define NFS_ATTR_FATTR_ATIME (1U << 12)
75#define NFS_ATTR_FATTR_MTIME (1U << 13)
76#define NFS_ATTR_FATTR_CTIME (1U << 14)
77#define NFS_ATTR_FATTR_PREMTIME (1U << 15)
78#define NFS_ATTR_FATTR_PRECTIME (1U << 16)
79#define NFS_ATTR_FATTR_CHANGE (1U << 17)
80#define NFS_ATTR_FATTR_PRECHANGE (1U << 18)
81#define NFS_ATTR_FATTR_V4_REFERRAL (1U << 19) /* NFSv4 referral */
82
83#define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
84 | NFS_ATTR_FATTR_MODE \
85 | NFS_ATTR_FATTR_NLINK \
86 | NFS_ATTR_FATTR_OWNER \
87 | NFS_ATTR_FATTR_GROUP \
88 | NFS_ATTR_FATTR_RDEV \
89 | NFS_ATTR_FATTR_SIZE \
90 | NFS_ATTR_FATTR_FSID \
91 | NFS_ATTR_FATTR_FILEID \
92 | NFS_ATTR_FATTR_ATIME \
93 | NFS_ATTR_FATTR_MTIME \
94 | NFS_ATTR_FATTR_CTIME)
95#define NFS_ATTR_FATTR_V2 (NFS_ATTR_FATTR \
96 | NFS_ATTR_FATTR_BLOCKS_USED)
97#define NFS_ATTR_FATTR_V3 (NFS_ATTR_FATTR \
98 | NFS_ATTR_FATTR_SPACE_USED)
99#define NFS_ATTR_FATTR_V4 (NFS_ATTR_FATTR \
100 | NFS_ATTR_FATTR_SPACE_USED \
101 | NFS_ATTR_FATTR_CHANGE)
68 102
69/* 103/*
70 * Info on the file system 104 * Info on the file system