diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2017-02-17 18:42:32 -0500 |
---|---|---|
committer | Anna Schumaker <Anna.Schumaker@Netapp.com> | 2017-02-22 13:49:11 -0500 |
commit | 9d8cacbf5636657d2cd0dda17438a56d806d3224 (patch) | |
tree | 80b2c01795b952d8fd4c8dad20c2c9a971666cab | |
parent | df3ab232e462bce20710596d697ade6b72497694 (diff) |
NFSv4: Fix reboot recovery in copy offload
Copy offload code needs to be hooked into the code for handling
NFS4ERR_BAD_STATEID by ensuring that we set the "stateid" field
in struct nfs4_exception.
Reported-by: Olga Kornievskaia <aglo@umich.edu>
Fixes: 2e72448b07dc3 ("NFS: Add COPY nfs operation")
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Cc: stable@vger.kernel.org # v4.7+
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
-rw-r--r-- | fs/nfs/nfs42proc.c | 63 |
1 files changed, 37 insertions, 26 deletions
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c index 98cf58341066..1e486c73ec94 100644 --- a/fs/nfs/nfs42proc.c +++ b/fs/nfs/nfs42proc.c | |||
@@ -129,30 +129,26 @@ out_unlock: | |||
129 | return err; | 129 | return err; |
130 | } | 130 | } |
131 | 131 | ||
132 | static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src, | 132 | static ssize_t _nfs42_proc_copy(struct file *src, |
133 | struct nfs_lock_context *src_lock, | 133 | struct nfs_lock_context *src_lock, |
134 | struct file *dst, loff_t pos_dst, | 134 | struct file *dst, |
135 | struct nfs_lock_context *dst_lock, | 135 | struct nfs_lock_context *dst_lock, |
136 | size_t count) | 136 | struct nfs42_copy_args *args, |
137 | struct nfs42_copy_res *res) | ||
137 | { | 138 | { |
138 | struct nfs42_copy_args args = { | ||
139 | .src_fh = NFS_FH(file_inode(src)), | ||
140 | .src_pos = pos_src, | ||
141 | .dst_fh = NFS_FH(file_inode(dst)), | ||
142 | .dst_pos = pos_dst, | ||
143 | .count = count, | ||
144 | }; | ||
145 | struct nfs42_copy_res res; | ||
146 | struct rpc_message msg = { | 139 | struct rpc_message msg = { |
147 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY], | 140 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY], |
148 | .rpc_argp = &args, | 141 | .rpc_argp = args, |
149 | .rpc_resp = &res, | 142 | .rpc_resp = res, |
150 | }; | 143 | }; |
151 | struct inode *dst_inode = file_inode(dst); | 144 | struct inode *dst_inode = file_inode(dst); |
152 | struct nfs_server *server = NFS_SERVER(dst_inode); | 145 | struct nfs_server *server = NFS_SERVER(dst_inode); |
146 | loff_t pos_src = args->src_pos; | ||
147 | loff_t pos_dst = args->dst_pos; | ||
148 | size_t count = args->count; | ||
153 | int status; | 149 | int status; |
154 | 150 | ||
155 | status = nfs4_set_rw_stateid(&args.src_stateid, src_lock->open_context, | 151 | status = nfs4_set_rw_stateid(&args->src_stateid, src_lock->open_context, |
156 | src_lock, FMODE_READ); | 152 | src_lock, FMODE_READ); |
157 | if (status) | 153 | if (status) |
158 | return status; | 154 | return status; |
@@ -162,7 +158,7 @@ static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src, | |||
162 | if (status) | 158 | if (status) |
163 | return status; | 159 | return status; |
164 | 160 | ||
165 | status = nfs4_set_rw_stateid(&args.dst_stateid, dst_lock->open_context, | 161 | status = nfs4_set_rw_stateid(&args->dst_stateid, dst_lock->open_context, |
166 | dst_lock, FMODE_WRITE); | 162 | dst_lock, FMODE_WRITE); |
167 | if (status) | 163 | if (status) |
168 | return status; | 164 | return status; |
@@ -172,22 +168,22 @@ static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src, | |||
172 | return status; | 168 | return status; |
173 | 169 | ||
174 | status = nfs4_call_sync(server->client, server, &msg, | 170 | status = nfs4_call_sync(server->client, server, &msg, |
175 | &args.seq_args, &res.seq_res, 0); | 171 | &args->seq_args, &res->seq_res, 0); |
176 | if (status == -ENOTSUPP) | 172 | if (status == -ENOTSUPP) |
177 | server->caps &= ~NFS_CAP_COPY; | 173 | server->caps &= ~NFS_CAP_COPY; |
178 | if (status) | 174 | if (status) |
179 | return status; | 175 | return status; |
180 | 176 | ||
181 | if (res.write_res.verifier.committed != NFS_FILE_SYNC) { | 177 | if (res->write_res.verifier.committed != NFS_FILE_SYNC) { |
182 | status = nfs_commit_file(dst, &res.write_res.verifier.verifier); | 178 | status = nfs_commit_file(dst, &res->write_res.verifier.verifier); |
183 | if (status) | 179 | if (status) |
184 | return status; | 180 | return status; |
185 | } | 181 | } |
186 | 182 | ||
187 | truncate_pagecache_range(dst_inode, pos_dst, | 183 | truncate_pagecache_range(dst_inode, pos_dst, |
188 | pos_dst + res.write_res.count); | 184 | pos_dst + res->write_res.count); |
189 | 185 | ||
190 | return res.write_res.count; | 186 | return res->write_res.count; |
191 | } | 187 | } |
192 | 188 | ||
193 | ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src, | 189 | ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src, |
@@ -197,8 +193,22 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src, | |||
197 | struct nfs_server *server = NFS_SERVER(file_inode(dst)); | 193 | struct nfs_server *server = NFS_SERVER(file_inode(dst)); |
198 | struct nfs_lock_context *src_lock; | 194 | struct nfs_lock_context *src_lock; |
199 | struct nfs_lock_context *dst_lock; | 195 | struct nfs_lock_context *dst_lock; |
200 | struct nfs4_exception src_exception = { }; | 196 | struct nfs42_copy_args args = { |
201 | struct nfs4_exception dst_exception = { }; | 197 | .src_fh = NFS_FH(file_inode(src)), |
198 | .src_pos = pos_src, | ||
199 | .dst_fh = NFS_FH(file_inode(dst)), | ||
200 | .dst_pos = pos_dst, | ||
201 | .count = count, | ||
202 | }; | ||
203 | struct nfs42_copy_res res; | ||
204 | struct nfs4_exception src_exception = { | ||
205 | .inode = file_inode(src), | ||
206 | .stateid = &args.src_stateid, | ||
207 | }; | ||
208 | struct nfs4_exception dst_exception = { | ||
209 | .inode = file_inode(dst), | ||
210 | .stateid = &args.dst_stateid, | ||
211 | }; | ||
202 | ssize_t err, err2; | 212 | ssize_t err, err2; |
203 | 213 | ||
204 | if (!nfs_server_capable(file_inode(dst), NFS_CAP_COPY)) | 214 | if (!nfs_server_capable(file_inode(dst), NFS_CAP_COPY)) |
@@ -208,7 +218,6 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src, | |||
208 | if (IS_ERR(src_lock)) | 218 | if (IS_ERR(src_lock)) |
209 | return PTR_ERR(src_lock); | 219 | return PTR_ERR(src_lock); |
210 | 220 | ||
211 | src_exception.inode = file_inode(src); | ||
212 | src_exception.state = src_lock->open_context->state; | 221 | src_exception.state = src_lock->open_context->state; |
213 | 222 | ||
214 | dst_lock = nfs_get_lock_context(nfs_file_open_context(dst)); | 223 | dst_lock = nfs_get_lock_context(nfs_file_open_context(dst)); |
@@ -217,15 +226,17 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src, | |||
217 | goto out_put_src_lock; | 226 | goto out_put_src_lock; |
218 | } | 227 | } |
219 | 228 | ||
220 | dst_exception.inode = file_inode(dst); | ||
221 | dst_exception.state = dst_lock->open_context->state; | 229 | dst_exception.state = dst_lock->open_context->state; |
222 | 230 | ||
223 | do { | 231 | do { |
224 | inode_lock(file_inode(dst)); | 232 | inode_lock(file_inode(dst)); |
225 | err = _nfs42_proc_copy(src, pos_src, src_lock, | 233 | err = _nfs42_proc_copy(src, src_lock, |
226 | dst, pos_dst, dst_lock, count); | 234 | dst, dst_lock, |
235 | &args, &res); | ||
227 | inode_unlock(file_inode(dst)); | 236 | inode_unlock(file_inode(dst)); |
228 | 237 | ||
238 | if (err >= 0) | ||
239 | break; | ||
229 | if (err == -ENOTSUPP) { | 240 | if (err == -ENOTSUPP) { |
230 | err = -EOPNOTSUPP; | 241 | err = -EOPNOTSUPP; |
231 | break; | 242 | break; |