Skip to content

Commit df9606a

Browse files
committed
NFSD: Refactor NFSv3 CREATE
The NFSv3 CREATE and NFSv4 OPEN(CREATE) use cases are about to diverge such that it makes sense to split do_nfsd_create() into one version for NFSv3 and one for NFSv4. As a first step, copy do_nfsd_create() to nfs3proc.c and remove NFSv4-specific logic. One immediate legibility benefit is that the logic for handling NFSv3 createhow is now quite straightforward. NFSv4 createhow has some subtleties that IMO do not belong in generic code. Signed-off-by: Chuck Lever <[email protected]>
1 parent 5f46e95 commit df9606a

File tree

1 file changed

+121
-6
lines changed

1 file changed

+121
-6
lines changed

fs/nfsd/nfs3proc.c

Lines changed: 121 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <linux/fs.h>
99
#include <linux/ext2_fs.h>
1010
#include <linux/magic.h>
11+
#include <linux/namei.h>
1112

1213
#include "cache.h"
1314
#include "xdr3.h"
@@ -220,10 +221,126 @@ nfsd3_proc_write(struct svc_rqst *rqstp)
220221
}
221222

222223
/*
223-
* With NFSv3, CREATE processing is a lot easier than with NFSv2.
224-
* At least in theory; we'll see how it fares in practice when the
225-
* first reports about SunOS compatibility problems start to pour in...
224+
* Implement NFSv3's unchecked, guarded, and exclusive CREATE
225+
* semantics for regular files. Except for the created file,
226+
* this operation is stateless on the server.
227+
*
228+
* Upon return, caller must release @fhp and @resfhp.
226229
*/
230+
static __be32
231+
nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
232+
struct svc_fh *resfhp, struct nfsd3_createargs *argp)
233+
{
234+
struct iattr *iap = &argp->attrs;
235+
struct dentry *parent, *child;
236+
__u32 v_mtime, v_atime;
237+
struct inode *inode;
238+
__be32 status;
239+
int host_err;
240+
241+
if (isdotent(argp->name, argp->len))
242+
return nfserr_exist;
243+
if (!(iap->ia_valid & ATTR_MODE))
244+
iap->ia_mode = 0;
245+
246+
status = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
247+
if (status != nfs_ok)
248+
return status;
249+
250+
parent = fhp->fh_dentry;
251+
inode = d_inode(parent);
252+
253+
host_err = fh_want_write(fhp);
254+
if (host_err)
255+
return nfserrno(host_err);
256+
257+
fh_lock_nested(fhp, I_MUTEX_PARENT);
258+
259+
child = lookup_one_len(argp->name, parent, argp->len);
260+
if (IS_ERR(child)) {
261+
status = nfserrno(PTR_ERR(child));
262+
goto out;
263+
}
264+
265+
if (d_really_is_negative(child)) {
266+
status = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
267+
if (status != nfs_ok)
268+
goto out;
269+
}
270+
271+
status = fh_compose(resfhp, fhp->fh_export, child, fhp);
272+
if (status != nfs_ok)
273+
goto out;
274+
275+
v_mtime = 0;
276+
v_atime = 0;
277+
if (argp->createmode == NFS3_CREATE_EXCLUSIVE) {
278+
u32 *verifier = (u32 *)argp->verf;
279+
280+
/*
281+
* Solaris 7 gets confused (bugid 4218508) if these have
282+
* the high bit set, as do xfs filesystems without the
283+
* "bigtime" feature. So just clear the high bits.
284+
*/
285+
v_mtime = verifier[0] & 0x7fffffff;
286+
v_atime = verifier[1] & 0x7fffffff;
287+
}
288+
289+
if (d_really_is_positive(child)) {
290+
status = nfs_ok;
291+
292+
switch (argp->createmode) {
293+
case NFS3_CREATE_UNCHECKED:
294+
if (!d_is_reg(child))
295+
break;
296+
iap->ia_valid &= ATTR_SIZE;
297+
goto set_attr;
298+
case NFS3_CREATE_GUARDED:
299+
status = nfserr_exist;
300+
break;
301+
case NFS3_CREATE_EXCLUSIVE:
302+
if (d_inode(child)->i_mtime.tv_sec == v_mtime &&
303+
d_inode(child)->i_atime.tv_sec == v_atime &&
304+
d_inode(child)->i_size == 0) {
305+
break;
306+
}
307+
status = nfserr_exist;
308+
}
309+
goto out;
310+
}
311+
312+
if (!IS_POSIXACL(inode))
313+
iap->ia_mode &= ~current_umask();
314+
315+
host_err = vfs_create(&init_user_ns, inode, child, iap->ia_mode, true);
316+
if (host_err < 0) {
317+
status = nfserrno(host_err);
318+
goto out;
319+
}
320+
321+
/* A newly created file already has a file size of zero. */
322+
if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0))
323+
iap->ia_valid &= ~ATTR_SIZE;
324+
if (argp->createmode == NFS3_CREATE_EXCLUSIVE) {
325+
iap->ia_valid = ATTR_MTIME | ATTR_ATIME |
326+
ATTR_MTIME_SET | ATTR_ATIME_SET;
327+
iap->ia_mtime.tv_sec = v_mtime;
328+
iap->ia_atime.tv_sec = v_atime;
329+
iap->ia_mtime.tv_nsec = 0;
330+
iap->ia_atime.tv_nsec = 0;
331+
}
332+
333+
set_attr:
334+
status = nfsd_create_setattr(rqstp, fhp, resfhp, iap);
335+
336+
out:
337+
fh_unlock(fhp);
338+
if (child && !IS_ERR(child))
339+
dput(child);
340+
fh_drop_write(fhp);
341+
return status;
342+
}
343+
227344
static __be32
228345
nfsd3_proc_create(struct svc_rqst *rqstp)
229346
{
@@ -239,9 +356,7 @@ nfsd3_proc_create(struct svc_rqst *rqstp)
239356
dirfhp = fh_copy(&resp->dirfh, &argp->fh);
240357
newfhp = fh_init(&resp->fh, NFS3_FHSIZE);
241358

242-
resp->status = do_nfsd_create(rqstp, dirfhp, argp->name, argp->len,
243-
&argp->attrs, newfhp, argp->createmode,
244-
(u32 *)argp->verf, NULL, NULL);
359+
resp->status = nfsd3_create_file(rqstp, dirfhp, newfhp, argp);
245360
return rpc_success;
246361
}
247362

0 commit comments

Comments
 (0)