Skip to content

Commit 254454a

Browse files
committed
NFSD: Refactor NFSv4 OPEN(CREATE)
Copy do_nfsd_create() to nfs4proc.c and remove NFSv3-specific logic. Signed-off-by: Chuck Lever <[email protected]>
1 parent df9606a commit 254454a

File tree

1 file changed

+152
-10
lines changed

1 file changed

+152
-10
lines changed

fs/nfsd/nfs4proc.c

Lines changed: 152 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
#include <linux/falloc.h>
3838
#include <linux/slab.h>
3939
#include <linux/kthread.h>
40+
#include <linux/namei.h>
41+
4042
#include <linux/sunrpc/addr.h>
4143
#include <linux/nfs_ssc.h>
4244

@@ -235,6 +237,154 @@ static void nfsd4_set_open_owner_reply_cache(struct nfsd4_compound_state *cstate
235237
&resfh->fh_handle);
236238
}
237239

240+
static inline bool nfsd4_create_is_exclusive(int createmode)
241+
{
242+
return createmode == NFS4_CREATE_EXCLUSIVE ||
243+
createmode == NFS4_CREATE_EXCLUSIVE4_1;
244+
}
245+
246+
/*
247+
* Implement NFSv4's unchecked, guarded, and exclusive create
248+
* semantics for regular files. Open state for this new file is
249+
* subsequently fabricated in nfsd4_process_open2().
250+
*
251+
* Upon return, caller must release @fhp and @resfhp.
252+
*/
253+
static __be32
254+
nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
255+
struct svc_fh *resfhp, struct nfsd4_open *open)
256+
{
257+
struct iattr *iap = &open->op_iattr;
258+
struct dentry *parent, *child;
259+
__u32 v_mtime, v_atime;
260+
struct inode *inode;
261+
__be32 status;
262+
int host_err;
263+
264+
if (isdotent(open->op_fname, open->op_fnamelen))
265+
return nfserr_exist;
266+
if (!(iap->ia_valid & ATTR_MODE))
267+
iap->ia_mode = 0;
268+
269+
status = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
270+
if (status != nfs_ok)
271+
return status;
272+
parent = fhp->fh_dentry;
273+
inode = d_inode(parent);
274+
275+
host_err = fh_want_write(fhp);
276+
if (host_err)
277+
return nfserrno(host_err);
278+
279+
fh_lock_nested(fhp, I_MUTEX_PARENT);
280+
281+
child = lookup_one_len(open->op_fname, parent, open->op_fnamelen);
282+
if (IS_ERR(child)) {
283+
status = nfserrno(PTR_ERR(child));
284+
goto out;
285+
}
286+
287+
if (d_really_is_negative(child)) {
288+
status = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
289+
if (status != nfs_ok)
290+
goto out;
291+
}
292+
293+
status = fh_compose(resfhp, fhp->fh_export, child, fhp);
294+
if (status != nfs_ok)
295+
goto out;
296+
297+
v_mtime = 0;
298+
v_atime = 0;
299+
if (nfsd4_create_is_exclusive(open->op_createmode)) {
300+
u32 *verifier = (u32 *)open->op_verf.data;
301+
302+
/*
303+
* Solaris 7 gets confused (bugid 4218508) if these have
304+
* the high bit set, as do xfs filesystems without the
305+
* "bigtime" feature. So just clear the high bits. If this
306+
* is ever changed to use different attrs for storing the
307+
* verifier, then do_open_lookup() will also need to be
308+
* fixed accordingly.
309+
*/
310+
v_mtime = verifier[0] & 0x7fffffff;
311+
v_atime = verifier[1] & 0x7fffffff;
312+
}
313+
314+
if (d_really_is_positive(child)) {
315+
status = nfs_ok;
316+
317+
switch (open->op_createmode) {
318+
case NFS4_CREATE_UNCHECKED:
319+
if (!d_is_reg(child))
320+
break;
321+
322+
/*
323+
* In NFSv4, we don't want to truncate the file
324+
* now. This would be wrong if the OPEN fails for
325+
* some other reason. Furthermore, if the size is
326+
* nonzero, we should ignore it according to spec!
327+
*/
328+
open->op_truncate = (iap->ia_valid & ATTR_SIZE) &&
329+
!iap->ia_size;
330+
break;
331+
case NFS4_CREATE_GUARDED:
332+
status = nfserr_exist;
333+
break;
334+
case NFS4_CREATE_EXCLUSIVE:
335+
if (d_inode(child)->i_mtime.tv_sec == v_mtime &&
336+
d_inode(child)->i_atime.tv_sec == v_atime &&
337+
d_inode(child)->i_size == 0) {
338+
open->op_created = true;
339+
break; /* subtle */
340+
}
341+
status = nfserr_exist;
342+
break;
343+
case NFS4_CREATE_EXCLUSIVE4_1:
344+
if (d_inode(child)->i_mtime.tv_sec == v_mtime &&
345+
d_inode(child)->i_atime.tv_sec == v_atime &&
346+
d_inode(child)->i_size == 0) {
347+
open->op_created = true;
348+
goto set_attr; /* subtle */
349+
}
350+
status = nfserr_exist;
351+
}
352+
goto out;
353+
}
354+
355+
if (!IS_POSIXACL(inode))
356+
iap->ia_mode &= ~current_umask();
357+
358+
host_err = vfs_create(&init_user_ns, inode, child, iap->ia_mode, true);
359+
if (host_err < 0) {
360+
status = nfserrno(host_err);
361+
goto out;
362+
}
363+
open->op_created = true;
364+
365+
/* A newly created file already has a file size of zero. */
366+
if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0))
367+
iap->ia_valid &= ~ATTR_SIZE;
368+
if (nfsd4_create_is_exclusive(open->op_createmode)) {
369+
iap->ia_valid = ATTR_MTIME | ATTR_ATIME |
370+
ATTR_MTIME_SET|ATTR_ATIME_SET;
371+
iap->ia_mtime.tv_sec = v_mtime;
372+
iap->ia_atime.tv_sec = v_atime;
373+
iap->ia_mtime.tv_nsec = 0;
374+
iap->ia_atime.tv_nsec = 0;
375+
}
376+
377+
set_attr:
378+
status = nfsd_create_setattr(rqstp, fhp, resfhp, iap);
379+
380+
out:
381+
fh_unlock(fhp);
382+
if (child && !IS_ERR(child))
383+
dput(child);
384+
fh_drop_write(fhp);
385+
return status;
386+
}
387+
238388
static __be32
239389
do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_open *open, struct svc_fh **resfh)
240390
{
@@ -264,16 +414,8 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru
264414
* yes | yes | GUARDED4 | GUARDED4
265415
*/
266416

267-
/*
268-
* Note: create modes (UNCHECKED,GUARDED...) are the same
269-
* in NFSv4 as in v3 except EXCLUSIVE4_1.
270-
*/
271417
current->fs->umask = open->op_umask;
272-
status = do_nfsd_create(rqstp, current_fh, open->op_fname,
273-
open->op_fnamelen, &open->op_iattr,
274-
*resfh, open->op_createmode,
275-
(u32 *)open->op_verf.data,
276-
&open->op_truncate, &open->op_created);
418+
status = nfsd4_create_file(rqstp, current_fh, *resfh, open);
277419
current->fs->umask = 0;
278420

279421
if (!status && open->op_label.len)
@@ -284,7 +426,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru
284426
* use the returned bitmask to indicate which attributes
285427
* we used to store the verifier:
286428
*/
287-
if (nfsd_create_is_exclusive(open->op_createmode) && status == 0)
429+
if (nfsd4_create_is_exclusive(open->op_createmode) && status == 0)
288430
open->op_bmval[1] |= (FATTR4_WORD1_TIME_ACCESS |
289431
FATTR4_WORD1_TIME_MODIFY);
290432
} else

0 commit comments

Comments
 (0)