diff options
-rw-r--r-- | fs/nfs/inode.c | 243 | ||||
-rw-r--r-- | fs/nfs/nfs2xdr.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs3xdr.c | 6 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 6 | ||||
-rw-r--r-- | include/linux/nfs_xdr.h | 48 |
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 | ||
891 | static int nfs_ctime_need_update(const struct inode *inode, const struct nfs_fattr *fattr) | 916 | static 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 | ||
896 | static int nfs_size_need_update(const struct inode *inode, const struct nfs_fattr *fattr) | 923 | static 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 | } |
1048 | out_noforce: | 1088 | out_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; |
3054 | xdr_error: | 3054 | xdr_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 | ||
29 | struct nfs_fattr { | 29 | struct 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 |