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.7-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

Pull NFS client bugfixes from Trond Myklebust:

- Fix a bunch of deadlock situations:
* State recovery can deadlock if we fail to release sequence ids
before scheduling the recovery thread.
* Calling deactivate_super() from an RPC workqueue thread can
deadlock because of the call to rpc_shutdown_client.

- Display the device name correctly in /proc/*/mounts

- Fix a number of incorrect error return values:
* When NFSv3 mounts fail due to a timeout.
* On NFSv4.1 backchannel setup failure
* On NFSv4 open access checks

- pnfs_find_alloc_layout() must check the layout pointer for NULL

- Fix a regression in the legacy DNS resolved

* tag 'nfs-for-3.7-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
NFS4: nfs4_opendata_access should return errno
NFSv4: Initialise the NFSv4.1 slot table highest_used_slotid correctly
SUNRPC: return proper errno from backchannel_rqst
NFS: add nfs_sb_deactive_async to avoid deadlock
nfs: Show original device name verbatim in /proc/*/mount{s,info}
nfsv3: Make v3 mounts fail with ETIMEDOUTs instead EIO on mountd timeouts
nfs: Check whether a layout pointer is NULL before free it
NFS: fix bug in legacy DNS resolver.
NFSv4: nfs4_locku_done must release the sequence id
NFSv4.1: We must release the sequence id when we fail to get a session slot
NFS: Wait for session recovery to finish before returning

+110 -35
+3 -2
fs/nfs/dns_resolve.c
··· 217 217 { 218 218 char buf1[NFS_DNS_HOSTNAME_MAXLEN+1]; 219 219 struct nfs_dns_ent key, *item; 220 - unsigned long ttl; 220 + unsigned int ttl; 221 221 ssize_t len; 222 222 int ret = -EINVAL; 223 223 ··· 240 240 key.namelen = len; 241 241 memset(&key.h, 0, sizeof(key.h)); 242 242 243 - ttl = get_expiry(&buf); 243 + if (get_uint(&buf, &ttl) < 0) 244 + goto out; 244 245 if (ttl == 0) 245 246 goto out; 246 247 key.h.expiry_time = ttl + seconds_since_boot();
+4 -1
fs/nfs/inode.c
··· 685 685 if (ctx->cred != NULL) 686 686 put_rpccred(ctx->cred); 687 687 dput(ctx->dentry); 688 - nfs_sb_deactive(sb); 688 + if (is_sync) 689 + nfs_sb_deactive(sb); 690 + else 691 + nfs_sb_deactive_async(sb); 689 692 kfree(ctx->mdsthreshold); 690 693 kfree(ctx); 691 694 }
+4 -2
fs/nfs/internal.h
··· 351 351 extern void __exit unregister_nfs_fs(void); 352 352 extern void nfs_sb_active(struct super_block *sb); 353 353 extern void nfs_sb_deactive(struct super_block *sb); 354 + extern void nfs_sb_deactive_async(struct super_block *sb); 354 355 355 356 /* namespace.c */ 357 + #define NFS_PATH_CANONICAL 1 356 358 extern char *nfs_path(char **p, struct dentry *dentry, 357 - char *buffer, ssize_t buflen); 359 + char *buffer, ssize_t buflen, unsigned flags); 358 360 extern struct vfsmount *nfs_d_automount(struct path *path); 359 361 struct vfsmount *nfs_submount(struct nfs_server *, struct dentry *, 360 362 struct nfs_fh *, struct nfs_fattr *); ··· 500 498 char *buffer, ssize_t buflen) 501 499 { 502 500 char *dummy; 503 - return nfs_path(&dummy, dentry, buffer, buflen); 501 + return nfs_path(&dummy, dentry, buffer, buflen, NFS_PATH_CANONICAL); 504 502 } 505 503 506 504 /*
+1 -1
fs/nfs/mount_clnt.c
··· 181 181 else 182 182 msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC_MNT]; 183 183 184 - status = rpc_call_sync(mnt_clnt, &msg, 0); 184 + status = rpc_call_sync(mnt_clnt, &msg, RPC_TASK_SOFT|RPC_TASK_TIMEOUT); 185 185 rpc_shutdown_client(mnt_clnt); 186 186 187 187 if (status < 0)
+14 -5
fs/nfs/namespace.c
··· 33 33 * @dentry - pointer to dentry 34 34 * @buffer - result buffer 35 35 * @buflen - length of buffer 36 + * @flags - options (see below) 36 37 * 37 38 * Helper function for constructing the server pathname 38 39 * by arbitrary hashed dentry. ··· 41 40 * This is mainly for use in figuring out the path on the 42 41 * server side when automounting on top of an existing partition 43 42 * and in generating /proc/mounts and friends. 43 + * 44 + * Supported flags: 45 + * NFS_PATH_CANONICAL: ensure there is exactly one slash after 46 + * the original device (export) name 47 + * (if unset, the original name is returned verbatim) 44 48 */ 45 - char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen) 49 + char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen, 50 + unsigned flags) 46 51 { 47 52 char *end; 48 53 int namelen; ··· 81 74 rcu_read_unlock(); 82 75 goto rename_retry; 83 76 } 84 - if (*end != '/') { 77 + if ((flags & NFS_PATH_CANONICAL) && *end != '/') { 85 78 if (--buflen < 0) { 86 79 spin_unlock(&dentry->d_lock); 87 80 rcu_read_unlock(); ··· 98 91 return end; 99 92 } 100 93 namelen = strlen(base); 101 - /* Strip off excess slashes in base string */ 102 - while (namelen > 0 && base[namelen - 1] == '/') 103 - namelen--; 94 + if (flags & NFS_PATH_CANONICAL) { 95 + /* Strip off excess slashes in base string */ 96 + while (namelen > 0 && base[namelen - 1] == '/') 97 + namelen--; 98 + } 104 99 buflen -= namelen; 105 100 if (buflen < 0) { 106 101 spin_unlock(&dentry->d_lock);
+2 -1
fs/nfs/nfs4namespace.c
··· 81 81 static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen) 82 82 { 83 83 char *limit; 84 - char *path = nfs_path(&limit, dentry, buffer, buflen); 84 + char *path = nfs_path(&limit, dentry, buffer, buflen, 85 + NFS_PATH_CANONICAL); 85 86 if (!IS_ERR(path)) { 86 87 char *path_component = nfs_path_component(path, limit); 87 88 if (path_component)
+28 -18
fs/nfs/nfs4proc.c
··· 339 339 dprintk("%s ERROR: %d Reset session\n", __func__, 340 340 errorcode); 341 341 nfs4_schedule_session_recovery(clp->cl_session, errorcode); 342 - exception->retry = 1; 343 - break; 342 + goto wait_on_recovery; 344 343 #endif /* defined(CONFIG_NFS_V4_1) */ 345 344 case -NFS4ERR_FILE_OPEN: 346 345 if (exception->timeout > HZ) { ··· 1571 1572 data->timestamp = jiffies; 1572 1573 if (nfs4_setup_sequence(data->o_arg.server, 1573 1574 &data->o_arg.seq_args, 1574 - &data->o_res.seq_res, task)) 1575 - return; 1576 - rpc_call_start(task); 1575 + &data->o_res.seq_res, 1576 + task) != 0) 1577 + nfs_release_seqid(data->o_arg.seqid); 1578 + else 1579 + rpc_call_start(task); 1577 1580 return; 1578 1581 unlock_no_action: 1579 1582 rcu_read_unlock(); ··· 1749 1748 1750 1749 /* even though OPEN succeeded, access is denied. Close the file */ 1751 1750 nfs4_close_state(state, fmode); 1752 - return -NFS4ERR_ACCESS; 1751 + return -EACCES; 1753 1752 } 1754 1753 1755 1754 /* ··· 2197 2196 nfs4_put_open_state(calldata->state); 2198 2197 nfs_free_seqid(calldata->arg.seqid); 2199 2198 nfs4_put_state_owner(sp); 2200 - nfs_sb_deactive(sb); 2199 + nfs_sb_deactive_async(sb); 2201 2200 kfree(calldata); 2202 2201 } 2203 2202 ··· 2297 2296 if (nfs4_setup_sequence(NFS_SERVER(inode), 2298 2297 &calldata->arg.seq_args, 2299 2298 &calldata->res.seq_res, 2300 - task)) 2301 - goto out; 2302 - rpc_call_start(task); 2299 + task) != 0) 2300 + nfs_release_seqid(calldata->arg.seqid); 2301 + else 2302 + rpc_call_start(task); 2303 2303 out: 2304 2304 dprintk("%s: done!\n", __func__); 2305 2305 } ··· 4531 4529 if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) 4532 4530 rpc_restart_call_prepare(task); 4533 4531 } 4532 + nfs_release_seqid(calldata->arg.seqid); 4534 4533 } 4535 4534 4536 4535 static void nfs4_locku_prepare(struct rpc_task *task, void *data) ··· 4548 4545 calldata->timestamp = jiffies; 4549 4546 if (nfs4_setup_sequence(calldata->server, 4550 4547 &calldata->arg.seq_args, 4551 - &calldata->res.seq_res, task)) 4552 - return; 4553 - rpc_call_start(task); 4548 + &calldata->res.seq_res, 4549 + task) != 0) 4550 + nfs_release_seqid(calldata->arg.seqid); 4551 + else 4552 + rpc_call_start(task); 4554 4553 } 4555 4554 4556 4555 static const struct rpc_call_ops nfs4_locku_ops = { ··· 4697 4692 /* Do we need to do an open_to_lock_owner? */ 4698 4693 if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) { 4699 4694 if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) 4700 - return; 4695 + goto out_release_lock_seqid; 4701 4696 data->arg.open_stateid = &state->stateid; 4702 4697 data->arg.new_lock_owner = 1; 4703 4698 data->res.open_seqid = data->arg.open_seqid; ··· 4706 4701 data->timestamp = jiffies; 4707 4702 if (nfs4_setup_sequence(data->server, 4708 4703 &data->arg.seq_args, 4709 - &data->res.seq_res, task)) 4704 + &data->res.seq_res, 4705 + task) == 0) { 4706 + rpc_call_start(task); 4710 4707 return; 4711 - rpc_call_start(task); 4712 - dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); 4708 + } 4709 + nfs_release_seqid(data->arg.open_seqid); 4710 + out_release_lock_seqid: 4711 + nfs_release_seqid(data->arg.lock_seqid); 4712 + dprintk("%s: done!, ret = %d\n", __func__, task->tk_status); 4713 4713 } 4714 4714 4715 4715 static void nfs4_recover_lock_prepare(struct rpc_task *task, void *calldata) ··· 5677 5667 tbl->slots = new; 5678 5668 tbl->max_slots = max_slots; 5679 5669 } 5680 - tbl->highest_used_slotid = -1; /* no slot is currently used */ 5670 + tbl->highest_used_slotid = NFS4_NO_SLOT; 5681 5671 for (i = 0; i < tbl->max_slots; i++) 5682 5672 tbl->slots[i].seq_nr = ivalue; 5683 5673 spin_unlock(&tbl->slot_tbl_lock);
+2 -2
fs/nfs/pnfs.c
··· 925 925 if (likely(nfsi->layout == NULL)) { /* Won the race? */ 926 926 nfsi->layout = new; 927 927 return new; 928 - } 929 - pnfs_free_layout_hdr(new); 928 + } else if (new != NULL) 929 + pnfs_free_layout_hdr(new); 930 930 out_existing: 931 931 pnfs_get_layout_hdr(nfsi->layout); 932 932 return nfsi->layout;
+50 -1
fs/nfs/super.c
··· 54 54 #include <linux/parser.h> 55 55 #include <linux/nsproxy.h> 56 56 #include <linux/rcupdate.h> 57 + #include <linux/kthread.h> 57 58 58 59 #include <asm/uaccess.h> 59 60 ··· 416 415 } 417 416 EXPORT_SYMBOL_GPL(nfs_sb_deactive); 418 417 418 + static int nfs_deactivate_super_async_work(void *ptr) 419 + { 420 + struct super_block *sb = ptr; 421 + 422 + deactivate_super(sb); 423 + module_put_and_exit(0); 424 + return 0; 425 + } 426 + 427 + /* 428 + * same effect as deactivate_super, but will do final unmount in kthread 429 + * context 430 + */ 431 + static void nfs_deactivate_super_async(struct super_block *sb) 432 + { 433 + struct task_struct *task; 434 + char buf[INET6_ADDRSTRLEN + 1]; 435 + struct nfs_server *server = NFS_SB(sb); 436 + struct nfs_client *clp = server->nfs_client; 437 + 438 + if (!atomic_add_unless(&sb->s_active, -1, 1)) { 439 + rcu_read_lock(); 440 + snprintf(buf, sizeof(buf), 441 + rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR)); 442 + rcu_read_unlock(); 443 + 444 + __module_get(THIS_MODULE); 445 + task = kthread_run(nfs_deactivate_super_async_work, sb, 446 + "%s-deactivate-super", buf); 447 + if (IS_ERR(task)) { 448 + pr_err("%s: kthread_run: %ld\n", 449 + __func__, PTR_ERR(task)); 450 + /* make synchronous call and hope for the best */ 451 + deactivate_super(sb); 452 + module_put(THIS_MODULE); 453 + } 454 + } 455 + } 456 + 457 + void nfs_sb_deactive_async(struct super_block *sb) 458 + { 459 + struct nfs_server *server = NFS_SB(sb); 460 + 461 + if (atomic_dec_and_test(&server->active)) 462 + nfs_deactivate_super_async(sb); 463 + } 464 + EXPORT_SYMBOL_GPL(nfs_sb_deactive_async); 465 + 419 466 /* 420 467 * Deliver file system statistics to userspace 421 468 */ ··· 820 771 int err = 0; 821 772 if (!page) 822 773 return -ENOMEM; 823 - devname = nfs_path(&dummy, root, page, PAGE_SIZE); 774 + devname = nfs_path(&dummy, root, page, PAGE_SIZE, 0); 824 775 if (IS_ERR(devname)) 825 776 err = PTR_ERR(devname); 826 777 else
+1 -1
fs/nfs/unlink.c
··· 95 95 96 96 nfs_dec_sillycount(data->dir); 97 97 nfs_free_unlinkdata(data); 98 - nfs_sb_deactive(sb); 98 + nfs_sb_deactive_async(sb); 99 99 } 100 100 101 101 static void nfs_unlink_prepare(struct rpc_task *task, void *calldata)
+1 -1
net/sunrpc/backchannel_rqst.c
··· 172 172 xprt_free_allocation(req); 173 173 174 174 dprintk("RPC: setup backchannel transport failed\n"); 175 - return -1; 175 + return -ENOMEM; 176 176 } 177 177 EXPORT_SYMBOL_GPL(xprt_setup_backchannel); 178 178