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+
238388static __be32
239389do_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