[pnfs] [PATCH 3/8] pnfs: pnfs_do_flush
Fred Isaman
iisaman at citi.umich.edu
Thu May 1 09:02:12 EDT 2008
Adds a hook into the "check if request needs flushed" routines.
This will be needed to allow driver the ability to prevent comingling
of layout driver handled requests and fallback nfs requests.
Signed-off-by: Fred Isaman <iisaman at citi.umich.edu>
---
fs/nfs/pnfs.c | 42 ++++++++++++++++++++++++++++++++++++++++++
fs/nfs/pnfs.h | 25 +++++++++++++++++++++++++
fs/nfs/write.c | 4 ++--
include/linux/nfs4_pnfs.h | 9 +++++++++
4 files changed, 78 insertions(+), 2 deletions(-)
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index ee2f10a..e7ef1ac 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -807,6 +807,28 @@ pnfs_has_layout(struct pnfs_layout_type *lo,
return ret;
}
+static struct pnfs_layout_segment *
+pnfs_find_get_lseg(struct inode *inode,
+ loff_t pos,
+ size_t count,
+ enum pnfs_iomode iomode)
+{
+ struct nfs_inode *nfsi = NFS_I(inode);
+ struct pnfs_layout_segment *lseg;
+ struct pnfs_layout_type *lo;
+ struct nfs4_pnfs_layout_segment range;
+
+ lo = get_lock_current_layout(nfsi);
+ if (!lo)
+ return NULL;
+ range.iomode = iomode;
+ range.offset = pos;
+ range.length = count;
+ lseg = pnfs_has_layout(lo, &range, 1);
+ put_unlock_current_layout(nfsi, lo);
+ return lseg;
+}
+
/* Update the file's layout for the given range and iomode.
* Layout is retreived from the server if needed.
* If lsegpp is given, the appropriate layout segment is referenced and
@@ -1544,6 +1566,26 @@ int _pnfs_try_to_read_data(struct nfs_read_data *data,
}
}
+/* Given an nfs request, determine if it should be flushed before proceeding.
+ * It should default to returning False, returning True only if there is a
+ * specific reason to flush.
+ */
+int _pnfs_do_flush(struct inode *inode, struct nfs_page *req,
+ struct pnfs_fsdata *fsdata)
+{
+ struct nfs_server *nfss = NFS_SERVER(inode);
+ struct pnfs_layout_segment *lseg;
+ loff_t pos = (req->wb_index << PAGE_CACHE_SHIFT) + req->wb_offset;
+ int status = 0;
+
+ lseg = pnfs_find_get_lseg(inode, pos, req->wb_bytes, IOMODE_RW);
+ /* Note that lseg==NULL may be useful info for do_flush */
+ status = nfss->pnfs_curr_ld->ld_policy_ops->do_flush(lseg, req,
+ fsdata);
+ put_lseg(lseg);
+ return status;
+}
+
int _pnfs_try_to_write_data(struct nfs_write_data *data,
const struct rpc_call_ops *call_ops, int how)
{
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index 3014f34..04ae8ec 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -59,6 +59,8 @@ ssize_t pnfs_file_write(struct file *, const char __user *, size_t, loff_t *);
void pnfs_get_layout_done(struct pnfs_layout_type *,
struct nfs4_pnfs_layoutget *, int);
void pnfs_layout_release(struct pnfs_layout_type *);
+int _pnfs_do_flush(struct inode *inode, struct nfs_page *req,
+ struct pnfs_fsdata *fsdata);
#define PNFS_EXISTS_LDIO_OP(srv, opname) ((srv)->pnfs_curr_ld && \
(srv)->pnfs_curr_ld->ld_io_ops && \
@@ -109,6 +111,24 @@ static inline int pnfs_try_to_commit(struct nfs_write_data *data)
return 1;
}
+/* req may not be locked, so we have to be prepared for req->wb_page being
+ * set to NULL at any time.
+ */
+static inline int pnfs_do_flush(struct nfs_page *req, void *fsdata)
+{
+ struct page *page = req->wb_page;
+ struct inode *inode;
+
+ if (!page)
+ return 1;
+ inode = page->mapping->host;
+
+ if (PNFS_EXISTS_LDPOLICY_OP(NFS_SERVER(inode), do_flush))
+ return _pnfs_do_flush(inode, req, fsdata);
+ else
+ return 0;
+}
+
#else /* CONFIG_PNFS */
static inline int pnfs_try_to_read_data(struct nfs_read_data *data,
@@ -129,6 +149,11 @@ static inline int pnfs_try_to_commit(struct nfs_write_data *data)
return 1;
}
+static inline int pnfs_do_flush(struct nfs_page *req, void *fsdata)
+{
+ return 0;
+}
+
#endif /* CONFIG_PNFS */
#endif /* FS_NFS_PNFS_H */
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 656af5f..e3abd97 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -654,7 +654,7 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx,
rqend = req->wb_offset + req->wb_bytes;
if (req->wb_context != ctx
|| req->wb_page != page
- || !nfs_dirty_request(req)
+ || !nfs_dirty_request(req) || pnfs_do_flush(req, NULL)
|| offset > rqend || end < req->wb_offset) {
nfs_clear_page_tag_locked(req);
return ERR_PTR(-EBUSY);
@@ -699,7 +699,7 @@ int nfs_flush_incompatible(struct file *file, struct page *page)
if (req == NULL)
return 0;
do_flush = req->wb_page != page || req->wb_context != ctx
- || !nfs_dirty_request(req);
+ || !nfs_dirty_request(req) || pnfs_do_flush(req, NULL);
nfs_release_request(req);
if (!do_flush)
return 0;
diff --git a/include/linux/nfs4_pnfs.h b/include/linux/nfs4_pnfs.h
index 654767a..4bee636 100644
--- a/include/linux/nfs4_pnfs.h
+++ b/include/linux/nfs4_pnfs.h
@@ -48,6 +48,11 @@ struct pnfs_layout_type {
u8 ld_data[]; /* layout driver private data */
};
+struct pnfs_fsdata {
+ int ok_to_use_pnfs;
+};
+
+
static inline struct inode *
PNFS_INODE(struct pnfs_layout_type *lo)
{
@@ -173,6 +178,10 @@ struct layoutdriver_policy_operations {
/* test for nfs page cache coalescing */
int (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *, struct nfs_page *);
+ /* Test for pre-write request flushing */
+ int (*do_flush)(struct pnfs_layout_segment *lseg, struct nfs_page *req,
+ struct pnfs_fsdata *fsdata);
+
/* Retreive the block size of the file system. If gather_across_stripes == 1,
* then the file system will gather requests into the block size.
* TODO: Where will the layout driver get this info? It is hard coded in PVFS2.
--
1.5.3.3
More information about the pNFS
mailing list