Commit fc6eabbb authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfs-for-4.16-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

Pull NFS client bugfixes from Trond Myklebust:
 "Hightlights include the following stable fixes:

   - NFS: Fix an incorrect type in struct nfs_direct_req

   - pNFS: Prevent the layout header refcount going to zero in
     pnfs_roc()

   - NFS: Fix unstable write completion"

* tag 'nfs-for-4.16-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  NFS: Fix unstable write completion
  pNFS: Prevent the layout header refcount going to zero in pnfs_roc()
  NFS: Fix an incorrect type in struct nfs_direct_req
parents 0c8efd61 c4f24df9
...@@ -86,10 +86,10 @@ struct nfs_direct_req { ...@@ -86,10 +86,10 @@ struct nfs_direct_req {
struct nfs_direct_mirror mirrors[NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX]; struct nfs_direct_mirror mirrors[NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX];
int mirror_count; int mirror_count;
loff_t io_start; /* Start offset for I/O */
ssize_t count, /* bytes actually processed */ ssize_t count, /* bytes actually processed */
max_count, /* max expected count */ max_count, /* max expected count */
bytes_left, /* bytes left to be sent */ bytes_left, /* bytes left to be sent */
io_start, /* start of IO */
error; /* any reported error */ error; /* any reported error */
struct completion completion; /* wait for i/o completion */ struct completion completion; /* wait for i/o completion */
......
...@@ -292,8 +292,11 @@ pnfs_detach_layout_hdr(struct pnfs_layout_hdr *lo) ...@@ -292,8 +292,11 @@ pnfs_detach_layout_hdr(struct pnfs_layout_hdr *lo)
void void
pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo) pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo)
{ {
struct inode *inode = lo->plh_inode; struct inode *inode;
if (!lo)
return;
inode = lo->plh_inode;
pnfs_layoutreturn_before_put_layout_hdr(lo); pnfs_layoutreturn_before_put_layout_hdr(lo);
if (refcount_dec_and_lock(&lo->plh_refcount, &inode->i_lock)) { if (refcount_dec_and_lock(&lo->plh_refcount, &inode->i_lock)) {
...@@ -1241,10 +1244,12 @@ bool pnfs_roc(struct inode *ino, ...@@ -1241,10 +1244,12 @@ bool pnfs_roc(struct inode *ino,
spin_lock(&ino->i_lock); spin_lock(&ino->i_lock);
lo = nfsi->layout; lo = nfsi->layout;
if (!lo || !pnfs_layout_is_valid(lo) || if (!lo || !pnfs_layout_is_valid(lo) ||
test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) {
lo = NULL;
goto out_noroc; goto out_noroc;
if (test_bit(NFS_LAYOUT_RETURN_LOCK, &lo->plh_flags)) { }
pnfs_get_layout_hdr(lo); pnfs_get_layout_hdr(lo);
if (test_bit(NFS_LAYOUT_RETURN_LOCK, &lo->plh_flags)) {
spin_unlock(&ino->i_lock); spin_unlock(&ino->i_lock);
wait_on_bit(&lo->plh_flags, NFS_LAYOUT_RETURN, wait_on_bit(&lo->plh_flags, NFS_LAYOUT_RETURN,
TASK_UNINTERRUPTIBLE); TASK_UNINTERRUPTIBLE);
...@@ -1312,10 +1317,12 @@ bool pnfs_roc(struct inode *ino, ...@@ -1312,10 +1317,12 @@ bool pnfs_roc(struct inode *ino,
struct pnfs_layoutdriver_type *ld = NFS_SERVER(ino)->pnfs_curr_ld; struct pnfs_layoutdriver_type *ld = NFS_SERVER(ino)->pnfs_curr_ld;
if (ld->prepare_layoutreturn) if (ld->prepare_layoutreturn)
ld->prepare_layoutreturn(args); ld->prepare_layoutreturn(args);
pnfs_put_layout_hdr(lo);
return true; return true;
} }
if (layoutreturn) if (layoutreturn)
pnfs_send_layoutreturn(lo, &stateid, iomode, true); pnfs_send_layoutreturn(lo, &stateid, iomode, true);
pnfs_put_layout_hdr(lo);
return false; return false;
} }
......
...@@ -1876,40 +1876,43 @@ int nfs_generic_commit_list(struct inode *inode, struct list_head *head, ...@@ -1876,40 +1876,43 @@ int nfs_generic_commit_list(struct inode *inode, struct list_head *head,
return status; return status;
} }
int nfs_commit_inode(struct inode *inode, int how) static int __nfs_commit_inode(struct inode *inode, int how,
struct writeback_control *wbc)
{ {
LIST_HEAD(head); LIST_HEAD(head);
struct nfs_commit_info cinfo; struct nfs_commit_info cinfo;
int may_wait = how & FLUSH_SYNC; int may_wait = how & FLUSH_SYNC;
int error = 0; int ret, nscan;
int res;
nfs_init_cinfo_from_inode(&cinfo, inode); nfs_init_cinfo_from_inode(&cinfo, inode);
nfs_commit_begin(cinfo.mds); nfs_commit_begin(cinfo.mds);
res = nfs_scan_commit(inode, &head, &cinfo); for (;;) {
if (res) ret = nscan = nfs_scan_commit(inode, &head, &cinfo);
error = nfs_generic_commit_list(inode, &head, how, &cinfo); if (ret <= 0)
break;
ret = nfs_generic_commit_list(inode, &head, how, &cinfo);
if (ret < 0)
break;
ret = 0;
if (wbc && wbc->sync_mode == WB_SYNC_NONE) {
if (nscan < wbc->nr_to_write)
wbc->nr_to_write -= nscan;
else
wbc->nr_to_write = 0;
}
if (nscan < INT_MAX)
break;
cond_resched();
}
nfs_commit_end(cinfo.mds); nfs_commit_end(cinfo.mds);
if (res == 0) if (ret || !may_wait)
return res; return ret;
if (error < 0) return wait_on_commit(cinfo.mds);
goto out_error; }
if (!may_wait)
goto out_mark_dirty; int nfs_commit_inode(struct inode *inode, int how)
error = wait_on_commit(cinfo.mds); {
if (error < 0) return __nfs_commit_inode(inode, how, NULL);
return error;
return res;
out_error:
res = error;
/* Note: If we exit without ensuring that the commit is complete,
* we must mark the inode as dirty. Otherwise, future calls to
* sync_inode() with the WB_SYNC_ALL flag set will fail to ensure
* that the data is on the disk.
*/
out_mark_dirty:
__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
return res;
} }
EXPORT_SYMBOL_GPL(nfs_commit_inode); EXPORT_SYMBOL_GPL(nfs_commit_inode);
...@@ -1919,11 +1922,11 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) ...@@ -1919,11 +1922,11 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc)
int flags = FLUSH_SYNC; int flags = FLUSH_SYNC;
int ret = 0; int ret = 0;
if (wbc->sync_mode == WB_SYNC_NONE) {
/* no commits means nothing needs to be done */ /* no commits means nothing needs to be done */
if (!atomic_long_read(&nfsi->commit_info.ncommit)) if (!atomic_long_read(&nfsi->commit_info.ncommit))
return ret; goto check_requests_outstanding;
if (wbc->sync_mode == WB_SYNC_NONE) {
/* Don't commit yet if this is a non-blocking flush and there /* Don't commit yet if this is a non-blocking flush and there
* are a lot of outstanding writes for this mapping. * are a lot of outstanding writes for this mapping.
*/ */
...@@ -1934,16 +1937,16 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) ...@@ -1934,16 +1937,16 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc)
flags = 0; flags = 0;
} }
ret = nfs_commit_inode(inode, flags); ret = __nfs_commit_inode(inode, flags, wbc);
if (ret >= 0) { if (!ret) {
if (wbc->sync_mode == WB_SYNC_NONE) { if (flags & FLUSH_SYNC)
if (ret < wbc->nr_to_write)
wbc->nr_to_write -= ret;
else
wbc->nr_to_write = 0;
}
return 0; return 0;
} } else if (atomic_long_read(&nfsi->commit_info.ncommit))
goto out_mark_dirty;
check_requests_outstanding:
if (!atomic_read(&nfsi->commit_info.rpcs_out))
return ret;
out_mark_dirty: out_mark_dirty:
__mark_inode_dirty(inode, I_DIRTY_DATASYNC); __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment