diff options
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/blocklayout/blocklayout.c | 1 | ||||
-rw-r--r-- | fs/nfs/blocklayout/blocklayoutdm.c | 4 | ||||
-rw-r--r-- | fs/nfs/callback_proc.c | 61 | ||||
-rw-r--r-- | fs/nfs/idmap.c | 13 | ||||
-rw-r--r-- | fs/nfs/nfs4client.c | 45 | ||||
-rw-r--r-- | fs/nfs/nfs4filelayout.c | 7 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 70 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 8 | ||||
-rw-r--r-- | fs/nfs/objlayout/objio_osd.c | 1 | ||||
-rw-r--r-- | fs/nfs/pnfs.c | 218 | ||||
-rw-r--r-- | fs/nfs/pnfs.h | 13 | ||||
-rw-r--r-- | fs/nfs/unlink.c | 20 |
12 files changed, 154 insertions, 307 deletions
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index 434b93e..4fa788c 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c @@ -1273,7 +1273,6 @@ static const struct nfs_pageio_ops bl_pg_write_ops = { static struct pnfs_layoutdriver_type blocklayout_type = { .id = LAYOUT_BLOCK_VOLUME, .name = "LAYOUT_BLOCK_VOLUME", - .owner = THIS_MODULE, .read_pagelist = bl_read_pagelist, .write_pagelist = bl_write_pagelist, .alloc_layout_hdr = bl_alloc_layout_hdr, diff --git a/fs/nfs/blocklayout/blocklayoutdm.c b/fs/nfs/blocklayout/blocklayoutdm.c index 6fc7b5c..737d839 100644 --- a/fs/nfs/blocklayout/blocklayoutdm.c +++ b/fs/nfs/blocklayout/blocklayoutdm.c @@ -55,8 +55,7 @@ static void dev_remove(struct net *net, dev_t dev) bl_pipe_msg.bl_wq = &nn->bl_wq; memset(msg, 0, sizeof(*msg)); - msg->len = sizeof(bl_msg) + bl_msg.totallen; - msg->data = kzalloc(msg->len, GFP_NOFS); + msg->data = kzalloc(1 + sizeof(bl_umount_request), GFP_NOFS); if (!msg->data) goto out; @@ -67,6 +66,7 @@ static void dev_remove(struct net *net, dev_t dev) memcpy(msg->data, &bl_msg, sizeof(bl_msg)); dataptr = (uint8_t *) msg->data; memcpy(&dataptr[sizeof(bl_msg)], &bl_umount_request, sizeof(bl_umount_request)); + msg->len = sizeof(bl_msg) + bl_msg.totallen; add_wait_queue(&nn->bl_wq, &wq); if (rpc_queue_upcall(nn->bl_device_pipe, msg) < 0) { diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 2960512..264d1aa 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -183,15 +183,60 @@ static u32 initiate_file_draining(struct nfs_client *clp, static u32 initiate_bulk_draining(struct nfs_client *clp, struct cb_layoutrecallargs *args) { - int stat; + struct nfs_server *server; + struct pnfs_layout_hdr *lo; + struct inode *ino; + u32 rv = NFS4ERR_NOMATCHING_LAYOUT; + struct pnfs_layout_hdr *tmp; + LIST_HEAD(recall_list); + LIST_HEAD(free_me_list); + struct pnfs_layout_range range = { + .iomode = IOMODE_ANY, + .offset = 0, + .length = NFS4_MAX_UINT64, + }; - if (args->cbl_recall_type == RETURN_FSID) - stat = pnfs_destroy_layouts_byfsid(clp, &args->cbl_fsid, true); - else - stat = pnfs_destroy_layouts_byclid(clp, true); - if (stat != 0) - return NFS4ERR_DELAY; - return NFS4ERR_NOMATCHING_LAYOUT; + spin_lock(&clp->cl_lock); + rcu_read_lock(); + list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { + if ((args->cbl_recall_type == RETURN_FSID) && + memcmp(&server->fsid, &args->cbl_fsid, + sizeof(struct nfs_fsid))) + continue; + + list_for_each_entry(lo, &server->layouts, plh_layouts) { + ino = igrab(lo->plh_inode); + if (!ino) + continue; + spin_lock(&ino->i_lock); + /* Is this layout in the process of being freed? */ + if (NFS_I(ino)->layout != lo) { + spin_unlock(&ino->i_lock); + iput(ino); + continue; + } + pnfs_get_layout_hdr(lo); + spin_unlock(&ino->i_lock); + list_add(&lo->plh_bulk_recall, &recall_list); + } + } + rcu_read_unlock(); + spin_unlock(&clp->cl_lock); + + list_for_each_entry_safe(lo, tmp, + &recall_list, plh_bulk_recall) { + ino = lo->plh_inode; + spin_lock(&ino->i_lock); + set_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags); + if (pnfs_mark_matching_lsegs_invalid(lo, &free_me_list, &range)) + rv = NFS4ERR_DELAY; + list_del_init(&lo->plh_bulk_recall); + spin_unlock(&ino->i_lock); + pnfs_free_lseg_list(&free_me_list); + pnfs_put_layout_hdr(lo); + iput(ino); + } + return rv; } static u32 do_callback_layoutrecall(struct nfs_client *clp, diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index cf4ed87..bc3968fa 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -725,9 +725,9 @@ out1: return ret; } -static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data, size_t datalen) +static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data) { - return key_instantiate_and_link(key, data, datalen, + return key_instantiate_and_link(key, data, strlen(data) + 1, id_resolver_cache->thread_keyring, authkey); } @@ -737,7 +737,6 @@ static int nfs_idmap_read_and_verify_message(struct idmap_msg *im, struct key *key, struct key *authkey) { char id_str[NFS_UINT_MAXLEN]; - size_t len; int ret = -ENOKEY; /* ret = -ENOKEY */ @@ -747,15 +746,13 @@ static int nfs_idmap_read_and_verify_message(struct idmap_msg *im, case IDMAP_CONV_NAMETOID: if (strcmp(upcall->im_name, im->im_name) != 0) break; - /* Note: here we store the NUL terminator too */ - len = sprintf(id_str, "%d", im->im_id) + 1; - ret = nfs_idmap_instantiate(key, authkey, id_str, len); + sprintf(id_str, "%d", im->im_id); + ret = nfs_idmap_instantiate(key, authkey, id_str); break; case IDMAP_CONV_IDTONAME: if (upcall->im_id != im->im_id) break; - len = strlen(im->im_name); - ret = nfs_idmap_instantiate(key, authkey, im->im_name, len); + ret = nfs_idmap_instantiate(key, authkey, im->im_name); break; default: ret = -EINVAL; diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index c53189d..2e9779b 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c @@ -300,7 +300,7 @@ int nfs40_walk_client_list(struct nfs_client *new, struct rpc_cred *cred) { struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id); - struct nfs_client *pos, *prev = NULL; + struct nfs_client *pos, *n, *prev = NULL; struct nfs4_setclientid_res clid = { .clientid = new->cl_clientid, .confirm = new->cl_confirm, @@ -308,23 +308,10 @@ int nfs40_walk_client_list(struct nfs_client *new, int status = -NFS4ERR_STALE_CLIENTID; spin_lock(&nn->nfs_client_lock); - list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) { + list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) { /* If "pos" isn't marked ready, we can't trust the * remaining fields in "pos" */ - if (pos->cl_cons_state > NFS_CS_READY) { - atomic_inc(&pos->cl_count); - spin_unlock(&nn->nfs_client_lock); - - if (prev) - nfs_put_client(prev); - prev = pos; - - status = nfs_wait_client_init_complete(pos); - spin_lock(&nn->nfs_client_lock); - if (status < 0) - continue; - } - if (pos->cl_cons_state != NFS_CS_READY) + if (pos->cl_cons_state < NFS_CS_READY) continue; if (pos->rpc_ops != new->rpc_ops) @@ -436,16 +423,16 @@ int nfs41_walk_client_list(struct nfs_client *new, struct rpc_cred *cred) { struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id); - struct nfs_client *pos, *prev = NULL; + struct nfs_client *pos, *n, *prev = NULL; int status = -NFS4ERR_STALE_CLIENTID; spin_lock(&nn->nfs_client_lock); - list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) { + list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) { /* If "pos" isn't marked ready, we can't trust the * remaining fields in "pos", especially the client * ID and serverowner fields. Wait for CREATE_SESSION * to finish. */ - if (pos->cl_cons_state > NFS_CS_READY) { + if (pos->cl_cons_state < NFS_CS_READY) { atomic_inc(&pos->cl_count); spin_unlock(&nn->nfs_client_lock); @@ -453,17 +440,18 @@ int nfs41_walk_client_list(struct nfs_client *new, nfs_put_client(prev); prev = pos; + nfs4_schedule_lease_recovery(pos); status = nfs_wait_client_init_complete(pos); - if (status == 0) { - nfs4_schedule_lease_recovery(pos); - status = nfs4_wait_clnt_recover(pos); + if (status < 0) { + nfs_put_client(pos); + spin_lock(&nn->nfs_client_lock); + continue; } + status = pos->cl_cons_state; spin_lock(&nn->nfs_client_lock); if (status < 0) continue; } - if (pos->cl_cons_state != NFS_CS_READY) - continue; if (pos->rpc_ops != new->rpc_ops) continue; @@ -481,18 +469,17 @@ int nfs41_walk_client_list(struct nfs_client *new, continue; atomic_inc(&pos->cl_count); - *result = pos; - status = 0; + spin_unlock(&nn->nfs_client_lock); dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n", __func__, pos, atomic_read(&pos->cl_count)); - break; + + *result = pos; + return 0; } /* No matching nfs_client found. */ spin_unlock(&nn->nfs_client_lock); dprintk("NFS: <-- %s status = %d\n", __func__, status); - if (prev) - nfs_put_client(prev); return status; } #endif /* CONFIG_NFS_V4_1 */ diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 4fb234d..194c484 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c @@ -99,8 +99,7 @@ static void filelayout_reset_write(struct nfs_write_data *data) task->tk_status = pnfs_write_done_resend_to_mds(hdr->inode, &hdr->pages, - hdr->completion_ops, - hdr->dreq); + hdr->completion_ops); } } @@ -120,8 +119,7 @@ static void filelayout_reset_read(struct nfs_read_data *data) task->tk_status = pnfs_read_done_resend_to_mds(hdr->inode, &hdr->pages, - hdr->completion_ops, - hdr->dreq); + hdr->completion_ops); } } @@ -129,6 +127,7 @@ static void filelayout_fenceme(struct inode *inode, struct pnfs_layout_hdr *lo) { if (!test_and_clear_bit(NFS_LAYOUT_RETURN, &lo->plh_flags)) return; + clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags); pnfs_return_layout(inode); } diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index e3c6121..cf747ef 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1374,12 +1374,6 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state case -ENOMEM: err = 0; goto out; - case -NFS4ERR_DELAY: - case -NFS4ERR_GRACE: - set_bit(NFS_DELEGATED_STATE, &state->flags); - ssleep(1); - err = -EAGAIN; - goto out; } err = nfs4_handle_exception(server, err, &exception); } while (exception.retry); @@ -1469,7 +1463,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) struct nfs4_state_owner *sp = data->owner; if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0) - goto out_wait; + return; /* * Check if we still need to send an OPEN call, or if we can use * a delegation instead. @@ -1504,7 +1498,6 @@ unlock_no_action: rcu_read_unlock(); out_no_action: task->tk_action = NULL; -out_wait: nfs4_sequence_done(task, &data->o_res.seq_res); } @@ -2157,7 +2150,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) dprintk("%s: begin!\n", __func__); if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) - goto out_wait; + return; task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; calldata->arg.fmode = FMODE_READ|FMODE_WRITE; @@ -2179,14 +2172,16 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) if (!call_close) { /* Note: exit _without_ calling nfs4_close_done */ - goto out_no_action; + task->tk_action = NULL; + nfs4_sequence_done(task, &calldata->res.seq_res); + goto out; } if (calldata->arg.fmode == 0) { task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE]; if (calldata->roc && pnfs_roc_drain(inode, &calldata->roc_barrier, task)) - goto out_wait; + goto out; } nfs_fattr_init(calldata->res.fattr); @@ -2196,12 +2191,8 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) &calldata->res.seq_res, task) != 0) nfs_release_seqid(calldata->arg.seqid); +out: dprintk("%s: done!\n", __func__); - return; -out_no_action: - task->tk_action = NULL; -out_wait: - nfs4_sequence_done(task, &calldata->res.seq_res); } static const struct rpc_call_ops nfs4_close_ops = { @@ -4432,10 +4423,12 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data) struct nfs4_unlockdata *calldata = data; if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) - goto out_wait; + return; if (test_bit(NFS_LOCK_INITIALIZED, &calldata->lsp->ls_flags) == 0) { /* Note: exit _without_ running nfs4_locku_done */ - goto out_no_action; + task->tk_action = NULL; + nfs4_sequence_done(task, &calldata->res.seq_res); + return; } calldata->timestamp = jiffies; if (nfs4_setup_sequence(calldata->server, @@ -4443,11 +4436,6 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data) &calldata->res.seq_res, task) != 0) nfs_release_seqid(calldata->arg.seqid); - return; -out_no_action: - task->tk_action = NULL; -out_wait: - nfs4_sequence_done(task, &calldata->res.seq_res); } static const struct rpc_call_ops nfs4_locku_ops = { @@ -4513,9 +4501,9 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * if (status != 0) goto out; /* Is this a delegated lock? */ - lsp = request->fl_u.nfs4_fl.owner; - if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) == 0) + if (test_bit(NFS_DELEGATED_STATE, &state->flags)) goto out; + lsp = request->fl_u.nfs4_fl.owner; seqid = nfs_alloc_seqid(&lsp->ls_seqid, GFP_KERNEL); status = -ENOMEM; if (seqid == NULL) @@ -4588,7 +4576,7 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) dprintk("%s: begin!\n", __func__); if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0) - goto out_wait; + return; /* Do we need to do an open_to_lock_owner? */ if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) { if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) { @@ -4608,8 +4596,6 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) nfs_release_seqid(data->arg.open_seqid); out_release_lock_seqid: nfs_release_seqid(data->arg.lock_seqid); -out_wait: - nfs4_sequence_done(task, &data->res.seq_res); dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); } @@ -6093,13 +6079,11 @@ static struct page **nfs4_alloc_pages(size_t size, gfp_t gfp_flags) static void nfs4_layoutget_release(void *calldata) { struct nfs4_layoutget *lgp = calldata; - struct inode *inode = lgp->args.inode; - struct nfs_server *server = NFS_SERVER(inode); + struct nfs_server *server = NFS_SERVER(lgp->args.inode); size_t max_pages = max_response_pages(server); dprintk("--> %s\n", __func__); nfs4_free_pages(lgp->args.layout.pages, max_pages); - pnfs_put_layout_hdr(NFS_I(inode)->layout); put_nfs_open_context(lgp->args.ctx); kfree(calldata); dprintk("<-- %s\n", __func__); @@ -6114,8 +6098,7 @@ static const struct rpc_call_ops nfs4_layoutget_call_ops = { struct pnfs_layout_segment * nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags) { - struct inode *inode = lgp->args.inode; - struct nfs_server *server = NFS_SERVER(inode); + struct nfs_server *server = NFS_SERVER(lgp->args.inode); size_t max_pages = max_response_pages(server); struct rpc_task *task; struct rpc_message msg = { @@ -6145,18 +6128,13 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags) lgp->res.layoutp = &lgp->args.layout; lgp->res.seq_res.sr_slot = NULL; nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0); - - /* nfs4_layoutget_release calls pnfs_put_layout_hdr */ - pnfs_get_layout_hdr(NFS_I(inode)->layout); - task = rpc_run_task(&task_setup_data); if (IS_ERR(task)) return ERR_CAST(task); status = nfs4_wait_for_completion_rpc_task(task); if (status == 0) status = task->tk_status; - /* if layoutp->len is 0, nfs4_layoutget_prepare called rpc_exit */ - if (status == 0 && lgp->res.layoutp->len) + if (status == 0) lseg = pnfs_layout_process(lgp); rpc_put_task(task); dprintk("<-- %s status=%d\n", __func__, status); @@ -6372,8 +6350,22 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata) static void nfs4_layoutcommit_release(void *calldata) { struct nfs4_layoutcommit_data *data = calldata; + struct pnfs_layout_segment *lseg, *tmp; + unsigned long *bitlock = &NFS_I(data->args.inode)->flags; pnfs_cleanup_layoutcommit(data); + /* Matched by references in pnfs_set_layoutcommit */ + list_for_each_entry_safe(lseg, tmp, &data->lseg_list, pls_lc_list) { + list_del_init(&lseg->pls_lc_list); + if (test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, + &lseg->pls_flags)) + pnfs_put_lseg(lseg); + } + + clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock); + smp_mb__after_clear_bit(); + wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING); + put_rpccred(data->cred); kfree(data); } diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 994fbe2..e61f68d 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1877,13 +1877,7 @@ again: status = PTR_ERR(clnt); break; } - /* Note: this is safe because we haven't yet marked the - * client as ready, so we are the only user of - * clp->cl_rpcclient - */ - clnt = xchg(&clp->cl_rpcclient, clnt); - rpc_shutdown_client(clnt); - clnt = clp->cl_rpcclient; + clp->cl_rpcclient = clnt; goto again; case -NFS4ERR_MINOR_VERS_MISMATCH: diff --git a/fs/nfs/objlayout/objio_osd.c b/fs/nfs/objlayout/objio_osd.c index 88f9611..c6f9906 100644 --- a/fs/nfs/objlayout/objio_osd.c +++ b/fs/nfs/objlayout/objio_osd.c @@ -647,7 +647,6 @@ static struct pnfs_layoutdriver_type objlayout_type = { .flags = PNFS_LAYOUTRET_ON_SETATTR | PNFS_LAYOUTRET_ON_ERROR, - .owner = THIS_MODULE, .alloc_layout_hdr = objlayout_alloc_layout_hdr, .free_layout_hdr = objlayout_free_layout_hdr, diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 3b71623..d00260b 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -417,16 +417,6 @@ should_free_lseg(struct pnfs_layout_range *lseg_range, lo_seg_intersecting(lseg_range, recall_range); } -static bool pnfs_lseg_dec_and_remove_zero(struct pnfs_layout_segment *lseg, - struct list_head *tmp_list) -{ - if (!atomic_dec_and_test(&lseg->pls_refcount)) - return false; - pnfs_layout_remove_lseg(lseg->pls_layout, lseg); - list_add(&lseg->pls_list, tmp_list); - return true; -} - /* Returns 1 if lseg is removed from list, 0 otherwise */ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg, struct list_head *tmp_list) @@ -440,8 +430,11 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg, */ dprintk("%s: lseg %p ref %d\n", __func__, lseg, atomic_read(&lseg->pls_refcount)); - if (pnfs_lseg_dec_and_remove_zero(lseg, tmp_list)) + if (atomic_dec_and_test(&lseg->pls_refcount)) { + pnfs_layout_remove_lseg(lseg->pls_layout, lseg); + list_add(&lseg->pls_list, tmp_list); rv = 1; + } } return rv; } @@ -512,147 +505,37 @@ pnfs_destroy_layout(struct nfs_inode *nfsi) } EXPORT_SYMBOL_GPL(pnfs_destroy_layout); -static bool -pnfs_layout_add_bulk_destroy_list(struct inode *inode, - struct list_head *layout_list) -{ - struct pnfs_layout_hdr *lo; - bool ret = false; - - spin_lock(&inode->i_lock); - lo = NFS_I(inode)->layout; - if (lo != NULL && list_empty(&lo->plh_bulk_destroy)) { - pnfs_get_layout_hdr(lo); - list_add(&lo->plh_bulk_destroy, layout_list); - ret = true; - } - spin_unlock(&inode->i_lock); - return ret; -} - -/* Caller must hold rcu_read_lock and clp->cl_lock */ -static int -pnfs_layout_bulk_destroy_byserver_locked(struct nfs_client *clp, - struct nfs_server *server, - struct list_head *layout_list) -{ - struct pnfs_layout_hdr *lo, *next; - struct inode *inode; - - list_for_each_entry_safe(lo, next, &server->layouts, plh_layouts) { - inode = igrab(lo->plh_inode); - if (inode == NULL) - continue; - list_del_init(&lo->plh_layouts); - if (pnfs_layout_add_bulk_destroy_list(inode, layout_list)) - continue; - rcu_read_unlock(); - spin_unlock(&clp->cl_lock); - iput(inode); - spin_lock(&clp->cl_lock); - rcu_read_lock(); - return -EAGAIN; - } - return 0; -} - -static int -pnfs_layout_free_bulk_destroy_list(struct list_head *layout_list, - bool is_bulk_recall) +/* + * Called by the state manger to remove all layouts established under an + * expired lease. + */ +void +pnfs_destroy_all_layouts(struct nfs_client *clp) { + struct nfs_server *server; struct pnfs_layout_hdr *lo; - struct inode *inode; - struct pnfs_layout_range range = { - .iomode = IOMODE_ANY, - .offset = 0, - .length = NFS4_MAX_UINT64, - }; - LIST_HEAD(lseg_list); - int ret = 0; - - while (!list_empty(layout_list)) { - lo = list_entry(layout_list->next, struct pnfs_layout_hdr, - plh_bulk_destroy); - dprintk("%s freeing layout for inode %lu\n", __func__, - lo->plh_inode->i_ino); - inode = lo->plh_inode; - spin_lock(&inode->i_lock); - list_del_init(&lo->plh_bulk_destroy); - lo->plh_block_lgets++; /* permanently block new LAYOUTGETs */ - if (is_bulk_recall) - set_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags); - if (pnfs_mark_matching_lsegs_invalid(lo, &lseg_list, &range)) - ret = -EAGAIN; - spin_unlock(&inode->i_lock); - pnfs_free_lseg_list(&lseg_list); - pnfs_put_layout_hdr(lo); - iput(inode); - } - return ret; -} + LIST_HEAD(tmp_list); -int -pnfs_destroy_layouts_byfsid(struct nfs_client *clp, - struct nfs_fsid *fsid, - bool is_recall) -{ - struct nfs_server *server; - LIST_HEAD(layout_list); + nfs4_deviceid_mark_client_invalid(clp); + nfs4_deviceid_purge_client(clp); spin_lock(&clp->cl_lock); rcu_read_lock(); -restart: list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { - if (memcmp(&server->fsid, fsid, sizeof(*fsid)) != 0) - continue; - if (pnfs_layout_bulk_destroy_byserver_locked(clp, - server, - &layout_list) != 0) - goto restart; + if (!list_empty(&server->layouts)) + list_splice_init(&server->layouts, &tmp_list); } rcu_read_unlock(); spin_unlock(&clp->cl_lock); - if (list_empty(&layout_list)) - return 0; - return pnfs_layout_free_bulk_destroy_list(&layout_list, is_recall); -} - -int -pnfs_destroy_layouts_byclid(struct nfs_client *clp, - bool is_recall) -{ - struct nfs_server *server; - LIST_HEAD(layout_list); - - spin_lock(&clp->cl_lock); - rcu_read_lock(); -restart: - list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { - if (pnfs_layout_bulk_destroy_byserver_locked(clp, - server, - &layout_list) != 0) - goto restart; + while (!list_empty(&tmp_list)) { + lo = list_entry(tmp_list.next, struct pnfs_layout_hdr, + plh_layouts); + dprintk("%s freeing layout for inode %lu\n", __func__, + lo->plh_inode->i_ino); + list_del_init(&lo->plh_layouts); + pnfs_destroy_layout(NFS_I(lo->plh_inode)); } - rcu_read_unlock(); - spin_unlock(&clp->cl_lock); - - if (list_empty(&layout_list)) - return 0; - return pnfs_layout_free_bulk_destroy_list(&layout_list, is_recall); -} - -/* - * Called by the state manger to remove all layouts established under an - * expired lease. - */ -void -pnfs_destroy_all_layouts(struct nfs_client *clp) -{ - nfs4_deviceid_mark_client_invalid(clp); - nfs4_deviceid_purge_client(clp); - - pnfs_destroy_layouts_byclid(clp, false); } /* @@ -784,21 +667,6 @@ send_layoutget(struct pnfs_layout_hdr *lo, return lseg; } -static void pnfs_clear_layoutcommit(struct inode *inode, - struct list_head *head) -{ - struct nfs_inode *nfsi = NFS_I(inode); - struct pnfs_layout_segment *lseg, *tmp; - - if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) - return; - list_for_each_entry_safe(lseg, tmp, &nfsi->layout->plh_segs, pls_list) { - if (!test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags)) - continue; - pnfs_lseg_dec_and_remove_zero(lseg, head); - } -} - /* * Initiates a LAYOUTRETURN(FILE), and removes the pnfs_layout_hdr * when the layout segment list is empty. @@ -830,7 +698,6 @@ _pnfs_return_layout(struct inode *ino) /* Reference matched in nfs4_layoutreturn_release */ pnfs_get_layout_hdr(lo); empty = list_empty(&lo->plh_segs); - pnfs_clear_layoutcommit(ino, &tmp_list); pnfs_mark_matching_lsegs_invalid(lo, &tmp_list, NULL); /* Don't send a LAYOUTRETURN if list was initially empty */ if (empty) { @@ -843,6 +710,8 @@ _pnfs_return_layout(struct inode *ino) spin_unlock(&ino->i_lock); pnfs_free_lseg_list(&tmp_list); + WARN_ON(test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)); + lrp = kzalloc(sizeof(*lrp), GFP_KERNEL); if (unlikely(lrp == NULL)) { status = -ENOMEM; @@ -1019,7 +888,7 @@ alloc_init_layout_hdr(struct inode *ino, atomic_set(&lo->plh_refcount, 1); INIT_LIST_HEAD(&lo->plh_layouts); INIT_LIST_HEAD(&lo->plh_segs); - INIT_LIST_HEAD(&lo->plh_bulk_destroy); + INIT_LIST_HEAD(&lo->plh_bulk_recall); lo->plh_inode = ino; lo->plh_lc_cred = get_rpccred(ctx->state->owner->so_cred); return lo; @@ -1443,15 +1312,13 @@ EXPORT_SYMBOL_GPL(pnfs_generic_pg_test); int pnfs_write_done_resend_to_mds(struct inode *inode, struct list_head *head, - const struct nfs_pgio_completion_ops *compl_ops, - struct nfs_direct_req *dreq) + const struct nfs_pgio_completion_ops *compl_ops) { struct nfs_pageio_descriptor pgio; LIST_HEAD(failed); /* Resend all requests through the MDS */ nfs_pageio_init_write(&pgio, inode, FLUSH_STABLE, compl_ops); - pgio.pg_dreq = dreq; while (!list_empty(head)) { struct nfs_page *req = nfs_list_entry(head->next); @@ -1480,13 +1347,13 @@ static void pnfs_ld_handle_write_error(struct nfs_write_data *data) dprintk("pnfs write error = %d\n", hdr->pnfs_error); if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags & PNFS_LAYOUTRET_ON_ERROR) { + clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags); pnfs_return_layout(hdr->inode); } if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) data->task.tk_status = pnfs_write_done_resend_to_mds(hdr->inode, &hdr->pages, - hdr->completion_ops, - hdr->dreq); + hdr->completion_ops); } /* @@ -1601,15 +1468,13 @@ EXPORT_SYMBOL_GPL(pnfs_generic_pg_writepages); int pnfs_read_done_resend_to_mds(struct inode *inode, struct list_head *head, - const struct nfs_pgio_completion_ops *compl_ops, - struct nfs_direct_req *dreq) + const struct nfs_pgio_completion_ops *compl_ops) { struct nfs_pageio_descriptor pgio; LIST_HEAD(failed); /* Resend all requests through the MDS */ nfs_pageio_init_read(&pgio, inode, compl_ops); - pgio.pg_dreq = dreq; while (!list_empty(head)) { struct nfs_page *req = nfs_list_entry(head->next); @@ -1634,13 +1499,13 @@ static void pnfs_ld_handle_read_error(struct nfs_read_data *data) dprintk("pnfs read error = %d\n", hdr->pnfs_error); if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags & PNFS_LAYOUTRET_ON_ERROR) { + clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags); pnfs_return_layout(hdr->inode); } if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) data->task.tk_status = pnfs_read_done_resend_to_mds(hdr->inode, &hdr->pages, - hdr->completion_ops, - hdr->dreq); + hdr->completion_ops); } /* @@ -1766,27 +1631,11 @@ static void pnfs_list_write_lseg(struct inode *inode, struct list_head *listp) list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) { if (lseg->pls_range.iomode == IOMODE_RW && - test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags)) + test_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags)) list_add(&lseg->pls_lc_list, listp); } } -static void pnfs_list_write_lseg_done(struct inode *inode, struct list_head *listp) -{ - struct pnfs_layout_segment *lseg, *tmp; - unsigned long *bitlock = &NFS_I(inode)->flags; - - /* Matched by references in pnfs_set_layoutcommit */ - list_for_each_entry_safe(lseg, tmp, listp, pls_lc_list) { - list_del_init(&lseg->pls_lc_list); - pnfs_put_lseg(lseg); - } - - clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock); - smp_mb__after_clear_bit(); - wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING); -} - void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg) { pnfs_layout_io_set_failed(lseg->pls_layout, lseg->pls_range.iomode); @@ -1831,7 +1680,6 @@ void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data) if (nfss->pnfs_curr_ld->cleanup_layoutcommit) nfss->pnfs_curr_ld->cleanup_layoutcommit(data); - pnfs_list_write_lseg_done(data->args.inode, &data->lseg_list); } /* diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 94ba804..dbf7bba 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -132,7 +132,7 @@ struct pnfs_layoutdriver_type { struct pnfs_layout_hdr { atomic_t plh_refcount; struct list_head plh_layouts; /* other client layouts */ - struct list_head plh_bulk_destroy; + struct list_head plh_bulk_recall; /* clnt list of bulk recalls */ struct list_head plh_segs; /* layout segments list */ nfs4_stateid plh_stateid; atomic_t plh_outstanding; /* number of RPCs out */ @@ -196,11 +196,6 @@ struct pnfs_layout_segment *pnfs_layout_process(struct nfs4_layoutget *lgp); void pnfs_free_lseg_list(struct list_head *tmp_list); void pnfs_destroy_layout(struct nfs_inode *); void pnfs_destroy_all_layouts(struct nfs_client *); -int pnfs_destroy_layouts_byfsid(struct nfs_client *clp, - struct nfs_fsid *fsid, - bool is_recall); -int pnfs_destroy_layouts_byclid(struct nfs_client *clp, - bool is_recall); void pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo); void pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, const nfs4_stateid *new, @@ -230,11 +225,9 @@ struct pnfs_layout_segment *pnfs_update_layout(struct inode *ino, void nfs4_deviceid_mark_client_invalid(struct nfs_client *clp); int pnfs_read_done_resend_to_mds(struct inode *inode, struct list_head *head, - const struct nfs_pgio_completion_ops *compl_ops, - struct nfs_direct_req *dreq); + const struct nfs_pgio_completion_ops *compl_ops); int pnfs_write_done_resend_to_mds(struct inode *inode, struct list_head *head, - const struct nfs_pgio_completion_ops *compl_ops, - struct nfs_direct_req *dreq); + const struct nfs_pgio_completion_ops *compl_ops); struct nfs4_threshold *pnfs_mdsthreshold_alloc(void); /* nfs4_deviceid_flags */ diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 6edc807..3f79c77 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -336,14 +336,20 @@ static void nfs_async_rename_done(struct rpc_task *task, void *calldata) struct inode *old_dir = data->old_dir; struct inode *new_dir = data->new_dir; struct dentry *old_dentry = data->old_dentry; + struct dentry *new_dentry = data->new_dentry; if (!NFS_PROTO(old_dir)->rename_done(task, old_dir, new_dir)) { rpc_restart_call_prepare(task); return; } - if (task->tk_status != 0) + if (task->tk_status != 0) { nfs_cancel_async_unlink(old_dentry); + return; + } + + d_drop(old_dentry); + d_drop(new_dentry); } /** @@ -544,18 +550,6 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry) error = rpc_wait_for_completion_task(task); if (error == 0) error = task->tk_status; - switch (error) { - case 0: - /* The rename succeeded */ - nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); - d_move(dentry, sdentry); - break; - case -ERESTARTSYS: - /* The result of the rename is unknown. Play it safe by - * forcing a new lookup */ - d_drop(dentry); - d_drop(sdentry); - } rpc_put_task(task); out_dput: dput(sdentry); |