2014-11-07 19:44:30

by Anna Schumaker

[permalink] [raw]
Subject: [PATCH v4 0/3] NFS: Add ALLOCATE and DEALLOCATE support

From: Anna Schumaker <[email protected]>

These patches add client support for the ALLOCATE and DEALLOCATE operations
part of NFS v4.2, which are triggered by a vfs_fallocate() call.

Changes in v4:
- Check if we are modifying a regular file, and return nfserr_inval if not.

These patches and the corresponding server changes are available in the
[fallocate] branch of

git://git.linux-nfs.org/projects/anna/linux-nfs.git

Questions? Comments? Thougts?

Anna


Anna Schumaker (3):
VFS: Rename do_fallocate() to vfs_fallocate()
nfsd: Add ALLOCATE support
nfsd: Add DEALLOCATE support

drivers/staging/android/ashmem.c | 2 +-
fs/ioctl.c | 2 +-
fs/nfsd/nfs4proc.c | 51 ++++++++++++++++++++++++++++++++++++++++
fs/nfsd/nfs4xdr.c | 21 +++++++++++++++--
fs/nfsd/vfs.c | 23 ++++++++++++++++++
fs/nfsd/vfs.h | 2 ++
fs/nfsd/xdr4.h | 9 +++++++
fs/open.c | 5 ++--
include/linux/fs.h | 2 +-
mm/madvise.c | 2 +-
10 files changed, 111 insertions(+), 8 deletions(-)

--
2.1.3



2014-11-07 21:22:37

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH v4 0/3] NFS: Add ALLOCATE and DEALLOCATE support

On Fri, Nov 07, 2014 at 02:44:24PM -0500, [email protected] wrote:
> From: Anna Schumaker <[email protected]>
>
> These patches add client support for the ALLOCATE and DEALLOCATE operations
> part of NFS v4.2, which are triggered by a vfs_fallocate() call.
>
> Changes in v4:
> - Check if we are modifying a regular file, and return nfserr_inval if not.

Thanks, applying for 3.19 (with minor change noted on patch 2.)

--b.

>
> These patches and the corresponding server changes are available in the
> [fallocate] branch of
>
> git://git.linux-nfs.org/projects/anna/linux-nfs.git
>
> Questions? Comments? Thougts?
>
> Anna
>
>
> Anna Schumaker (3):
> VFS: Rename do_fallocate() to vfs_fallocate()
> nfsd: Add ALLOCATE support
> nfsd: Add DEALLOCATE support
>
> drivers/staging/android/ashmem.c | 2 +-
> fs/ioctl.c | 2 +-
> fs/nfsd/nfs4proc.c | 51 ++++++++++++++++++++++++++++++++++++++++
> fs/nfsd/nfs4xdr.c | 21 +++++++++++++++--
> fs/nfsd/vfs.c | 23 ++++++++++++++++++
> fs/nfsd/vfs.h | 2 ++
> fs/nfsd/xdr4.h | 9 +++++++
> fs/open.c | 5 ++--
> include/linux/fs.h | 2 +-
> mm/madvise.c | 2 +-
> 10 files changed, 111 insertions(+), 8 deletions(-)
>
> --
> 2.1.3
>

2014-11-07 19:44:33

by Anna Schumaker

[permalink] [raw]
Subject: [PATCH v4 2/3] nfsd: Add ALLOCATE support

From: Anna Schumaker <[email protected]>

The ALLOCATE operation is used to preallocate space in a file. I can do
this by using vfs_fallocate() to do the actual preallocation.

ALLOCATE only returns a status indicator, so we don't need to write a
special encode() function.

Signed-off-by: Anna Schumaker <[email protected]>
---
fs/nfsd/nfs4proc.c | 36 ++++++++++++++++++++++++++++++++++++
fs/nfsd/nfs4xdr.c | 19 ++++++++++++++++++-
fs/nfsd/vfs.c | 23 +++++++++++++++++++++++
fs/nfsd/vfs.h | 2 ++
fs/nfsd/xdr4.h | 8 ++++++++
5 files changed, 87 insertions(+), 1 deletion(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 0beb023..a261f18 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1014,6 +1014,36 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
}

static __be32
+nfsd4_fallocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_fallocate *fallocate, int flags)
+{
+ __be32 status = nfserr_notsupp;
+ struct file *file;
+
+ status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), cstate,
+ &fallocate->falloc_stateid,
+ WR_STATE, &file);
+ if (status != nfs_ok) {
+ dprintk("NFSD: nfsd4_fallocate: couldn't process stateid!\n");
+ return status;
+ }
+
+ status = nfsd4_vfs_fallocate(rqstp, &cstate->current_fh, file,
+ fallocate->falloc_offset,
+ fallocate->falloc_length,
+ flags);
+ fput(file);
+ return status;
+}
+
+static __be32
+nfsd4_allocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_fallocate *fallocate)
+{
+ return nfsd4_fallocate(rqstp, cstate, fallocate, 0);
+}
+
+static __be32
nfsd4_seek(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_seek *seek)
{
@@ -1929,6 +1959,12 @@ static struct nfsd4_operation nfsd4_ops[] = {
},

/* NFSv4.2 operations */
+ [OP_ALLOCATE] = {
+ .op_func = (nfsd4op_func)nfsd4_allocate,
+ .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
+ .op_name = "OP_ALLOCATE",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_write_rsize,
+ },
[OP_SEEK] = {
.op_func = (nfsd4op_func)nfsd4_seek,
.op_name = "OP_SEEK",
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index eeea7a9..a60cff8 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1514,6 +1514,23 @@ static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, str
}

static __be32
+nfsd4_decode_fallocate(struct nfsd4_compoundargs *argp,
+ struct nfsd4_fallocate *fallocate)
+{
+ DECODE_HEAD;
+
+ status = nfsd4_decode_stateid(argp, &fallocate->falloc_stateid);
+ if (status)
+ return status;
+
+ READ_BUF(16);
+ p = xdr_decode_hyper(p, &fallocate->falloc_offset);
+ xdr_decode_hyper(p, &fallocate->falloc_length);
+
+ DECODE_TAIL;
+}
+
+static __be32
nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek)
{
DECODE_HEAD;
@@ -1604,7 +1621,7 @@ static nfsd4_dec nfsd4_dec_ops[] = {
[OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_reclaim_complete,

/* new operations for NFSv4.2 */
- [OP_ALLOCATE] = (nfsd4_dec)nfsd4_decode_notsupp,
+ [OP_ALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate,
[OP_COPY] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_COPY_NOTIFY] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_DEALLOCATE] = (nfsd4_dec)nfsd4_decode_notsupp,
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 989129e..2157e79 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -16,6 +16,7 @@
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/splice.h>
+#include <linux/falloc.h>
#include <linux/fcntl.h>
#include <linux/namei.h>
#include <linux/delay.h>
@@ -533,6 +534,28 @@ __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
}
#endif

+__be32 nfsd4_vfs_fallocate(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ struct file *file, loff_t offset, loff_t len,
+ int flags)
+{
+ __be32 err;
+ int error;
+
+ if (!S_ISREG(file_inode(file)->i_mode))
+ return nfserr_inval;
+
+ err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, NFSD_MAY_WRITE);
+ if (err)
+ return err;
+
+ error = vfs_fallocate(file, flags, offset, len);
+ if (!error)
+ error = commit_metadata(fhp);
+
+ if (error == -ENODEV)
+ return nfserr_inval;
+ return nfserrno(error);
+}
#endif /* defined(CONFIG_NFSD_V4) */

#ifdef CONFIG_NFSD_V3
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index c2ff3f1..7ffdb14 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -54,6 +54,8 @@ int nfsd_mountpoint(struct dentry *, struct svc_export *);
#ifdef CONFIG_NFSD_V4
__be32 nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *,
struct xdr_netobj *);
+__be32 nfsd4_vfs_fallocate(struct svc_rqst *, struct svc_fh *,
+ struct file *, loff_t, loff_t, int);
#endif /* CONFIG_NFSD_V4 */
__be32 nfsd_create(struct svc_rqst *, struct svc_fh *,
char *name, int len, struct iattr *attrs,
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 5720e94..eeaa0d0 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -428,6 +428,13 @@ struct nfsd4_reclaim_complete {
u32 rca_one_fs;
};

+struct nfsd4_fallocate {
+ /* request */
+ stateid_t falloc_stateid;
+ loff_t falloc_offset;
+ u64 falloc_length;
+};
+
struct nfsd4_seek {
/* request */
stateid_t seek_stateid;
@@ -486,6 +493,7 @@ struct nfsd4_op {
struct nfsd4_free_stateid free_stateid;

/* NFSv4.2 */
+ struct nfsd4_fallocate allocate;
struct nfsd4_seek seek;
} u;
struct nfs4_replay * replay;
--
2.1.3


2014-11-07 21:01:17

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH v4 2/3] nfsd: Add ALLOCATE support

On Fri, Nov 07, 2014 at 02:44:26PM -0500, [email protected] wrote:
> @@ -533,6 +534,28 @@ __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
> }
> #endif
>
> +__be32 nfsd4_vfs_fallocate(struct svc_rqst *rqstp, struct svc_fh *fhp,
> + struct file *file, loff_t offset, loff_t len,
> + int flags)
> +{
> + __be32 err;
> + int error;
> +
> + if (!S_ISREG(file_inode(file)->i_mode))
> + return nfserr_inval;
> +
> + err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, NFSD_MAY_WRITE);
> + if (err)
> + return err;
> +
> + error = vfs_fallocate(file, flags, offset, len);
> + if (!error)
> + error = commit_metadata(fhp);
> +
> + if (error == -ENODEV)
> + return nfserr_inval;


I don't think we need this check any more.

I'll just remove it myself as I apply if there's no objection.

--b.

2014-11-07 21:02:16

by Anna Schumaker

[permalink] [raw]
Subject: Re: [PATCH v4 2/3] nfsd: Add ALLOCATE support

On 11/07/2014 04:01 PM, J. Bruce Fields wrote:
> On Fri, Nov 07, 2014 at 02:44:26PM -0500, [email protected] wrote:
>> @@ -533,6 +534,28 @@ __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
>> }
>> #endif
>>
>> +__be32 nfsd4_vfs_fallocate(struct svc_rqst *rqstp, struct svc_fh *fhp,
>> + struct file *file, loff_t offset, loff_t len,
>> + int flags)
>> +{
>> + __be32 err;
>> + int error;
>> +
>> + if (!S_ISREG(file_inode(file)->i_mode))
>> + return nfserr_inval;
>> +
>> + err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, NFSD_MAY_WRITE);
>> + if (err)
>> + return err;
>> +
>> + error = vfs_fallocate(file, flags, offset, len);
>> + if (!error)
>> + error = commit_metadata(fhp);
>> +
>> + if (error == -ENODEV)
>> + return nfserr_inval;
>
>
> I don't think we need this check any more.
>
> I'll just remove it myself as I apply if there's no objection.

Right! Thanks for the reminder, I have no objections if you remove it :)

Anna
>
> --b.
>


2014-11-07 19:44:31

by Anna Schumaker

[permalink] [raw]
Subject: [PATCH v4 1/3] VFS: Rename do_fallocate() to vfs_fallocate()

From: Anna Schumaker <[email protected]>

This function needs to be exported so it can be used by the NFSD module
when responding to the new ALLOCATE and DEALLOCATE operations in NFS
v4.2. Christoph Hellwig suggested renaming the function to stay
consistent with how other vfs functions are named.

Signed-off-by: Anna Schumaker <[email protected]>
---
drivers/staging/android/ashmem.c | 2 +-
fs/ioctl.c | 2 +-
fs/open.c | 5 +++--
include/linux/fs.h | 2 +-
mm/madvise.c | 2 +-
5 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
index ad4f579..27eecfe 100644
--- a/drivers/staging/android/ashmem.c
+++ b/drivers/staging/android/ashmem.c
@@ -446,7 +446,7 @@ ashmem_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
loff_t start = range->pgstart * PAGE_SIZE;
loff_t end = (range->pgend + 1) * PAGE_SIZE;

- do_fallocate(range->asma->file,
+ vfs_fallocate(range->asma->file,
FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
start, end - start);
range->purged = ASHMEM_WAS_PURGED;
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 8ac3fad..0bd61421 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -443,7 +443,7 @@ int ioctl_preallocate(struct file *filp, void __user *argp)
return -EINVAL;
}

- return do_fallocate(filp, FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len);
+ return vfs_fallocate(filp, FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len);
}

static int file_ioctl(struct file *filp, unsigned int cmd,
diff --git a/fs/open.c b/fs/open.c
index de92c13..192c429 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -222,7 +222,7 @@ SYSCALL_DEFINE2(ftruncate64, unsigned int, fd, loff_t, length)
#endif /* BITS_PER_LONG == 32 */


-int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
+int vfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
{
struct inode *inode = file_inode(file);
long ret;
@@ -298,6 +298,7 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
sb_end_write(inode->i_sb);
return ret;
}
+EXPORT_SYMBOL_GPL(vfs_fallocate);

SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len)
{
@@ -305,7 +306,7 @@ SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len)
int error = -EBADF;

if (f.file) {
- error = do_fallocate(f.file, mode, offset, len);
+ error = vfs_fallocate(f.file, mode, offset, len);
fdput(f);
}
return error;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 9ab779e..4439c99 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2060,7 +2060,7 @@ struct filename {
extern long vfs_truncate(struct path *, loff_t);
extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
struct file *filp);
-extern int do_fallocate(struct file *file, int mode, loff_t offset,
+extern int vfs_fallocate(struct file *file, int mode, loff_t offset,
loff_t len);
extern long do_sys_open(int dfd, const char __user *filename, int flags,
umode_t mode);
diff --git a/mm/madvise.c b/mm/madvise.c
index 0938b30..a271adc 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -326,7 +326,7 @@ static long madvise_remove(struct vm_area_struct *vma,
*/
get_file(f);
up_read(&current->mm->mmap_sem);
- error = do_fallocate(f,
+ error = vfs_fallocate(f,
FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
offset, end - start);
fput(f);
--
2.1.3


2014-11-07 19:44:33

by Anna Schumaker

[permalink] [raw]
Subject: [PATCH v4 3/3] nfsd: Add DEALLOCATE support

From: Anna Schumaker <[email protected]>

DEALLOCATE only returns a status value, meaning we can use the noop()
xdr encoder to reply to the client.

Signed-off-by: Anna Schumaker <[email protected]>
---
fs/nfsd/nfs4proc.c | 15 +++++++++++++++
fs/nfsd/nfs4xdr.c | 2 +-
fs/nfsd/xdr4.h | 1 +
3 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index a261f18..74fb15e 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -33,6 +33,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <linux/file.h>
+#include <linux/falloc.h>
#include <linux/slab.h>

#include "idmap.h"
@@ -1044,6 +1045,14 @@ nfsd4_allocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
}

static __be32
+nfsd4_deallocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_fallocate *fallocate)
+{
+ return nfsd4_fallocate(rqstp, cstate, fallocate,
+ FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE);
+}
+
+static __be32
nfsd4_seek(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_seek *seek)
{
@@ -1965,6 +1974,12 @@ static struct nfsd4_operation nfsd4_ops[] = {
.op_name = "OP_ALLOCATE",
.op_rsize_bop = (nfsd4op_rsize)nfsd4_write_rsize,
},
+ [OP_DEALLOCATE] = {
+ .op_func = (nfsd4op_func)nfsd4_deallocate,
+ .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
+ .op_name = "OP_DEALLOCATE",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_write_rsize,
+ },
[OP_SEEK] = {
.op_func = (nfsd4op_func)nfsd4_seek,
.op_name = "OP_SEEK",
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index a60cff8..0622d4f 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1624,7 +1624,7 @@ static nfsd4_dec nfsd4_dec_ops[] = {
[OP_ALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate,
[OP_COPY] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_COPY_NOTIFY] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_DEALLOCATE] = (nfsd4_dec)nfsd4_decode_notsupp,
+ [OP_DEALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate,
[OP_IO_ADVISE] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_LAYOUTERROR] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_LAYOUTSTATS] = (nfsd4_dec)nfsd4_decode_notsupp,
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index eeaa0d0..90a5925 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -494,6 +494,7 @@ struct nfsd4_op {

/* NFSv4.2 */
struct nfsd4_fallocate allocate;
+ struct nfsd4_fallocate deallocate;
struct nfsd4_seek seek;
} u;
struct nfs4_replay * replay;
--
2.1.3