All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC] Performing direct I/O on sector-aligned requests
@ 2012-04-18 14:18 Alexandre Depoutovitch
  2012-04-18 16:19 ` Myklebust, Trond
  2012-04-29 21:03 ` [PATCH RFC v2] " Alexandre Depoutovitch
  0 siblings, 2 replies; 15+ messages in thread
From: Alexandre Depoutovitch @ 2012-04-18 14:18 UTC (permalink / raw)
  To: linux-nfs

NFS daemons always perform buffered IO on files. As a result, write
requests that are not aligned on a file system block boundary take about
15 times more time to complete compared to the same writes that are file
system block aligned. This patch fixes the problem by analyzing alignment
of the IO request that comes to NFS daemon and using Direct I/O mechanism
when all of the following are true:
1. Request is not aligned on a file system block boundary
2. Request is aligned on an underlying block device’s sector boundary.
3. Request size is a multiple of the sector size.
In all other cases, buffered IO is performed as has been done before.

After applying a patch, the resulting performance of all types of
requests, except unaligned writes remains the same, while performance of
unaligned writes improves 15 times.
A new flag is exposed to users through /proc/fs/nfsd/direct_io node. The
default value of 1 results in the above behavior. Writing 0 to the node
turns off the optimization, and forces NFS daemon to always use buffered
IO (as it has done before). Writing 2 to the node tells NFS daemon to use
direct I/O even if request is file system block aligned.

I have tested this patch by running concurrent NFS writes to an exported
 file system and verifying locally that writes reached the disk.

diff -uNr a/fs/direct-io.c b/fs/direct-io.c
--- a/fs/direct-io.c           2011-10-24 14:06:32.000000000 -0400
+++ b/fs/direct-io.c         2012-03-28 15:41:12.000000000 -0400
@@ -152,11 +152,27 @@
                int nr_pages;
 
                nr_pages = min(dio->total_pages - dio->curr_page,
DIO_PAGES);
-              ret = get_user_pages_fast(
-                             
dio->curr_user_address,                              /* Where from? */
-                             
nr_pages,                                            /* How many pages? */
-                              dio->rw ==
READ,                             /* Write to memory? */
-                             
&dio->pages[0]);                             /* Put results here */
+
+              if (current->mm) {
+                              ret = get_user_pages_fast(
+                                             
dio->curr_user_address,                              /* Where from? */
+                                             
nr_pages,                                            /* How many pages? */
+                                              dio->rw ==
READ,                             /* Write to memory? */
+                                             
&dio->pages[0]);                             /* Put results here */
+              } else {
+                              // For kernel threads mm is NULL, so all we
need is to increment
+                              // page's reference count and add page to
dio->pages array
+                              int i;
+                              struct page* page;
+                              unsigned long start_pfn =
__pa(dio->curr_user_address) >> PAGE_SHIFT;
+                              for (i = 0; i < nr_pages; i++) {
+                                              page =
pfn_to_page(start_pfn + i);
+                                              page_cache_get(page);
+                                              dio->pages[i] = page;
+                              }
+
+                              ret = nr_pages; // No need to lock pages:
this is kernel thread and the pages are in kernel as well
+              }
 
                if (ret < 0 && dio->blocks_available && (dio->rw & WRITE))
{
                                struct page *page = ZERO_PAGE(0);
diff -uNr a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
--- a/fs/nfsd/lockd.c       2011-10-24 14:06:32.000000000 -0400
+++ b/fs/nfsd/lockd.c    2012-03-28 15:40:29.000000000 -0400
@@ -36,7 +36,7 @@
                fh.fh_export = NULL;
 
                exp_readlock();
-              nfserr = nfsd_open(rqstp, &fh, S_IFREG, NFSD_MAY_LOCK,
filp);
+              nfserr = nfsd_open(rqstp, &fh, S_IFREG, NFSD_MAY_LOCK,
filp, 0, 0);
                fh_put(&fh);
                exp_readunlock();
                /* We return nlm error codes as nlm doesn't know
diff -uNr a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
--- a/fs/nfsd/nfs4state.c               2011-10-24 14:06:32.000000000
-0400
+++ b/fs/nfsd/nfs4state.c            2012-03-28 15:40:29.000000000 -0400
@@ -2557,7 +2557,7 @@
 
                if (!fp->fi_fds[oflag]) {
                                status = nfsd_open(rqstp, cur_fh, S_IFREG,
access,
-                                              &fp->fi_fds[oflag]);
+                                              &fp->fi_fds[oflag], 0, 0);
                                if (status)
                                                return status;
                }
@@ -3951,7 +3951,7 @@
                struct file *file;
                int err;
 
-              err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
+              err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file,
0, 0);
                if (err)
                                return err;
                err = vfs_test_lock(file, lock);
diff -uNr a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
--- a/fs/nfsd/nfsctl.c      2011-10-24 14:06:32.000000000 -0400
+++ b/fs/nfsd/nfsctl.c    2012-03-28 15:40:29.000000000 -0400
@@ -46,6 +46,7 @@
                NFSD_TempPorts,
                NFSD_MaxBlkSize,
                NFSD_SupportedEnctypes,
+              NFSD_DirectIO,
                /*
                 * The below MUST come last.  Otherwise we leave a hole in
nfsd_files[]
                 * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops
@@ -78,6 +79,7 @@
 static ssize_t write_ports(struct file *file, char *buf, size_t size);
 static ssize_t write_temp_ports(struct file *file, char *buf, size_t
size);
 static ssize_t write_maxblksize(struct file *file, char *buf, size_t
size);
+static ssize_t write_directio(struct file *file, char *buf, size_t size);
 #ifdef CONFIG_NFSD_V4
 static ssize_t write_leasetime(struct file *file, char *buf, size_t
size);
 static ssize_t write_gracetime(struct file *file, char *buf, size_t
size);
@@ -103,6 +105,7 @@
                [NFSD_Ports] = write_ports,
                [NFSD_TempPorts] = write_temp_ports,
                [NFSD_MaxBlkSize] = write_maxblksize,
+              [NFSD_DirectIO] = write_directio,
 #ifdef CONFIG_NFSD_V4
                [NFSD_Leasetime] = write_leasetime,
                [NFSD_Gracetime] = write_gracetime,
@@ -1348,6 +1351,58 @@
                                                                          
                                      nfsd_max_blksize);
 }
 
+int nfsd_directio_mode = DIO_FS_UNALIGNED;
+
+/**
+ * nfsd_directio_mode - sets conditions when direct IO is activated
+ *
+ * Input:
+ *                                          buf:                       
ignored
+ *                                          size:                      
zero
+ *
+ * OR
+ *
+ * Input:
+ *                                          buf:                        C
string containing an unsigned
+ *
                                                                        
integer value representing the new
+ *
                                                                        
NFS direct IO mode
+ *                                          size:                      
non-zero length of C string in @buf
+ * Output:
+ *          On success:        passed-in buffer filled with
'\n'-terminated C string
+ *                                          containing numeric value of
the current direct IO mode
+ *                                          return code is the size in
bytes of the string
+ *
+ * Possible modes are:
+ *          DIO_NEVER (0) - never use direct I/O
+ *                          DIO_FS_UNALIGNED (1) - use direct I/O only
for requests that FS unaligned
+ *                                          and block device aligned
+ *                          DIO_SECTOR_ALIGNED (2) - use direct I/O for
all block device aligned IO
+ *          On error:             return code is zero or a negative errno
value
+ */
+static ssize_t write_directio(struct file *file, char *buf, size_t size)
+{
+              char *mesg = buf;
+              if (size > 0) {
+                              int mode;
+                              int rv = get_int(&mesg, &mode);
+                              if (rv)
+                                              return rv;
+                              if (mode < DIO_NEVER || mode >
DIO_BDEV_ALIGNED)
+                                              return -EINVAL;
+                              /*
+                              There is no need for synchronization here.
No harm will happen
+                              even if mode was changed between opening a
file and choosing whether
+                              to choose direct or buffered path. When we
choosing a path we make sure
+                              that the file has been opened in the
compatible mode
+                              */
+                              nfsd_directio_mode = mode;
+                              printk(KERN_WARNING"NFSD direct I/O mode
changed to %d.",
+                                              nfsd_directio_mode);
+              }
+
+              return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n",
nfsd_directio_mode);
+}
+
 #ifdef CONFIG_NFSD_V4
 static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t
size, time_t *time)
 {
@@ -1525,6 +1580,7 @@
                                [NFSD_Ports] = {"portlist",
&transaction_ops, S_IWUSR|S_IRUGO},
                                [NFSD_TempPorts] = {"tempportlist",
&transaction_ops, S_IWUSR|S_IRUGO},
                                [NFSD_MaxBlkSize] = {"max_block_size",
&transaction_ops, S_IWUSR|S_IRUGO},
+                              [NFSD_DirectIO] = {"direct_io",
&transaction_ops, S_IWUSR|S_IRUGO},
 #if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE)
                                [NFSD_SupportedEnctypes] =
{"supported_krb5_enctypes", &supported_enctypes_ops, S_IRUGO},
 #endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */
diff -uNr a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
--- a/fs/nfsd/nfsd.h        2011-10-24 14:06:32.000000000 -0400
+++ b/fs/nfsd/nfsd.h      2012-04-17 11:45:55.000000000 -0400
@@ -68,6 +68,14 @@
 
 extern int nfsd_max_blksize;
 
+enum {
+              DIO_NEVER = 0,// Never use Direct I/O. The first value
+              DIO_FS_UNALIGNED = 1,               // Use Direct I/O when
request is FS unaligned
+              DIO_BDEV_ALIGNED =2, // Always use Direct I/O when
possible. The last value
+};
+
+extern int nfsd_directio_mode;
+
 static inline int nfsd_v4client(struct svc_rqst *rq)
 {
                return rq->rq_prog == NFS_PROGRAM && rq->rq_vers == 4;
diff -uNr a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
--- a/fs/nfsd/vfs.c            2011-10-24 14:06:32.000000000 -0400
+++ b/fs/nfsd/vfs.c         2012-04-17 11:48:29.000000000 -0400
@@ -28,6 +28,7 @@
 #include <asm/uaccess.h>
 #include <linux/exportfs.h>
 #include <linux/writeback.h>
+#include <linux/blkdev.h>
 
 #ifdef CONFIG_NFSD_V3
 #include "xdr3.h"
@@ -718,6 +719,255 @@
                return break_lease(inode, mode | O_NONBLOCK);
 }
 
+/*
+ Copies data between two iovec arrays. Individual array elements might
have
+ different sizes, but total size of data described by the two arrays must
+ be the same
+*/
+static int nfsd_copy_iovec(const struct iovec* svec, const unsigned int
scount,
+                                                              struct
iovec* dvec, const unsigned int dcount, size_t size) {
+              size_t cur_size, soff, doff, tocopy, srem , drem ;
+              unsigned int di, si;
+
+              cur_size = iov_length(svec, scount);
+              if (cur_size != iov_length(dvec, dcount))
+                              return -EINVAL;
+
+              srem = drem = 0;
+              di = si = 0;
+              soff = doff = 0;
+              while (cur_size > 0)         {
+                              if (si >= scount || di >= dcount)
+                                              return -EFAULT;
+
+                              srem = svec[si].iov_len - soff;
+                              drem = dvec[di].iov_len - doff;
+                              tocopy = (srem > drem) ? drem : srem;
+                              memcpy((char*)(dvec[di].iov_base) + doff, 
(char*)(svec[si].iov_base) + soff, tocopy);
+                              cur_size -= tocopy;
+                              srem -= tocopy;
+                              drem -= tocopy;
+                              doff += tocopy;
+                              soff += tocopy;
+                              if (srem == 0) {
+                                              si++;
+                                              soff = 0;
+                              }
+                              if (drem == 0) {
+                                              di++;
+                                              doff = 0;
+                              }
+              }
+              if (si != scount || di != dcount || srem !=0 || drem != 0)
+              {
+                              printk(KERN_WARNING"In copy_iovec: si=%lu,
scount=%lu, di=%lu, dcount=%lu, srem=%lu, drem=%lu",
+                                              (unsigned long)si,
(unsigned long)scount, (unsigned long)di,
+                                              (unsigned long)dcount,
(unsigned long)srem, (unsigned long)drem);
+                              return -EFAULT;
+              }
+
+              return 0;
+}
+
+/*
+ Allocates iovec array where each element has page alligned base address
and
+ size of a page. Needed for DIRECT I/O to be possbile from this array
+ */
+static int nfsd_allocate_paged_iovec(size_t size, unsigned int* pcount,
+                              struct iovec** pvec) {
+              unsigned int i;
+              unsigned int page_num = size / PAGE_SIZE;
+              struct iovec * vec = NULL;
+             
+              *pvec = NULL;
+              *pcount = 0;
+              if (page_num * PAGE_SIZE != size)
+                              page_num++;
+
+              vec = kmalloc(sizeof(struct iovec) * page_num, GFP_KERNEL);
+              if (!vec)
+                              return -ENOMEM;
+              memset(vec, 0, sizeof(struct iovec) * page_num);
+              *pvec = vec;
+              *pcount = page_num;
+             
+              for (i = 0; i < page_num; i++) {
+                              vec[i].iov_base =
(void*)__get_free_page(GFP_KERNEL);
+                              if (!vec[i].iov_base)
+                                              return -ENOMEM;
+                              vec[i].iov_len = PAGE_SIZE;
+              }
+
+              if (size % PAGE_SIZE)
+                              vec[page_num - 1].iov_len = size %
PAGE_SIZE;
+
+              return 0;
+}
+
+/*
+ Deallocates iovec array, allocated by nfsd_allocate_paged_iovec
+*/
+static void nfsd_free_paged_iovec(unsigned int count, struct iovec* vec)
{
+              unsigned int i;
+              if (vec) {
+                              for (i = 0; i < count; i++)
+                                              if (vec[i].iov_base)
+                                                             
free_page((unsigned long)(vec[i].iov_base));
+                              kfree(vec);
+              }
+}
+
+/*
+ Performs direct I/O for a given NFS write request
+*/
+static ssize_t nfsd_vfs_write_direct(struct file *file, const struct
iovec *vec,
+                                 unsigned long vlen, loff_t *pos) {
+              ssize_t result = -EINVAL;
+              unsigned int page_num;
+              struct iovec *aligned_vec = NULL;
+             
+              // Check size to be multiple of sectors
+              size_t size = iov_length(vec, vlen);
+
+              if (size == 0)
+                              return vfs_writev(file, (struct iovec
__user *)vec, vlen, pos);
+
+              // Allocate necesary number of pages
+              result = nfsd_allocate_paged_iovec(size, &page_num,
&aligned_vec);
+              if (result) {
+                              printk(KERN_WARNING"Cannot allocate
aligned_vec.");
+                              goto out;
+              }
+
+              // Copy data
+              result = nfsd_copy_iovec(vec, vlen, aligned_vec, page_num,
size);
+              if(result) {
+                              printk(KERN_WARNING"Wrong amount of data
copied to aligned buffer.");
+                              goto out;
+              }
+
+              // Call further
+              result = vfs_writev(file, (struct iovec __user
*)aligned_vec, page_num, pos);
+
+out:
+              nfsd_free_paged_iovec(page_num, aligned_vec);
+              return result;
+}
+
+
+/*
+ Performs direct I/O for a given NFS read request
+*/
+static ssize_t nfsd_vfs_read_direct(struct file *file, struct iovec *vec,
+                                unsigned long vlen, loff_t *pos) {
+              unsigned int page_num;
+              struct iovec *aligned_vec = NULL;
+              ssize_t result = -EINVAL;
+              size_t size;
+             
+              // Check size to be multiple of sectors
+              size = iov_length(vec, vlen);
+             
+              if (size == 0)
+                              return vfs_readv(file, (struct iovec __user
*)vec, vlen, pos);
+
+              // Allocate necesary number of pages
+              result = nfsd_allocate_paged_iovec(size, &page_num,
&aligned_vec);
+              if (result) {
+                              printk(KERN_WARNING"Cannot allocate
aligned_vec.");
+                              goto out;
+              }
+
+              // Call further
+              result = vfs_readv(file, (struct iovec __user
*)aligned_vec, page_num, pos);
+              if (result < 0) {
+                              printk(KERN_WARNING"Error during read
operation.");
+                              goto out;
+              }
+
+              // Copy data
+              if(nfsd_copy_iovec(aligned_vec, page_num, vec, vlen, size))
{
+                              printk(KERN_WARNING"Wrong amount of data
copied from aligned buffer.");
+                              goto out;
+              }
+
+out:
+              nfsd_free_paged_iovec(page_num, aligned_vec);
+
+              return result;
+}
+
+// Returns number of terminal zero bits for a given number (number
alignment)
+static unsigned int get_alignment(loff_t n) {
+              unsigned int i=0;
+              if (n == 0)
+                              return (unsigned int)-1; // 0 is alligned
to any number
+              while ((n & 1) == 0 && n > 0) {
+                              n = n >> 1;
+                              i++;
+              }
+              return i;
+}
+
+// Returns the alignment of I/O request
+static unsigned int io_alignment(const loff_t offset,
+                              const unsigned long size) {
+              unsigned int i1, i2;
+
+              i1 = get_alignment(offset);
+              i2 = get_alignment(size);
+
+              return i1 > i2 ? i2 : i1;
+}
+
+
+/*
+ Based on the I/O request and file system parameters determines if
+ direct I/O can be used to perform the given request
+ Either file or sb are needed to retrieve file system and device
+ paramters
+*/
+static int can_use_direct_io(const struct file *file,
+                              const struct super_block* sb,
+                              const loff_t offset, const unsigned long
size) {
+              unsigned int blkbits = 0;
+              struct inode *inode;
+              unsigned int fsblkbits = 0;
+              unsigned int alignment  = io_alignment(offset, size);
+
+              if (alignment == 0)
+                              return 0;
+
+              if (file == NULL && sb == NULL)
+                              return 0;
+
+              if (nfsd_directio_mode == DIO_NEVER)
+                              return 0;
+             
+              if (file != NULL && sb == NULL) {
+                              inode = file->f_path.dentry->d_inode;
+                              sb = inode->i_sb;
+                              fsblkbits = inode->i_blkbits;
+              }
+
+              if (sb !=NULL) {
+                              blkbits = sb->s_blocksize_bits;
+                              fsblkbits = sb->s_blocksize_bits;
+                              if (sb->s_bdev)
+                                              blkbits =
blksize_bits(bdev_logical_block_size(sb->s_bdev));
+              } else
+                              blkbits = fsblkbits;
+
+              if (alignment >= fsblkbits && fsblkbits > 0 &&
nfsd_directio_mode != DIO_BDEV_ALIGNED)
+                              return 0;
+
+              if (alignment < blkbits)
+                              return 0;
+
+              return 1;
+}
+
+
 /*
  * Open an existing file or directory.
  * The access argument indicates the type of open (read/write/lock)
@@ -725,13 +975,15 @@
  */
 __be32
 nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
-                                              int access, struct file
**filp)
+                                              int access, struct file
**filp,
+                                              const loff_t offset, const
unsigned long size)
 {
                struct dentry      *dentry;
                struct inode       *inode;
                int                          flags = O_RDONLY|O_LARGEFILE;
                __be32                 err;
                int                          host_err = 0;
+              struct super_block* sb;
 
                validate_process_creds();
 
@@ -774,6 +1026,11 @@
                                else
                                                flags =
O_WRONLY|O_LARGEFILE;
                }
+
+              sb = fhp->fh_export->ex_path.mnt->mnt_sb;
+              if (size && can_use_direct_io(NULL, sb, offset, size))
+                              flags |= O_DIRECT;
+
                *filp = dentry_open(dget(dentry),
mntget(fhp->fh_export->ex_path.mnt),
                                                    flags,
current_cred());
                if (IS_ERR(*filp))
@@ -885,8 +1142,10 @@
                return __splice_from_pipe(pipe, sd, nfsd_splice_actor);
 }
 
+
+
 static __be32
-nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file
*file,
+ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file
*file,
               loff_t offset, struct kvec *vec, int vlen, unsigned long
*count)
 {
                mm_segment_t                oldfs;
@@ -899,21 +1158,29 @@
                if (rqstp->rq_vers >= 3)
                                file->f_flags |= O_NONBLOCK;
 
-              if (file->f_op->splice_read && rqstp->rq_splice_ok) {
-                              struct splice_desc sd = {
-                                              .len                       
= 0,
-                                              .total_len            =
*count,
-                                              .pos                      
= offset,
-                                              .u.data                  =
rqstp,
-                              };
-
-                              rqstp->rq_resused = 1;
-                              host_err = splice_direct_to_actor(file,
&sd, nfsd_direct_splice_actor);
-              } else {
+              if (file->f_flags & O_DIRECT) {
+                              // So far we do not support splice IO, so
always do regular
                                oldfs = get_fs();
                                set_fs(KERNEL_DS);
-                              host_err = vfs_readv(file, (struct iovec
__user *)vec, vlen, &offset);
+                              host_err = nfsd_vfs_read_direct(file,
(struct iovec*)vec, vlen, &offset);
                                set_fs(oldfs);
+              } else {
+                              if (file->f_op->splice_read &&
rqstp->rq_splice_ok) {
+                                              struct splice_desc sd = {
+                                                             
.len                        = 0,
+                                                             
.total_len            = *count,
+                                                             
.pos                       = offset,
+                                                             
.u.data                  = rqstp,
+                                              };
+
+                                              rqstp->rq_resused = 1;
+                                              host_err =
splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor);
+                              } else {
+                                              oldfs = get_fs();
+                                              set_fs(KERNEL_DS);
+                                              host_err = vfs_readv(file,
(struct iovec __user *)vec, vlen, &offset);
+                                              set_fs(oldfs);
+                              }
                }
 
                if (host_err >= 0) {
@@ -1024,7 +1291,11 @@
 
                /* Write the data. */
                oldfs = get_fs(); set_fs(KERNEL_DS);
-              host_err = vfs_writev(file, (struct iovec __user *)vec,
vlen, &offset);
+              if (file->f_flags & O_DIRECT)
+                              host_err = nfsd_vfs_write_direct(file,
(struct iovec*)vec, vlen, &offset);
+              else
+                              host_err = vfs_writev(file, (struct iovec
__user *)vec, vlen, &offset);
+
                set_fs(oldfs);
                if (host_err < 0)
                                goto out_nfserr;
@@ -1064,8 +1335,9 @@
                struct inode *inode;
                struct raparms   *ra;
                __be32 err;
+              unsigned long size = iov_length((struct iovec*)vec, vlen);
 
-              err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
+              err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file,
offset,  size);
                if (err)
                                return err;
 
@@ -1133,7 +1405,8 @@
                                err = nfsd_vfs_write(rqstp, fhp, file,
offset, vec, vlen, cnt,
                                                                stablep);
                } else {
-                              err = nfsd_open(rqstp, fhp, S_IFREG,
NFSD_MAY_WRITE, &file);
+                              unsigned long size = iov_length((struct
iovec*)vec, vlen);
+                              err = nfsd_open(rqstp, fhp, S_IFREG,
NFSD_MAY_WRITE, &file, offset, size);
                                if (err)
                                                goto out;
 
@@ -1173,7 +1446,7 @@
                }
 
                err = nfsd_open(rqstp, fhp, S_IFREG,
-                                             
NFSD_MAY_WRITE|NFSD_MAY_NOT_BREAK_LEASE, &file);
+                                             
NFSD_MAY_WRITE|NFSD_MAY_NOT_BREAK_LEASE, &file, 0, 0);
                if (err)
                                goto out;
                if (EX_ISSYNC(fhp->fh_export)) {
@@ -2018,7 +2291,7 @@
                struct file            *file;
                loff_t                     offset = *offsetp;
 
-              err = nfsd_open(rqstp, fhp, S_IFDIR, NFSD_MAY_READ, &file);
+              err = nfsd_open(rqstp, fhp, S_IFDIR, NFSD_MAY_READ, &file,
0, 0);
                if (err)
                                goto out;
 
diff -uNr a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
--- a/fs/nfsd/vfs.h           2011-10-24 14:06:32.000000000 -0400
+++ b/fs/nfsd/vfs.h         2012-03-28 15:40:29.000000000 -0400
@@ -66,7 +66,7 @@
                                                                loff_t,
unsigned long);
 #endif /* CONFIG_NFSD_V3 */
 __be32                                nfsd_open(struct svc_rqst *, struct
svc_fh *, int,
-                                                              int, struct
file **);
+                                                              int, struct
file **, const loff_t, const unsigned long);
 void                      nfsd_close(struct file *);
 __be32                                nfsd_read(struct svc_rqst *, struct
svc_fh *,
                                                                loff_t,
struct kvec *, int, unsigned long *);

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2012-05-15 18:50 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-04-18 14:18 [PATCH RFC] Performing direct I/O on sector-aligned requests Alexandre Depoutovitch
2012-04-18 16:19 ` Myklebust, Trond
2012-04-18 17:56   ` Alexandre Depoutovitch
2012-04-29 21:03 ` [PATCH RFC v2] " Alexandre Depoutovitch
2012-04-30 19:56   ` Matthew Wilcox
2012-04-30 21:39     ` Alexandre Depoutovitch
     [not found]   ` <1508773761.4854678.1335731939770.JavaMail.root-uUpdlAIx0AHkdGAVcyJ/gDSPNL9O62GLZeezCHUQhQ4@public.gmane.org>
2012-04-30 18:22     ` Jeff Moyer
2012-04-30 18:22       ` Jeff Moyer
2012-05-15 18:50       ` Alexandre Depoutovitch
2012-05-08 19:51     ` Alexandre Depoutovitch
2012-05-08 19:51       ` Alexandre Depoutovitch
2012-05-11 18:36     ` Dean
2012-05-11 18:36       ` Dean
     [not found]       ` <4FAD5C44.50407-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2012-05-15 17:44         ` Alexandre Depoutovitch
2012-05-15 17:44           ` Alexandre Depoutovitch

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.