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

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs:
  9p: Optimize TCREATE by eliminating a redundant fid clone.
  9p: cleanup: remove unneeded assignment
  9p: Add mksock support
  fs/9p: Make sure we properly instantiate dentry.
  9p: add 9P2000.L rename operation
  9p: add 9P2000.L statfs operation
  9p: VFS switches for 9p2000.L: VFS switches
  9p: VFS switches for 9p2000.L: protocol and client changes
This commit is contained in:
Linus Torvalds 2010-05-24 07:41:13 -07:00
commit 4fd5ec509b
9 changed files with 261 additions and 33 deletions

View File

@ -40,7 +40,9 @@
extern struct file_system_type v9fs_fs_type;
extern const struct address_space_operations v9fs_addr_operations;
extern const struct file_operations v9fs_file_operations;
extern const struct file_operations v9fs_file_operations_dotl;
extern const struct file_operations v9fs_dir_operations;
extern const struct file_operations v9fs_dir_operations_dotl;
extern const struct dentry_operations v9fs_dentry_operations;
extern const struct dentry_operations v9fs_cached_dentry_operations;

View File

@ -203,3 +203,11 @@ const struct file_operations v9fs_dir_operations = {
.open = v9fs_file_open,
.release = v9fs_dir_release,
};
const struct file_operations v9fs_dir_operations_dotl = {
.read = generic_read_dir,
.llseek = generic_file_llseek,
.readdir = v9fs_dir_readdir,
.open = v9fs_file_open,
.release = v9fs_dir_release,
};

View File

@ -296,3 +296,14 @@ const struct file_operations v9fs_file_operations = {
.mmap = generic_file_readonly_mmap,
.fsync = v9fs_file_fsync,
};
const struct file_operations v9fs_file_operations_dotl = {
.llseek = generic_file_llseek,
.read = v9fs_file_read,
.write = v9fs_file_write,
.open = v9fs_file_open,
.release = v9fs_dir_release,
.lock = v9fs_file_lock,
.mmap = generic_file_readonly_mmap,
.fsync = v9fs_file_fsync,
};

View File

@ -44,9 +44,12 @@
#include "cache.h"
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_dir_inode_operations_dotu;
static const struct inode_operations v9fs_dir_inode_operations_dotl;
static const struct inode_operations v9fs_file_inode_operations;
static const struct inode_operations v9fs_file_inode_operations_dotl;
static const struct inode_operations v9fs_symlink_inode_operations;
static const struct inode_operations v9fs_symlink_inode_operations_dotl;
/**
* unixmode2p9mode - convert unix mode bits to plan 9
@ -273,25 +276,44 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
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;
if (v9fs_proto_dotl(v9ses)) {
inode->i_op = &v9fs_file_inode_operations_dotl;
inode->i_fop = &v9fs_file_operations_dotl;
} else {
inode->i_op = &v9fs_file_inode_operations;
inode->i_fop = &v9fs_file_operations;
}
break;
case S_IFLNK:
if (!v9fs_proto_dotu(v9ses)) {
P9_DPRINTK(P9_DEBUG_ERROR,
"extended modes used w/o 9P2000.u\n");
if (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)) {
P9_DPRINTK(P9_DEBUG_ERROR, "extended modes used with "
"legacy protocol.\n");
err = -EINVAL;
goto error;
}
inode->i_op = &v9fs_symlink_inode_operations;
if (v9fs_proto_dotl(v9ses))
inode->i_op = &v9fs_symlink_inode_operations_dotl;
else
inode->i_op = &v9fs_symlink_inode_operations;
break;
case S_IFDIR:
inc_nlink(inode);
if (v9fs_proto_dotu(v9ses))
inode->i_op = &v9fs_dir_inode_operations_ext;
if (v9fs_proto_dotl(v9ses))
inode->i_op = &v9fs_dir_inode_operations_dotl;
else if (v9fs_proto_dotu(v9ses))
inode->i_op = &v9fs_dir_inode_operations_dotu;
else
inode->i_op = &v9fs_dir_inode_operations;
inode->i_fop = &v9fs_dir_operations;
if (v9fs_proto_dotl(v9ses))
inode->i_fop = &v9fs_dir_operations_dotl;
else
inode->i_fop = &v9fs_dir_operations;
break;
default:
P9_DPRINTK(P9_DEBUG_ERROR, "BAD mode 0x%x S_IFMT 0x%x\n",
@ -432,14 +454,12 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
{
int retval;
struct inode *file_inode;
struct v9fs_session_info *v9ses;
struct p9_fid *v9fid;
P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file,
rmdir);
file_inode = file->d_inode;
v9ses = v9fs_inode2v9ses(file_inode);
v9fid = v9fs_fid_clone(file);
if (IS_ERR(v9fid))
return PTR_ERR(v9fid);
@ -482,12 +502,11 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
ofid = NULL;
fid = NULL;
name = (char *) dentry->d_name.name;
dfid = v9fs_fid_clone(dentry->d_parent);
dfid = v9fs_fid_lookup(dentry->d_parent);
if (IS_ERR(dfid)) {
err = PTR_ERR(dfid);
P9_DPRINTK(P9_DEBUG_VFS, "fid clone failed %d\n", err);
dfid = NULL;
goto error;
P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
return ERR_PTR(err);
}
/* clone a fid to use for creation */
@ -495,8 +514,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
if (IS_ERR(ofid)) {
err = PTR_ERR(ofid);
P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
ofid = NULL;
goto error;
return ERR_PTR(err);
}
err = p9_client_fcreate(ofid, name, perm, mode, extension);
@ -506,14 +524,13 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
}
/* now walk from the parent so we can get unopened fid */
fid = p9_client_walk(dfid, 1, &name, 0);
fid = p9_client_walk(dfid, 1, &name, 1);
if (IS_ERR(fid)) {
err = PTR_ERR(fid);
P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
fid = NULL;
goto error;
} else
dfid = NULL;
}
/* instantiate inode and assign the unopened fid to the dentry */
inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
@ -536,9 +553,6 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
return ofid;
error:
if (dfid)
p9_client_clunk(dfid);
if (ofid)
p9_client_clunk(ofid);
@ -673,8 +687,8 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
if (IS_ERR(fid)) {
result = PTR_ERR(fid);
if (result == -ENOENT) {
d_add(dentry, NULL);
return NULL;
inode = NULL;
goto inst_out;
}
return ERR_PTR(result);
@ -691,7 +705,8 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
if (result < 0)
goto error;
if ((fid->qid.version) && (v9ses->cache))
inst_out:
if (v9ses->cache)
dentry->d_op = &v9fs_cached_dentry_operations;
else
dentry->d_op = &v9fs_dentry_operations;
@ -770,6 +785,13 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
goto clunk_olddir;
}
if (v9fs_proto_dotl(v9ses)) {
retval = p9_client_rename(oldfid, newdirfid,
(char *) new_dentry->d_name.name);
if (retval != -ENOSYS)
goto clunk_newdir;
}
/* 9P can only handle file rename in the same directory */
if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) {
P9_DPRINTK(P9_DEBUG_ERROR,
@ -1195,6 +1217,8 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
sprintf(name, "c %u %u", MAJOR(rdev), MINOR(rdev));
else if (S_ISFIFO(mode))
*name = 0;
else if (S_ISSOCK(mode))
*name = 0;
else {
__putname(name);
return -EINVAL;
@ -1206,7 +1230,21 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
return retval;
}
static const struct inode_operations v9fs_dir_inode_operations_ext = {
static const struct inode_operations v9fs_dir_inode_operations_dotu = {
.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,
.getattr = v9fs_vfs_getattr,
.setattr = v9fs_vfs_setattr,
};
static const struct inode_operations v9fs_dir_inode_operations_dotl = {
.create = v9fs_vfs_create,
.lookup = v9fs_vfs_lookup,
.symlink = v9fs_vfs_symlink,
@ -1237,6 +1275,11 @@ static const struct inode_operations v9fs_file_inode_operations = {
.setattr = v9fs_vfs_setattr,
};
static const struct inode_operations v9fs_file_inode_operations_dotl = {
.getattr = v9fs_vfs_getattr,
.setattr = v9fs_vfs_setattr,
};
static const struct inode_operations v9fs_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = v9fs_vfs_follow_link,
@ -1244,3 +1287,11 @@ static const struct inode_operations v9fs_symlink_inode_operations = {
.getattr = v9fs_vfs_getattr,
.setattr = v9fs_vfs_setattr,
};
static const struct inode_operations v9fs_symlink_inode_operations_dotl = {
.readlink = generic_readlink,
.follow_link = v9fs_vfs_follow_link,
.put_link = v9fs_vfs_put_link,
.getattr = v9fs_vfs_getattr,
.setattr = v9fs_vfs_setattr,
};

View File

@ -38,6 +38,7 @@
#include <linux/idr.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/statfs.h>
#include <net/9p/9p.h>
#include <net/9p/client.h>
@ -45,7 +46,7 @@
#include "v9fs_vfs.h"
#include "fid.h"
static const struct super_operations v9fs_super_ops;
static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl;
/**
* v9fs_set_super - set the superblock
@ -76,7 +77,10 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
sb->s_blocksize_bits = fls(v9ses->maxdata - 1);
sb->s_blocksize = 1 << sb->s_blocksize_bits;
sb->s_magic = V9FS_MAGIC;
sb->s_op = &v9fs_super_ops;
if (v9fs_proto_dotl(v9ses))
sb->s_op = &v9fs_super_ops_dotl;
else
sb->s_op = &v9fs_super_ops;
sb->s_bdi = &v9ses->bdi;
sb->s_flags = flags | MS_ACTIVE | MS_SYNCHRONOUS | MS_DIRSYNC |
@ -211,6 +215,42 @@ v9fs_umount_begin(struct super_block *sb)
v9fs_session_begin_cancel(v9ses);
}
static int v9fs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct v9fs_session_info *v9ses;
struct p9_fid *fid;
struct p9_rstatfs rs;
int res;
fid = v9fs_fid_lookup(dentry);
if (IS_ERR(fid)) {
res = PTR_ERR(fid);
goto done;
}
v9ses = v9fs_inode2v9ses(dentry->d_inode);
if (v9fs_proto_dotl(v9ses)) {
res = p9_client_statfs(fid, &rs);
if (res == 0) {
buf->f_type = rs.type;
buf->f_bsize = rs.bsize;
buf->f_blocks = rs.blocks;
buf->f_bfree = rs.bfree;
buf->f_bavail = rs.bavail;
buf->f_files = rs.files;
buf->f_ffree = rs.ffree;
buf->f_fsid.val[0] = rs.fsid & 0xFFFFFFFFUL;
buf->f_fsid.val[1] = (rs.fsid >> 32) & 0xFFFFFFFFUL;
buf->f_namelen = rs.namelen;
}
if (res != -ENOSYS)
goto done;
}
res = simple_statfs(dentry, buf);
done:
return res;
}
static const struct super_operations v9fs_super_ops = {
#ifdef CONFIG_9P_FSCACHE
.alloc_inode = v9fs_alloc_inode,
@ -222,6 +262,17 @@ static const struct super_operations v9fs_super_ops = {
.umount_begin = v9fs_umount_begin,
};
static const struct super_operations v9fs_super_ops_dotl = {
#ifdef CONFIG_9P_FSCACHE
.alloc_inode = v9fs_alloc_inode,
.destroy_inode = v9fs_destroy_inode,
#endif
.statfs = v9fs_statfs,
.clear_inode = v9fs_clear_inode,
.show_options = generic_show_options,
.umount_begin = v9fs_umount_begin,
};
struct file_system_type v9fs_fs_type = {
.name = "9p",
.get_sb = v9fs_get_sb,

View File

@ -86,6 +86,10 @@ do { \
/**
* enum p9_msg_t - 9P message types
* @P9_TSTATFS: file system status request
* @P9_RSTATFS: file system status response
* @P9_TRENAME: rename request
* @P9_RRENAME: rename response
* @P9_TVERSION: version handshake request
* @P9_RVERSION: version handshake response
* @P9_TAUTH: request to establish authentication channel
@ -125,6 +129,10 @@ do { \
*/
enum p9_msg_t {
P9_TSTATFS = 8,
P9_RSTATFS,
P9_TRENAME = 20,
P9_RRENAME,
P9_TVERSION = 100,
P9_RVERSION,
P9_TAUTH = 102,
@ -350,6 +358,31 @@ struct p9_wstat {
};
/* Structures for Protocol Operations */
struct p9_tstatfs {
u32 fid;
};
struct p9_rstatfs {
u32 type;
u32 bsize;
u64 blocks;
u64 bfree;
u64 bavail;
u64 files;
u64 ffree;
u64 fsid;
u32 namelen;
};
struct p9_trename {
u32 fid;
u32 newdirfid;
struct p9_str name;
};
struct p9_rrename {
};
struct p9_tversion {
u32 msize;
struct p9_str version;

View File

@ -195,6 +195,8 @@ struct p9_fid {
struct list_head dlist; /* list of all fids attached to a dentry */
};
int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb);
int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, char *name);
int p9_client_version(struct p9_client *);
struct p9_client *p9_client_create(const char *dev_name, char *options);
void p9_client_destroy(struct p9_client *clnt);

View File

@ -1321,7 +1321,8 @@ static int p9_client_statsize(struct p9_wstat *wst, int proto_version)
if (wst->muid)
ret += strlen(wst->muid);
if (proto_version == p9_proto_2000u) {
if ((proto_version == p9_proto_2000u) ||
(proto_version == p9_proto_2000L)) {
ret += 2+4+4+4; /* extension[s] n_uid[4] n_gid[4] n_muid[4] */
if (wst->extension)
ret += strlen(wst->extension);
@ -1364,3 +1365,70 @@ int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
return err;
}
EXPORT_SYMBOL(p9_client_wstat);
int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb)
{
int err;
struct p9_req_t *req;
struct p9_client *clnt;
err = 0;
clnt = fid->clnt;
P9_DPRINTK(P9_DEBUG_9P, ">>> TSTATFS fid %d\n", fid->fid);
req = p9_client_rpc(clnt, P9_TSTATFS, "d", fid->fid);
if (IS_ERR(req)) {
err = PTR_ERR(req);
goto error;
}
err = p9pdu_readf(req->rc, clnt->proto_version, "ddqqqqqqd", &sb->type,
&sb->bsize, &sb->blocks, &sb->bfree, &sb->bavail,
&sb->files, &sb->ffree, &sb->fsid, &sb->namelen);
if (err) {
p9pdu_dump(1, req->rc);
p9_free_req(clnt, req);
goto error;
}
P9_DPRINTK(P9_DEBUG_9P, "<<< RSTATFS fid %d type 0x%lx bsize %ld "
"blocks %llu bfree %llu bavail %llu files %llu ffree %llu "
"fsid %llu namelen %ld\n",
fid->fid, (long unsigned int)sb->type, (long int)sb->bsize,
sb->blocks, sb->bfree, sb->bavail, sb->files, sb->ffree,
sb->fsid, (long int)sb->namelen);
p9_free_req(clnt, req);
error:
return err;
}
EXPORT_SYMBOL(p9_client_statfs);
int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, char *name)
{
int err;
struct p9_req_t *req;
struct p9_client *clnt;
err = 0;
clnt = fid->clnt;
P9_DPRINTK(P9_DEBUG_9P, ">>> TRENAME fid %d newdirfid %d name %s\n",
fid->fid, newdirfid->fid, name);
req = p9_client_rpc(clnt, P9_TRENAME, "dds", fid->fid,
newdirfid->fid, name);
if (IS_ERR(req)) {
err = PTR_ERR(req);
goto error;
}
P9_DPRINTK(P9_DEBUG_9P, "<<< RRENAME fid %d\n", fid->fid);
p9_free_req(clnt, req);
error:
return err;
}
EXPORT_SYMBOL(p9_client_rename);

View File

@ -341,7 +341,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
}
break;
case '?':
if (proto_version != p9_proto_2000u)
if ((proto_version != p9_proto_2000u) &&
(proto_version != p9_proto_2000L))
return 0;
break;
default:
@ -488,7 +489,8 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
}
break;
case '?':
if (proto_version != p9_proto_2000u)
if ((proto_version != p9_proto_2000u) &&
(proto_version != p9_proto_2000L))
return 0;
break;
default: