|
@@ -256,6 +256,7 @@ put_lseg_locked(struct pnfs_layout_segment *lseg,
|
|
|
spin_unlock(&clp->cl_lock);
|
|
|
clear_bit(NFS_LAYOUT_BULK_RECALL, &lseg->pls_layout->plh_flags);
|
|
|
}
|
|
|
+ rpc_wake_up(&NFS_SERVER(ino)->roc_rpcwaitq);
|
|
|
list_add(&lseg->pls_list, tmp_list);
|
|
|
return 1;
|
|
|
}
|
|
@@ -401,7 +402,8 @@ pnfs_layoutgets_blocked(struct pnfs_layout_hdr *lo, nfs4_stateid *stateid,
|
|
|
if ((stateid) &&
|
|
|
(int)(lo->plh_barrier - be32_to_cpu(stateid->stateid.seqid)) >= 0)
|
|
|
return true;
|
|
|
- return test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) ||
|
|
|
+ return lo->plh_block_lgets ||
|
|
|
+ test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) ||
|
|
|
(list_empty(&lo->plh_segs) &&
|
|
|
(atomic_read(&lo->plh_outstanding) > lget));
|
|
|
}
|
|
@@ -474,6 +476,83 @@ send_layoutget(struct pnfs_layout_hdr *lo,
|
|
|
return lseg;
|
|
|
}
|
|
|
|
|
|
+bool pnfs_roc(struct inode *ino)
|
|
|
+{
|
|
|
+ struct pnfs_layout_hdr *lo;
|
|
|
+ struct pnfs_layout_segment *lseg, *tmp;
|
|
|
+ LIST_HEAD(tmp_list);
|
|
|
+ bool found = false;
|
|
|
+
|
|
|
+ spin_lock(&ino->i_lock);
|
|
|
+ lo = NFS_I(ino)->layout;
|
|
|
+ if (!lo || !test_and_clear_bit(NFS_LAYOUT_ROC, &lo->plh_flags) ||
|
|
|
+ test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags))
|
|
|
+ goto out_nolayout;
|
|
|
+ list_for_each_entry_safe(lseg, tmp, &lo->plh_segs, pls_list)
|
|
|
+ if (test_bit(NFS_LSEG_ROC, &lseg->pls_flags)) {
|
|
|
+ mark_lseg_invalid(lseg, &tmp_list);
|
|
|
+ found = true;
|
|
|
+ }
|
|
|
+ if (!found)
|
|
|
+ goto out_nolayout;
|
|
|
+ lo->plh_block_lgets++;
|
|
|
+ get_layout_hdr(lo); /* matched in pnfs_roc_release */
|
|
|
+ spin_unlock(&ino->i_lock);
|
|
|
+ pnfs_free_lseg_list(&tmp_list);
|
|
|
+ return true;
|
|
|
+
|
|
|
+out_nolayout:
|
|
|
+ spin_unlock(&ino->i_lock);
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+void pnfs_roc_release(struct inode *ino)
|
|
|
+{
|
|
|
+ struct pnfs_layout_hdr *lo;
|
|
|
+
|
|
|
+ spin_lock(&ino->i_lock);
|
|
|
+ lo = NFS_I(ino)->layout;
|
|
|
+ lo->plh_block_lgets--;
|
|
|
+ put_layout_hdr_locked(lo);
|
|
|
+ spin_unlock(&ino->i_lock);
|
|
|
+}
|
|
|
+
|
|
|
+void pnfs_roc_set_barrier(struct inode *ino, u32 barrier)
|
|
|
+{
|
|
|
+ struct pnfs_layout_hdr *lo;
|
|
|
+
|
|
|
+ spin_lock(&ino->i_lock);
|
|
|
+ lo = NFS_I(ino)->layout;
|
|
|
+ if ((int)(barrier - lo->plh_barrier) > 0)
|
|
|
+ lo->plh_barrier = barrier;
|
|
|
+ spin_unlock(&ino->i_lock);
|
|
|
+}
|
|
|
+
|
|
|
+bool pnfs_roc_drain(struct inode *ino, u32 *barrier)
|
|
|
+{
|
|
|
+ struct nfs_inode *nfsi = NFS_I(ino);
|
|
|
+ struct pnfs_layout_segment *lseg;
|
|
|
+ bool found = false;
|
|
|
+
|
|
|
+ spin_lock(&ino->i_lock);
|
|
|
+ list_for_each_entry(lseg, &nfsi->layout->plh_segs, pls_list)
|
|
|
+ if (test_bit(NFS_LSEG_ROC, &lseg->pls_flags)) {
|
|
|
+ found = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (!found) {
|
|
|
+ struct pnfs_layout_hdr *lo = nfsi->layout;
|
|
|
+ u32 current_seqid = be32_to_cpu(lo->plh_stateid.stateid.seqid);
|
|
|
+
|
|
|
+ /* Since close does not return a layout stateid for use as
|
|
|
+ * a barrier, we choose the worst-case barrier.
|
|
|
+ */
|
|
|
+ *barrier = current_seqid + atomic_read(&lo->plh_outstanding);
|
|
|
+ }
|
|
|
+ spin_unlock(&ino->i_lock);
|
|
|
+ return found;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Compare two layout segments for sorting into layout cache.
|
|
|
* We want to preferentially return RW over RO layouts, so ensure those
|
|
@@ -732,6 +811,11 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
|
|
|
*lgp->lsegpp = lseg;
|
|
|
pnfs_insert_layout(lo, lseg);
|
|
|
|
|
|
+ if (res->return_on_close) {
|
|
|
+ set_bit(NFS_LSEG_ROC, &lseg->pls_flags);
|
|
|
+ set_bit(NFS_LAYOUT_ROC, &lo->plh_flags);
|
|
|
+ }
|
|
|
+
|
|
|
/* Done processing layoutget. Set the layout stateid */
|
|
|
pnfs_set_layout_stateid(lo, &res->stateid, false);
|
|
|
spin_unlock(&ino->i_lock);
|