2005-09-10 00:04:19 +04:00
/*
* linux / fs / 9 p / vfs_inode . c
*
2005-09-10 00:04:26 +04:00
* This file contains vfs inode ops for the 9 P2000 protocol .
2005-09-10 00:04:19 +04:00
*
* Copyright ( C ) 2004 by Eric Van Hensbergen < ericvh @ gmail . com >
* Copyright ( C ) 2002 by Ron Minnich < rminnich @ lanl . gov >
*
* This program is free software ; you can redistribute it and / or modify
2006-03-25 14:07:28 +03:00
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation .
2005-09-10 00:04:19 +04:00
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to :
* Free Software Foundation
* 51 Franklin Street , Fifth Floor
* Boston , MA 02111 - 1301 USA
*
*/
# include <linux/module.h>
# include <linux/errno.h>
# include <linux/fs.h>
# include <linux/file.h>
# include <linux/pagemap.h>
# include <linux/stat.h>
# include <linux/string.h>
# include <linux/inet.h>
# include <linux/namei.h>
# include <linux/idr.h>
Detach sched.h from mm.h
First thing mm.h does is including sched.h solely for can_do_mlock() inline
function which has "current" dereference inside. By dealing with can_do_mlock()
mm.h can be detached from sched.h which is good. See below, why.
This patch
a) removes unconditional inclusion of sched.h from mm.h
b) makes can_do_mlock() normal function in mm/mlock.c
c) exports can_do_mlock() to not break compilation
d) adds sched.h inclusions back to files that were getting it indirectly.
e) adds less bloated headers to some files (asm/signal.h, jiffies.h) that were
getting them indirectly
Net result is:
a) mm.h users would get less code to open, read, preprocess, parse, ... if
they don't need sched.h
b) sched.h stops being dependency for significant number of files:
on x86_64 allmodconfig touching sched.h results in recompile of 4083 files,
after patch it's only 3744 (-8.3%).
Cross-compile tested on
all arm defconfigs, all mips defconfigs, all powerpc defconfigs,
alpha alpha-up
arm
i386 i386-up i386-defconfig i386-allnoconfig
ia64 ia64-up
m68k
mips
parisc parisc-up
powerpc powerpc-up
s390 s390-up
sparc sparc-up
sparc64 sparc64-up
um-x86_64
x86_64 x86_64-up x86_64-defconfig x86_64-allnoconfig
as well as my two usual configs.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-21 01:22:52 +04:00
# include <linux/sched.h>
2007-07-11 02:57:28 +04:00
# include <net/9p/9p.h>
# include <net/9p/client.h>
2005-09-10 00:04:19 +04:00
# include "v9fs.h"
# include "v9fs_vfs.h"
# include "fid.h"
2007-02-12 11:55:38 +03:00
static const struct inode_operations v9fs_dir_inode_operations ;
static const struct inode_operations v9fs_dir_inode_operations_ext ;
static const struct inode_operations v9fs_file_inode_operations ;
static const struct inode_operations v9fs_symlink_inode_operations ;
2005-09-10 00:04:19 +04:00
/**
* unixmode2p9mode - convert unix mode bits to plan 9
* @ v9ses : v9fs session information
* @ mode : mode to convert
*
*/
2005-09-10 00:04:26 +04:00
static int unixmode2p9mode ( struct v9fs_session_info * v9ses , int mode )
2005-09-10 00:04:19 +04:00
{
int res ;
res = mode & 0777 ;
if ( S_ISDIR ( mode ) )
2007-07-11 02:57:28 +04:00
res | = P9_DMDIR ;
2007-10-17 23:31:07 +04:00
if ( v9fs_extended ( v9ses ) ) {
2005-09-10 00:04:19 +04:00
if ( S_ISLNK ( mode ) )
2007-07-11 02:57:28 +04:00
res | = P9_DMSYMLINK ;
2005-09-10 00:04:19 +04:00
if ( v9ses - > nodev = = 0 ) {
if ( S_ISSOCK ( mode ) )
2007-07-11 02:57:28 +04:00
res | = P9_DMSOCKET ;
2005-09-10 00:04:19 +04:00
if ( S_ISFIFO ( mode ) )
2007-07-11 02:57:28 +04:00
res | = P9_DMNAMEDPIPE ;
2005-09-10 00:04:19 +04:00
if ( S_ISBLK ( mode ) )
2007-07-11 02:57:28 +04:00
res | = P9_DMDEVICE ;
2005-09-10 00:04:19 +04:00
if ( S_ISCHR ( mode ) )
2007-07-11 02:57:28 +04:00
res | = P9_DMDEVICE ;
2005-09-10 00:04:19 +04:00
}
if ( ( mode & S_ISUID ) = = S_ISUID )
2007-07-11 02:57:28 +04:00
res | = P9_DMSETUID ;
2005-09-10 00:04:19 +04:00
if ( ( mode & S_ISGID ) = = S_ISGID )
2007-07-11 02:57:28 +04:00
res | = P9_DMSETGID ;
2008-02-07 04:25:06 +03:00
if ( ( mode & S_ISVTX ) = = S_ISVTX )
res | = P9_DMSETVTX ;
2007-07-11 02:57:28 +04:00
if ( ( mode & P9_DMLINK ) )
res | = P9_DMLINK ;
2005-09-10 00:04:19 +04:00
}
return res ;
}
/**
* p9mode2unixmode - convert plan9 mode bits to unix mode bits
* @ v9ses : v9fs session information
* @ mode : mode to convert
*
*/
2005-09-10 00:04:26 +04:00
static int p9mode2unixmode ( struct v9fs_session_info * v9ses , int mode )
2005-09-10 00:04:19 +04:00
{
int res ;
res = mode & 0777 ;
2007-07-11 02:57:28 +04:00
if ( ( mode & P9_DMDIR ) = = P9_DMDIR )
2005-09-10 00:04:19 +04:00
res | = S_IFDIR ;
2007-10-17 23:31:07 +04:00
else if ( ( mode & P9_DMSYMLINK ) & & ( v9fs_extended ( v9ses ) ) )
2005-09-10 00:04:19 +04:00
res | = S_IFLNK ;
2007-10-17 23:31:07 +04:00
else if ( ( mode & P9_DMSOCKET ) & & ( v9fs_extended ( v9ses ) )
2005-09-10 00:04:19 +04:00
& & ( v9ses - > nodev = = 0 ) )
res | = S_IFSOCK ;
2007-10-17 23:31:07 +04:00
else if ( ( mode & P9_DMNAMEDPIPE ) & & ( v9fs_extended ( v9ses ) )
2005-09-10 00:04:19 +04:00
& & ( v9ses - > nodev = = 0 ) )
res | = S_IFIFO ;
2007-10-17 23:31:07 +04:00
else if ( ( mode & P9_DMDEVICE ) & & ( v9fs_extended ( v9ses ) )
2005-09-10 00:04:19 +04:00
& & ( v9ses - > nodev = = 0 ) )
res | = S_IFBLK ;
else
res | = S_IFREG ;
2007-10-17 23:31:07 +04:00
if ( v9fs_extended ( v9ses ) ) {
2007-07-11 02:57:28 +04:00
if ( ( mode & P9_DMSETUID ) = = P9_DMSETUID )
2005-09-10 00:04:19 +04:00
res | = S_ISUID ;
2007-07-11 02:57:28 +04:00
if ( ( mode & P9_DMSETGID ) = = P9_DMSETGID )
2005-09-10 00:04:19 +04:00
res | = S_ISGID ;
2008-02-07 04:25:06 +03:00
if ( ( mode & P9_DMSETVTX ) = = P9_DMSETVTX )
res | = S_ISVTX ;
2005-09-10 00:04:19 +04:00
}
return res ;
}
2008-03-05 16:08:09 +03:00
/**
* v9fs_uflags2omode - convert posix open flags to plan 9 mode bits
* @ uflags : flags to convert
2008-06-25 02:39:39 +04:00
* @ extended : if . u extensions are active
2008-03-05 16:08:09 +03:00
*/
2008-06-25 02:39:39 +04:00
int v9fs_uflags2omode ( int uflags , int extended )
2006-03-02 13:54:30 +03:00
{
int ret ;
ret = 0 ;
switch ( uflags & 3 ) {
default :
case O_RDONLY :
2007-07-11 02:57:28 +04:00
ret = P9_OREAD ;
2006-03-02 13:54:30 +03:00
break ;
case O_WRONLY :
2007-07-11 02:57:28 +04:00
ret = P9_OWRITE ;
2006-03-02 13:54:30 +03:00
break ;
case O_RDWR :
2007-07-11 02:57:28 +04:00
ret = P9_ORDWR ;
2006-03-02 13:54:30 +03:00
break ;
}
if ( uflags & O_TRUNC )
2007-07-11 02:57:28 +04:00
ret | = P9_OTRUNC ;
2006-03-02 13:54:30 +03:00
2008-06-25 02:39:39 +04:00
if ( extended ) {
if ( uflags & O_EXCL )
ret | = P9_OEXCL ;
if ( uflags & O_APPEND )
ret | = P9_OAPPEND ;
}
2006-03-02 13:54:30 +03:00
return ret ;
}
2005-09-10 00:04:19 +04:00
/**
2006-01-08 12:05:00 +03:00
* v9fs_blank_wstat - helper function to setup a 9 P stat structure
2005-09-10 00:04:19 +04:00
* @ v9ses : 9 P session info ( for determining extended mode )
2006-01-08 12:05:00 +03:00
* @ wstat : structure to initialize
2005-09-10 00:04:19 +04:00
*
*/
2005-09-10 00:04:26 +04:00
static void
2007-07-11 02:57:28 +04:00
v9fs_blank_wstat ( struct p9_wstat * wstat )
2005-09-10 00:04:19 +04:00
{
2006-01-08 12:05:00 +03:00
wstat - > type = ~ 0 ;
wstat - > dev = ~ 0 ;
wstat - > qid . type = ~ 0 ;
wstat - > qid . version = ~ 0 ;
* ( ( long long * ) & wstat - > qid . path ) = ~ 0 ;
wstat - > mode = ~ 0 ;
wstat - > atime = ~ 0 ;
wstat - > mtime = ~ 0 ;
wstat - > length = ~ 0 ;
wstat - > name = NULL ;
wstat - > uid = NULL ;
wstat - > gid = NULL ;
wstat - > muid = NULL ;
wstat - > n_uid = ~ 0 ;
wstat - > n_gid = ~ 0 ;
wstat - > n_muid = ~ 0 ;
wstat - > extension = NULL ;
2005-09-10 00:04:19 +04:00
}
/**
* v9fs_get_inode - helper function to setup an inode
* @ sb : superblock
* @ mode : mode to setup inode with
*
*/
struct inode * v9fs_get_inode ( struct super_block * sb , int mode )
{
2009-07-19 23:41:56 +04:00
int err ;
2006-03-02 13:54:30 +03:00
struct inode * inode ;
2005-09-10 00:04:27 +04:00
struct v9fs_session_info * v9ses = sb - > s_fs_info ;
2005-09-10 00:04:19 +04:00
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " super block: %p mode: %o \n " , sb , mode ) ;
2005-09-10 00:04:19 +04:00
inode = new_inode ( sb ) ;
2009-07-19 23:41:56 +04:00
if ( ! inode ) {
P9_EPRINTK ( KERN_WARNING , " Problem allocating inode \n " ) ;
return - ENOMEM ;
}
inode - > i_mode = mode ;
inode - > i_uid = current_fsuid ( ) ;
inode - > i_gid = current_fsgid ( ) ;
inode - > i_blocks = 0 ;
inode - > i_rdev = 0 ;
inode - > i_atime = inode - > i_mtime = inode - > i_ctime = CURRENT_TIME ;
inode - > i_mapping - > a_ops = & v9fs_addr_operations ;
switch ( mode & S_IFMT ) {
case S_IFIFO :
case S_IFBLK :
case S_IFCHR :
case S_IFSOCK :
if ( ! v9fs_extended ( v9ses ) ) {
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_ERROR ,
2009-07-19 23:41:56 +04:00
" special files without extended mode \n " ) ;
err = - EINVAL ;
goto error ;
2005-09-10 00:04:19 +04:00
}
2009-07-19 23:41:56 +04:00
init_special_inode ( inode , inode - > i_mode , inode - > i_rdev ) ;
break ;
case S_IFREG :
inode - > i_op = & v9fs_file_inode_operations ;
inode - > i_fop = & v9fs_file_operations ;
break ;
case S_IFLNK :
if ( ! v9fs_extended ( v9ses ) ) {
P9_DPRINTK ( P9_DEBUG_ERROR ,
" extended modes used w/o 9P2000.u \n " ) ;
err = - EINVAL ;
goto error ;
}
inode - > i_op = & v9fs_symlink_inode_operations ;
break ;
case S_IFDIR :
inc_nlink ( inode ) ;
if ( v9fs_extended ( v9ses ) )
inode - > i_op = & v9fs_dir_inode_operations_ext ;
else
inode - > i_op = & v9fs_dir_inode_operations ;
inode - > i_fop = & v9fs_dir_operations ;
break ;
default :
P9_DPRINTK ( P9_DEBUG_ERROR , " BAD mode 0x%x S_IFMT 0x%x \n " ,
mode , mode & S_IFMT ) ;
err = - EINVAL ;
goto error ;
2005-09-10 00:04:19 +04:00
}
2009-07-19 23:41:56 +04:00
2005-09-10 00:04:19 +04:00
return inode ;
2009-07-19 23:41:56 +04:00
error :
iput ( inode ) ;
return ERR_PTR ( err ) ;
2005-09-10 00:04:19 +04:00
}
2007-07-11 02:57:28 +04:00
/*
2006-03-02 13:54:30 +03:00
static struct v9fs_fid *
v9fs_clone_walk ( struct v9fs_session_info * v9ses , u32 fid , struct dentry * dentry )
{
int err ;
2006-12-07 07:36:29 +03:00
int nfid ;
2006-03-02 13:54:30 +03:00
struct v9fs_fid * ret ;
struct v9fs_fcall * fcall ;
nfid = v9fs_get_idpool ( & v9ses - > fidpool ) ;
if ( nfid < 0 ) {
2005-09-28 08:45:24 +04:00
eprintk ( KERN_WARNING , " no free fids available \n " ) ;
2006-03-08 08:55:42 +03:00
return ERR_PTR ( - ENOSPC ) ;
2005-09-28 08:45:24 +04:00
}
2006-03-02 13:54:30 +03:00
err = v9fs_t_walk ( v9ses , fid , nfid , ( char * ) dentry - > d_name . name ,
& fcall ) ;
if ( err < 0 ) {
2006-05-15 20:44:21 +04:00
if ( fcall & & fcall - > id = = RWALK )
goto clunk_fid ;
2006-03-02 13:54:30 +03:00
PRINT_FCALL_ERROR ( " walk error " , fcall ) ;
v9fs_put_idpool ( nfid , & v9ses - > fidpool ) ;
goto error ;
2005-09-28 08:45:24 +04:00
}
2006-03-02 13:54:30 +03:00
2006-01-08 12:04:58 +03:00
kfree ( fcall ) ;
fcall = NULL ;
2006-03-02 13:54:30 +03:00
ret = v9fs_fid_create ( v9ses , nfid ) ;
if ( ! ret ) {
err = - ENOMEM ;
goto clunk_fid ;
}
2005-09-28 08:45:24 +04:00
2006-03-02 13:54:30 +03:00
err = v9fs_fid_insert ( ret , dentry ) ;
if ( err < 0 ) {
v9fs_fid_destroy ( ret ) ;
goto clunk_fid ;
2005-09-28 08:45:24 +04:00
}
2005-09-10 00:04:19 +04:00
2006-03-02 13:54:30 +03:00
return ret ;
2005-09-10 00:04:19 +04:00
2006-03-02 13:54:30 +03:00
clunk_fid :
v9fs_t_clunk ( v9ses , nfid ) ;
2005-09-10 00:04:19 +04:00
2006-03-02 13:54:30 +03:00
error :
kfree ( fcall ) ;
return ERR_PTR ( err ) ;
}
2007-07-11 02:57:28 +04:00
*/
2005-09-10 00:04:19 +04:00
2008-03-05 16:08:09 +03:00
/**
* v9fs_inode_from_fid - populate an inode by issuing a attribute request
* @ v9ses : session information
* @ fid : fid to issue attribute request for
* @ sb : superblock on which to create inode
*
*/
2006-03-25 14:07:25 +03:00
static struct inode *
2007-07-11 02:57:28 +04:00
v9fs_inode_from_fid ( struct v9fs_session_info * v9ses , struct p9_fid * fid ,
2006-03-02 13:54:30 +03:00
struct super_block * sb )
{
int err , umode ;
struct inode * ret ;
2008-10-16 17:30:07 +04:00
struct p9_wstat * st ;
2006-01-08 12:05:00 +03:00
2006-03-02 13:54:30 +03:00
ret = NULL ;
2007-07-11 02:57:28 +04:00
st = p9_client_stat ( fid ) ;
if ( IS_ERR ( st ) ) {
err = PTR_ERR ( st ) ;
st = NULL ;
2006-03-02 13:54:30 +03:00
goto error ;
2005-09-10 00:04:19 +04:00
}
2007-07-11 02:57:28 +04:00
umode = p9mode2unixmode ( v9ses , st - > mode ) ;
2006-03-02 13:54:30 +03:00
ret = v9fs_get_inode ( sb , umode ) ;
if ( IS_ERR ( ret ) ) {
err = PTR_ERR ( ret ) ;
ret = NULL ;
goto error ;
}
2005-09-10 00:04:19 +04:00
2007-07-11 02:57:28 +04:00
v9fs_stat2inode ( st , ret , sb ) ;
ret - > i_ino = v9fs_qid2ino ( & st - > qid ) ;
kfree ( st ) ;
2006-03-02 13:54:30 +03:00
return ret ;
2005-09-10 00:04:19 +04:00
2006-03-02 13:54:30 +03:00
error :
2007-07-11 02:57:28 +04:00
kfree ( st ) ;
2006-03-02 13:54:30 +03:00
if ( ret )
iput ( ret ) ;
2005-09-10 00:04:19 +04:00
2006-03-02 13:54:30 +03:00
return ERR_PTR ( err ) ;
2005-09-10 00:04:19 +04:00
}
/**
* v9fs_remove - helper function to remove files and directories
2005-09-10 00:04:26 +04:00
* @ dir : directory inode that is being deleted
* @ file : dentry that is being deleted
* @ rmdir : removing a directory
2005-09-10 00:04:19 +04:00
*
*/
static int v9fs_remove ( struct inode * dir , struct dentry * file , int rmdir )
{
2007-07-11 02:57:28 +04:00
struct inode * file_inode ;
struct v9fs_session_info * v9ses ;
struct p9_fid * v9fid ;
2005-09-10 00:04:19 +04:00
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " inode: %p dentry: %p rmdir: %d \n " , dir , file ,
2005-09-10 00:04:19 +04:00
rmdir ) ;
file_inode = file - > d_inode ;
v9ses = v9fs_inode2v9ses ( file_inode ) ;
2007-04-24 01:41:11 +04:00
v9fid = v9fs_fid_clone ( file ) ;
2007-10-17 23:31:07 +04:00
if ( IS_ERR ( v9fid ) )
2007-01-26 11:57:06 +03:00
return PTR_ERR ( v9fid ) ;
2005-09-10 00:04:19 +04:00
2007-07-11 02:57:28 +04:00
return p9_client_remove ( v9fid ) ;
2005-09-10 00:04:19 +04:00
}
2006-03-02 13:54:30 +03:00
static int
v9fs_open_created ( struct inode * inode , struct file * file )
{
return 0 ;
}
2007-07-11 02:57:28 +04:00
2005-09-10 00:04:19 +04:00
/**
2007-07-11 02:57:28 +04:00
* v9fs_create - Create a file
2008-03-05 16:08:09 +03:00
* @ v9ses : session information
* @ dir : directory that dentry is being created in
2007-07-11 02:57:28 +04:00
* @ dentry : dentry that is being created
* @ perm : create permissions
* @ mode : open mode
2008-03-05 16:08:09 +03:00
* @ extension : 9 p2000 . u extension string to support devices , etc .
2005-09-10 00:04:19 +04:00
*
*/
2007-07-11 02:57:28 +04:00
static struct p9_fid *
v9fs_create ( struct v9fs_session_info * v9ses , struct inode * dir ,
struct dentry * dentry , char * extension , u32 perm , u8 mode )
2005-09-10 00:04:19 +04:00
{
2006-03-02 13:54:30 +03:00
int err ;
2007-07-11 02:57:28 +04:00
char * name ;
struct p9_fid * dfid , * ofid , * fid ;
2006-03-02 13:54:30 +03:00
struct inode * inode ;
2008-10-16 17:30:07 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " name %s \n " , dentry - > d_name . name ) ;
2007-07-11 02:57:28 +04:00
err = 0 ;
ofid = NULL ;
fid = NULL ;
name = ( char * ) dentry - > d_name . name ;
2007-01-26 11:57:06 +03:00
dfid = v9fs_fid_clone ( dentry - > d_parent ) ;
2007-10-17 23:31:07 +04:00
if ( IS_ERR ( dfid ) ) {
2007-01-26 11:57:06 +03:00
err = PTR_ERR ( dfid ) ;
2008-10-16 17:30:07 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " fid clone failed %d \n " , err ) ;
2007-07-11 02:57:28 +04:00
dfid = NULL ;
2007-01-26 11:57:06 +03:00
goto error ;
}
2006-03-02 13:54:30 +03:00
2007-07-11 02:57:28 +04:00
/* clone a fid to use for creation */
ofid = p9_client_walk ( dfid , 0 , NULL , 1 ) ;
if ( IS_ERR ( ofid ) ) {
err = PTR_ERR ( ofid ) ;
2008-10-16 17:30:07 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " p9_client_walk failed %d \n " , err ) ;
2007-07-11 02:57:28 +04:00
ofid = NULL ;
goto error ;
}
2006-03-02 13:54:30 +03:00
2007-07-11 02:57:28 +04:00
err = p9_client_fcreate ( ofid , name , perm , mode , extension ) ;
2008-10-16 17:30:07 +04:00
if ( err < 0 ) {
P9_DPRINTK ( P9_DEBUG_VFS , " p9_client_fcreate failed %d \n " , err ) ;
2007-07-11 02:57:28 +04:00
goto error ;
2008-10-16 17:30:07 +04:00
}
2006-03-02 13:54:30 +03:00
2007-07-11 02:57:28 +04:00
/* now walk from the parent so we can get unopened fid */
fid = p9_client_walk ( dfid , 1 , & name , 0 ) ;
if ( IS_ERR ( fid ) ) {
err = PTR_ERR ( fid ) ;
2008-10-16 17:30:07 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " p9_client_walk failed %d \n " , err ) ;
2007-07-11 02:57:28 +04:00
fid = NULL ;
2006-03-02 13:54:30 +03:00
goto error ;
2007-07-11 02:57:28 +04:00
} else
dfid = NULL ;
2006-03-02 13:54:30 +03:00
2007-07-11 02:57:28 +04:00
/* instantiate inode and assign the unopened fid to the dentry */
inode = v9fs_inode_from_fid ( v9ses , fid , dir - > i_sb ) ;
2006-03-02 13:54:30 +03:00
if ( IS_ERR ( inode ) ) {
err = PTR_ERR ( inode ) ;
2008-10-16 17:30:07 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " inode creation failed %d \n " , err ) ;
2006-03-02 13:54:30 +03:00
goto error ;
}
2007-10-17 23:31:07 +04:00
if ( v9ses - > cache )
2007-02-11 22:21:39 +03:00
dentry - > d_op = & v9fs_cached_dentry_operations ;
else
dentry - > d_op = & v9fs_dentry_operations ;
2007-07-11 02:57:28 +04:00
2006-03-02 13:54:30 +03:00
d_instantiate ( dentry , inode ) ;
2009-07-19 23:41:57 +04:00
err = v9fs_fid_add ( dentry , fid ) ;
if ( err < 0 )
goto error ;
2007-07-11 02:57:28 +04:00
return ofid ;
2006-03-02 13:54:30 +03:00
2007-07-11 02:57:28 +04:00
error :
if ( dfid )
p9_client_clunk ( dfid ) ;
if ( ofid )
p9_client_clunk ( ofid ) ;
if ( fid )
p9_client_clunk ( fid ) ;
return ERR_PTR ( err ) ;
}
/**
* v9fs_vfs_create - VFS hook to create files
2008-03-05 16:08:09 +03:00
* @ dir : directory inode that is being created
2007-07-11 02:57:28 +04:00
* @ dentry : dentry that is being deleted
* @ mode : create permissions
* @ nd : path information
*
*/
2006-03-02 13:54:30 +03:00
2007-07-11 02:57:28 +04:00
static int
v9fs_vfs_create ( struct inode * dir , struct dentry * dentry , int mode ,
struct nameidata * nd )
{
int err ;
u32 perm ;
int flags ;
struct v9fs_session_info * v9ses ;
struct p9_fid * fid ;
struct file * filp ;
err = 0 ;
fid = NULL ;
v9ses = v9fs_inode2v9ses ( dir ) ;
perm = unixmode2p9mode ( v9ses , mode ) ;
if ( nd & & nd - > flags & LOOKUP_OPEN )
flags = nd - > intent . open . flags - 1 ;
else
flags = O_RDWR ;
fid = v9fs_create ( v9ses , dir , dentry , NULL , perm ,
2008-06-25 02:39:39 +04:00
v9fs_uflags2omode ( flags , v9fs_extended ( v9ses ) ) ) ;
2007-07-11 02:57:28 +04:00
if ( IS_ERR ( fid ) ) {
err = PTR_ERR ( fid ) ;
fid = NULL ;
goto error ;
}
/* if we are opening a file, assign the open fid to the file */
if ( nd & & nd - > flags & LOOKUP_OPEN ) {
2006-03-02 13:54:30 +03:00
filp = lookup_instantiate_filp ( nd , dentry , v9fs_open_created ) ;
if ( IS_ERR ( filp ) ) {
2007-07-11 02:57:28 +04:00
err = PTR_ERR ( filp ) ;
goto error ;
2006-03-02 13:54:30 +03:00
}
2007-07-11 02:57:28 +04:00
filp - > private_data = fid ;
} else
p9_client_clunk ( fid ) ;
2006-03-02 13:54:30 +03:00
return 0 ;
error :
2007-07-11 02:57:28 +04:00
if ( fid )
p9_client_clunk ( fid ) ;
2006-03-02 13:54:30 +03:00
return err ;
2005-09-10 00:04:19 +04:00
}
/**
* v9fs_vfs_mkdir - VFS mkdir hook to create a directory
2008-03-05 16:08:09 +03:00
* @ dir : inode that is being unlinked
2005-09-10 00:04:19 +04:00
* @ dentry : dentry that is being unlinked
* @ mode : mode for new directory
*
*/
2006-03-02 13:54:30 +03:00
static int v9fs_vfs_mkdir ( struct inode * dir , struct dentry * dentry , int mode )
2005-09-10 00:04:19 +04:00
{
2006-03-02 13:54:30 +03:00
int err ;
2007-07-11 02:57:28 +04:00
u32 perm ;
2006-03-02 13:54:30 +03:00
struct v9fs_session_info * v9ses ;
2007-07-11 02:57:28 +04:00
struct p9_fid * fid ;
2006-03-02 13:54:30 +03:00
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " name %s \n " , dentry - > d_name . name ) ;
err = 0 ;
2006-03-02 13:54:30 +03:00
v9ses = v9fs_inode2v9ses ( dir ) ;
perm = unixmode2p9mode ( v9ses , mode | S_IFDIR ) ;
2007-07-11 02:57:28 +04:00
fid = v9fs_create ( v9ses , dir , dentry , NULL , perm , P9_OREAD ) ;
if ( IS_ERR ( fid ) ) {
err = PTR_ERR ( fid ) ;
fid = NULL ;
2006-03-02 13:54:30 +03:00
}
2007-07-11 02:57:28 +04:00
if ( fid )
p9_client_clunk ( fid ) ;
2006-03-02 13:54:30 +03:00
return err ;
2005-09-10 00:04:19 +04:00
}
/**
* v9fs_vfs_lookup - VFS lookup hook to " walk " to a new inode
* @ dir : inode that is being walked from
* @ dentry : dentry that is being walked to ?
* @ nameidata : path data
*
*/
static struct dentry * v9fs_vfs_lookup ( struct inode * dir , struct dentry * dentry ,
struct nameidata * nameidata )
{
struct super_block * sb ;
struct v9fs_session_info * v9ses ;
2007-07-11 02:57:28 +04:00
struct p9_fid * dfid , * fid ;
2005-09-10 00:04:19 +04:00
struct inode * inode ;
2007-07-11 02:57:28 +04:00
char * name ;
2005-09-10 00:04:19 +04:00
int result = 0 ;
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " dir: %p dentry: (%s) %p nameidata: %p \n " ,
2006-03-08 08:55:42 +03:00
dir , dentry - > d_name . name , dentry , nameidata ) ;
2005-09-10 00:04:19 +04:00
sb = dir - > i_sb ;
v9ses = v9fs_inode2v9ses ( dir ) ;
2007-07-11 02:57:28 +04:00
dfid = v9fs_fid_lookup ( dentry - > d_parent ) ;
if ( IS_ERR ( dfid ) )
2008-02-07 11:15:26 +03:00
return ERR_CAST ( dfid ) ;
2007-07-11 02:57:28 +04:00
name = ( char * ) dentry - > d_name . name ;
fid = p9_client_walk ( dfid , 1 , & name , 1 ) ;
if ( IS_ERR ( fid ) ) {
result = PTR_ERR ( fid ) ;
2005-09-10 00:04:19 +04:00
if ( result = = - ENOENT ) {
d_add ( dentry , NULL ) ;
return NULL ;
}
2007-07-11 02:57:28 +04:00
return ERR_PTR ( result ) ;
2005-09-10 00:04:19 +04:00
}
2007-07-11 02:57:28 +04:00
inode = v9fs_inode_from_fid ( v9ses , fid , dir - > i_sb ) ;
if ( IS_ERR ( inode ) ) {
result = PTR_ERR ( inode ) ;
inode = NULL ;
goto error ;
2005-09-10 00:04:19 +04:00
}
2007-07-11 02:57:28 +04:00
result = v9fs_fid_add ( dentry , fid ) ;
2006-03-02 13:54:30 +03:00
if ( result < 0 )
2007-07-11 02:57:28 +04:00
goto error ;
2006-03-02 13:54:30 +03:00
2007-10-17 23:31:07 +04:00
if ( ( fid - > qid . version ) & & ( v9ses - > cache ) )
2007-02-11 22:21:39 +03:00
dentry - > d_op = & v9fs_cached_dentry_operations ;
else
dentry - > d_op = & v9fs_dentry_operations ;
2005-09-10 00:04:19 +04:00
d_add ( dentry , inode ) ;
return NULL ;
2007-07-11 02:57:28 +04:00
error :
2008-09-25 01:22:22 +04:00
p9_client_clunk ( fid ) ;
2007-01-26 11:57:06 +03:00
2005-09-10 00:04:19 +04:00
return ERR_PTR ( result ) ;
}
/**
* v9fs_vfs_unlink - VFS unlink hook to delete an inode
* @ i : inode that is being unlinked
2005-09-10 00:04:26 +04:00
* @ d : dentry that is being unlinked
2005-09-10 00:04:19 +04:00
*
*/
static int v9fs_vfs_unlink ( struct inode * i , struct dentry * d )
{
return v9fs_remove ( i , d , 0 ) ;
}
/**
* v9fs_vfs_rmdir - VFS unlink hook to delete a directory
* @ i : inode that is being unlinked
2005-09-10 00:04:26 +04:00
* @ d : dentry that is being unlinked
2005-09-10 00:04:19 +04:00
*
*/
static int v9fs_vfs_rmdir ( struct inode * i , struct dentry * d )
{
return v9fs_remove ( i , d , 1 ) ;
}
/**
* v9fs_vfs_rename - VFS hook to rename an inode
* @ old_dir : old dir inode
* @ old_dentry : old dentry
* @ new_dir : new dir inode
* @ new_dentry : new dentry
*
*/
static int
v9fs_vfs_rename ( struct inode * old_dir , struct dentry * old_dentry ,
struct inode * new_dir , struct dentry * new_dentry )
{
2007-07-11 02:57:28 +04:00
struct inode * old_inode ;
struct v9fs_session_info * v9ses ;
struct p9_fid * oldfid ;
struct p9_fid * olddirfid ;
struct p9_fid * newdirfid ;
struct p9_wstat wstat ;
int retval ;
2005-09-10 00:04:19 +04:00
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " \n " ) ;
retval = 0 ;
old_inode = old_dentry - > d_inode ;
v9ses = v9fs_inode2v9ses ( old_inode ) ;
oldfid = v9fs_fid_lookup ( old_dentry ) ;
2007-10-17 23:31:07 +04:00
if ( IS_ERR ( oldfid ) )
2007-01-26 11:57:06 +03:00
return PTR_ERR ( oldfid ) ;
olddirfid = v9fs_fid_clone ( old_dentry - > d_parent ) ;
2007-10-17 23:31:07 +04:00
if ( IS_ERR ( olddirfid ) ) {
2007-01-26 11:57:06 +03:00
retval = PTR_ERR ( olddirfid ) ;
2007-07-11 02:57:28 +04:00
goto done ;
2007-01-26 11:57:06 +03:00
}
newdirfid = v9fs_fid_clone ( new_dentry - > d_parent ) ;
2007-10-17 23:31:07 +04:00
if ( IS_ERR ( newdirfid ) ) {
2007-01-26 11:57:06 +03:00
retval = PTR_ERR ( newdirfid ) ;
2007-07-11 02:57:28 +04:00
goto clunk_olddir ;
2005-09-10 00:04:19 +04:00
}
/* 9P can only handle file rename in the same directory */
if ( memcmp ( & olddirfid - > qid , & newdirfid - > qid , sizeof ( newdirfid - > qid ) ) ) {
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_ERROR ,
" old dir and new dir are different \n " ) ;
2007-01-26 11:57:04 +03:00
retval = - EXDEV ;
2007-07-11 02:57:28 +04:00
goto clunk_newdir ;
2005-09-10 00:04:19 +04:00
}
2006-01-08 12:05:00 +03:00
v9fs_blank_wstat ( & wstat ) ;
2007-10-17 23:31:07 +04:00
wstat . muid = v9ses - > uname ;
2006-01-08 12:05:00 +03:00
wstat . name = ( char * ) new_dentry - > d_name . name ;
2007-07-11 02:57:28 +04:00
retval = p9_client_wstat ( oldfid , & wstat ) ;
2005-09-10 00:04:19 +04:00
2007-07-11 02:57:28 +04:00
clunk_newdir :
2007-10-23 22:48:33 +04:00
p9_client_clunk ( newdirfid ) ;
2005-09-10 00:04:19 +04:00
2007-07-11 02:57:28 +04:00
clunk_olddir :
2007-10-23 22:48:33 +04:00
p9_client_clunk ( olddirfid ) ;
2007-01-26 11:57:06 +03:00
2007-07-11 02:57:28 +04:00
done :
2005-09-10 00:04:19 +04:00
return retval ;
}
/**
2006-01-10 02:10:13 +03:00
* v9fs_vfs_getattr - retrieve file metadata
2008-03-05 16:08:09 +03:00
* @ mnt : mount information
* @ dentry : file to get attributes on
* @ stat : metadata structure to populate
2005-09-10 00:04:19 +04:00
*
*/
static int
v9fs_vfs_getattr ( struct vfsmount * mnt , struct dentry * dentry ,
struct kstat * stat )
{
2007-07-11 02:57:28 +04:00
int err ;
struct v9fs_session_info * v9ses ;
struct p9_fid * fid ;
2008-10-16 17:30:07 +04:00
struct p9_wstat * st ;
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " dentry: %p \n " , dentry ) ;
err = - EPERM ;
v9ses = v9fs_inode2v9ses ( dentry - > d_inode ) ;
2007-07-13 22:01:27 +04:00
if ( v9ses - > cache = = CACHE_LOOSE )
return simple_getattr ( mnt , dentry , stat ) ;
2007-07-11 02:57:28 +04:00
fid = v9fs_fid_lookup ( dentry ) ;
if ( IS_ERR ( fid ) )
2007-01-26 11:57:06 +03:00
return PTR_ERR ( fid ) ;
2005-09-10 00:04:19 +04:00
2007-07-11 02:57:28 +04:00
st = p9_client_stat ( fid ) ;
if ( IS_ERR ( st ) )
return PTR_ERR ( st ) ;
2005-09-10 00:04:19 +04:00
2007-07-11 02:57:28 +04:00
v9fs_stat2inode ( st , dentry - > d_inode , dentry - > d_inode - > i_sb ) ;
2005-09-10 00:04:19 +04:00
generic_fillattr ( dentry - > d_inode , stat ) ;
2007-07-11 02:57:28 +04:00
kfree ( st ) ;
return 0 ;
2005-09-10 00:04:19 +04:00
}
/**
* v9fs_vfs_setattr - set file metadata
* @ dentry : file whose metadata to set
* @ iattr : metadata assignment structure
*
*/
static int v9fs_vfs_setattr ( struct dentry * dentry , struct iattr * iattr )
{
2007-07-11 02:57:28 +04:00
int retval ;
struct v9fs_session_info * v9ses ;
struct p9_fid * fid ;
struct p9_wstat wstat ;
2005-09-10 00:04:19 +04:00
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " \n " ) ;
retval = - EPERM ;
v9ses = v9fs_inode2v9ses ( dentry - > d_inode ) ;
fid = v9fs_fid_lookup ( dentry ) ;
2007-01-26 11:57:06 +03:00
if ( IS_ERR ( fid ) )
return PTR_ERR ( fid ) ;
2005-09-10 00:04:19 +04:00
2006-01-08 12:05:00 +03:00
v9fs_blank_wstat ( & wstat ) ;
2005-09-10 00:04:19 +04:00
if ( iattr - > ia_valid & ATTR_MODE )
2006-01-08 12:05:00 +03:00
wstat . mode = unixmode2p9mode ( v9ses , iattr - > ia_mode ) ;
2005-09-10 00:04:19 +04:00
if ( iattr - > ia_valid & ATTR_MTIME )
2006-01-08 12:05:00 +03:00
wstat . mtime = iattr - > ia_mtime . tv_sec ;
2005-09-10 00:04:19 +04:00
if ( iattr - > ia_valid & ATTR_ATIME )
2006-01-08 12:05:00 +03:00
wstat . atime = iattr - > ia_atime . tv_sec ;
2005-09-10 00:04:19 +04:00
if ( iattr - > ia_valid & ATTR_SIZE )
2006-01-08 12:05:00 +03:00
wstat . length = iattr - > ia_size ;
2005-09-10 00:04:19 +04:00
2007-10-17 23:31:07 +04:00
if ( v9fs_extended ( v9ses ) ) {
2006-01-08 12:05:00 +03:00
if ( iattr - > ia_valid & ATTR_UID )
wstat . n_uid = iattr - > ia_uid ;
2005-09-10 00:04:19 +04:00
2006-01-08 12:05:00 +03:00
if ( iattr - > ia_valid & ATTR_GID )
wstat . n_gid = iattr - > ia_gid ;
2005-09-10 00:04:19 +04:00
}
2007-07-11 02:57:28 +04:00
retval = p9_client_wstat ( fid , & wstat ) ;
if ( retval > = 0 )
retval = inode_setattr ( dentry - > d_inode , iattr ) ;
2005-09-10 00:04:19 +04:00
2007-07-11 02:57:28 +04:00
return retval ;
2005-09-10 00:04:19 +04:00
}
/**
2006-01-08 12:05:00 +03:00
* v9fs_stat2inode - populate an inode structure with mistat info
* @ stat : Plan 9 metadata ( mistat ) structure
2005-09-10 00:04:19 +04:00
* @ inode : inode to populate
* @ sb : superblock of filesystem
*
*/
void
2008-10-16 17:30:07 +04:00
v9fs_stat2inode ( struct p9_wstat * stat , struct inode * inode ,
2006-01-08 12:05:00 +03:00
struct super_block * sb )
2005-09-10 00:04:19 +04:00
{
2006-01-08 12:05:00 +03:00
char ext [ 32 ] ;
2005-09-10 00:04:19 +04:00
struct v9fs_session_info * v9ses = sb - > s_fs_info ;
inode - > i_nlink = 1 ;
2006-01-08 12:05:00 +03:00
inode - > i_atime . tv_sec = stat - > atime ;
inode - > i_mtime . tv_sec = stat - > mtime ;
inode - > i_ctime . tv_sec = stat - > mtime ;
2005-09-10 00:04:19 +04:00
2007-10-17 23:31:07 +04:00
inode - > i_uid = v9ses - > dfltuid ;
inode - > i_gid = v9ses - > dfltgid ;
2005-09-10 00:04:19 +04:00
2007-10-17 23:31:07 +04:00
if ( v9fs_extended ( v9ses ) ) {
2006-01-08 12:05:00 +03:00
inode - > i_uid = stat - > n_uid ;
inode - > i_gid = stat - > n_gid ;
2005-09-10 00:04:19 +04:00
}
2006-01-08 12:05:00 +03:00
inode - > i_mode = p9mode2unixmode ( v9ses , stat - > mode ) ;
2005-09-10 00:04:19 +04:00
if ( ( S_ISBLK ( inode - > i_mode ) ) | | ( S_ISCHR ( inode - > i_mode ) ) ) {
char type = 0 ;
int major = - 1 ;
int minor = - 1 ;
2006-01-08 12:05:00 +03:00
2008-10-16 17:30:07 +04:00
strncpy ( ext , stat - > extension , sizeof ( ext ) ) ;
2006-01-08 12:05:00 +03:00
sscanf ( ext , " %c %u %u " , & type , & major , & minor ) ;
2005-09-10 00:04:19 +04:00
switch ( type ) {
case ' c ' :
inode - > i_mode & = ~ S_IFBLK ;
inode - > i_mode | = S_IFCHR ;
break ;
case ' b ' :
break ;
default :
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_ERROR ,
2008-10-16 17:30:07 +04:00
" Unknown special type %c %s \n " , type ,
stat - > extension ) ;
2005-09-10 00:04:19 +04:00
} ;
inode - > i_rdev = MKDEV ( major , minor ) ;
9p: fix device file handling
In v9fs_get_inode(), for block, as well as char devices (in theory),
the function init_special_inode() is called to set up callback functions
for file ops. this function uses the file mode's value to determine whether
to use block or char dev functions. In v9fs_inode_from_fid(), the function
p9mode2unixmode() is used, but for all devices it initially returns S_IFBLK,
then uses v9fs_get_inode() to initialise a new inode, then finally uses
v9fs_stat2inode(), which would determine whether the inode is a block or
character device. However, at that point init_special_inode() had already
decided to use the block device functions, so even if the inode's mode is
turned to a character device, the block functions are still used to operate
on them. The attached patch simply calls init_special_inode() again for devices
after parsing device node data in v9fs_stat2inode() so that the proper functions
are used.
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
2008-10-17 21:44:46 +04:00
init_special_inode ( inode , inode - > i_mode , inode - > i_rdev ) ;
2005-09-10 00:04:19 +04:00
} else
inode - > i_rdev = 0 ;
2006-01-08 12:05:00 +03:00
inode - > i_size = stat - > length ;
2005-09-10 00:04:19 +04:00
2007-07-11 02:57:28 +04:00
/* not real number of blocks, but 512 byte ones ... */
inode - > i_blocks = ( inode - > i_size + 512 - 1 ) > > 9 ;
2005-09-10 00:04:19 +04:00
}
/**
* v9fs_qid2ino - convert qid into inode number
* @ qid : qid to hash
*
* BUG : potential for inode number collisions ?
*/
2007-07-11 02:57:28 +04:00
ino_t v9fs_qid2ino ( struct p9_qid * qid )
2005-09-10 00:04:19 +04:00
{
u64 path = qid - > path + 2 ;
ino_t i = 0 ;
if ( sizeof ( ino_t ) = = sizeof ( path ) )
memcpy ( & i , & path , sizeof ( ino_t ) ) ;
else
i = ( ino_t ) ( path ^ ( path > > 32 ) ) ;
return i ;
}
/**
* v9fs_readlink - read a symlink ' s location ( internal version )
* @ dentry : dentry for symlink
2005-09-10 00:04:26 +04:00
* @ buffer : buffer to load symlink location into
2005-09-10 00:04:19 +04:00
* @ buflen : length of buffer
*
*/
static int v9fs_readlink ( struct dentry * dentry , char * buffer , int buflen )
{
2007-07-11 02:57:28 +04:00
int retval ;
2005-09-10 00:04:19 +04:00
2007-07-11 02:57:28 +04:00
struct v9fs_session_info * v9ses ;
struct p9_fid * fid ;
2008-10-16 17:30:07 +04:00
struct p9_wstat * st ;
2005-09-10 00:04:19 +04:00
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " %s \n " , dentry - > d_name . name ) ;
retval = - EPERM ;
v9ses = v9fs_inode2v9ses ( dentry - > d_inode ) ;
fid = v9fs_fid_lookup ( dentry ) ;
2007-10-17 23:31:07 +04:00
if ( IS_ERR ( fid ) )
2007-01-26 11:57:06 +03:00
return PTR_ERR ( fid ) ;
2005-09-10 00:04:19 +04:00
2007-10-17 23:31:07 +04:00
if ( ! v9fs_extended ( v9ses ) )
2007-07-11 02:57:28 +04:00
return - EBADF ;
2005-09-10 00:04:19 +04:00
2007-07-11 02:57:28 +04:00
st = p9_client_stat ( fid ) ;
if ( IS_ERR ( st ) )
return PTR_ERR ( st ) ;
2005-09-10 00:04:19 +04:00
2007-07-11 02:57:28 +04:00
if ( ! ( st - > mode & P9_DMSYMLINK ) ) {
2005-09-10 00:04:19 +04:00
retval = - EINVAL ;
2007-07-11 02:57:28 +04:00
goto done ;
2005-09-10 00:04:19 +04:00
}
/* copy extension buffer into buffer */
2008-10-16 17:30:07 +04:00
strncpy ( buffer , st - > extension , buflen ) ;
2005-09-10 00:04:19 +04:00
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_VFS ,
2008-10-16 17:30:07 +04:00
" %s -> %s (%s) \n " , dentry - > d_name . name , st - > extension , buffer ) ;
2005-09-10 00:04:19 +04:00
2007-07-11 02:57:28 +04:00
retval = buflen ;
2007-01-26 11:57:06 +03:00
2007-07-11 02:57:28 +04:00
done :
kfree ( st ) ;
2005-09-10 00:04:19 +04:00
return retval ;
}
/**
* v9fs_vfs_readlink - read a symlink ' s location
* @ dentry : dentry for symlink
2008-03-05 16:08:09 +03:00
* @ buffer : buffer to load symlink location into
2005-09-10 00:04:19 +04:00
* @ buflen : length of buffer
*
*/
static int v9fs_vfs_readlink ( struct dentry * dentry , char __user * buffer ,
int buflen )
{
int retval ;
int ret ;
char * link = __getname ( ) ;
2006-06-25 16:48:31 +04:00
if ( unlikely ( ! link ) )
return - ENOMEM ;
2005-09-23 08:43:52 +04:00
if ( buflen > PATH_MAX )
buflen = PATH_MAX ;
2005-09-10 00:04:19 +04:00
2008-12-20 01:47:40 +03:00
P9_DPRINTK ( P9_DEBUG_VFS , " dentry: %s (%p) \n " , dentry - > d_name . name ,
dentry ) ;
2005-09-10 00:04:19 +04:00
retval = v9fs_readlink ( dentry , link , buflen ) ;
if ( retval > 0 ) {
if ( ( ret = copy_to_user ( buffer , link , retval ) ) ! = 0 ) {
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_ERROR ,
" problem copying to user: %d \n " , ret ) ;
2005-09-10 00:04:19 +04:00
retval = ret ;
}
}
2005-11-07 11:59:36 +03:00
__putname ( link ) ;
2005-09-10 00:04:19 +04:00
return retval ;
}
/**
* v9fs_vfs_follow_link - follow a symlink path
* @ dentry : dentry for symlink
* @ nd : nameidata
*
*/
static void * v9fs_vfs_follow_link ( struct dentry * dentry , struct nameidata * nd )
{
int len = 0 ;
char * link = __getname ( ) ;
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " %s n " , dentry - > d_name . name ) ;
2005-09-10 00:04:19 +04:00
if ( ! link )
link = ERR_PTR ( - ENOMEM ) ;
else {
2006-03-25 14:07:26 +03:00
len = v9fs_readlink ( dentry , link , PATH_MAX ) ;
2005-09-10 00:04:19 +04:00
if ( len < 0 ) {
2005-11-07 11:59:36 +03:00
__putname ( link ) ;
2005-09-10 00:04:19 +04:00
link = ERR_PTR ( len ) ;
} else
link [ len ] = 0 ;
}
nd_set_link ( nd , link ) ;
return NULL ;
}
/**
* v9fs_vfs_put_link - release a symlink path
* @ dentry : dentry for symlink
* @ nd : nameidata
2008-03-05 16:08:09 +03:00
* @ p : unused
2005-09-10 00:04:19 +04:00
*
*/
2008-03-05 16:08:09 +03:00
static void
v9fs_vfs_put_link ( struct dentry * dentry , struct nameidata * nd , void * p )
2005-09-10 00:04:19 +04:00
{
char * s = nd_get_link ( nd ) ;
2008-12-20 01:45:21 +03:00
P9_DPRINTK ( P9_DEBUG_VFS , " %s %s \n " , dentry - > d_name . name ,
IS_ERR ( s ) ? " <error> " : s ) ;
2005-09-10 00:04:19 +04:00
if ( ! IS_ERR ( s ) )
2005-11-07 11:59:36 +03:00
__putname ( s ) ;
2005-09-10 00:04:19 +04:00
}
2008-03-05 16:08:09 +03:00
/**
* v9fs_vfs_mkspecial - create a special file
* @ dir : inode to create special file in
* @ dentry : dentry to create
* @ mode : mode to create special file
* @ extension : 9 p2000 . u format extension string representing special file
*
*/
2006-01-08 12:05:00 +03:00
static int v9fs_vfs_mkspecial ( struct inode * dir , struct dentry * dentry ,
int mode , const char * extension )
2005-09-10 00:04:19 +04:00
{
2007-07-11 02:57:28 +04:00
u32 perm ;
2006-01-08 12:05:00 +03:00
struct v9fs_session_info * v9ses ;
2007-07-11 02:57:28 +04:00
struct p9_fid * fid ;
2005-09-10 00:04:19 +04:00
2006-03-02 13:54:30 +03:00
v9ses = v9fs_inode2v9ses ( dir ) ;
2007-10-17 23:31:07 +04:00
if ( ! v9fs_extended ( v9ses ) ) {
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_ERROR , " not extended \n " ) ;
2006-03-02 13:54:30 +03:00
return - EPERM ;
2005-09-10 00:04:19 +04:00
}
2007-01-26 11:57:06 +03:00
perm = unixmode2p9mode ( v9ses , mode ) ;
2007-07-11 02:57:28 +04:00
fid = v9fs_create ( v9ses , dir , dentry , ( char * ) extension , perm ,
P9_OREAD ) ;
if ( IS_ERR ( fid ) )
return PTR_ERR ( fid ) ;
2007-01-26 11:57:06 +03:00
2007-07-11 02:57:28 +04:00
p9_client_clunk ( fid ) ;
2006-03-02 13:54:30 +03:00
return 0 ;
2006-01-08 12:05:00 +03:00
}
/**
* v9fs_vfs_symlink - helper function to create symlinks
* @ dir : directory inode containing symlink
* @ dentry : dentry for symlink
* @ symname : symlink data
*
2008-03-05 16:08:09 +03:00
* See Also : 9 P2000 . u RFC for more information
2006-01-08 12:05:00 +03:00
*
*/
static int
v9fs_vfs_symlink ( struct inode * dir , struct dentry * dentry , const char * symname )
{
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " %lu,%s,%s \n " , dir - > i_ino ,
dentry - > d_name . name , symname ) ;
2006-01-08 12:05:00 +03:00
return v9fs_vfs_mkspecial ( dir , dentry , S_IFLNK , symname ) ;
}
/**
* v9fs_vfs_link - create a hardlink
* @ old_dentry : dentry for file to link to
* @ dir : inode destination for new link
* @ dentry : dentry for link
*
*/
static int
v9fs_vfs_link ( struct dentry * old_dentry , struct inode * dir ,
struct dentry * dentry )
{
int retval ;
2007-07-11 02:57:28 +04:00
struct p9_fid * oldfid ;
2006-01-08 12:05:00 +03:00
char * name ;
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_VFS ,
" %lu,%s,%s \n " , dir - > i_ino , dentry - > d_name . name ,
2006-01-08 12:05:00 +03:00
old_dentry - > d_name . name ) ;
2007-01-26 11:57:06 +03:00
oldfid = v9fs_fid_clone ( old_dentry ) ;
2007-10-17 23:31:07 +04:00
if ( IS_ERR ( oldfid ) )
2007-01-26 11:57:06 +03:00
return PTR_ERR ( oldfid ) ;
2006-01-08 12:05:00 +03:00
name = __getname ( ) ;
2007-01-26 11:57:06 +03:00
if ( unlikely ( ! name ) ) {
retval = - ENOMEM ;
goto clunk_fid ;
}
2006-06-25 16:48:31 +04:00
2006-03-25 14:07:26 +03:00
sprintf ( name , " %d \n " , oldfid - > fid ) ;
2007-07-11 02:57:28 +04:00
retval = v9fs_vfs_mkspecial ( dir , dentry , P9_DMLINK , name ) ;
2006-01-08 12:05:00 +03:00
__putname ( name ) ;
2005-09-10 00:04:19 +04:00
2007-01-26 11:57:06 +03:00
clunk_fid :
2007-07-11 02:57:28 +04:00
p9_client_clunk ( oldfid ) ;
2005-09-10 00:04:19 +04:00
return retval ;
}
/**
* v9fs_vfs_mknod - create a special file
* @ dir : inode destination for new link
* @ dentry : dentry for file
* @ mode : mode for creation
2008-03-05 16:08:09 +03:00
* @ rdev : device associated with special file
2005-09-10 00:04:19 +04:00
*
*/
static int
v9fs_vfs_mknod ( struct inode * dir , struct dentry * dentry , int mode , dev_t rdev )
{
2006-01-08 12:05:00 +03:00
int retval ;
char * name ;
2005-09-10 00:04:19 +04:00
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_VFS ,
" %lu,%s mode: %x MAJOR: %u MINOR: %u \n " , dir - > i_ino ,
2005-09-10 00:04:19 +04:00
dentry - > d_name . name , mode , MAJOR ( rdev ) , MINOR ( rdev ) ) ;
2006-01-08 12:05:00 +03:00
if ( ! new_valid_dev ( rdev ) )
return - EINVAL ;
2005-09-10 00:04:19 +04:00
2006-01-08 12:05:00 +03:00
name = __getname ( ) ;
2006-03-25 14:07:27 +03:00
if ( ! name )
return - ENOMEM ;
2005-09-10 00:04:19 +04:00
/* build extension */
if ( S_ISBLK ( mode ) )
2006-01-08 12:05:00 +03:00
sprintf ( name , " b %u %u " , MAJOR ( rdev ) , MINOR ( rdev ) ) ;
2005-09-10 00:04:19 +04:00
else if ( S_ISCHR ( mode ) )
2006-01-08 12:05:00 +03:00
sprintf ( name , " c %u %u " , MAJOR ( rdev ) , MINOR ( rdev ) ) ;
2005-09-10 00:04:26 +04:00
else if ( S_ISFIFO ( mode ) )
2006-01-08 12:05:00 +03:00
* name = 0 ;
2005-09-10 00:04:19 +04:00
else {
2006-01-08 12:05:00 +03:00
__putname ( name ) ;
return - EINVAL ;
2005-09-10 00:04:19 +04:00
}
2006-01-08 12:05:00 +03:00
retval = v9fs_vfs_mkspecial ( dir , dentry , mode , name ) ;
__putname ( name ) ;
2005-09-10 00:04:19 +04:00
return retval ;
}
2007-02-12 11:55:38 +03:00
static const struct inode_operations v9fs_dir_inode_operations_ext = {
2005-09-10 00:04:19 +04:00
. create = v9fs_vfs_create ,
. lookup = v9fs_vfs_lookup ,
. symlink = v9fs_vfs_symlink ,
. link = v9fs_vfs_link ,
. unlink = v9fs_vfs_unlink ,
. mkdir = v9fs_vfs_mkdir ,
. rmdir = v9fs_vfs_rmdir ,
. mknod = v9fs_vfs_mknod ,
. rename = v9fs_vfs_rename ,
. readlink = v9fs_vfs_readlink ,
. getattr = v9fs_vfs_getattr ,
. setattr = v9fs_vfs_setattr ,
} ;
2007-02-12 11:55:38 +03:00
static const struct inode_operations v9fs_dir_inode_operations = {
2005-09-10 00:04:27 +04:00
. create = v9fs_vfs_create ,
. lookup = v9fs_vfs_lookup ,
. unlink = v9fs_vfs_unlink ,
. mkdir = v9fs_vfs_mkdir ,
. rmdir = v9fs_vfs_rmdir ,
. mknod = v9fs_vfs_mknod ,
. rename = v9fs_vfs_rename ,
. getattr = v9fs_vfs_getattr ,
. setattr = v9fs_vfs_setattr ,
} ;
2007-02-12 11:55:38 +03:00
static const struct inode_operations v9fs_file_inode_operations = {
2005-09-10 00:04:19 +04:00
. getattr = v9fs_vfs_getattr ,
. setattr = v9fs_vfs_setattr ,
} ;
2007-02-12 11:55:38 +03:00
static const struct inode_operations v9fs_symlink_inode_operations = {
2005-09-10 00:04:19 +04:00
. readlink = v9fs_vfs_readlink ,
. follow_link = v9fs_vfs_follow_link ,
. put_link = v9fs_vfs_put_link ,
. getattr = v9fs_vfs_getattr ,
. setattr = v9fs_vfs_setattr ,
} ;