pnfs: allow splicing pre-encoded pages into the layoutcommit args
authorChristoph Hellwig <hch@lst.de>
Thu, 21 Aug 2014 16:09:25 +0000 (11:09 -0500)
committerTrond Myklebust <trond.myklebust@primarydata.com>
Wed, 10 Sep 2014 19:47:01 +0000 (12:47 -0700)
Currently there is no XDR buffer space allocated for the per-layout driver
layoutcommit payload, which leads to server buffer overflows in the
blocklayout driver even under simple workloads.  As we can't do per-layout
sizes for XDR operations we'll have to splice a previously encoded list
of pages into the XDR stream, similar to how we handle ACL buffers.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
fs/nfs/nfs4xdr.c
fs/nfs/pnfs.c
fs/nfs/pnfs.h
include/linux/nfs_xdr.h

index e13b59d8d9aa1374990c5eee9acec623c1193537..f2cd957adb907ecc0e0e0dcad99ac3c60b13e8a9 100644 (file)
@@ -395,7 +395,10 @@ static int nfs4_stat_to_errno(int);
                                2 /* last byte written */ + \
                                1 /* nt_timechanged (false) */ + \
                                1 /* layoutupdate4 layout type */ + \
-                               1 /* NULL filelayout layoutupdate4 payload */)
+                               1 /* layoutupdate4 opaqueue len */)
+                                 /* the actual content of layoutupdate4 should
+                                    be allocated by drivers and spliced in
+                                    using xdr_write_pages */
 #define decode_layoutcommit_maxsz (op_decode_hdr_maxsz + 3)
 #define encode_layoutreturn_maxsz (8 + op_encode_hdr_maxsz + \
                                encode_stateid_maxsz + \
@@ -1990,7 +1993,7 @@ encode_layoutget(struct xdr_stream *xdr,
 static int
 encode_layoutcommit(struct xdr_stream *xdr,
                    struct inode *inode,
-                   const struct nfs4_layoutcommit_args *args,
+                   struct nfs4_layoutcommit_args *args,
                    struct compound_hdr *hdr)
 {
        __be32 *p;
@@ -2011,11 +2014,16 @@ encode_layoutcommit(struct xdr_stream *xdr,
        *p++ = cpu_to_be32(0); /* Never send time_modify_changed */
        *p++ = cpu_to_be32(NFS_SERVER(args->inode)->pnfs_curr_ld->id);/* type */
 
-       if (NFS_SERVER(inode)->pnfs_curr_ld->encode_layoutcommit)
+       if (NFS_SERVER(inode)->pnfs_curr_ld->encode_layoutcommit) {
                NFS_SERVER(inode)->pnfs_curr_ld->encode_layoutcommit(
                        NFS_I(inode)->layout, xdr, args);
-       else
-               encode_uint32(xdr, 0); /* no layout-type payload */
+       } else {
+               encode_uint32(xdr, args->layoutupdate_len);
+               if (args->layoutupdate_pages) {
+                       xdr_write_pages(xdr, args->layoutupdate_pages, 0,
+                                       args->layoutupdate_len);
+               }
+       }
 
        return 0;
 }
index 57b5728e0b8ee8924e85675c7b1b5903614ef3c9..8827ab130ed3c33301e7b428b39fc784910e77b3 100644 (file)
@@ -1854,6 +1854,7 @@ void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data)
 int
 pnfs_layoutcommit_inode(struct inode *inode, bool sync)
 {
+       struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld;
        struct nfs4_layoutcommit_data *data;
        struct nfs_inode *nfsi = NFS_I(inode);
        loff_t end_pos;
@@ -1904,6 +1905,20 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
        data->args.lastbytewritten = end_pos - 1;
        data->res.server = NFS_SERVER(inode);
 
+       if (ld->prepare_layoutcommit) {
+               status = ld->prepare_layoutcommit(&data->args);
+               if (status) {
+                       spin_lock(&inode->i_lock);
+                       if (end_pos < nfsi->layout->plh_lwb)
+                               nfsi->layout->plh_lwb = end_pos;
+                       spin_unlock(&inode->i_lock);
+                       put_rpccred(data->cred);
+                       set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags);
+                       goto clear_layoutcommitting;
+               }
+       }
+
+
        status = nfs4_proc_layoutcommit(data, sync);
 out:
        if (status)
index 1dd8a5e96c9f8b8c751de20ed754bef28bff3a28..8835b5a320ccf16ea23a4f62fc83938bd971f3fa 100644 (file)
@@ -128,8 +128,8 @@ struct pnfs_layoutdriver_type {
                                     const struct nfs4_layoutreturn_args *args);
 
        void (*cleanup_layoutcommit) (struct nfs4_layoutcommit_data *data);
-
-       void (*encode_layoutcommit) (struct pnfs_layout_hdr *layoutid,
+       int (*prepare_layoutcommit) (struct nfs4_layoutcommit_args *args);
+       void (*encode_layoutcommit) (struct pnfs_layout_hdr *lo,
                                     struct xdr_stream *xdr,
                                     const struct nfs4_layoutcommit_args *args);
 };
index e563b2c976ef48bdfd397792920f8ff7e4db4f6e..f4092c6b90fb7a431a62bbd849d1ba34ac00112f 100644 (file)
@@ -279,6 +279,9 @@ struct nfs4_layoutcommit_args {
        __u64 lastbytewritten;
        struct inode *inode;
        const u32 *bitmask;
+       size_t layoutupdate_len;
+       struct page *layoutupdate_page;
+       struct page **layoutupdate_pages;
 };
 
 struct nfs4_layoutcommit_res {