Commit 8f40f672 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs

* 'for-linus' of ssh://master.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs:
  9p: fix error path during early mount
  9p: make cryptic unknown error from server less scary
  9p: fix flags length in net
  9p: Correct fidpool creation failure in p9_client_create
  9p: use struct mutex instead of struct semaphore
  9p: propagate parse_option changes to client and transports
  fs/9p/v9fs.c (v9fs_parse_options): Handle kstrdup and match_strdup failure.
  9p: Documentation updates
  add match_strlcpy() us it to make v9fs make uname and remotename parsing more robust
parents 8978a318 887b3ece
......@@ -22,6 +22,21 @@
#include <linux/list.h>
/**
* struct v9fs_dentry - 9p private data stored in dentry d_fsdata
* @lock: protects the fidlist
* @fidlist: list of FIDs currently associated with this dentry
*
* This structure defines the 9p private data associated with
* a particular dentry. In particular, this private data is used
* to lookup which 9P FID handle should be used for a particular VFS
* operation. FID handles are associated with dentries instead of
* inodes in order to more closely map functionality to the Plan 9
* expected behavior for FID reclaimation and tracking.
*
* See Also: Mapping FIDs to Linux VFS model in
* Design and Implementation of the Linux 9P File System documentation
*/
struct v9fs_dentry {
spinlock_t lock; /* protect fidlist */
struct list_head fidlist;
......
......@@ -71,19 +71,19 @@ static match_table_t tokens = {
/**
* v9fs_parse_options - parse mount options into session structure
* @options: options string passed from mount
* @v9ses: existing v9fs session information
*
* Return 0 upon success, -ERRNO upon failure.
*/
static void v9fs_parse_options(struct v9fs_session_info *v9ses)
static int v9fs_parse_options(struct v9fs_session_info *v9ses)
{
char *options;
substring_t args[MAX_OPT_ARGS];
char *p;
int option = 0;
char *s, *e;
int ret;
int ret = 0;
/* setup defaults */
v9ses->afid = ~0;
......@@ -91,19 +91,26 @@ static void v9fs_parse_options(struct v9fs_session_info *v9ses)
v9ses->cache = 0;
if (!v9ses->options)
return;
return 0;
options = kstrdup(v9ses->options, GFP_KERNEL);
if (!options) {
P9_DPRINTK(P9_DEBUG_ERROR,
"failed to allocate copy of option string\n");
return -ENOMEM;
}
while ((p = strsep(&options, ",")) != NULL) {
int token;
if (!*p)
continue;
token = match_token(p, tokens, args);
if (token < Opt_uname) {
ret = match_int(&args[0], &option);
if (ret < 0) {
int r = match_int(&args[0], &option);
if (r < 0) {
P9_DPRINTK(P9_DEBUG_ERROR,
"integer field, but no integer?\n");
ret = r;
continue;
}
}
......@@ -125,10 +132,10 @@ static void v9fs_parse_options(struct v9fs_session_info *v9ses)
v9ses->afid = option;
break;
case Opt_uname:
match_strcpy(v9ses->uname, &args[0]);
match_strlcpy(v9ses->uname, &args[0], PATH_MAX);
break;
case Opt_remotename:
match_strcpy(v9ses->aname, &args[0]);
match_strlcpy(v9ses->aname, &args[0], PATH_MAX);
break;
case Opt_nodevmap:
v9ses->nodev = 1;
......@@ -139,6 +146,13 @@ static void v9fs_parse_options(struct v9fs_session_info *v9ses)
case Opt_access:
s = match_strdup(&args[0]);
if (!s) {
P9_DPRINTK(P9_DEBUG_ERROR,
"failed to allocate copy"
" of option argument\n");
ret = -ENOMEM;
break;
}
v9ses->flags &= ~V9FS_ACCESS_MASK;
if (strcmp(s, "user") == 0)
v9ses->flags |= V9FS_ACCESS_USER;
......@@ -158,6 +172,7 @@ static void v9fs_parse_options(struct v9fs_session_info *v9ses)
}
}
kfree(options);
return ret;
}
/**
......@@ -173,6 +188,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
{
int retval = -EINVAL;
struct p9_fid *fid;
int rc;
v9ses->uname = __getname();
if (!v9ses->uname)
......@@ -190,8 +206,21 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
v9ses->uid = ~0;
v9ses->dfltuid = V9FS_DEFUID;
v9ses->dfltgid = V9FS_DEFGID;
v9ses->options = kstrdup(data, GFP_KERNEL);
v9fs_parse_options(v9ses);
if (data) {
v9ses->options = kstrdup(data, GFP_KERNEL);
if (!v9ses->options) {
P9_DPRINTK(P9_DEBUG_ERROR,
"failed to allocate copy of option string\n");
retval = -ENOMEM;
goto error;
}
}
rc = v9fs_parse_options(v9ses);
if (rc < 0) {
retval = rc;
goto error;
}
v9ses->clnt = p9_client_create(dev_name, v9ses->options);
......@@ -233,7 +262,6 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
return fid;
error:
v9fs_session_close(v9ses);
return ERR_PTR(retval);
}
......@@ -256,9 +284,12 @@ void v9fs_session_close(struct v9fs_session_info *v9ses)
}
/**
* v9fs_session_cancel - mark transport as disconnected
* and cancel all pending requests.
* v9fs_session_cancel - terminate a session
* @v9ses: session to terminate
*
* mark transport as disconnected and cancel all pending requests.
*/
void v9fs_session_cancel(struct v9fs_session_info *v9ses) {
P9_DPRINTK(P9_DEBUG_ERROR, "cancel session %p\n", v9ses);
p9_client_disconnect(v9ses->clnt);
......
......@@ -21,18 +21,69 @@
*
*/
/*
* Session structure provides information for an opened session
*
*/
/**
* enum p9_session_flags - option flags for each 9P session
* @V9FS_EXTENDED: whether or not to use 9P2000.u extensions
* @V9FS_ACCESS_SINGLE: only the mounting user can access the hierarchy
* @V9FS_ACCESS_USER: a new attach will be issued for every user (default)
* @V9FS_ACCESS_ANY: use a single attach for all users
* @V9FS_ACCESS_MASK: bit mask of different ACCESS options
*
* Session flags reflect options selected by users at mount time
*/
enum p9_session_flags {
V9FS_EXTENDED = 0x01,
V9FS_ACCESS_SINGLE = 0x02,
V9FS_ACCESS_USER = 0x04,
V9FS_ACCESS_ANY = 0x06,
V9FS_ACCESS_MASK = 0x06,
};
/* possible values of ->cache */
/**
* enum p9_cache_modes - user specified cache preferences
* @CACHE_NONE: do not cache data, dentries, or directory contents (default)
* @CACHE_LOOSE: cache data, dentries, and directory contents w/no consistency
*
* eventually support loose, tight, time, session, default always none
*/
enum p9_cache_modes {
CACHE_NONE,
CACHE_LOOSE,
};
/**
* struct v9fs_session_info - per-instance session information
* @flags: session options of type &p9_session_flags
* @nodev: set to 1 to disable device mapping
* @debug: debug level
* @afid: authentication handle
* @cache: cache mode of type &p9_cache_modes
* @options: copy of options string given by user
* @uname: string user name to mount hierarchy as
* @aname: mount specifier for remote hierarchy
* @maxdata: maximum data to be sent/recvd per protocol message
* @dfltuid: default numeric userid to mount hierarchy as
* @dfltgid: default numeric groupid to mount hierarchy as
* @uid: if %V9FS_ACCESS_SINGLE, the numeric uid which mounted the hierarchy
* @clnt: reference to 9P network client instantiated for this session
* @debugfs_dir: reference to debugfs_dir which can be used for add'l debug
*
* This structure holds state for each session instance established during
* a sys_mount() .
*
* Bugs: there seems to be a lot of state which could be condensed and/or
* removed.
*/
struct v9fs_session_info {
/* options */
unsigned char flags; /* session flags */
unsigned char nodev; /* set to 1 if no disable device mapping */
unsigned short debug; /* debug level */
unsigned int afid; /* authentication fid */
unsigned int cache; /* cache mode */
unsigned char flags;
unsigned char nodev;
unsigned short debug;
unsigned int afid;
unsigned int cache;
char *options; /* copy of mount options */
char *uname; /* user name to mount as */
......@@ -45,22 +96,6 @@ struct v9fs_session_info {
struct dentry *debugfs_dir;
};
/* session flags */
enum {
V9FS_EXTENDED = 0x01, /* 9P2000.u */
V9FS_ACCESS_MASK = 0x06, /* access mask */
V9FS_ACCESS_SINGLE = 0x02, /* only one user can access the files */
V9FS_ACCESS_USER = 0x04, /* attache per user */
V9FS_ACCESS_ANY = 0x06, /* use the same attach for all users */
};
/* possible values of ->cache */
/* eventually support loose, tight, time, session, default always none */
enum {
CACHE_NONE, /* default */
CACHE_LOOSE, /* no consistency */
};
extern struct dentry *v9fs_debugfs_root;
struct p9_fid *v9fs_session_init(struct v9fs_session_info *, const char *,
......
......@@ -43,7 +43,7 @@
/**
* v9fs_vfs_readpage - read an entire page in from 9P
*
* @file: file being read
* @filp: file being read
* @page: structure to page
*
*/
......
......@@ -60,7 +60,7 @@ static inline int dt_type(struct p9_stat *mistat)
/**
* v9fs_dir_readdir - read a directory
* @filep: opened file structure
* @filp: opened file structure
* @dirent: directory structure ???
* @filldir: function to populate directory structure ???
*
......
......@@ -90,10 +90,11 @@ int v9fs_file_open(struct inode *inode, struct file *file)
/**
* v9fs_file_lock - lock a file (or directory)
* @inode: inode to be opened
* @file: file being opened
* @filp: file to be locked
* @cmd: lock command
* @fl: file lock structure
*
* XXX - this looks like a local only lock, we should extend into 9P
* Bugs: this looks like a local only lock, we should extend into 9P
* by using open exclusive
*/
......@@ -118,7 +119,7 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
/**
* v9fs_file_read - read from a file
* @filep: file pointer to read
* @filp: file pointer to read
* @data: data buffer to read data into
* @count: size of buffer
* @offset: offset at which to read data
......@@ -142,7 +143,7 @@ v9fs_file_read(struct file *filp, char __user * data, size_t count,
/**
* v9fs_file_write - write to a file
* @filep: file pointer to write
* @filp: file pointer to write
* @data: data buffer to write data from
* @count: size of buffer
* @offset: offset at which to write data
......
......@@ -129,6 +129,12 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
return res;
}
/**
* v9fs_uflags2omode- convert posix open flags to plan 9 mode bits
* @uflags: flags to convert
*
*/
int v9fs_uflags2omode(int uflags)
{
int ret;
......@@ -312,6 +318,14 @@ error:
}
*/
/**
* 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
*
*/
static struct inode *
v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
struct super_block *sb)
......@@ -384,9 +398,12 @@ v9fs_open_created(struct inode *inode, struct file *file)
/**
* v9fs_create - Create a file
* @v9ses: session information
* @dir: directory that dentry is being created in
* @dentry: dentry that is being created
* @perm: create permissions
* @mode: open mode
* @extension: 9p2000.u extension string to support devices, etc.
*
*/
static struct p9_fid *
......@@ -461,7 +478,7 @@ error:
/**
* v9fs_vfs_create - VFS hook to create files
* @inode: directory inode that is being created
* @dir: directory inode that is being created
* @dentry: dentry that is being deleted
* @mode: create permissions
* @nd: path information
......@@ -519,7 +536,7 @@ error:
/**
* v9fs_vfs_mkdir - VFS mkdir hook to create a directory
* @inode: inode that is being unlinked
* @dir: inode that is being unlinked
* @dentry: dentry that is being unlinked
* @mode: mode for new directory
*
......@@ -703,9 +720,9 @@ done:
/**
* v9fs_vfs_getattr - retrieve file metadata
* @mnt - mount information
* @dentry - file to get attributes on
* @stat - metadata structure to populate
* @mnt: mount information
* @dentry: file to get attributes on
* @stat: metadata structure to populate
*
*/
......@@ -928,7 +945,7 @@ done:
/**
* v9fs_vfs_readlink - read a symlink's location
* @dentry: dentry for symlink
* @buf: buffer to load symlink location into
* @buffer: buffer to load symlink location into
* @buflen: length of buffer
*
*/
......@@ -996,10 +1013,12 @@ static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
* v9fs_vfs_put_link - release a symlink path
* @dentry: dentry for symlink
* @nd: nameidata
* @p: unused
*
*/
static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
static void
v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
{
char *s = nd_get_link(nd);
......@@ -1008,6 +1027,15 @@ static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void
__putname(s);
}
/**
* 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: 9p2000.u format extension string representing special file
*
*/
static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
int mode, const char *extension)
{
......@@ -1037,7 +1065,7 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
* @dentry: dentry for symlink
* @symname: symlink data
*
* See 9P2000.u RFC for more information
* See Also: 9P2000.u RFC for more information
*
*/
......@@ -1058,10 +1086,6 @@ v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
*
*/
/* XXX - lots of code dup'd from symlink and creates,
* figure out a better reuse strategy
*/
static int
v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *dentry)
......@@ -1098,7 +1122,7 @@ clunk_fid:
* @dir: inode destination for new link
* @dentry: dentry for file
* @mode: mode for creation
* @dev_t: device associated with special file
* @rdev: device associated with special file
*
*/
......
......@@ -75,6 +75,7 @@ static int v9fs_set_super(struct super_block *s, void *data)
* v9fs_fill_super - populate superblock with info
* @sb: superblock
* @v9ses: session information
* @flags: flags propagated from v9fs_get_sb()
*
*/
......@@ -127,29 +128,26 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
fid = v9fs_session_init(v9ses, dev_name, data);
if (IS_ERR(fid)) {
retval = PTR_ERR(fid);
fid = NULL;
kfree(v9ses);
v9ses = NULL;
goto error;
goto close_session;
}
st = p9_client_stat(fid);
if (IS_ERR(st)) {
retval = PTR_ERR(st);
goto error;
goto clunk_fid;
}
sb = sget(fs_type, NULL, v9fs_set_super, v9ses);
if (IS_ERR(sb)) {
retval = PTR_ERR(sb);
goto error;
goto free_stat;
}
v9fs_fill_super(sb, v9ses, flags);
inode = v9fs_get_inode(sb, S_IFDIR | mode);
if (IS_ERR(inode)) {
retval = PTR_ERR(inode);
goto error;
goto release_sb;
}
inode->i_uid = uid;
......@@ -158,7 +156,7 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
root = d_alloc_root(inode);
if (!root) {
retval = -ENOMEM;
goto error;
goto release_sb;
}
sb->s_root = root;
......@@ -169,21 +167,22 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
return simple_set_mnt(mnt, sb);
error:
kfree(st);
if (fid)
p9_client_clunk(fid);
if (v9ses) {
v9fs_session_close(v9ses);
kfree(v9ses);
}
release_sb:
if (sb) {
up_write(&sb->s_umount);
deactivate_super(sb);
}
free_stat:
kfree(st);
clunk_fid:
p9_client_clunk(fid);
close_session:
v9fs_session_close(v9ses);
kfree(v9ses);
return retval;
}
......
......@@ -29,5 +29,5 @@ int match_token(char *, match_table_t table, substring_t args[]);
int match_int(substring_t *, int *result);
int match_octal(substring_t *, int *result);
int match_hex(substring_t *, int *result);
void match_strcpy(char *, const substring_t *);
size_t match_strlcpy(char *, const substring_t *, size_t);
char *match_strdup(const substring_t *);
......@@ -29,14 +29,31 @@
#ifdef CONFIG_NET_9P_DEBUG
#define P9_DEBUG_ERROR (1<<0)
#define P9_DEBUG_9P (1<<2)
#define P9_DEBUG_VFS (1<<3)
#define P9_DEBUG_CONV (1<<4)
#define P9_DEBUG_MUX (1<<5)
#define P9_DEBUG_TRANS (1<<6)
#define P9_DEBUG_SLABS (1<<7)
#define P9_DEBUG_FCALL (1<<8)
/**
* enum p9_debug_flags - bits for mount time debug parameter
* @P9_DEBUG_ERROR: more verbose error messages including original error string
* @P9_DEBUG_9P: 9P protocol tracing
* @P9_DEBUG_VFS: VFS API tracing
* @P9_DEBUG_CONV: protocol conversion tracing
* @P9_DEBUG_MUX: trace management of concurrent transactions
* @P9_DEBUG_TRANS: transport tracing
* @P9_DEBUG_SLABS: memory management tracing
* @P9_DEBUG_FCALL: verbose dump of protocol messages
*
* These flags are passed at mount time to turn on various levels of
* verbosity and tracing which will be output to the system logs.
*/
enum p9_debug_flags {
P9_DEBUG_ERROR = (1<<0),
P9_DEBUG_9P = (1<<2),
P9_DEBUG_VFS = (1<<3),
P9_DEBUG_CONV = (1<<4),
P9_DEBUG_MUX = (1<<5),
P9_DEBUG_TRANS = (1<<6),
P9_DEBUG_SLABS = (1<<7),
P9_DEBUG_FCALL = (1<<8),
};
extern unsigned int p9_debug_level;
......@@ -62,9 +79,47 @@ do { \
format , __FUNCTION__, task_pid_nr(current), ## arg); \
} while (0)
/**
* enum p9_msg_t - 9P message types
* @P9_TVERSION: version handshake request
* @P9_RVERSION: version handshake response
* @P9_TAUTH: request to establish authentication channel
* @P9_RAUTH: response with authentication information
* @P9_TATTACH: establish user access to file service
* @P9_RATTACH: response with top level handle to file hierarchy
* @P9_TERROR: not used
* @P9_RERROR: response for any failed request
* @P9_TFLUSH: request to abort a previous request
* @P9_RFLUSH: response when previous request has been cancelled
* @P9_TWALK: descend a directory hierarchy
* @P9_RWALK: response with new handle for position within hierarchy
* @P9_TOPEN: prepare a handle for I/O on an existing file
* @P9_ROPEN: response with file access information
* @P9_TCREATE: prepare a handle for I/O on a new file
* @P9_RCREATE: response with file access information
* @P9_TREAD: request to transfer data from a file or directory
* @P9_RREAD: response with data requested
* @P9_TWRITE: reuqest to transfer data to a file
* @P9_RWRITE: response with out much data was transfered to file
* @P9_TCLUNK: forget about a handle to an entity within the file system
* @P9_RCLUNK: response when server has forgotten about the handle
* @P9_TREMOVE: request to remove an entity from the hierarchy
* @P9_RREMOVE: response when server has removed the entity
* @P9_TSTAT: request file entity attributes
* @P9_RSTAT: response with file entity attributes
* @P9_TWSTAT: request to update file entity attributes
* @P9_RWSTAT: response when file entity attributes are updated
*
* There are 14 basic operations in 9P2000, paired as
* requests and responses. The one special case is ERROR
* as there is no @P9_TERROR request for clients to transmit to
* the server, but the server may respond to any other request
* with an @P9_RERROR.
*
* See Also: http://plan9.bell-labs.com/sys/man/5/INDEX.html
*/
/* Message Types */
enum {
enum p9_msg_t {
P9_TVERSION = 100,
P9_RVERSION,
P9_TAUTH = 102,
......@@ -95,30 +150,71 @@ enum {
P9_RWSTAT,
};
/* open modes */
enum {
/**
* enum p9_open_mode_t - 9P open modes
* @P9_OREAD: open file for reading only
* @P9_OWRITE: open file for writing only
* @P9_ORDWR: open file for reading or writing
* @P9_OEXEC: open file fo