pNFS: Don't discard layout segments that are marked for return
If there are layout segments that are marked for return, then we need to ensure that pnfs_mark_matching_lsegs_return() does not just silently discard them, but it should tell the caller that there is a layoutreturn scheduled. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
parent
cd3f77d74a
commit
e0b7d420f7
fs/nfs
@ -283,19 +283,22 @@ static u32 initiate_file_draining(struct nfs_client *clp,
|
|||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pnfs_mark_matching_lsegs_return(lo, &free_me_list,
|
switch (pnfs_mark_matching_lsegs_return(lo, &free_me_list,
|
||||||
&args->cbl_range,
|
&args->cbl_range,
|
||||||
be32_to_cpu(args->cbl_stateid.seqid))) {
|
be32_to_cpu(args->cbl_stateid.seqid))) {
|
||||||
|
case 0:
|
||||||
|
case -EBUSY:
|
||||||
|
/* There are layout segments that need to be returned */
|
||||||
rv = NFS4_OK;
|
rv = NFS4_OK;
|
||||||
goto unlock;
|
break;
|
||||||
}
|
case -ENOENT:
|
||||||
|
/* Embrace your forgetfulness! */
|
||||||
|
rv = NFS4ERR_NOMATCHING_LAYOUT;
|
||||||
|
|
||||||
/* Embrace your forgetfulness! */
|
if (NFS_SERVER(ino)->pnfs_curr_ld->return_range) {
|
||||||
rv = NFS4ERR_NOMATCHING_LAYOUT;
|
NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo,
|
||||||
|
&args->cbl_range);
|
||||||
if (NFS_SERVER(ino)->pnfs_curr_ld->return_range) {
|
}
|
||||||
NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo,
|
|
||||||
&args->cbl_range);
|
|
||||||
}
|
}
|
||||||
unlock:
|
unlock:
|
||||||
spin_unlock(&ino->i_lock);
|
spin_unlock(&ino->i_lock);
|
||||||
|
@ -2238,15 +2238,31 @@ out_forget:
|
|||||||
return ERR_PTR(-EAGAIN);
|
return ERR_PTR(-EAGAIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mark_lseg_invalid_or_return(struct pnfs_layout_segment *lseg,
|
||||||
|
struct list_head *tmp_list)
|
||||||
|
{
|
||||||
|
if (!mark_lseg_invalid(lseg, tmp_list))
|
||||||
|
return 0;
|
||||||
|
pnfs_cache_lseg_for_layoutreturn(lseg->pls_layout, lseg);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pnfs_mark_matching_lsegs_return - Free or return matching layout segments
|
* pnfs_mark_matching_lsegs_return - Free or return matching layout segments
|
||||||
* @lo: pointer to layout header
|
* @lo: pointer to layout header
|
||||||
* @tmp_list: list header to be used with pnfs_free_lseg_list()
|
* @tmp_list: list header to be used with pnfs_free_lseg_list()
|
||||||
* @return_range: describe layout segment ranges to be returned
|
* @return_range: describe layout segment ranges to be returned
|
||||||
|
* @seq: stateid seqid to match
|
||||||
*
|
*
|
||||||
* This function is mainly intended for use by layoutrecall. It attempts
|
* This function is mainly intended for use by layoutrecall. It attempts
|
||||||
* to free the layout segment immediately, or else to mark it for return
|
* to free the layout segment immediately, or else to mark it for return
|
||||||
* as soon as its reference count drops to zero.
|
* as soon as its reference count drops to zero.
|
||||||
|
*
|
||||||
|
* Returns
|
||||||
|
* - 0: a layoutreturn needs to be scheduled.
|
||||||
|
* - EBUSY: there are layout segment that are still in use.
|
||||||
|
* - ENOENT: there are no layout segments that need to be returned.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
|
pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
|
||||||
@ -2259,9 +2275,6 @@ pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
|
|||||||
|
|
||||||
dprintk("%s:Begin lo %p\n", __func__, lo);
|
dprintk("%s:Begin lo %p\n", __func__, lo);
|
||||||
|
|
||||||
if (list_empty(&lo->plh_segs))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
assert_spin_locked(&lo->plh_inode->i_lock);
|
assert_spin_locked(&lo->plh_inode->i_lock);
|
||||||
|
|
||||||
list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list)
|
list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list)
|
||||||
@ -2271,16 +2284,23 @@ pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
|
|||||||
lseg, lseg->pls_range.iomode,
|
lseg, lseg->pls_range.iomode,
|
||||||
lseg->pls_range.offset,
|
lseg->pls_range.offset,
|
||||||
lseg->pls_range.length);
|
lseg->pls_range.length);
|
||||||
if (mark_lseg_invalid(lseg, tmp_list))
|
if (mark_lseg_invalid_or_return(lseg, tmp_list))
|
||||||
continue;
|
continue;
|
||||||
remaining++;
|
remaining++;
|
||||||
set_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags);
|
set_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remaining)
|
if (remaining) {
|
||||||
pnfs_set_plh_return_info(lo, return_range->iomode, seq);
|
pnfs_set_plh_return_info(lo, return_range->iomode, seq);
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
return remaining;
|
if (!list_empty(&lo->plh_return_segs)) {
|
||||||
|
pnfs_set_plh_return_info(lo, return_range->iomode, seq);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pnfs_error_mark_layout_for_return(struct inode *inode,
|
void pnfs_error_mark_layout_for_return(struct inode *inode,
|
||||||
@ -2305,7 +2325,7 @@ void pnfs_error_mark_layout_for_return(struct inode *inode,
|
|||||||
* segments at hand when sending layoutreturn. See pnfs_put_lseg()
|
* segments at hand when sending layoutreturn. See pnfs_put_lseg()
|
||||||
* for how it works.
|
* for how it works.
|
||||||
*/
|
*/
|
||||||
if (!pnfs_mark_matching_lsegs_return(lo, &lo->plh_return_segs, &range, 0)) {
|
if (pnfs_mark_matching_lsegs_return(lo, &lo->plh_return_segs, &range, 0) != -EBUSY) {
|
||||||
nfs4_stateid stateid;
|
nfs4_stateid stateid;
|
||||||
enum pnfs_iomode iomode;
|
enum pnfs_iomode iomode;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user