Merge tag 'nfs-for-3.8-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

Pull NFS client bugfixes from Trond Myklebust:

- Error reporting in nfs_xdev_mount incorrectly maps all errors to
ENOMEM

- Fix an NFSv4 refcounting issue

- Fix a mount failure when the server reboots during NFSv4 trunking
discovery

- NFSv4.1 mounts may need to run the lease recovery thread.

- Don't silently fail setattr() requests on mountpoints

- Fix a SUNRPC socket/transport livelock and priority queue issue

- We must handle NFS4ERR_DELAY when resetting the NFSv4.1 session.

* tag 'nfs-for-3.8-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
NFSv4.1: Handle NFS4ERR_DELAY when resetting the NFSv4.1 session
SUNRPC: When changing the queue priority, ensure that we change the owner
NFS: Don't silently fail setattr() requests on mountpoints
NFSv4.1: Ensure that nfs41_walk_client_list() does start lease recovery
NFSv4: Fix NFSv4 trunking discovery
NFSv4: Fix NFSv4 reference counting for trunked sessions
NFS: Fix error reporting in nfs_xdev_mount

Changed files
+86 -58
fs
net
sunrpc
+20
fs/nfs/namespace.c
··· 177 177 return mnt; 178 178 } 179 179 180 + static int 181 + nfs_namespace_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) 182 + { 183 + if (NFS_FH(dentry->d_inode)->size != 0) 184 + return nfs_getattr(mnt, dentry, stat); 185 + generic_fillattr(dentry->d_inode, stat); 186 + return 0; 187 + } 188 + 189 + static int 190 + nfs_namespace_setattr(struct dentry *dentry, struct iattr *attr) 191 + { 192 + if (NFS_FH(dentry->d_inode)->size != 0) 193 + return nfs_setattr(dentry, attr); 194 + return -EACCES; 195 + } 196 + 180 197 const struct inode_operations nfs_mountpoint_inode_operations = { 181 198 .getattr = nfs_getattr, 199 + .setattr = nfs_setattr, 182 200 }; 183 201 184 202 const struct inode_operations nfs_referral_inode_operations = { 203 + .getattr = nfs_namespace_getattr, 204 + .setattr = nfs_namespace_setattr, 185 205 }; 186 206 187 207 static void nfs_expire_automounts(struct work_struct *work)
+26 -36
fs/nfs/nfs4client.c
··· 236 236 error = nfs4_discover_server_trunking(clp, &old); 237 237 if (error < 0) 238 238 goto error; 239 + nfs_put_client(clp); 239 240 if (clp != old) { 240 241 clp->cl_preserve_clid = true; 241 - nfs_put_client(clp); 242 242 clp = old; 243 - atomic_inc(&clp->cl_count); 244 243 } 245 244 246 245 return clp; ··· 305 306 .clientid = new->cl_clientid, 306 307 .confirm = new->cl_confirm, 307 308 }; 308 - int status; 309 + int status = -NFS4ERR_STALE_CLIENTID; 309 310 310 311 spin_lock(&nn->nfs_client_lock); 311 312 list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) { ··· 331 332 332 333 if (prev) 333 334 nfs_put_client(prev); 335 + prev = pos; 334 336 335 337 status = nfs4_proc_setclientid_confirm(pos, &clid, cred); 336 - if (status == 0) { 338 + switch (status) { 339 + case -NFS4ERR_STALE_CLIENTID: 340 + break; 341 + case 0: 337 342 nfs4_swap_callback_idents(pos, new); 338 343 339 - nfs_put_client(pos); 344 + prev = NULL; 340 345 *result = pos; 341 346 dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n", 342 347 __func__, pos, atomic_read(&pos->cl_count)); 343 - return 0; 344 - } 345 - if (status != -NFS4ERR_STALE_CLIENTID) { 346 - nfs_put_client(pos); 347 - dprintk("NFS: <-- %s status = %d, no result\n", 348 - __func__, status); 349 - return status; 348 + default: 349 + goto out; 350 350 } 351 351 352 352 spin_lock(&nn->nfs_client_lock); 353 - prev = pos; 354 353 } 354 + spin_unlock(&nn->nfs_client_lock); 355 355 356 - /* 357 - * No matching nfs_client found. This should be impossible, 358 - * because the new nfs_client has already been added to 359 - * nfs_client_list by nfs_get_client(). 360 - * 361 - * Don't BUG(), since the caller is holding a mutex. 362 - */ 356 + /* No match found. The server lost our clientid */ 357 + out: 363 358 if (prev) 364 359 nfs_put_client(prev); 365 - spin_unlock(&nn->nfs_client_lock); 366 - pr_err("NFS: %s Error: no matching nfs_client found\n", __func__); 367 - return -NFS4ERR_STALE_CLIENTID; 360 + dprintk("NFS: <-- %s status = %d\n", __func__, status); 361 + return status; 368 362 } 369 363 370 364 #ifdef CONFIG_NFS_V4_1 ··· 424 432 { 425 433 struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id); 426 434 struct nfs_client *pos, *n, *prev = NULL; 427 - int error; 435 + int status = -NFS4ERR_STALE_CLIENTID; 428 436 429 437 spin_lock(&nn->nfs_client_lock); 430 438 list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) { ··· 440 448 nfs_put_client(prev); 441 449 prev = pos; 442 450 443 - error = nfs_wait_client_init_complete(pos); 444 - if (error < 0) { 451 + nfs4_schedule_lease_recovery(pos); 452 + status = nfs_wait_client_init_complete(pos); 453 + if (status < 0) { 445 454 nfs_put_client(pos); 446 455 spin_lock(&nn->nfs_client_lock); 447 456 continue; 448 457 } 449 - 458 + status = pos->cl_cons_state; 450 459 spin_lock(&nn->nfs_client_lock); 460 + if (status < 0) 461 + continue; 451 462 } 452 463 453 464 if (pos->rpc_ops != new->rpc_ops) ··· 468 473 if (!nfs4_match_serverowners(pos, new)) 469 474 continue; 470 475 476 + atomic_inc(&pos->cl_count); 471 477 spin_unlock(&nn->nfs_client_lock); 472 478 dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n", 473 479 __func__, pos, atomic_read(&pos->cl_count)); ··· 477 481 return 0; 478 482 } 479 483 480 - /* 481 - * No matching nfs_client found. This should be impossible, 482 - * because the new nfs_client has already been added to 483 - * nfs_client_list by nfs_get_client(). 484 - * 485 - * Don't BUG(), since the caller is holding a mutex. 486 - */ 484 + /* No matching nfs_client found. */ 487 485 spin_unlock(&nn->nfs_client_lock); 488 - pr_err("NFS: %s Error: no matching nfs_client found\n", __func__); 489 - return -NFS4ERR_STALE_CLIENTID; 486 + dprintk("NFS: <-- %s status = %d\n", __func__, status); 487 + return status; 490 488 } 491 489 #endif /* CONFIG_NFS_V4_1 */ 492 490
+14 -8
fs/nfs/nfs4state.c
··· 136 136 clp->cl_confirm = clid.confirm; 137 137 138 138 status = nfs40_walk_client_list(clp, result, cred); 139 - switch (status) { 140 - case -NFS4ERR_STALE_CLIENTID: 141 - set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); 142 - case 0: 139 + if (status == 0) { 143 140 /* Sustain the lease, even if it's empty. If the clientid4 144 141 * goes stale it's of no use for trunking discovery. */ 145 142 nfs4_schedule_state_renewal(*result); 146 - break; 147 143 } 148 - 149 144 out: 150 145 return status; 151 146 } ··· 1858 1863 case -ETIMEDOUT: 1859 1864 case -EAGAIN: 1860 1865 ssleep(1); 1866 + case -NFS4ERR_STALE_CLIENTID: 1861 1867 dprintk("NFS: %s after status %d, retrying\n", 1862 1868 __func__, status); 1863 1869 goto again; ··· 2018 2022 nfs4_begin_drain_session(clp); 2019 2023 cred = nfs4_get_exchange_id_cred(clp); 2020 2024 status = nfs4_proc_destroy_session(clp->cl_session, cred); 2021 - if (status && status != -NFS4ERR_BADSESSION && 2022 - status != -NFS4ERR_DEADSESSION) { 2025 + switch (status) { 2026 + case 0: 2027 + case -NFS4ERR_BADSESSION: 2028 + case -NFS4ERR_DEADSESSION: 2029 + break; 2030 + case -NFS4ERR_BACK_CHAN_BUSY: 2031 + case -NFS4ERR_DELAY: 2032 + set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); 2033 + status = 0; 2034 + ssleep(1); 2035 + goto out; 2036 + default: 2023 2037 status = nfs4_recovery_handle_error(clp, status); 2024 2038 goto out; 2025 2039 }
+9 -13
fs/nfs/super.c
··· 2589 2589 struct nfs_server *server; 2590 2590 struct dentry *mntroot = ERR_PTR(-ENOMEM); 2591 2591 struct nfs_subversion *nfs_mod = NFS_SB(data->sb)->nfs_client->cl_nfs_mod; 2592 - int error; 2593 2592 2594 - dprintk("--> nfs_xdev_mount_common()\n"); 2593 + dprintk("--> nfs_xdev_mount()\n"); 2595 2594 2596 2595 mount_info.mntfh = mount_info.cloned->fh; 2597 2596 2598 2597 /* create a new volume representation */ 2599 2598 server = nfs_mod->rpc_ops->clone_server(NFS_SB(data->sb), data->fh, data->fattr, data->authflavor); 2600 - if (IS_ERR(server)) { 2601 - error = PTR_ERR(server); 2602 - goto out_err; 2603 - } 2604 2599 2605 - mntroot = nfs_fs_mount_common(server, flags, dev_name, &mount_info, nfs_mod); 2606 - dprintk("<-- nfs_xdev_mount_common() = 0\n"); 2607 - out: 2600 + if (IS_ERR(server)) 2601 + mntroot = ERR_CAST(server); 2602 + else 2603 + mntroot = nfs_fs_mount_common(server, flags, 2604 + dev_name, &mount_info, nfs_mod); 2605 + 2606 + dprintk("<-- nfs_xdev_mount() = %ld\n", 2607 + IS_ERR(mntroot) ? PTR_ERR(mntroot) : 0L); 2608 2608 return mntroot; 2609 - 2610 - out_err: 2611 - dprintk("<-- nfs_xdev_mount_common() = %d [error]\n", error); 2612 - goto out; 2613 2609 } 2614 2610 2615 2611 #if IS_ENABLED(CONFIG_NFS_V4)
+17 -1
net/sunrpc/sched.c
··· 98 98 list_add(&task->u.tk_wait.timer_list, &queue->timer_list.list); 99 99 } 100 100 101 + static void rpc_rotate_queue_owner(struct rpc_wait_queue *queue) 102 + { 103 + struct list_head *q = &queue->tasks[queue->priority]; 104 + struct rpc_task *task; 105 + 106 + if (!list_empty(q)) { 107 + task = list_first_entry(q, struct rpc_task, u.tk_wait.list); 108 + if (task->tk_owner == queue->owner) 109 + list_move_tail(&task->u.tk_wait.list, q); 110 + } 111 + } 112 + 101 113 static void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int priority) 102 114 { 103 - queue->priority = priority; 115 + if (queue->priority != priority) { 116 + /* Fairness: rotate the list when changing priority */ 117 + rpc_rotate_queue_owner(queue); 118 + queue->priority = priority; 119 + } 104 120 } 105 121 106 122 static void rpc_set_waitqueue_owner(struct rpc_wait_queue *queue, pid_t pid)