Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6
[sfrench/cifs-2.6.git] / fs / nfs / pnfs.h
index e2612ea0cbed0162d9fcfb74e2824d1617dfd054..bc4827202e7a2c862ae628c1e27b0bae48a9a93d 100644 (file)
@@ -30,6 +30,8 @@
 #ifndef FS_NFS_PNFS_H
 #define FS_NFS_PNFS_H
 
+#include <linux/nfs_page.h>
+
 enum {
        NFS_LSEG_VALID = 0,     /* cleared when lseg is recalled/returned */
        NFS_LSEG_ROC,           /* roc bit received from server */
@@ -41,6 +43,13 @@ struct pnfs_layout_segment {
        atomic_t pls_refcount;
        unsigned long pls_flags;
        struct pnfs_layout_hdr *pls_layout;
+       struct rpc_cred *pls_lc_cred; /* LAYOUTCOMMIT credential */
+       loff_t pls_end_pos; /* LAYOUTCOMMIT write end */
+};
+
+enum pnfs_try_status {
+       PNFS_ATTEMPTED     = 0,
+       PNFS_NOT_ATTEMPTED = 1,
 };
 
 #ifdef CONFIG_NFS_V4_1
@@ -61,10 +70,25 @@ struct pnfs_layoutdriver_type {
        const u32 id;
        const char *name;
        struct module *owner;
-       int (*set_layoutdriver) (struct nfs_server *);
-       int (*clear_layoutdriver) (struct nfs_server *);
        struct pnfs_layout_segment * (*alloc_lseg) (struct pnfs_layout_hdr *layoutid, struct nfs4_layoutget_res *lgr);
        void (*free_lseg) (struct pnfs_layout_segment *lseg);
+
+       /* test for nfs page cache coalescing */
+       int (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *, struct nfs_page *);
+
+       /* Returns true if layoutdriver wants to divert this request to
+        * driver's commit routine.
+        */
+       bool (*mark_pnfs_commit)(struct pnfs_layout_segment *lseg);
+       struct list_head * (*choose_commit_list) (struct nfs_page *req);
+       int (*commit_pagelist)(struct inode *inode, struct list_head *mds_pages, int how);
+
+       /*
+        * Return PNFS_ATTEMPTED to indicate the layout code has attempted
+        * I/O, else return PNFS_NOT_ATTEMPTED to fall back to normal NFS
+        */
+       enum pnfs_try_status (*read_pagelist) (struct nfs_read_data *nfs_data);
+       enum pnfs_try_status (*write_pagelist) (struct nfs_write_data *nfs_data, int how);
 };
 
 struct pnfs_layout_hdr {
@@ -85,57 +109,10 @@ struct pnfs_device {
        unsigned int  layout_type;
        unsigned int  mincount;
        struct page **pages;
-       void          *area;
        unsigned int  pgbase;
        unsigned int  pglen;
 };
 
-/*
- * Device ID RCU cache. A device ID is unique per client ID and layout type.
- */
-#define NFS4_DEVICE_ID_HASH_BITS       5
-#define NFS4_DEVICE_ID_HASH_SIZE       (1 << NFS4_DEVICE_ID_HASH_BITS)
-#define NFS4_DEVICE_ID_HASH_MASK       (NFS4_DEVICE_ID_HASH_SIZE - 1)
-
-static inline u32
-nfs4_deviceid_hash(struct nfs4_deviceid *id)
-{
-       unsigned char *cptr = (unsigned char *)id->data;
-       unsigned int nbytes = NFS4_DEVICEID4_SIZE;
-       u32 x = 0;
-
-       while (nbytes--) {
-               x *= 37;
-               x += *cptr++;
-       }
-       return x & NFS4_DEVICE_ID_HASH_MASK;
-}
-
-struct pnfs_deviceid_node {
-       struct hlist_node       de_node;
-       struct nfs4_deviceid    de_id;
-       atomic_t                de_ref;
-};
-
-struct pnfs_deviceid_cache {
-       spinlock_t              dc_lock;
-       atomic_t                dc_ref;
-       void                    (*dc_free_callback)(struct pnfs_deviceid_node *);
-       struct hlist_head       dc_deviceids[NFS4_DEVICE_ID_HASH_SIZE];
-};
-
-extern int pnfs_alloc_init_deviceid_cache(struct nfs_client *,
-                       void (*free_callback)(struct pnfs_deviceid_node *));
-extern void pnfs_put_deviceid_cache(struct nfs_client *);
-extern struct pnfs_deviceid_node *pnfs_find_get_deviceid(
-                               struct pnfs_deviceid_cache *,
-                               struct nfs4_deviceid *);
-extern struct pnfs_deviceid_node *pnfs_add_deviceid(
-                               struct pnfs_deviceid_cache *,
-                               struct pnfs_deviceid_node *);
-extern void pnfs_put_deviceid(struct pnfs_deviceid_cache *c,
-                             struct pnfs_deviceid_node *devid);
-
 extern int pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *);
 extern void pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *);
 
@@ -146,11 +123,18 @@ extern int nfs4_proc_layoutget(struct nfs4_layoutget *lgp);
 
 /* pnfs.c */
 void get_layout_hdr(struct pnfs_layout_hdr *lo);
+void put_lseg(struct pnfs_layout_segment *lseg);
 struct pnfs_layout_segment *
 pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx,
                   enum pnfs_iomode access_type);
 void set_pnfs_layoutdriver(struct nfs_server *, u32 id);
 void unset_pnfs_layoutdriver(struct nfs_server *);
+enum pnfs_try_status pnfs_try_to_write_data(struct nfs_write_data *,
+                                            const struct rpc_call_ops *, int);
+enum pnfs_try_status pnfs_try_to_read_data(struct nfs_read_data *,
+                                           const struct rpc_call_ops *);
+void pnfs_pageio_init_read(struct nfs_pageio_descriptor *, struct inode *);
+void pnfs_pageio_init_write(struct nfs_pageio_descriptor *, struct inode *);
 int pnfs_layout_process(struct nfs4_layoutget *lgp);
 void pnfs_free_lseg_list(struct list_head *tmp_list);
 void pnfs_destroy_layout(struct nfs_inode *);
@@ -169,7 +153,8 @@ bool pnfs_roc(struct inode *ino);
 void pnfs_roc_release(struct inode *ino);
 void pnfs_roc_set_barrier(struct inode *ino, u32 barrier);
 bool pnfs_roc_drain(struct inode *ino, u32 *barrier);
-
+void pnfs_set_layoutcommit(struct nfs_write_data *wdata);
+int pnfs_layoutcommit_inode(struct inode *inode, bool sync);
 
 static inline int lo_fail_bit(u32 iomode)
 {
@@ -177,12 +162,67 @@ static inline int lo_fail_bit(u32 iomode)
                         NFS_LAYOUT_RW_FAILED : NFS_LAYOUT_RO_FAILED;
 }
 
+static inline struct pnfs_layout_segment *
+get_lseg(struct pnfs_layout_segment *lseg)
+{
+       if (lseg) {
+               atomic_inc(&lseg->pls_refcount);
+               smp_mb__after_atomic_inc();
+       }
+       return lseg;
+}
+
 /* Return true if a layout driver is being used for this mountpoint */
 static inline int pnfs_enabled_sb(struct nfs_server *nfss)
 {
        return nfss->pnfs_curr_ld != NULL;
 }
 
+static inline void
+pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
+{
+       if (lseg) {
+               struct pnfs_layoutdriver_type *ld;
+
+               ld = NFS_SERVER(req->wb_page->mapping->host)->pnfs_curr_ld;
+               if (ld->mark_pnfs_commit && ld->mark_pnfs_commit(lseg)) {
+                       set_bit(PG_PNFS_COMMIT, &req->wb_flags);
+                       req->wb_commit_lseg = get_lseg(lseg);
+               }
+       }
+}
+
+static inline int
+pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how)
+{
+       if (!test_and_clear_bit(NFS_INO_PNFS_COMMIT, &NFS_I(inode)->flags))
+               return PNFS_NOT_ATTEMPTED;
+       return NFS_SERVER(inode)->pnfs_curr_ld->commit_pagelist(inode, mds_pages, how);
+}
+
+static inline struct list_head *
+pnfs_choose_commit_list(struct nfs_page *req, struct list_head *mds)
+{
+       struct list_head *rv;
+
+       if (test_and_clear_bit(PG_PNFS_COMMIT, &req->wb_flags)) {
+               struct inode *inode = req->wb_commit_lseg->pls_layout->plh_inode;
+
+               set_bit(NFS_INO_PNFS_COMMIT, &NFS_I(inode)->flags);
+               rv = NFS_SERVER(inode)->pnfs_curr_ld->choose_commit_list(req);
+               /* matched by ref taken when PG_PNFS_COMMIT is set */
+               put_lseg(req->wb_commit_lseg);
+       } else
+               rv = mds;
+       return rv;
+}
+
+static inline void pnfs_clear_request_commit(struct nfs_page *req)
+{
+       if (test_and_clear_bit(PG_PNFS_COMMIT, &req->wb_flags))
+               put_lseg(req->wb_commit_lseg);
+}
+
 #else  /* CONFIG_NFS_V4_1 */
 
 static inline void pnfs_destroy_all_layouts(struct nfs_client *clp)
@@ -193,6 +233,16 @@ static inline void pnfs_destroy_layout(struct nfs_inode *nfsi)
 {
 }
 
+static inline struct pnfs_layout_segment *
+get_lseg(struct pnfs_layout_segment *lseg)
+{
+       return NULL;
+}
+
+static inline void put_lseg(struct pnfs_layout_segment *lseg)
+{
+}
+
 static inline struct pnfs_layout_segment *
 pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx,
                   enum pnfs_iomode access_type)
@@ -200,6 +250,20 @@ pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx,
        return NULL;
 }
 
+static inline enum pnfs_try_status
+pnfs_try_to_read_data(struct nfs_read_data *data,
+                     const struct rpc_call_ops *call_ops)
+{
+       return PNFS_NOT_ATTEMPTED;
+}
+
+static inline enum pnfs_try_status
+pnfs_try_to_write_data(struct nfs_write_data *data,
+                      const struct rpc_call_ops *call_ops, int how)
+{
+       return PNFS_NOT_ATTEMPTED;
+}
+
 static inline bool
 pnfs_roc(struct inode *ino)
 {
@@ -230,6 +294,43 @@ static inline void unset_pnfs_layoutdriver(struct nfs_server *s)
 {
 }
 
+static inline void
+pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *ino)
+{
+       pgio->pg_test = NULL;
+}
+
+static inline void
+pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *ino)
+{
+       pgio->pg_test = NULL;
+}
+
+static inline void
+pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
+{
+}
+
+static inline int
+pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how)
+{
+       return PNFS_NOT_ATTEMPTED;
+}
+
+static inline struct list_head *
+pnfs_choose_commit_list(struct nfs_page *req, struct list_head *mds)
+{
+       return mds;
+}
+
+static inline void pnfs_clear_request_commit(struct nfs_page *req)
+{
+}
+
+static inline int pnfs_layoutcommit_inode(struct inode *inode, bool sync)
+{
+       return 0;
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 #endif /* FS_NFS_PNFS_H */