@ -3353,13 +3353,50 @@ out:
return error ;
}
struct dentry * vfs_tmpfile ( struct dentry * dentry , umode_t mode , int open_flag )
{
static const struct qstr name = QSTR_INIT ( " / " , 1 ) ;
struct dentry * child = NULL ;
struct inode * dir = dentry - > d_inode ;
struct inode * inode ;
int error ;
/* we want directory to be writable */
error = inode_permission ( dir , MAY_WRITE | MAY_EXEC ) ;
if ( error )
goto out_err ;
error = - EOPNOTSUPP ;
if ( ! dir - > i_op - > tmpfile )
goto out_err ;
error = - ENOMEM ;
child = d_alloc ( dentry , & name ) ;
if ( unlikely ( ! child ) )
goto out_err ;
error = dir - > i_op - > tmpfile ( dir , child , mode ) ;
if ( error )
goto out_err ;
error = - ENOENT ;
inode = child - > d_inode ;
if ( unlikely ( ! inode ) )
goto out_err ;
if ( ! ( open_flag & O_EXCL ) ) {
spin_lock ( & inode - > i_lock ) ;
inode - > i_state | = I_LINKABLE ;
spin_unlock ( & inode - > i_lock ) ;
}
return child ;
out_err :
dput ( child ) ;
return ERR_PTR ( error ) ;
}
EXPORT_SYMBOL ( vfs_tmpfile ) ;
static int do_tmpfile ( struct nameidata * nd , unsigned flags ,
const struct open_flags * op ,
struct file * file , int * opened )
{
static const struct qstr name = QSTR_INIT ( " / " , 1 ) ;
struct dentry * child ;
struct inode * dir ;
struct path path ;
int error = path_lookupat ( nd , flags | LOOKUP_DIRECTORY , & path ) ;
if ( unlikely ( error ) )
@ -3367,25 +3404,12 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags,
error = mnt_want_write ( path . mnt ) ;
if ( unlikely ( error ) )
goto out ;
dir = path . dentry - > d_inode ;
/* we want directory to be writable */
error = inode_permission ( dir , MAY_WRITE | MAY_EXEC ) ;
if ( error )
goto out2 ;
if ( ! dir - > i_op - > tmpfile ) {
error = - EOPNOTSUPP ;
goto out2 ;
}
child = d_alloc ( path . dentry , & name ) ;
if ( unlikely ( ! child ) ) {
error = - ENOMEM ;
child = vfs_tmpfile ( path . dentry , op - > mode , op - > open_flag ) ;
error = PTR_ERR ( child ) ;
if ( unlikely ( IS_ERR ( child ) ) )
goto out2 ;
}
dput ( path . dentry ) ;
path . dentry = child ;
error = dir - > i_op - > tmpfile ( dir , child , op - > mode ) ;
if ( error )
goto out2 ;
audit_inode ( nd - > name , child , 0 ) ;
/* Don't check for other permissions, the inode was just created */
error = may_open ( & path , 0 , op - > open_flag ) ;
@ -3396,14 +3420,8 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags,
if ( error )
goto out2 ;
error = open_check_o_direct ( file ) ;
if ( error ) {
if ( error )
fput ( file ) ;
} else if ( ! ( op - > open_flag & O_EXCL ) ) {
struct inode * inode = file_inode ( file ) ;
spin_lock ( & inode - > i_lock ) ;
inode - > i_state | = I_LINKABLE ;
spin_unlock ( & inode - > i_lock ) ;
}
out2 :
mnt_drop_write ( path . mnt ) ;
out :