Skip to content

Commit 5d53848

Browse files
committed
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
2 parents a12183c + 1166fde commit 5d53848

File tree

7 files changed

+96
-34
lines changed

7 files changed

+96
-34
lines changed

fs/nfs/blocklayout/blocklayoutdm.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ static void dev_remove(struct net *net, dev_t dev)
5555

5656
bl_pipe_msg.bl_wq = &nn->bl_wq;
5757
memset(msg, 0, sizeof(*msg));
58-
msg->data = kzalloc(1 + sizeof(bl_umount_request), GFP_NOFS);
58+
msg->len = sizeof(bl_msg) + bl_msg.totallen;
59+
msg->data = kzalloc(msg->len, GFP_NOFS);
5960
if (!msg->data)
6061
goto out;
6162

@@ -66,7 +67,6 @@ static void dev_remove(struct net *net, dev_t dev)
6667
memcpy(msg->data, &bl_msg, sizeof(bl_msg));
6768
dataptr = (uint8_t *) msg->data;
6869
memcpy(&dataptr[sizeof(bl_msg)], &bl_umount_request, sizeof(bl_umount_request));
69-
msg->len = sizeof(bl_msg) + bl_msg.totallen;
7070

7171
add_wait_queue(&nn->bl_wq, &wq);
7272
if (rpc_queue_upcall(nn->bl_device_pipe, msg) < 0) {

fs/nfs/idmap.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -726,9 +726,9 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons,
726726
return ret;
727727
}
728728

729-
static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data)
729+
static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data, size_t datalen)
730730
{
731-
return key_instantiate_and_link(key, data, strlen(data) + 1,
731+
return key_instantiate_and_link(key, data, datalen,
732732
id_resolver_cache->thread_keyring,
733733
authkey);
734734
}
@@ -738,6 +738,7 @@ static int nfs_idmap_read_and_verify_message(struct idmap_msg *im,
738738
struct key *key, struct key *authkey)
739739
{
740740
char id_str[NFS_UINT_MAXLEN];
741+
size_t len;
741742
int ret = -ENOKEY;
742743

743744
/* ret = -ENOKEY */
@@ -747,13 +748,15 @@ static int nfs_idmap_read_and_verify_message(struct idmap_msg *im,
747748
case IDMAP_CONV_NAMETOID:
748749
if (strcmp(upcall->im_name, im->im_name) != 0)
749750
break;
750-
sprintf(id_str, "%d", im->im_id);
751-
ret = nfs_idmap_instantiate(key, authkey, id_str);
751+
/* Note: here we store the NUL terminator too */
752+
len = sprintf(id_str, "%d", im->im_id) + 1;
753+
ret = nfs_idmap_instantiate(key, authkey, id_str, len);
752754
break;
753755
case IDMAP_CONV_IDTONAME:
754756
if (upcall->im_id != im->im_id)
755757
break;
756-
ret = nfs_idmap_instantiate(key, authkey, im->im_name);
758+
len = strlen(im->im_name);
759+
ret = nfs_idmap_instantiate(key, authkey, im->im_name, len);
757760
break;
758761
default:
759762
ret = -EINVAL;

fs/nfs/nfs4filelayout.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,6 @@ static void filelayout_fenceme(struct inode *inode, struct pnfs_layout_hdr *lo)
129129
{
130130
if (!test_and_clear_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))
131131
return;
132-
clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags);
133132
pnfs_return_layout(inode);
134133
}
135134

fs/nfs/nfs4proc.c

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2632,7 +2632,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
26322632
int status;
26332633

26342634
if (pnfs_ld_layoutret_on_setattr(inode))
2635-
pnfs_return_layout(inode);
2635+
pnfs_commit_and_return_layout(inode);
26362636

26372637
nfs_fattr_init(fattr);
26382638

@@ -6416,22 +6416,8 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata)
64166416
static void nfs4_layoutcommit_release(void *calldata)
64176417
{
64186418
struct nfs4_layoutcommit_data *data = calldata;
6419-
struct pnfs_layout_segment *lseg, *tmp;
6420-
unsigned long *bitlock = &NFS_I(data->args.inode)->flags;
64216419

64226420
pnfs_cleanup_layoutcommit(data);
6423-
/* Matched by references in pnfs_set_layoutcommit */
6424-
list_for_each_entry_safe(lseg, tmp, &data->lseg_list, pls_lc_list) {
6425-
list_del_init(&lseg->pls_lc_list);
6426-
if (test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT,
6427-
&lseg->pls_flags))
6428-
pnfs_put_lseg(lseg);
6429-
}
6430-
6431-
clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock);
6432-
smp_mb__after_clear_bit();
6433-
wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING);
6434-
64356421
put_rpccred(data->cred);
64366422
kfree(data);
64376423
}

fs/nfs/pnfs.c

Lines changed: 72 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,16 @@ should_free_lseg(struct pnfs_layout_range *lseg_range,
417417
lo_seg_intersecting(lseg_range, recall_range);
418418
}
419419

420+
static bool pnfs_lseg_dec_and_remove_zero(struct pnfs_layout_segment *lseg,
421+
struct list_head *tmp_list)
422+
{
423+
if (!atomic_dec_and_test(&lseg->pls_refcount))
424+
return false;
425+
pnfs_layout_remove_lseg(lseg->pls_layout, lseg);
426+
list_add(&lseg->pls_list, tmp_list);
427+
return true;
428+
}
429+
420430
/* Returns 1 if lseg is removed from list, 0 otherwise */
421431
static int mark_lseg_invalid(struct pnfs_layout_segment *lseg,
422432
struct list_head *tmp_list)
@@ -430,11 +440,8 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg,
430440
*/
431441
dprintk("%s: lseg %p ref %d\n", __func__, lseg,
432442
atomic_read(&lseg->pls_refcount));
433-
if (atomic_dec_and_test(&lseg->pls_refcount)) {
434-
pnfs_layout_remove_lseg(lseg->pls_layout, lseg);
435-
list_add(&lseg->pls_list, tmp_list);
443+
if (pnfs_lseg_dec_and_remove_zero(lseg, tmp_list))
436444
rv = 1;
437-
}
438445
}
439446
return rv;
440447
}
@@ -777,6 +784,21 @@ send_layoutget(struct pnfs_layout_hdr *lo,
777784
return lseg;
778785
}
779786

787+
static void pnfs_clear_layoutcommit(struct inode *inode,
788+
struct list_head *head)
789+
{
790+
struct nfs_inode *nfsi = NFS_I(inode);
791+
struct pnfs_layout_segment *lseg, *tmp;
792+
793+
if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags))
794+
return;
795+
list_for_each_entry_safe(lseg, tmp, &nfsi->layout->plh_segs, pls_list) {
796+
if (!test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags))
797+
continue;
798+
pnfs_lseg_dec_and_remove_zero(lseg, head);
799+
}
800+
}
801+
780802
/*
781803
* Initiates a LAYOUTRETURN(FILE), and removes the pnfs_layout_hdr
782804
* when the layout segment list is empty.
@@ -808,6 +830,7 @@ _pnfs_return_layout(struct inode *ino)
808830
/* Reference matched in nfs4_layoutreturn_release */
809831
pnfs_get_layout_hdr(lo);
810832
empty = list_empty(&lo->plh_segs);
833+
pnfs_clear_layoutcommit(ino, &tmp_list);
811834
pnfs_mark_matching_lsegs_invalid(lo, &tmp_list, NULL);
812835
/* Don't send a LAYOUTRETURN if list was initially empty */
813836
if (empty) {
@@ -820,8 +843,6 @@ _pnfs_return_layout(struct inode *ino)
820843
spin_unlock(&ino->i_lock);
821844
pnfs_free_lseg_list(&tmp_list);
822845

823-
WARN_ON(test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags));
824-
825846
lrp = kzalloc(sizeof(*lrp), GFP_KERNEL);
826847
if (unlikely(lrp == NULL)) {
827848
status = -ENOMEM;
@@ -845,6 +866,33 @@ _pnfs_return_layout(struct inode *ino)
845866
}
846867
EXPORT_SYMBOL_GPL(_pnfs_return_layout);
847868

869+
int
870+
pnfs_commit_and_return_layout(struct inode *inode)
871+
{
872+
struct pnfs_layout_hdr *lo;
873+
int ret;
874+
875+
spin_lock(&inode->i_lock);
876+
lo = NFS_I(inode)->layout;
877+
if (lo == NULL) {
878+
spin_unlock(&inode->i_lock);
879+
return 0;
880+
}
881+
pnfs_get_layout_hdr(lo);
882+
/* Block new layoutgets and read/write to ds */
883+
lo->plh_block_lgets++;
884+
spin_unlock(&inode->i_lock);
885+
filemap_fdatawait(inode->i_mapping);
886+
ret = pnfs_layoutcommit_inode(inode, true);
887+
if (ret == 0)
888+
ret = _pnfs_return_layout(inode);
889+
spin_lock(&inode->i_lock);
890+
lo->plh_block_lgets--;
891+
spin_unlock(&inode->i_lock);
892+
pnfs_put_layout_hdr(lo);
893+
return ret;
894+
}
895+
848896
bool pnfs_roc(struct inode *ino)
849897
{
850898
struct pnfs_layout_hdr *lo;
@@ -1458,7 +1506,6 @@ static void pnfs_ld_handle_write_error(struct nfs_write_data *data)
14581506
dprintk("pnfs write error = %d\n", hdr->pnfs_error);
14591507
if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags &
14601508
PNFS_LAYOUTRET_ON_ERROR) {
1461-
clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags);
14621509
pnfs_return_layout(hdr->inode);
14631510
}
14641511
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)
16131660
dprintk("pnfs read error = %d\n", hdr->pnfs_error);
16141661
if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags &
16151662
PNFS_LAYOUTRET_ON_ERROR) {
1616-
clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags);
16171663
pnfs_return_layout(hdr->inode);
16181664
}
16191665
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)
17461792

17471793
list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) {
17481794
if (lseg->pls_range.iomode == IOMODE_RW &&
1749-
test_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags))
1795+
test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags))
17501796
list_add(&lseg->pls_lc_list, listp);
17511797
}
17521798
}
17531799

1800+
static void pnfs_list_write_lseg_done(struct inode *inode, struct list_head *listp)
1801+
{
1802+
struct pnfs_layout_segment *lseg, *tmp;
1803+
unsigned long *bitlock = &NFS_I(inode)->flags;
1804+
1805+
/* Matched by references in pnfs_set_layoutcommit */
1806+
list_for_each_entry_safe(lseg, tmp, listp, pls_lc_list) {
1807+
list_del_init(&lseg->pls_lc_list);
1808+
pnfs_put_lseg(lseg);
1809+
}
1810+
1811+
clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock);
1812+
smp_mb__after_clear_bit();
1813+
wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING);
1814+
}
1815+
17541816
void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg)
17551817
{
17561818
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)
17951857

17961858
if (nfss->pnfs_curr_ld->cleanup_layoutcommit)
17971859
nfss->pnfs_curr_ld->cleanup_layoutcommit(data);
1860+
pnfs_list_write_lseg_done(data->args.inode, &data->lseg_list);
17981861
}
17991862

18001863
/*

fs/nfs/pnfs.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ void pnfs_set_layoutcommit(struct nfs_write_data *wdata);
219219
void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data);
220220
int pnfs_layoutcommit_inode(struct inode *inode, bool sync);
221221
int _pnfs_return_layout(struct inode *);
222+
int pnfs_commit_and_return_layout(struct inode *);
222223
void pnfs_ld_write_done(struct nfs_write_data *);
223224
void pnfs_ld_read_done(struct nfs_read_data *);
224225
struct pnfs_layout_segment *pnfs_update_layout(struct inode *ino,
@@ -407,6 +408,11 @@ static inline int pnfs_return_layout(struct inode *ino)
407408
return 0;
408409
}
409410

411+
static inline int pnfs_commit_and_return_layout(struct inode *inode)
412+
{
413+
return 0;
414+
}
415+
410416
static inline bool
411417
pnfs_ld_layoutret_on_setattr(struct inode *inode)
412418
{

net/sunrpc/sched.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ static void __rpc_add_wait_queue(struct rpc_wait_queue *queue,
180180
list_add_tail(&task->u.tk_wait.list, &queue->tasks[0]);
181181
task->tk_waitqueue = queue;
182182
queue->qlen++;
183+
/* barrier matches the read in rpc_wake_up_task_queue_locked() */
184+
smp_wmb();
183185
rpc_set_queued(task);
184186

185187
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
430432
*/
431433
static void rpc_wake_up_task_queue_locked(struct rpc_wait_queue *queue, struct rpc_task *task)
432434
{
433-
if (RPC_IS_QUEUED(task) && task->tk_waitqueue == queue)
434-
__rpc_do_wake_up_task(queue, task);
435+
if (RPC_IS_QUEUED(task)) {
436+
smp_rmb();
437+
if (task->tk_waitqueue == queue)
438+
__rpc_do_wake_up_task(queue, task);
439+
}
435440
}
436441

437442
/*

0 commit comments

Comments
 (0)