37
37
#include <linux/falloc.h>
38
38
#include <linux/slab.h>
39
39
#include <linux/kthread.h>
40
+ #include <linux/namei.h>
41
+
40
42
#include <linux/sunrpc/addr.h>
41
43
#include <linux/nfs_ssc.h>
42
44
@@ -235,6 +237,154 @@ static void nfsd4_set_open_owner_reply_cache(struct nfsd4_compound_state *cstate
235
237
& resfh -> fh_handle );
236
238
}
237
239
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
+
238
388
static __be32
239
389
do_open_lookup (struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate , struct nfsd4_open * open , struct svc_fh * * resfh )
240
390
{
@@ -264,16 +414,8 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru
264
414
* yes | yes | GUARDED4 | GUARDED4
265
415
*/
266
416
267
- /*
268
- * Note: create modes (UNCHECKED,GUARDED...) are the same
269
- * in NFSv4 as in v3 except EXCLUSIVE4_1.
270
- */
271
417
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 );
277
419
current -> fs -> umask = 0 ;
278
420
279
421
if (!status && open -> op_label .len )
@@ -284,7 +426,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru
284
426
* use the returned bitmask to indicate which attributes
285
427
* we used to store the verifier:
286
428
*/
287
- if (nfsd_create_is_exclusive (open -> op_createmode ) && status == 0 )
429
+ if (nfsd4_create_is_exclusive (open -> op_createmode ) && status == 0 )
288
430
open -> op_bmval [1 ] |= (FATTR4_WORD1_TIME_ACCESS |
289
431
FATTR4_WORD1_TIME_MODIFY );
290
432
} else
0 commit comments