diff options
author | Anna Schumaker <Anna.Schumaker@netapp.com> | 2014-11-25 13:18:15 -0500 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-11-25 16:38:32 -0500 |
commit | f4ac1674f5da420ef17896f0f222c5215ebcde80 (patch) | |
tree | 5ad22eac7b8ef584ce1b39b618aeb0b242dcccb7 /fs/nfs | |
parent | e9f456ca50e579dfacd996f50637f0bb0a585dfc (diff) |
nfs: Add ALLOCATE support
This patch adds support for using the NFS v4.2 operation ALLOCATE to
preallocate data in a file.
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/inode.c | 1 | ||||
-rw-r--r-- | fs/nfs/nfs42.h | 1 | ||||
-rw-r--r-- | fs/nfs/nfs42proc.c | 58 | ||||
-rw-r--r-- | fs/nfs/nfs42xdr.c | 75 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 1 | ||||
-rw-r--r-- | fs/nfs/nfs4file.c | 28 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 3 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 1 |
8 files changed, 167 insertions, 1 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 2b48ce58a584..4bffe637ea32 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -192,6 +192,7 @@ void nfs_zap_caches(struct inode *inode) | |||
192 | nfs_zap_caches_locked(inode); | 192 | nfs_zap_caches_locked(inode); |
193 | spin_unlock(&inode->i_lock); | 193 | spin_unlock(&inode->i_lock); |
194 | } | 194 | } |
195 | EXPORT_SYMBOL_GPL(nfs_zap_caches); | ||
195 | 196 | ||
196 | void nfs_zap_mapping(struct inode *inode, struct address_space *mapping) | 197 | void nfs_zap_mapping(struct inode *inode, struct address_space *mapping) |
197 | { | 198 | { |
diff --git a/fs/nfs/nfs42.h b/fs/nfs/nfs42.h index d10333a197bf..42656a9cf485 100644 --- a/fs/nfs/nfs42.h +++ b/fs/nfs/nfs42.h | |||
@@ -6,6 +6,7 @@ | |||
6 | #define __LINUX_FS_NFS_NFS4_2_H | 6 | #define __LINUX_FS_NFS_NFS4_2_H |
7 | 7 | ||
8 | /* nfs4.2proc.c */ | 8 | /* nfs4.2proc.c */ |
9 | int nfs42_proc_allocate(struct file *, loff_t, loff_t); | ||
9 | loff_t nfs42_proc_llseek(struct file *, loff_t, int); | 10 | loff_t nfs42_proc_llseek(struct file *, loff_t, int); |
10 | 11 | ||
11 | /* nfs4.2xdr.h */ | 12 | /* nfs4.2xdr.h */ |
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c index 056f5aafecc1..581f34e9d8a0 100644 --- a/fs/nfs/nfs42proc.c +++ b/fs/nfs/nfs42proc.c | |||
@@ -32,6 +32,64 @@ static int nfs42_set_rw_stateid(nfs4_stateid *dst, struct file *file, | |||
32 | return ret; | 32 | return ret; |
33 | } | 33 | } |
34 | 34 | ||
35 | static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep, | ||
36 | loff_t offset, loff_t len) | ||
37 | { | ||
38 | struct inode *inode = file_inode(filep); | ||
39 | struct nfs42_falloc_args args = { | ||
40 | .falloc_fh = NFS_FH(inode), | ||
41 | .falloc_offset = offset, | ||
42 | .falloc_length = len, | ||
43 | }; | ||
44 | struct nfs42_falloc_res res; | ||
45 | struct nfs_server *server = NFS_SERVER(inode); | ||
46 | int status; | ||
47 | |||
48 | msg->rpc_argp = &args; | ||
49 | msg->rpc_resp = &res; | ||
50 | |||
51 | status = nfs42_set_rw_stateid(&args.falloc_stateid, filep, FMODE_WRITE); | ||
52 | if (status) | ||
53 | return status; | ||
54 | |||
55 | return nfs4_call_sync(server->client, server, msg, | ||
56 | &args.seq_args, &res.seq_res, 0); | ||
57 | } | ||
58 | |||
59 | static int nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep, | ||
60 | loff_t offset, loff_t len) | ||
61 | { | ||
62 | struct nfs_server *server = NFS_SERVER(file_inode(filep)); | ||
63 | struct nfs4_exception exception = { }; | ||
64 | int err; | ||
65 | |||
66 | do { | ||
67 | err = _nfs42_proc_fallocate(msg, filep, offset, len); | ||
68 | if (err == -ENOTSUPP) | ||
69 | return -EOPNOTSUPP; | ||
70 | err = nfs4_handle_exception(server, err, &exception); | ||
71 | } while (exception.retry); | ||
72 | |||
73 | return err; | ||
74 | } | ||
75 | |||
76 | int nfs42_proc_allocate(struct file *filep, loff_t offset, loff_t len) | ||
77 | { | ||
78 | struct rpc_message msg = { | ||
79 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ALLOCATE], | ||
80 | }; | ||
81 | struct inode *inode = file_inode(filep); | ||
82 | int err; | ||
83 | |||
84 | if (!nfs_server_capable(inode, NFS_CAP_ALLOCATE)) | ||
85 | return -EOPNOTSUPP; | ||
86 | |||
87 | err = nfs42_proc_fallocate(&msg, filep, offset, len); | ||
88 | if (err == -EOPNOTSUPP) | ||
89 | NFS_SERVER(inode)->caps &= ~NFS_CAP_ALLOCATE; | ||
90 | return err; | ||
91 | } | ||
92 | |||
35 | loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence) | 93 | loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence) |
36 | { | 94 | { |
37 | struct inode *inode = file_inode(filep); | 95 | struct inode *inode = file_inode(filep); |
diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c index c90469b604b8..4248d034479c 100644 --- a/fs/nfs/nfs42xdr.c +++ b/fs/nfs/nfs42xdr.c | |||
@@ -4,6 +4,12 @@ | |||
4 | #ifndef __LINUX_FS_NFS_NFS4_2XDR_H | 4 | #ifndef __LINUX_FS_NFS_NFS4_2XDR_H |
5 | #define __LINUX_FS_NFS_NFS4_2XDR_H | 5 | #define __LINUX_FS_NFS_NFS4_2XDR_H |
6 | 6 | ||
7 | #define encode_fallocate_maxsz (encode_stateid_maxsz + \ | ||
8 | 2 /* offset */ + \ | ||
9 | 2 /* length */) | ||
10 | #define encode_allocate_maxsz (op_encode_hdr_maxsz + \ | ||
11 | encode_fallocate_maxsz) | ||
12 | #define decode_allocate_maxsz (op_decode_hdr_maxsz) | ||
7 | #define encode_seek_maxsz (op_encode_hdr_maxsz + \ | 13 | #define encode_seek_maxsz (op_encode_hdr_maxsz + \ |
8 | encode_stateid_maxsz + \ | 14 | encode_stateid_maxsz + \ |
9 | 2 /* offset */ + \ | 15 | 2 /* offset */ + \ |
@@ -14,6 +20,12 @@ | |||
14 | 2 /* offset */ + \ | 20 | 2 /* offset */ + \ |
15 | 2 /* length */) | 21 | 2 /* length */) |
16 | 22 | ||
23 | #define NFS4_enc_allocate_sz (compound_encode_hdr_maxsz + \ | ||
24 | encode_putfh_maxsz + \ | ||
25 | encode_allocate_maxsz) | ||
26 | #define NFS4_dec_allocate_sz (compound_decode_hdr_maxsz + \ | ||
27 | decode_putfh_maxsz + \ | ||
28 | decode_allocate_maxsz) | ||
17 | #define NFS4_enc_seek_sz (compound_encode_hdr_maxsz + \ | 29 | #define NFS4_enc_seek_sz (compound_encode_hdr_maxsz + \ |
18 | encode_putfh_maxsz + \ | 30 | encode_putfh_maxsz + \ |
19 | encode_seek_maxsz) | 31 | encode_seek_maxsz) |
@@ -22,6 +34,22 @@ | |||
22 | decode_seek_maxsz) | 34 | decode_seek_maxsz) |
23 | 35 | ||
24 | 36 | ||
37 | static void encode_fallocate(struct xdr_stream *xdr, | ||
38 | struct nfs42_falloc_args *args) | ||
39 | { | ||
40 | encode_nfs4_stateid(xdr, &args->falloc_stateid); | ||
41 | encode_uint64(xdr, args->falloc_offset); | ||
42 | encode_uint64(xdr, args->falloc_length); | ||
43 | } | ||
44 | |||
45 | static void encode_allocate(struct xdr_stream *xdr, | ||
46 | struct nfs42_falloc_args *args, | ||
47 | struct compound_hdr *hdr) | ||
48 | { | ||
49 | encode_op_hdr(xdr, OP_ALLOCATE, decode_allocate_maxsz, hdr); | ||
50 | encode_fallocate(xdr, args); | ||
51 | } | ||
52 | |||
25 | static void encode_seek(struct xdr_stream *xdr, | 53 | static void encode_seek(struct xdr_stream *xdr, |
26 | struct nfs42_seek_args *args, | 54 | struct nfs42_seek_args *args, |
27 | struct compound_hdr *hdr) | 55 | struct compound_hdr *hdr) |
@@ -33,6 +61,24 @@ static void encode_seek(struct xdr_stream *xdr, | |||
33 | } | 61 | } |
34 | 62 | ||
35 | /* | 63 | /* |
64 | * Encode ALLOCATE request | ||
65 | */ | ||
66 | static void nfs4_xdr_enc_allocate(struct rpc_rqst *req, | ||
67 | struct xdr_stream *xdr, | ||
68 | struct nfs42_falloc_args *args) | ||
69 | { | ||
70 | struct compound_hdr hdr = { | ||
71 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), | ||
72 | }; | ||
73 | |||
74 | encode_compound_hdr(xdr, req, &hdr); | ||
75 | encode_sequence(xdr, &args->seq_args, &hdr); | ||
76 | encode_putfh(xdr, args->falloc_fh, &hdr); | ||
77 | encode_allocate(xdr, args, &hdr); | ||
78 | encode_nops(&hdr); | ||
79 | } | ||
80 | |||
81 | /* | ||
36 | * Encode SEEK request | 82 | * Encode SEEK request |
37 | */ | 83 | */ |
38 | static void nfs4_xdr_enc_seek(struct rpc_rqst *req, | 84 | static void nfs4_xdr_enc_seek(struct rpc_rqst *req, |
@@ -50,6 +96,11 @@ static void nfs4_xdr_enc_seek(struct rpc_rqst *req, | |||
50 | encode_nops(&hdr); | 96 | encode_nops(&hdr); |
51 | } | 97 | } |
52 | 98 | ||
99 | static int decode_allocate(struct xdr_stream *xdr, struct nfs42_falloc_res *res) | ||
100 | { | ||
101 | return decode_op_hdr(xdr, OP_ALLOCATE); | ||
102 | } | ||
103 | |||
53 | static int decode_seek(struct xdr_stream *xdr, struct nfs42_seek_res *res) | 104 | static int decode_seek(struct xdr_stream *xdr, struct nfs42_seek_res *res) |
54 | { | 105 | { |
55 | int status; | 106 | int status; |
@@ -73,6 +124,30 @@ out_overflow: | |||
73 | } | 124 | } |
74 | 125 | ||
75 | /* | 126 | /* |
127 | * Decode ALLOCATE request | ||
128 | */ | ||
129 | static int nfs4_xdr_dec_allocate(struct rpc_rqst *rqstp, | ||
130 | struct xdr_stream *xdr, | ||
131 | struct nfs42_falloc_res *res) | ||
132 | { | ||
133 | struct compound_hdr hdr; | ||
134 | int status; | ||
135 | |||
136 | status = decode_compound_hdr(xdr, &hdr); | ||
137 | if (status) | ||
138 | goto out; | ||
139 | status = decode_sequence(xdr, &res->seq_res, rqstp); | ||
140 | if (status) | ||
141 | goto out; | ||
142 | status = decode_putfh(xdr); | ||
143 | if (status) | ||
144 | goto out; | ||
145 | status = decode_allocate(xdr, res); | ||
146 | out: | ||
147 | return status; | ||
148 | } | ||
149 | |||
150 | /* | ||
76 | * Decode SEEK request | 151 | * Decode SEEK request |
77 | */ | 152 | */ |
78 | static int nfs4_xdr_dec_seek(struct rpc_rqst *rqstp, | 153 | static int nfs4_xdr_dec_seek(struct rpc_rqst *rqstp, |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index be6cac37ea10..a08178764cf9 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -226,6 +226,7 @@ int nfs4_replace_transport(struct nfs_server *server, | |||
226 | const struct nfs4_fs_locations *locations); | 226 | const struct nfs4_fs_locations *locations); |
227 | 227 | ||
228 | /* nfs4proc.c */ | 228 | /* nfs4proc.c */ |
229 | extern int nfs4_handle_exception(struct nfs_server *, int, struct nfs4_exception *); | ||
229 | extern int nfs4_call_sync(struct rpc_clnt *, struct nfs_server *, | 230 | extern int nfs4_call_sync(struct rpc_clnt *, struct nfs_server *, |
230 | struct rpc_message *, struct nfs4_sequence_args *, | 231 | struct rpc_message *, struct nfs4_sequence_args *, |
231 | struct nfs4_sequence_res *, int); | 232 | struct nfs4_sequence_res *, int); |
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index c51fb4db9bfe..f78e9fd0735a 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c | |||
@@ -3,6 +3,8 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 1992 Rick Sladkey | 4 | * Copyright (C) 1992 Rick Sladkey |
5 | */ | 5 | */ |
6 | #include <linux/fs.h> | ||
7 | #include <linux/falloc.h> | ||
6 | #include <linux/nfs_fs.h> | 8 | #include <linux/nfs_fs.h> |
7 | #include "internal.h" | 9 | #include "internal.h" |
8 | #include "fscache.h" | 10 | #include "fscache.h" |
@@ -134,6 +136,29 @@ static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence) | |||
134 | return nfs_file_llseek(filep, offset, whence); | 136 | return nfs_file_llseek(filep, offset, whence); |
135 | } | 137 | } |
136 | } | 138 | } |
139 | |||
140 | static long nfs42_fallocate(struct file *filep, int mode, loff_t offset, loff_t len) | ||
141 | { | ||
142 | struct inode *inode = file_inode(filep); | ||
143 | long ret; | ||
144 | |||
145 | if (!S_ISREG(inode->i_mode)) | ||
146 | return -EOPNOTSUPP; | ||
147 | |||
148 | if (mode != 0) | ||
149 | return -EOPNOTSUPP; | ||
150 | |||
151 | ret = inode_newsize_ok(inode, offset + len); | ||
152 | if (ret < 0) | ||
153 | return ret; | ||
154 | |||
155 | mutex_lock(&inode->i_mutex); | ||
156 | ret = nfs42_proc_allocate(filep, offset, len); | ||
157 | mutex_unlock(&inode->i_mutex); | ||
158 | |||
159 | nfs_zap_caches(inode); | ||
160 | return ret; | ||
161 | } | ||
137 | #endif /* CONFIG_NFS_V4_2 */ | 162 | #endif /* CONFIG_NFS_V4_2 */ |
138 | 163 | ||
139 | const struct file_operations nfs4_file_operations = { | 164 | const struct file_operations nfs4_file_operations = { |
@@ -155,6 +180,9 @@ const struct file_operations nfs4_file_operations = { | |||
155 | .flock = nfs_flock, | 180 | .flock = nfs_flock, |
156 | .splice_read = nfs_file_splice_read, | 181 | .splice_read = nfs_file_splice_read, |
157 | .splice_write = iter_file_splice_write, | 182 | .splice_write = iter_file_splice_write, |
183 | #ifdef CONFIG_NFS_V4_2 | ||
184 | .fallocate = nfs42_fallocate, | ||
185 | #endif /* CONFIG_NFS_V4_2 */ | ||
158 | .check_flags = nfs_check_flags, | 186 | .check_flags = nfs_check_flags, |
159 | .setlease = simple_nosetlease, | 187 | .setlease = simple_nosetlease, |
160 | }; | 188 | }; |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 3138913d1cdf..b1b403b0ca0d 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -342,7 +342,7 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout) | |||
342 | /* This is the error handling routine for processes that are allowed | 342 | /* This is the error handling routine for processes that are allowed |
343 | * to sleep. | 343 | * to sleep. |
344 | */ | 344 | */ |
345 | static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception) | 345 | int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception) |
346 | { | 346 | { |
347 | struct nfs_client *clp = server->nfs_client; | 347 | struct nfs_client *clp = server->nfs_client; |
348 | struct nfs4_state *state = exception->state; | 348 | struct nfs4_state *state = exception->state; |
@@ -8424,6 +8424,7 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = { | |||
8424 | | NFS_CAP_POSIX_LOCK | 8424 | | NFS_CAP_POSIX_LOCK |
8425 | | NFS_CAP_STATEID_NFSV41 | 8425 | | NFS_CAP_STATEID_NFSV41 |
8426 | | NFS_CAP_ATOMIC_OPEN_V1 | 8426 | | NFS_CAP_ATOMIC_OPEN_V1 |
8427 | | NFS_CAP_ALLOCATE | ||
8427 | | NFS_CAP_SEEK, | 8428 | | NFS_CAP_SEEK, |
8428 | .init_client = nfs41_init_client, | 8429 | .init_client = nfs41_init_client, |
8429 | .shutdown_client = nfs41_shutdown_client, | 8430 | .shutdown_client = nfs41_shutdown_client, |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 206c08a60c7f..0a1484561e4b 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -7394,6 +7394,7 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
7394 | #endif /* CONFIG_NFS_V4_1 */ | 7394 | #endif /* CONFIG_NFS_V4_1 */ |
7395 | #ifdef CONFIG_NFS_V4_2 | 7395 | #ifdef CONFIG_NFS_V4_2 |
7396 | PROC(SEEK, enc_seek, dec_seek), | 7396 | PROC(SEEK, enc_seek, dec_seek), |
7397 | PROC(ALLOCATE, enc_allocate, dec_allocate), | ||
7397 | #endif /* CONFIG_NFS_V4_2 */ | 7398 | #endif /* CONFIG_NFS_V4_2 */ |
7398 | }; | 7399 | }; |
7399 | 7400 | ||