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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'nfs-for-3.16-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

Pull NFS client fixes from Trond Myklebust:
"Highlights include:

- Stable fix for a data corruption case due to incorrect cache
validation
- Fix a couple of false positive cache invalidations
- Fix NFSv4 security negotiation issues"

* tag 'nfs-for-3.16-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
NFSv4: test SECINFO RPC_AUTH_GSS pseudoflavors for support
NFS Return -EPERM if no supported or matching SECINFO flavor
NFS check the return of nfs4_negotiate_security in nfs4_submount
NFS: Don't mark the data cache as invalid if it has been flushed
NFS: Clear NFS_INO_REVAL_PAGECACHE when we update the file size
nfs: Fix cache_validity check in nfs_write_pageuptodate()

+104 -83
+41 -35
fs/nfs/inode.c
··· 147 147 return ret; 148 148 } 149 149 150 + static void nfs_set_cache_invalid(struct inode *inode, unsigned long flags) 151 + { 152 + struct nfs_inode *nfsi = NFS_I(inode); 153 + 154 + if (inode->i_mapping->nrpages == 0) 155 + flags &= ~NFS_INO_INVALID_DATA; 156 + nfsi->cache_validity |= flags; 157 + if (flags & NFS_INO_INVALID_DATA) 158 + nfs_fscache_invalidate(inode); 159 + } 160 + 150 161 /* 151 162 * Invalidate the local caches 152 163 */ ··· 173 162 174 163 memset(NFS_I(inode)->cookieverf, 0, sizeof(NFS_I(inode)->cookieverf)); 175 164 if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) { 176 - nfs_fscache_invalidate(inode); 177 - nfsi->cache_validity |= NFS_INO_INVALID_ATTR 165 + nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR 178 166 | NFS_INO_INVALID_DATA 179 167 | NFS_INO_INVALID_ACCESS 180 168 | NFS_INO_INVALID_ACL 181 - | NFS_INO_REVAL_PAGECACHE; 169 + | NFS_INO_REVAL_PAGECACHE); 182 170 } else 183 - nfsi->cache_validity |= NFS_INO_INVALID_ATTR 171 + nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR 184 172 | NFS_INO_INVALID_ACCESS 185 173 | NFS_INO_INVALID_ACL 186 - | NFS_INO_REVAL_PAGECACHE; 174 + | NFS_INO_REVAL_PAGECACHE); 187 175 nfs_zap_label_cache_locked(nfsi); 188 176 } 189 177 ··· 197 187 { 198 188 if (mapping->nrpages != 0) { 199 189 spin_lock(&inode->i_lock); 200 - NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA; 201 - nfs_fscache_invalidate(inode); 190 + nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA); 202 191 spin_unlock(&inode->i_lock); 203 192 } 204 193 } ··· 218 209 void nfs_invalidate_atime(struct inode *inode) 219 210 { 220 211 spin_lock(&inode->i_lock); 221 - NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME; 212 + nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATIME); 222 213 spin_unlock(&inode->i_lock); 223 214 } 224 215 EXPORT_SYMBOL_GPL(nfs_invalidate_atime); ··· 378 369 inode->i_mode = fattr->mode; 379 370 if ((fattr->valid & NFS_ATTR_FATTR_MODE) == 0 380 371 && nfs_server_capable(inode, NFS_CAP_MODE)) 381 - nfsi->cache_validity |= NFS_INO_INVALID_ATTR; 372 + nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR); 382 373 /* Why so? Because we want revalidate for devices/FIFOs, and 383 374 * that's precisely what we have in nfs_file_inode_operations. 384 375 */ ··· 424 415 if (fattr->valid & NFS_ATTR_FATTR_ATIME) 425 416 inode->i_atime = fattr->atime; 426 417 else if (nfs_server_capable(inode, NFS_CAP_ATIME)) 427 - nfsi->cache_validity |= NFS_INO_INVALID_ATTR; 418 + nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR); 428 419 if (fattr->valid & NFS_ATTR_FATTR_MTIME) 429 420 inode->i_mtime = fattr->mtime; 430 421 else if (nfs_server_capable(inode, NFS_CAP_MTIME)) 431 - nfsi->cache_validity |= NFS_INO_INVALID_ATTR; 422 + nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR); 432 423 if (fattr->valid & NFS_ATTR_FATTR_CTIME) 433 424 inode->i_ctime = fattr->ctime; 434 425 else if (nfs_server_capable(inode, NFS_CAP_CTIME)) 435 - nfsi->cache_validity |= NFS_INO_INVALID_ATTR; 426 + nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR); 436 427 if (fattr->valid & NFS_ATTR_FATTR_CHANGE) 437 428 inode->i_version = fattr->change_attr; 438 429 else if (nfs_server_capable(inode, NFS_CAP_CHANGE_ATTR)) 439 - nfsi->cache_validity |= NFS_INO_INVALID_ATTR; 430 + nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR); 440 431 if (fattr->valid & NFS_ATTR_FATTR_SIZE) 441 432 inode->i_size = nfs_size_to_loff_t(fattr->size); 442 433 else 443 - nfsi->cache_validity |= NFS_INO_INVALID_ATTR 444 - | NFS_INO_REVAL_PAGECACHE; 434 + nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR 435 + | NFS_INO_REVAL_PAGECACHE); 445 436 if (fattr->valid & NFS_ATTR_FATTR_NLINK) 446 437 set_nlink(inode, fattr->nlink); 447 438 else if (nfs_server_capable(inode, NFS_CAP_NLINK)) 448 - nfsi->cache_validity |= NFS_INO_INVALID_ATTR; 439 + nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR); 449 440 if (fattr->valid & NFS_ATTR_FATTR_OWNER) 450 441 inode->i_uid = fattr->uid; 451 442 else if (nfs_server_capable(inode, NFS_CAP_OWNER)) 452 - nfsi->cache_validity |= NFS_INO_INVALID_ATTR; 443 + nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR); 453 444 if (fattr->valid & NFS_ATTR_FATTR_GROUP) 454 445 inode->i_gid = fattr->gid; 455 446 else if (nfs_server_capable(inode, NFS_CAP_OWNER_GROUP)) 456 - nfsi->cache_validity |= NFS_INO_INVALID_ATTR; 447 + nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR); 457 448 if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED) 458 449 inode->i_blocks = fattr->du.nfs2.blocks; 459 450 if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) { ··· 559 550 560 551 spin_lock(&inode->i_lock); 561 552 i_size_write(inode, offset); 553 + /* Optimisation */ 554 + if (offset == 0) 555 + NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_DATA; 562 556 spin_unlock(&inode->i_lock); 563 557 564 558 truncate_pagecache(inode, offset); ··· 590 578 inode->i_uid = attr->ia_uid; 591 579 if ((attr->ia_valid & ATTR_GID) != 0) 592 580 inode->i_gid = attr->ia_gid; 593 - NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; 581 + nfs_set_cache_invalid(inode, NFS_INO_INVALID_ACCESS 582 + | NFS_INO_INVALID_ACL); 594 583 spin_unlock(&inode->i_lock); 595 584 } 596 585 if ((attr->ia_valid & ATTR_SIZE) != 0) { ··· 1114 1101 && inode->i_version == fattr->pre_change_attr) { 1115 1102 inode->i_version = fattr->change_attr; 1116 1103 if (S_ISDIR(inode->i_mode)) 1117 - nfsi->cache_validity |= NFS_INO_INVALID_DATA; 1104 + nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA); 1118 1105 ret |= NFS_INO_INVALID_ATTR; 1119 1106 } 1120 1107 /* If we have atomic WCC data, we may update some attributes */ ··· 1130 1117 && timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) { 1131 1118 memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); 1132 1119 if (S_ISDIR(inode->i_mode)) 1133 - nfsi->cache_validity |= NFS_INO_INVALID_DATA; 1120 + nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA); 1134 1121 ret |= NFS_INO_INVALID_ATTR; 1135 1122 } 1136 1123 if ((fattr->valid & NFS_ATTR_FATTR_PRESIZE) ··· 1140 1127 i_size_write(inode, nfs_size_to_loff_t(fattr->size)); 1141 1128 ret |= NFS_INO_INVALID_ATTR; 1142 1129 } 1143 - 1144 - if (nfsi->cache_validity & NFS_INO_INVALID_DATA) 1145 - nfs_fscache_invalidate(inode); 1146 1130 1147 1131 return ret; 1148 1132 } ··· 1199 1189 invalid |= NFS_INO_INVALID_ATIME; 1200 1190 1201 1191 if (invalid != 0) 1202 - nfsi->cache_validity |= invalid; 1192 + nfs_set_cache_invalid(inode, invalid); 1203 1193 1204 1194 nfsi->read_cache_jiffies = fattr->time_start; 1205 1195 return 0; ··· 1412 1402 1413 1403 static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr *fattr) 1414 1404 { 1415 - struct nfs_inode *nfsi = NFS_I(inode); 1405 + unsigned long invalid = NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; 1416 1406 1417 - nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; 1418 - if (S_ISDIR(inode->i_mode)) { 1419 - nfsi->cache_validity |= NFS_INO_INVALID_DATA; 1420 - nfs_fscache_invalidate(inode); 1421 - } 1407 + if (S_ISDIR(inode->i_mode)) 1408 + invalid |= NFS_INO_INVALID_DATA; 1409 + nfs_set_cache_invalid(inode, invalid); 1422 1410 if ((fattr->valid & NFS_ATTR_FATTR) == 0) 1423 1411 return 0; 1424 1412 return nfs_refresh_inode_locked(inode, fattr); ··· 1609 1601 if ((nfsi->npages == 0) || new_isize > cur_isize) { 1610 1602 i_size_write(inode, new_isize); 1611 1603 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; 1604 + invalid &= ~NFS_INO_REVAL_PAGECACHE; 1612 1605 } 1613 1606 dprintk("NFS: isize change on server for file %s/%ld " 1614 1607 "(%Ld to %Ld)\n", ··· 1711 1702 invalid &= ~NFS_INO_INVALID_DATA; 1712 1703 if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ) || 1713 1704 (save_cache_validity & NFS_INO_REVAL_FORCED)) 1714 - nfsi->cache_validity |= invalid; 1715 - 1716 - if (invalid & NFS_INO_INVALID_DATA) 1717 - nfs_fscache_invalidate(inode); 1705 + nfs_set_cache_invalid(inode, invalid); 1718 1706 1719 1707 return 0; 1720 1708 out_err:
+1 -1
fs/nfs/nfs4_fs.h
··· 230 230 extern struct file_system_type nfs4_fs_type; 231 231 232 232 /* nfs4namespace.c */ 233 - struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *, struct inode *, struct qstr *); 233 + struct rpc_clnt *nfs4_negotiate_security(struct rpc_clnt *, struct inode *, struct qstr *); 234 234 struct vfsmount *nfs4_submount(struct nfs_server *, struct dentry *, 235 235 struct nfs_fh *, struct nfs_fattr *); 236 236 int nfs4_replace_transport(struct nfs_server *server,
+57 -45
fs/nfs/nfs4namespace.c
··· 139 139 * @server: NFS server struct 140 140 * @flavors: List of security tuples returned by SECINFO procedure 141 141 * 142 - * Return the pseudoflavor of the first security mechanism in 143 - * "flavors" that is locally supported. Return RPC_AUTH_UNIX if 144 - * no matching flavor is found in the array. The "flavors" array 142 + * Return an rpc client that uses the first security mechanism in 143 + * "flavors" that is locally supported. The "flavors" array 145 144 * is searched in the order returned from the server, per RFC 3530 146 - * recommendation. 145 + * recommendation and each flavor is checked for membership in the 146 + * sec= mount option list if it exists. 147 + * 148 + * Return -EPERM if no matching flavor is found in the array. 149 + * 150 + * Please call rpc_shutdown_client() when you are done with this rpc client. 151 + * 147 152 */ 148 - static rpc_authflavor_t nfs_find_best_sec(struct nfs_server *server, 153 + static struct rpc_clnt *nfs_find_best_sec(struct rpc_clnt *clnt, 154 + struct nfs_server *server, 149 155 struct nfs4_secinfo_flavors *flavors) 150 156 { 151 - rpc_authflavor_t pseudoflavor; 157 + rpc_authflavor_t pflavor; 152 158 struct nfs4_secinfo4 *secinfo; 153 159 unsigned int i; 154 160 ··· 165 159 case RPC_AUTH_NULL: 166 160 case RPC_AUTH_UNIX: 167 161 case RPC_AUTH_GSS: 168 - pseudoflavor = rpcauth_get_pseudoflavor(secinfo->flavor, 162 + pflavor = rpcauth_get_pseudoflavor(secinfo->flavor, 169 163 &secinfo->flavor_info); 170 - /* make sure pseudoflavor matches sec= mount opt */ 171 - if (pseudoflavor != RPC_AUTH_MAXFLAVOR && 172 - nfs_auth_info_match(&server->auth_info, 173 - pseudoflavor)) 174 - return pseudoflavor; 175 - break; 164 + /* does the pseudoflavor match a sec= mount opt? */ 165 + if (pflavor != RPC_AUTH_MAXFLAVOR && 166 + nfs_auth_info_match(&server->auth_info, pflavor)) { 167 + struct rpc_clnt *new; 168 + struct rpc_cred *cred; 169 + 170 + /* Cloning creates an rpc_auth for the flavor */ 171 + new = rpc_clone_client_set_auth(clnt, pflavor); 172 + if (IS_ERR(new)) 173 + continue; 174 + /** 175 + * Check that the user actually can use the 176 + * flavor. This is mostly for RPC_AUTH_GSS 177 + * where cr_init obtains a gss context 178 + */ 179 + cred = rpcauth_lookupcred(new->cl_auth, 0); 180 + if (IS_ERR(cred)) { 181 + rpc_shutdown_client(new); 182 + continue; 183 + } 184 + put_rpccred(cred); 185 + return new; 186 + } 176 187 } 177 188 } 178 - 179 - /* if there were any sec= options then nothing matched */ 180 - if (server->auth_info.flavor_len > 0) 181 - return -EPERM; 182 - 183 - return RPC_AUTH_UNIX; 189 + return ERR_PTR(-EPERM); 184 190 } 185 191 186 - static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr *name) 192 + /** 193 + * nfs4_negotiate_security - in response to an NFS4ERR_WRONGSEC on lookup, 194 + * return an rpc_clnt that uses the best available security flavor with 195 + * respect to the secinfo flavor list and the sec= mount options. 196 + * 197 + * @clnt: RPC client to clone 198 + * @inode: directory inode 199 + * @name: lookup name 200 + * 201 + * Please call rpc_shutdown_client() when you are done with this rpc client. 202 + */ 203 + struct rpc_clnt * 204 + nfs4_negotiate_security(struct rpc_clnt *clnt, struct inode *inode, 205 + struct qstr *name) 187 206 { 188 207 struct page *page; 189 208 struct nfs4_secinfo_flavors *flavors; 190 - rpc_authflavor_t flavor; 209 + struct rpc_clnt *new; 191 210 int err; 192 211 193 212 page = alloc_page(GFP_KERNEL); 194 213 if (!page) 195 - return -ENOMEM; 214 + return ERR_PTR(-ENOMEM); 215 + 196 216 flavors = page_address(page); 197 217 198 218 err = nfs4_proc_secinfo(inode, name, flavors); 199 219 if (err < 0) { 200 - flavor = err; 220 + new = ERR_PTR(err); 201 221 goto out; 202 222 } 203 223 204 - flavor = nfs_find_best_sec(NFS_SERVER(inode), flavors); 224 + new = nfs_find_best_sec(clnt, NFS_SERVER(inode), flavors); 205 225 206 226 out: 207 227 put_page(page); 208 - return flavor; 209 - } 210 - 211 - /* 212 - * Please call rpc_shutdown_client() when you are done with this client. 213 - */ 214 - struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *clnt, struct inode *inode, 215 - struct qstr *name) 216 - { 217 - rpc_authflavor_t flavor; 218 - 219 - flavor = nfs4_negotiate_security(inode, name); 220 - if ((int)flavor < 0) 221 - return ERR_PTR((int)flavor); 222 - 223 - return rpc_clone_client_set_auth(clnt, flavor); 228 + return new; 224 229 } 225 230 226 231 static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, ··· 414 397 415 398 if (client->cl_auth->au_flavor != flavor) 416 399 flavor = client->cl_auth->au_flavor; 417 - else { 418 - rpc_authflavor_t new = nfs4_negotiate_security(dir, name); 419 - if ((int)new >= 0) 420 - flavor = new; 421 - } 422 400 mnt = nfs_do_submount(dentry, fh, fattr, flavor); 423 401 out: 424 402 rpc_shutdown_client(client);
+1 -1
fs/nfs/nfs4proc.c
··· 3247 3247 err = -EPERM; 3248 3248 if (client != *clnt) 3249 3249 goto out; 3250 - client = nfs4_create_sec_client(client, dir, name); 3250 + client = nfs4_negotiate_security(client, dir, name); 3251 3251 if (IS_ERR(client)) 3252 3252 return PTR_ERR(client); 3253 3253
+3 -1
fs/nfs/write.c
··· 934 934 935 935 if (nfs_have_delegated_attributes(inode)) 936 936 goto out; 937 - if (nfsi->cache_validity & (NFS_INO_INVALID_DATA|NFS_INO_REVAL_PAGECACHE)) 937 + if (nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) 938 938 return false; 939 939 smp_rmb(); 940 940 if (test_bit(NFS_INO_INVALIDATING, &nfsi->flags)) 941 941 return false; 942 942 out: 943 + if (nfsi->cache_validity & NFS_INO_INVALID_DATA) 944 + return false; 943 945 return PageUptodate(page) != 0; 944 946 } 945 947
+1
net/sunrpc/auth.c
··· 592 592 put_group_info(acred.group_info); 593 593 return ret; 594 594 } 595 + EXPORT_SYMBOL_GPL(rpcauth_lookupcred); 595 596 596 597 void 597 598 rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred,