Skip to content

Commit 27b6f53

Browse files
Peng TaoTom Haynes
authored andcommitted
nfs/flexfiles: send layoutreturn before freeing lseg
Otherwise we'll lose error tracking information when encoding layoutreturn. pnfs_put_lseg may be called from rpc callbacks. So we should not call pnfs_send_layoutreturn directly because it can deadlock in the rpc layer. Signed-off-by: Peng Tao <tao.peng@primarydata.com> Signed-off-by: Tom Haynes <loghyr@primarydata.com>
1 parent 193e3aa commit 27b6f53

File tree

1 file changed

+56
-25
lines changed

1 file changed

+56
-25
lines changed

fs/nfs/pnfs.c

Lines changed: 56 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -346,26 +346,62 @@ pnfs_layout_remove_lseg(struct pnfs_layout_hdr *lo,
346346
/* Return true if layoutreturn is needed */
347347
static bool
348348
pnfs_layout_need_return(struct pnfs_layout_hdr *lo,
349-
struct pnfs_layout_segment *lseg,
350-
nfs4_stateid *stateid, enum pnfs_iomode *iomode)
349+
struct pnfs_layout_segment *lseg)
351350
{
352351
struct pnfs_layout_segment *s;
353352

354353
if (!test_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags))
355354
return false;
356355

357356
list_for_each_entry(s, &lo->plh_segs, pls_list)
358-
if (test_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags))
357+
if (s != lseg && test_bit(NFS_LSEG_LAYOUTRETURN, &s->pls_flags))
359358
return false;
360359

361-
*stateid = lo->plh_stateid;
362-
*iomode = lo->plh_return_iomode;
363-
/* decreased in pnfs_send_layoutreturn() */
364-
lo->plh_block_lgets++;
365-
lo->plh_return_iomode = 0;
366360
return true;
367361
}
368362

363+
static void pnfs_layoutreturn_free_lseg(struct work_struct *work)
364+
{
365+
struct pnfs_layout_segment *lseg;
366+
struct pnfs_layout_hdr *lo;
367+
struct inode *inode;
368+
369+
lseg = container_of(work, struct pnfs_layout_segment, pls_work);
370+
WARN_ON(atomic_read(&lseg->pls_refcount));
371+
lo = lseg->pls_layout;
372+
inode = lo->plh_inode;
373+
374+
spin_lock(&inode->i_lock);
375+
if (pnfs_layout_need_return(lo, lseg)) {
376+
nfs4_stateid stateid;
377+
enum pnfs_iomode iomode;
378+
379+
stateid = lo->plh_stateid;
380+
iomode = lo->plh_return_iomode;
381+
/* decreased in pnfs_send_layoutreturn() */
382+
lo->plh_block_lgets++;
383+
lo->plh_return_iomode = 0;
384+
spin_unlock(&inode->i_lock);
385+
386+
pnfs_send_layoutreturn(lo, stateid, iomode, true);
387+
spin_lock(&inode->i_lock);
388+
} else
389+
/* match pnfs_get_layout_hdr #2 in pnfs_put_lseg */
390+
pnfs_put_layout_hdr(lo);
391+
pnfs_layout_remove_lseg(lo, lseg);
392+
spin_unlock(&inode->i_lock);
393+
pnfs_free_lseg(lseg);
394+
/* match pnfs_get_layout_hdr #1 in pnfs_put_lseg */
395+
pnfs_put_layout_hdr(lo);
396+
}
397+
398+
static void
399+
pnfs_layoutreturn_free_lseg_async(struct pnfs_layout_segment *lseg)
400+
{
401+
INIT_WORK(&lseg->pls_work, pnfs_layoutreturn_free_lseg);
402+
queue_work(nfsiod_workqueue, &lseg->pls_work);
403+
}
404+
369405
void
370406
pnfs_put_lseg(struct pnfs_layout_segment *lseg)
371407
{
@@ -381,21 +417,18 @@ pnfs_put_lseg(struct pnfs_layout_segment *lseg)
381417
lo = lseg->pls_layout;
382418
inode = lo->plh_inode;
383419
if (atomic_dec_and_lock(&lseg->pls_refcount, &inode->i_lock)) {
384-
bool need_return;
385-
nfs4_stateid stateid;
386-
enum pnfs_iomode iomode;
387-
388420
pnfs_get_layout_hdr(lo);
389-
pnfs_layout_remove_lseg(lo, lseg);
390-
need_return = pnfs_layout_need_return(lo, lseg,
391-
&stateid, &iomode);
392-
spin_unlock(&inode->i_lock);
393-
pnfs_free_lseg(lseg);
394-
if (need_return)
395-
pnfs_send_layoutreturn(lo, stateid, iomode,
396-
true);
397-
else
421+
if (pnfs_layout_need_return(lo, lseg)) {
422+
spin_unlock(&inode->i_lock);
423+
/* hdr reference dropped in nfs4_layoutreturn_release */
424+
pnfs_get_layout_hdr(lo);
425+
pnfs_layoutreturn_free_lseg_async(lseg);
426+
} else {
427+
pnfs_layout_remove_lseg(lo, lseg);
428+
spin_unlock(&inode->i_lock);
429+
pnfs_free_lseg(lseg);
398430
pnfs_put_layout_hdr(lo);
431+
}
399432
}
400433
}
401434
EXPORT_SYMBOL_GPL(pnfs_put_lseg);
@@ -1059,8 +1092,7 @@ bool pnfs_roc(struct inode *ino)
10591092
}
10601093
spin_unlock(&ino->i_lock);
10611094
if (layoutreturn)
1062-
pnfs_send_layoutreturn(lo, stateid, IOMODE_ANY, 0,
1063-
NFS4_MAX_UINT64, true);
1095+
pnfs_send_layoutreturn(lo, stateid, IOMODE_ANY, true);
10641096
return false;
10651097
}
10661098

@@ -1127,8 +1159,7 @@ bool pnfs_roc_drain(struct inode *ino, u32 *barrier, struct rpc_task *task)
11271159
spin_unlock(&ino->i_lock);
11281160
if (layoutreturn) {
11291161
rpc_sleep_on(&NFS_SERVER(ino)->roc_rpcwaitq, task, NULL);
1130-
pnfs_send_layoutreturn(lo, stateid, IOMODE_ANY, 0,
1131-
NFS4_MAX_UINT64, false);
1162+
pnfs_send_layoutreturn(lo, stateid, IOMODE_ANY, false);
11321163
}
11331164
return found;
11341165
}

0 commit comments

Comments
 (0)