@ -298,41 +298,12 @@ commit_metadata(struct svc_fh *fhp)
}
/*
* Set various file attributes .
* N . B . After this call fhp needs an fh_put
* Go over the attributes and take care of the small differences between
* NFS semantics and what Linux expects .
*/
__be32
nfsd_setattr ( struct svc_rqst * rqstp , struct svc_fh * fhp , struct iattr * iap ,
int check_guard , time_t guardtime )
static void
nfsd_sanitize_attrs ( struct inode * inode , struct iattr * iap )
{
struct dentry * dentry ;
struct inode * inode ;
int accmode = NFSD_MAY_SATTR ;
umode_t ftype = 0 ;
__be32 err ;
int host_err ;
int size_change = 0 ;
if ( iap - > ia_valid & ( ATTR_ATIME | ATTR_MTIME | ATTR_SIZE ) )
accmode | = NFSD_MAY_WRITE | NFSD_MAY_OWNER_OVERRIDE ;
if ( iap - > ia_valid & ATTR_SIZE )
ftype = S_IFREG ;
/* Get inode */
err = fh_verify ( rqstp , fhp , ftype , accmode ) ;
if ( err )
goto out ;
dentry = fhp - > fh_dentry ;
inode = dentry - > d_inode ;
/* Ignore any mode updates on symlinks */
if ( S_ISLNK ( inode - > i_mode ) )
iap - > ia_valid & = ~ ATTR_MODE ;
if ( ! iap - > ia_valid )
goto out ;
/*
* NFSv2 does not differentiate between " set-[ac]time-to-now "
* which only requires access , and " set-[ac]time-to-X " which
@ -342,8 +313,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
* convert to " set to now " instead of " set to explicit time "
*
* We only call inode_change_ok as the last test as technically
* it is not an interface that we should be using . It is only
* valid if the filesystem does not define it ' s own i_op - > setattr .
* it is not an interface that we should be using .
*/
# define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
# define MAX_TOUCH_TIME_ERROR (30*60)
@ -369,30 +339,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
iap - > ia_valid & = ~ BOTH_TIME_SET ;
}
}
/*
* The size case is special .
* It changes the file as well as the attributes .
*/
if ( iap - > ia_valid & ATTR_SIZE ) {
if ( iap - > ia_size < inode - > i_size ) {
err = nfsd_permission ( rqstp , fhp - > fh_export , dentry ,
NFSD_MAY_TRUNC | NFSD_MAY_OWNER_OVERRIDE ) ;
if ( err )
goto out ;
}
host_err = get_write_access ( inode ) ;
if ( host_err )
goto out_nfserr ;
size_change = 1 ;
host_err = locks_verify_truncate ( inode , NULL , iap - > ia_size ) ;
if ( host_err ) {
put_write_access ( inode ) ;
goto out_nfserr ;
}
}
/* sanitize the mode change */
if ( iap - > ia_valid & ATTR_MODE ) {
@ -415,32 +361,111 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
iap - > ia_valid | = ( ATTR_KILL_SUID | ATTR_KILL_SGID ) ;
}
}
}
/* Change the attributes. */
static __be32
nfsd_get_write_access ( struct svc_rqst * rqstp , struct svc_fh * fhp ,
struct iattr * iap )
{
struct inode * inode = fhp - > fh_dentry - > d_inode ;
int host_err ;
iap - > ia_valid | = ATTR_CTIME ;
if ( iap - > ia_size < inode - > i_size ) {
__be32 err ;
err = nfserr_notsync ;
if ( ! check_guard | | guardtime = = inode - > i_ctime . tv_sec ) {
host_err = nfsd_break_lease ( inode ) ;
if ( host_err )
goto out_nfserr ;
fh_lock ( fhp ) ;
err = nfsd_permission ( rqstp , fhp - > fh_export , fhp - > fh_dentry ,
NFSD_MAY_TRUNC | NFSD_MAY_OWNER_OVERRIDE ) ;
if ( err )
return err ;
}
host_err = notify_change ( dentry , iap , NULL ) ;
err = nfserrno ( host_err ) ;
fh_unlock ( fhp ) ;
host_err = get_write_access ( inode ) ;
if ( host_err )
goto out_nfserrno ;
host_err = locks_verify_truncate ( inode , NULL , iap - > ia_size ) ;
if ( host_err )
goto out_put_write_access ;
return 0 ;
out_put_write_access :
put_write_access ( inode ) ;
out_nfserrno :
return nfserrno ( host_err ) ;
}
/*
* Set various file attributes . After this call fhp needs an fh_put .
*/
__be32
nfsd_setattr ( struct svc_rqst * rqstp , struct svc_fh * fhp , struct iattr * iap ,
int check_guard , time_t guardtime )
{
struct dentry * dentry ;
struct inode * inode ;
int accmode = NFSD_MAY_SATTR ;
umode_t ftype = 0 ;
__be32 err ;
int host_err ;
int size_change = 0 ;
if ( iap - > ia_valid & ( ATTR_ATIME | ATTR_MTIME | ATTR_SIZE ) )
accmode | = NFSD_MAY_WRITE | NFSD_MAY_OWNER_OVERRIDE ;
if ( iap - > ia_valid & ATTR_SIZE )
ftype = S_IFREG ;
/* Get inode */
err = fh_verify ( rqstp , fhp , ftype , accmode ) ;
if ( err )
goto out ;
dentry = fhp - > fh_dentry ;
inode = dentry - > d_inode ;
/* Ignore any mode updates on symlinks */
if ( S_ISLNK ( inode - > i_mode ) )
iap - > ia_valid & = ~ ATTR_MODE ;
if ( ! iap - > ia_valid )
goto out ;
nfsd_sanitize_attrs ( inode , iap ) ;
/*
* The size case is special , it changes the file in addition to the
* attributes .
*/
if ( iap - > ia_valid & ATTR_SIZE ) {
err = nfsd_get_write_access ( rqstp , fhp , iap ) ;
if ( err )
goto out ;
size_change = 1 ;
}
iap - > ia_valid | = ATTR_CTIME ;
if ( check_guard & & guardtime ! = inode - > i_ctime . tv_sec ) {
err = nfserr_notsync ;
goto out_put_write_access ;
}
host_err = nfsd_break_lease ( inode ) ;
if ( host_err )
goto out_put_write_access_nfserror ;
fh_lock ( fhp ) ;
host_err = notify_change ( dentry , iap , NULL ) ;
fh_unlock ( fhp ) ;
out_put_write_access_nfserror :
err = nfserrno ( host_err ) ;
out_put_write_access :
if ( size_change )
put_write_access ( inode ) ;
if ( ! err )
commit_metadata ( fhp ) ;
out :
return err ;
out_nfserr :
err = nfserrno ( host_err ) ;
goto out ;
}
# if defined(CONFIG_NFSD_V2_ACL) || \