NFS client bugfixes for Linux 3.9
- Fix an NFSv4 idmapper regression - Fix an Oops in the pNFS blocks client - Fix up various issues with pNFS layoutcommit - Ensure correct read ordering of variables in rpc_wake_up_task_queue_locked -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.13 (GNU/Linux) iQIcBAABAgAGBQJRUedyAAoJEGcL54qWCgDyar0P/2pTT/yxX8ejTu5DmY7e4PYJ jhPG2AEqY/yMLn9GvB375VIs1L8tuY50+3NFhWZFjyNbEU3GV+5Y+kPpBtAgYiSI VyIXiJ/xMtXdYJMYuE/nh5jbcqJsHwGjpcIaSd5BuWzQUaoUYvLulxWd4QN8mmaT 5SuzmgV+7WIqV6RjlaYF82srcOKAjwemcrfRkCNzzJr6aT39gH2YdYFbDaTr7qhU fw0x3QlI7887vSNQcfaGbC1+jr6oe8wRCneOR0tceU/8bcj6zlUDk5HxqSOc28mA jUQieoVRggcM4s5DFpNcuwW6qCPZOmzv/OFD6oqnhyyonPOrue+7zaoujZmGNmjx dT2V/jQehanYD25WpDO8OyFXUeYE4x9bgHKsszhBTwr4x5D8ceEJ1sugcOPiTTxu tflbbuWbt+BguvXp4p8QayUj0V2cplM/nOovWyUG+BH46sz3Dtv46NOgJeO2a29g T6jayxmKCxvtPKtG0j34BzLngiKabZTSEhFms6Qarp9lwWvHWrR9KWGuDBNvy1Ts GMBN8P6Ib40yVi6Pwlj5Jpy6yLKVklHtJQpactr63AZmYrF4bBBSom+MWAh3X1iO QtF0x9Z1bBkXY2Q/u+3vWMxQtEPeW+pSiloj8aiceFAt33zKM+1bLofDhEw0s2fI wJEHYsGyGtDQINgP0v1e =OPbZ -----END PGP SIGNATURE----- Merge tag 'nfs-for-3.9-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs Pull NFS client bugfixes from Trond Myklebust: - Fix an NFSv4 idmapper regression - Fix an Oops in the pNFS blocks client - Fix up various issues with pNFS layoutcommit - Ensure correct read ordering of variables in rpc_wake_up_task_queue_locked * tag 'nfs-for-3.9-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: SUNRPC: Add barriers to ensure read ordering in rpc_wake_up_task_queue_locked NFSv4.1: Add a helper pnfs_commit_and_return_layout NFSv4.1: Always clear the NFS_INO_LAYOUTCOMMIT in layoutreturn NFSv4.1: Fix a race in pNFS layoutcommit pnfs-block: removing DM device maybe cause oops when call dev_remove NFSv4: Fix the string length returned by the idmapper
This commit is contained in:
Коммит
5d538483ea
|
@ -55,7 +55,8 @@ static void dev_remove(struct net *net, dev_t dev)
|
|||
|
||||
bl_pipe_msg.bl_wq = &nn->bl_wq;
|
||||
memset(msg, 0, sizeof(*msg));
|
||||
msg->data = kzalloc(1 + sizeof(bl_umount_request), GFP_NOFS);
|
||||
msg->len = sizeof(bl_msg) + bl_msg.totallen;
|
||||
msg->data = kzalloc(msg->len, GFP_NOFS);
|
||||
if (!msg->data)
|
||||
goto out;
|
||||
|
||||
|
@ -66,7 +67,6 @@ 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) {
|
||||
|
|
|
@ -726,9 +726,9 @@ out1:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data)
|
||||
static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data, size_t datalen)
|
||||
{
|
||||
return key_instantiate_and_link(key, data, strlen(data) + 1,
|
||||
return key_instantiate_and_link(key, data, datalen,
|
||||
id_resolver_cache->thread_keyring,
|
||||
authkey);
|
||||
}
|
||||
|
@ -738,6 +738,7 @@ 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,13 +748,15 @@ 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;
|
||||
sprintf(id_str, "%d", im->im_id);
|
||||
ret = nfs_idmap_instantiate(key, authkey, id_str);
|
||||
/* 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);
|
||||
break;
|
||||
case IDMAP_CONV_IDTONAME:
|
||||
if (upcall->im_id != im->im_id)
|
||||
break;
|
||||
ret = nfs_idmap_instantiate(key, authkey, im->im_name);
|
||||
len = strlen(im->im_name);
|
||||
ret = nfs_idmap_instantiate(key, authkey, im->im_name, len);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
|
|
|
@ -129,7 +129,6 @@ 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -2632,7 +2632,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
|
|||
int status;
|
||||
|
||||
if (pnfs_ld_layoutret_on_setattr(inode))
|
||||
pnfs_return_layout(inode);
|
||||
pnfs_commit_and_return_layout(inode);
|
||||
|
||||
nfs_fattr_init(fattr);
|
||||
|
||||
|
@ -6416,22 +6416,8 @@ 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);
|
||||
}
|
||||
|
|
|
@ -417,6 +417,16 @@ 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)
|
||||
|
@ -430,11 +440,8 @@ 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 (atomic_dec_and_test(&lseg->pls_refcount)) {
|
||||
pnfs_layout_remove_lseg(lseg->pls_layout, lseg);
|
||||
list_add(&lseg->pls_list, tmp_list);
|
||||
if (pnfs_lseg_dec_and_remove_zero(lseg, tmp_list))
|
||||
rv = 1;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
@ -777,6 +784,21 @@ 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.
|
||||
|
@ -808,6 +830,7 @@ _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) {
|
||||
|
@ -820,8 +843,6 @@ _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;
|
||||
|
@ -845,6 +866,33 @@ out:
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(_pnfs_return_layout);
|
||||
|
||||
int
|
||||
pnfs_commit_and_return_layout(struct inode *inode)
|
||||
{
|
||||
struct pnfs_layout_hdr *lo;
|
||||
int ret;
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
lo = NFS_I(inode)->layout;
|
||||
if (lo == NULL) {
|
||||
spin_unlock(&inode->i_lock);
|
||||
return 0;
|
||||
}
|
||||
pnfs_get_layout_hdr(lo);
|
||||
/* Block new layoutgets and read/write to ds */
|
||||
lo->plh_block_lgets++;
|
||||
spin_unlock(&inode->i_lock);
|
||||
filemap_fdatawait(inode->i_mapping);
|
||||
ret = pnfs_layoutcommit_inode(inode, true);
|
||||
if (ret == 0)
|
||||
ret = _pnfs_return_layout(inode);
|
||||
spin_lock(&inode->i_lock);
|
||||
lo->plh_block_lgets--;
|
||||
spin_unlock(&inode->i_lock);
|
||||
pnfs_put_layout_hdr(lo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool pnfs_roc(struct inode *ino)
|
||||
{
|
||||
struct pnfs_layout_hdr *lo;
|
||||
|
@ -1458,7 +1506,6 @@ 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))
|
||||
|
@ -1613,7 +1660,6 @@ 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))
|
||||
|
@ -1746,11 +1792,27 @@ 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_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags))
|
||||
test_and_clear_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);
|
||||
|
@ -1795,6 +1857,7 @@ 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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -219,6 +219,7 @@ void pnfs_set_layoutcommit(struct nfs_write_data *wdata);
|
|||
void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data);
|
||||
int pnfs_layoutcommit_inode(struct inode *inode, bool sync);
|
||||
int _pnfs_return_layout(struct inode *);
|
||||
int pnfs_commit_and_return_layout(struct inode *);
|
||||
void pnfs_ld_write_done(struct nfs_write_data *);
|
||||
void pnfs_ld_read_done(struct nfs_read_data *);
|
||||
struct pnfs_layout_segment *pnfs_update_layout(struct inode *ino,
|
||||
|
@ -407,6 +408,11 @@ static inline int pnfs_return_layout(struct inode *ino)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int pnfs_commit_and_return_layout(struct inode *inode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
pnfs_ld_layoutret_on_setattr(struct inode *inode)
|
||||
{
|
||||
|
|
|
@ -180,6 +180,8 @@ static void __rpc_add_wait_queue(struct rpc_wait_queue *queue,
|
|||
list_add_tail(&task->u.tk_wait.list, &queue->tasks[0]);
|
||||
task->tk_waitqueue = queue;
|
||||
queue->qlen++;
|
||||
/* barrier matches the read in rpc_wake_up_task_queue_locked() */
|
||||
smp_wmb();
|
||||
rpc_set_queued(task);
|
||||
|
||||
dprintk("RPC: %5u added to queue %p \"%s\"\n",
|
||||
|
@ -430,8 +432,11 @@ static void __rpc_do_wake_up_task(struct rpc_wait_queue *queue, struct rpc_task
|
|||
*/
|
||||
static void rpc_wake_up_task_queue_locked(struct rpc_wait_queue *queue, struct rpc_task *task)
|
||||
{
|
||||
if (RPC_IS_QUEUED(task) && task->tk_waitqueue == queue)
|
||||
__rpc_do_wake_up_task(queue, task);
|
||||
if (RPC_IS_QUEUED(task)) {
|
||||
smp_rmb();
|
||||
if (task->tk_waitqueue == queue)
|
||||
__rpc_do_wake_up_task(queue, task);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Загрузка…
Ссылка в новой задаче