NFS client bugfixe and cleanup for Linux 4.5

Bugfix:
 - pNFS: Fix for missing layoutreturn calls
 
 Cleanup:
 - pNFS: rename NFS_LAYOUT_RETURN_BEFORE_CLOSE for code clarity
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJWsUFjAAoJEGcL54qWCgDyipwP/0byMIrCx+B+w/tyBAhyb3Er
 7V9hM/r51EYwWVQp7POOV10oX2rEde9eyz3q5fRhLgximUNxtqLOTcaYIZH3r29q
 apuDyEKHSgj6JFu3UG1a8FtBCy8oGkvHglsw7xSq6PcX26rpP95vnSrsA1iDheyU
 zeYTcYgsYuhfXzwriNmAKD1ziPyTw5aeiSfzdBCDi+T9LnP2bKhPQ6j749vOwyO8
 wmRuwoAxFjt1xMmogUH9Bste7jX4YTF6Ww1PX1/A9LseipR9nW2ANO5yjupCnLLh
 ky4AVgunbjsbVt6XLo1DmageSqFtf340YyIX/ZFpb97I15qu7Vnzhmkgo2FjYdZE
 S/LRnUp8oDlSWRDAILnvD47br0jrjB7DUVThmyiYFTc135FTluzhzsWWJOT0DOp2
 uI6VtJ4pGd2gUo6K4R1PLAgzP6nxM+IulEbxhYrE4Eu9YfbdICQUmSFkszyv8Lej
 +yQXm3zx69i62/V/ipU4VQwt7943noVzRFyZMDCcLaN2S7J6JhN41/tI//SUlbHb
 e4N6Tb35HUrW6pBh1qeFnZqiN2mvB8RpZLQwpX8VnrYijljN1vh5szqj16fkVkiK
 MMoRS8c4fmIKc1Lxa54/kTKS1CWW7dVl35U5aBm+E7CvnemhA9AqTXrRTJOKgOE1
 SyTPxTEWwG658jy7xKLZ
 =ZSKC
 -----END PGP SIGNATURE-----

Merge tag 'nfs-for-4.5-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

Pull NFS client bugfix and cleanup from Trond Myklebust:
 "Bugfix:
   - pNFS: Fix for missing layoutreturn calls

  Cleanup:
   - pNFS: rename NFS_LAYOUT_RETURN_BEFORE_CLOSE for code clarity"

* tag 'nfs-for-4.5-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  NFS: Cleanup - rename NFS_LAYOUT_RETURN_BEFORE_CLOSE
  pNFS: Fix missing layoutreturn calls
This commit is contained in:
Linus Torvalds 2016-02-03 09:36:41 -08:00
commit 81b676bd87
4 changed files with 62 additions and 68 deletions

View File

@ -1215,7 +1215,7 @@ static int ff_layout_read_done_cb(struct rpc_task *task,
hdr->pgio_mirror_idx + 1, hdr->pgio_mirror_idx + 1,
&hdr->pgio_mirror_idx)) &hdr->pgio_mirror_idx))
goto out_eagain; goto out_eagain;
set_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, set_bit(NFS_LAYOUT_RETURN_REQUESTED,
&hdr->lseg->pls_layout->plh_flags); &hdr->lseg->pls_layout->plh_flags);
pnfs_read_resend_pnfs(hdr); pnfs_read_resend_pnfs(hdr);
return task->tk_status; return task->tk_status;

View File

@ -412,7 +412,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx,
OP_ILLEGAL, GFP_NOIO); OP_ILLEGAL, GFP_NOIO);
if (!fail_return) { if (!fail_return) {
if (ff_layout_has_available_ds(lseg)) if (ff_layout_has_available_ds(lseg))
set_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, set_bit(NFS_LAYOUT_RETURN_REQUESTED,
&lseg->pls_layout->plh_flags); &lseg->pls_layout->plh_flags);
else else
pnfs_error_mark_layout_for_return(ino, lseg); pnfs_error_mark_layout_for_return(ino, lseg);

View File

@ -52,9 +52,7 @@ static DEFINE_SPINLOCK(pnfs_spinlock);
*/ */
static LIST_HEAD(pnfs_modules_tbl); static LIST_HEAD(pnfs_modules_tbl);
static int static void pnfs_layoutreturn_before_put_layout_hdr(struct pnfs_layout_hdr *lo);
pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, const nfs4_stateid *stateid,
enum pnfs_iomode iomode, bool sync);
/* Return the registered pnfs layout driver module matching given id */ /* Return the registered pnfs layout driver module matching given id */
static struct pnfs_layoutdriver_type * static struct pnfs_layoutdriver_type *
@ -243,6 +241,8 @@ pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo)
{ {
struct inode *inode = lo->plh_inode; struct inode *inode = lo->plh_inode;
pnfs_layoutreturn_before_put_layout_hdr(lo);
if (atomic_dec_and_lock(&lo->plh_refcount, &inode->i_lock)) { if (atomic_dec_and_lock(&lo->plh_refcount, &inode->i_lock)) {
if (!list_empty(&lo->plh_segs)) if (!list_empty(&lo->plh_segs))
WARN_ONCE(1, "NFS: BUG unfreed layout segments.\n"); WARN_ONCE(1, "NFS: BUG unfreed layout segments.\n");
@ -345,58 +345,6 @@ pnfs_layout_remove_lseg(struct pnfs_layout_hdr *lo,
rpc_wake_up(&NFS_SERVER(inode)->roc_rpcwaitq); rpc_wake_up(&NFS_SERVER(inode)->roc_rpcwaitq);
} }
/* Return true if layoutreturn is needed */
static bool
pnfs_layout_need_return(struct pnfs_layout_hdr *lo,
struct pnfs_layout_segment *lseg)
{
struct pnfs_layout_segment *s;
if (!test_and_clear_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags))
return false;
list_for_each_entry(s, &lo->plh_segs, pls_list)
if (s != lseg && test_bit(NFS_LSEG_LAYOUTRETURN, &s->pls_flags))
return false;
return true;
}
static bool
pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo)
{
if (test_and_set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))
return false;
lo->plh_return_iomode = 0;
pnfs_get_layout_hdr(lo);
clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, &lo->plh_flags);
return true;
}
static void pnfs_layoutreturn_before_put_lseg(struct pnfs_layout_segment *lseg,
struct pnfs_layout_hdr *lo, struct inode *inode)
{
lo = lseg->pls_layout;
inode = lo->plh_inode;
spin_lock(&inode->i_lock);
if (pnfs_layout_need_return(lo, lseg)) {
nfs4_stateid stateid;
enum pnfs_iomode iomode;
bool send;
nfs4_stateid_copy(&stateid, &lo->plh_stateid);
iomode = lo->plh_return_iomode;
send = pnfs_prepare_layoutreturn(lo);
spin_unlock(&inode->i_lock);
if (send) {
/* Send an async layoutreturn so we dont deadlock */
pnfs_send_layoutreturn(lo, &stateid, iomode, false);
}
} else
spin_unlock(&inode->i_lock);
}
void void
pnfs_put_lseg(struct pnfs_layout_segment *lseg) pnfs_put_lseg(struct pnfs_layout_segment *lseg)
{ {
@ -410,15 +358,8 @@ pnfs_put_lseg(struct pnfs_layout_segment *lseg)
atomic_read(&lseg->pls_refcount), atomic_read(&lseg->pls_refcount),
test_bit(NFS_LSEG_VALID, &lseg->pls_flags)); test_bit(NFS_LSEG_VALID, &lseg->pls_flags));
/* Handle the case where refcount != 1 */
if (atomic_add_unless(&lseg->pls_refcount, -1, 1))
return;
lo = lseg->pls_layout; lo = lseg->pls_layout;
inode = lo->plh_inode; inode = lo->plh_inode;
/* Do we need a layoutreturn? */
if (test_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags))
pnfs_layoutreturn_before_put_lseg(lseg, lo, inode);
if (atomic_dec_and_lock(&lseg->pls_refcount, &inode->i_lock)) { if (atomic_dec_and_lock(&lseg->pls_refcount, &inode->i_lock)) {
if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags)) { if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags)) {
@ -937,6 +878,17 @@ void pnfs_clear_layoutreturn_waitbit(struct pnfs_layout_hdr *lo)
rpc_wake_up(&NFS_SERVER(lo->plh_inode)->roc_rpcwaitq); rpc_wake_up(&NFS_SERVER(lo->plh_inode)->roc_rpcwaitq);
} }
static bool
pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo)
{
if (test_and_set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))
return false;
lo->plh_return_iomode = 0;
pnfs_get_layout_hdr(lo);
clear_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags);
return true;
}
static int static int
pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, const nfs4_stateid *stateid, pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, const nfs4_stateid *stateid,
enum pnfs_iomode iomode, bool sync) enum pnfs_iomode iomode, bool sync)
@ -971,6 +923,48 @@ out:
return status; return status;
} }
/* Return true if layoutreturn is needed */
static bool
pnfs_layout_need_return(struct pnfs_layout_hdr *lo)
{
struct pnfs_layout_segment *s;
if (!test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags))
return false;
/* Defer layoutreturn until all lsegs are done */
list_for_each_entry(s, &lo->plh_segs, pls_list) {
if (test_bit(NFS_LSEG_LAYOUTRETURN, &s->pls_flags))
return false;
}
return true;
}
static void pnfs_layoutreturn_before_put_layout_hdr(struct pnfs_layout_hdr *lo)
{
struct inode *inode= lo->plh_inode;
if (!test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags))
return;
spin_lock(&inode->i_lock);
if (pnfs_layout_need_return(lo)) {
nfs4_stateid stateid;
enum pnfs_iomode iomode;
bool send;
nfs4_stateid_copy(&stateid, &lo->plh_stateid);
iomode = lo->plh_return_iomode;
send = pnfs_prepare_layoutreturn(lo);
spin_unlock(&inode->i_lock);
if (send) {
/* Send an async layoutreturn so we dont deadlock */
pnfs_send_layoutreturn(lo, &stateid, iomode, false);
}
} else
spin_unlock(&inode->i_lock);
}
/* /*
* Initiates a LAYOUTRETURN(FILE), and removes the pnfs_layout_hdr * Initiates a LAYOUTRETURN(FILE), and removes the pnfs_layout_hdr
* when the layout segment list is empty. * when the layout segment list is empty.
@ -1091,7 +1085,7 @@ bool pnfs_roc(struct inode *ino)
nfs4_stateid_copy(&stateid, &lo->plh_stateid); nfs4_stateid_copy(&stateid, &lo->plh_stateid);
/* always send layoutreturn if being marked so */ /* always send layoutreturn if being marked so */
if (test_and_clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, if (test_and_clear_bit(NFS_LAYOUT_RETURN_REQUESTED,
&lo->plh_flags)) &lo->plh_flags))
layoutreturn = pnfs_prepare_layoutreturn(lo); layoutreturn = pnfs_prepare_layoutreturn(lo);
@ -1772,7 +1766,7 @@ pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
pnfs_set_plh_return_iomode(lo, return_range->iomode); pnfs_set_plh_return_iomode(lo, return_range->iomode);
if (!mark_lseg_invalid(lseg, tmp_list)) if (!mark_lseg_invalid(lseg, tmp_list))
remaining++; remaining++;
set_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, set_bit(NFS_LAYOUT_RETURN_REQUESTED,
&lo->plh_flags); &lo->plh_flags);
} }
return remaining; return remaining;

View File

@ -94,8 +94,8 @@ enum {
NFS_LAYOUT_RO_FAILED = 0, /* get ro layout failed stop trying */ NFS_LAYOUT_RO_FAILED = 0, /* get ro layout failed stop trying */
NFS_LAYOUT_RW_FAILED, /* get rw layout failed stop trying */ NFS_LAYOUT_RW_FAILED, /* get rw layout failed stop trying */
NFS_LAYOUT_BULK_RECALL, /* bulk recall affecting layout */ NFS_LAYOUT_BULK_RECALL, /* bulk recall affecting layout */
NFS_LAYOUT_RETURN, /* Return this layout ASAP */ NFS_LAYOUT_RETURN, /* layoutreturn in progress */
NFS_LAYOUT_RETURN_BEFORE_CLOSE, /* Return this layout before close */ NFS_LAYOUT_RETURN_REQUESTED, /* Return this layout ASAP */
NFS_LAYOUT_INVALID_STID, /* layout stateid id is invalid */ NFS_LAYOUT_INVALID_STID, /* layout stateid id is invalid */
NFS_LAYOUT_FIRST_LAYOUTGET, /* Serialize first layoutget */ NFS_LAYOUT_FIRST_LAYOUTGET, /* Serialize first layoutget */
}; };