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+
227344static __be32
228345nfsd3_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