Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

NFSv4.2: SETXATTR should update ctime

Otherwise, `stat` will report a stale value to users.

Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>

authored by

Anna Schumaker and committed by
Trond Myklebust
86e2e1f6 64edd55d

+32 -7
+21 -4
fs/nfs/nfs42proc.c
··· 1190 1190 const void *buf, size_t buflen, int flags) 1191 1191 { 1192 1192 struct nfs_server *server = NFS_SERVER(inode); 1193 + __u32 bitmask[NFS_BITMASK_SZ]; 1193 1194 struct page *pages[NFS4XATTR_MAXPAGES]; 1194 1195 struct nfs42_setxattrargs arg = { 1195 1196 .fh = NFS_FH(inode), 1197 + .bitmask = bitmask, 1196 1198 .xattr_pages = pages, 1197 1199 .xattr_len = buflen, 1198 1200 .xattr_name = name, 1199 1201 .xattr_flags = flags, 1200 1202 }; 1201 - struct nfs42_setxattrres res; 1203 + struct nfs42_setxattrres res = { 1204 + .server = server, 1205 + }; 1202 1206 struct rpc_message msg = { 1203 1207 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETXATTR], 1204 1208 .rpc_argp = &arg, ··· 1214 1210 if (buflen > server->sxasize) 1215 1211 return -ERANGE; 1216 1212 1213 + res.fattr = nfs_alloc_fattr(); 1214 + if (!res.fattr) 1215 + return -ENOMEM; 1216 + 1217 1217 if (buflen > 0) { 1218 1218 np = nfs4_buf_to_pages_noslab(buf, buflen, arg.xattr_pages); 1219 - if (np < 0) 1220 - return np; 1219 + if (np < 0) { 1220 + ret = np; 1221 + goto out; 1222 + } 1221 1223 } else 1222 1224 np = 0; 1225 + 1226 + nfs4_bitmask_set(bitmask, server->cache_consistency_bitmask, 1227 + inode, NFS_INO_INVALID_CHANGE); 1223 1228 1224 1229 ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, 1225 1230 &res.seq_res, 1); ··· 1237 1224 for (; np > 0; np--) 1238 1225 put_page(pages[np - 1]); 1239 1226 1240 - if (!ret) 1227 + if (!ret) { 1241 1228 nfs4_update_changeattr(inode, &res.cinfo, timestamp, 0); 1229 + ret = nfs_post_op_update_inode(inode, res.fattr); 1230 + } 1242 1231 1232 + out: 1233 + kfree(res.fattr); 1243 1234 return ret; 1244 1235 } 1245 1236
+8 -3
fs/nfs/nfs42xdr.c
··· 212 212 #define NFS4_enc_setxattr_sz (compound_encode_hdr_maxsz + \ 213 213 encode_sequence_maxsz + \ 214 214 encode_putfh_maxsz + \ 215 - encode_setxattr_maxsz) 215 + encode_setxattr_maxsz + \ 216 + encode_getattr_maxsz) 216 217 #define NFS4_dec_setxattr_sz (compound_decode_hdr_maxsz + \ 217 218 decode_sequence_maxsz + \ 218 219 decode_putfh_maxsz + \ 219 - decode_setxattr_maxsz) 220 + decode_setxattr_maxsz + \ 221 + decode_getattr_maxsz) 220 222 #define NFS4_enc_listxattrs_sz (compound_encode_hdr_maxsz + \ 221 223 encode_sequence_maxsz + \ 222 224 encode_putfh_maxsz + \ ··· 722 720 encode_sequence(xdr, &args->seq_args, &hdr); 723 721 encode_putfh(xdr, args->fh, &hdr); 724 722 encode_setxattr(xdr, args, &hdr); 723 + encode_getfattr(xdr, args->bitmask, &hdr); 725 724 encode_nops(&hdr); 726 725 } 727 726 ··· 1582 1579 status = decode_putfh(xdr); 1583 1580 if (status) 1584 1581 goto out; 1585 - 1586 1582 status = decode_setxattr(xdr, &res->cinfo); 1583 + if (status) 1584 + goto out; 1585 + status = decode_getfattr(xdr, res->fattr, res->server); 1587 1586 out: 1588 1587 return status; 1589 1588 }
+3
include/linux/nfs_xdr.h
··· 1528 1528 struct nfs42_setxattrargs { 1529 1529 struct nfs4_sequence_args seq_args; 1530 1530 struct nfs_fh *fh; 1531 + const u32 *bitmask; 1531 1532 const char *xattr_name; 1532 1533 u32 xattr_flags; 1533 1534 size_t xattr_len; ··· 1538 1537 struct nfs42_setxattrres { 1539 1538 struct nfs4_sequence_res seq_res; 1540 1539 struct nfs4_change_info cinfo; 1540 + struct nfs_fattr *fattr; 1541 + const struct nfs_server *server; 1541 1542 }; 1542 1543 1543 1544 struct nfs42_getxattrargs {