Commit 5643135a authored by Venkateswararao Jujjuri (JV)'s avatar Venkateswararao Jujjuri (JV) Committed by Eric Van Hensbergen

fs/9p: This patch implements TLCREATE for 9p2000.L protocol.

SYNOPSIS

    size[4] Tlcreate tag[2] fid[4] name[s] flags[4] mode[4] gid[4]

    size[4] Rlcreate tag[2] qid[13] iounit[4]

DESCRIPTION

The Tlreate request asks the file server to create a new regular file with the
name supplied, in the directory (dir) represented by fid.
The mode argument specifies the permissions to use. New file is created with
the uid if the fid and with supplied gid.

The flags argument represent Linux access mode flags with which the caller
is requesting to open the file with. Protocol allows all the Linux access
modes but it is upto the server to allow/disallow any of these acess modes.
If the server doesn't support any of the access mode, it is expected to
return error.
Signed-off-by: default avatarVenkateswararao Jujjuri <jvrao@linux.vnet.ibm.com>
Signed-off-by: default avatarEric Van Hensbergen <ericvh@gmail.com>
parent 01a622bd
...@@ -641,6 +641,118 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, ...@@ -641,6 +641,118 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
return ERR_PTR(err); return ERR_PTR(err);
} }
/**
* v9fs_vfs_create_dotl - VFS hook to create files for 9P2000.L protocol.
* @dir: directory inode that is being created
* @dentry: dentry that is being deleted
* @mode: create permissions
* @nd: path information
*
*/
static int
v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode,
struct nameidata *nd)
{
int err = 0;
char *name = NULL;
gid_t gid;
int flags;
struct v9fs_session_info *v9ses;
struct p9_fid *fid = NULL;
struct p9_fid *dfid, *ofid;
struct file *filp;
struct p9_qid qid;
struct inode *inode;
v9ses = v9fs_inode2v9ses(dir);
if (nd && nd->flags & LOOKUP_OPEN)
flags = nd->intent.open.flags - 1;
else
flags = O_RDWR;
name = (char *) dentry->d_name.name;
P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_create_dotl: name:%s flags:0x%x "
"mode:0x%x\n", name, flags, mode);
dfid = v9fs_fid_lookup(dentry->d_parent);
if (IS_ERR(dfid)) {
err = PTR_ERR(dfid);
P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
return err;
}
/* clone a fid to use for creation */
ofid = p9_client_walk(dfid, 0, NULL, 1);
if (IS_ERR(ofid)) {
err = PTR_ERR(ofid);
P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
return err;
}
gid = v9fs_get_fsgid_for_create(dir);
err = p9_client_create_dotl(ofid, name, flags, mode, gid, &qid);
if (err < 0) {
P9_DPRINTK(P9_DEBUG_VFS,
"p9_client_open_dotl failed in creat %d\n",
err);
goto error;
}
/* No need to populate the inode if we are not opening the file AND
* not in cached mode.
*/
if (!v9ses->cache && !(nd && nd->flags & LOOKUP_OPEN)) {
/* Not in cached mode. No need to populate inode with stat */
dentry->d_op = &v9fs_dentry_operations;
p9_client_clunk(ofid);
d_instantiate(dentry, NULL);
return 0;
}
/* Now walk from the parent so we can get an unopened fid. */
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;
}
/* instantiate inode and assign the unopened fid to dentry */
inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err);
goto error;
}
dentry->d_op = &v9fs_cached_dentry_operations;
d_instantiate(dentry, inode);
err = v9fs_fid_add(dentry, fid);
if (err < 0)
goto error;
/* if we are opening a file, assign the open fid to the file */
if (nd && nd->flags & LOOKUP_OPEN) {
filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created);
if (IS_ERR(filp)) {
p9_client_clunk(ofid);
return PTR_ERR(filp);
}
filp->private_data = ofid;
} else
p9_client_clunk(ofid);
return 0;
error:
if (ofid)
p9_client_clunk(ofid);
if (fid)
p9_client_clunk(fid);
return err;
}
/** /**
* v9fs_vfs_create - VFS hook to create files * v9fs_vfs_create - VFS hook to create files
* @dir: directory inode that is being created * @dir: directory inode that is being created
...@@ -1808,7 +1920,7 @@ static const struct inode_operations v9fs_dir_inode_operations_dotu = { ...@@ -1808,7 +1920,7 @@ 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_dir_inode_operations_dotl = {
.create = v9fs_vfs_create, .create = v9fs_vfs_create_dotl,
.lookup = v9fs_vfs_lookup, .lookup = v9fs_vfs_lookup,
.link = v9fs_vfs_link_dotl, .link = v9fs_vfs_link_dotl,
.symlink = v9fs_vfs_symlink_dotl, .symlink = v9fs_vfs_symlink_dotl,
......
...@@ -92,6 +92,8 @@ do { \ ...@@ -92,6 +92,8 @@ do { \
* @P9_RSYMLINK: make symlink response * @P9_RSYMLINK: make symlink response
* @P9_TMKNOD: create a special file object request * @P9_TMKNOD: create a special file object request
* @P9_RMKNOD: create a special file object response * @P9_RMKNOD: create a special file object response
* @P9_TLCREATE: prepare a handle for I/O on an new file for 9P2000.L
* @P9_RLCREATE: response with file access information for 9P2000.L
* @P9_TRENAME: rename request * @P9_TRENAME: rename request
* @P9_RRENAME: rename response * @P9_RRENAME: rename response
* @P9_TMKDIR: create a directory request * @P9_TMKDIR: create a directory request
...@@ -137,6 +139,8 @@ do { \ ...@@ -137,6 +139,8 @@ do { \
enum p9_msg_t { enum p9_msg_t {
P9_TSTATFS = 8, P9_TSTATFS = 8,
P9_RSTATFS, P9_RSTATFS,
P9_TLCREATE = 14,
P9_RLCREATE,
P9_TSYMLINK = 16, P9_TSYMLINK = 16,
P9_RSYMLINK, P9_RSYMLINK,
P9_TMKNOD = 18, P9_TMKNOD = 18,
......
...@@ -229,6 +229,8 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, ...@@ -229,6 +229,8 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
int p9_client_link(struct p9_fid *fid, struct p9_fid *oldfid, char *newname); int p9_client_link(struct p9_fid *fid, struct p9_fid *oldfid, char *newname);
int p9_client_symlink(struct p9_fid *fid, char *name, char *symname, gid_t gid, int p9_client_symlink(struct p9_fid *fid, char *name, char *symname, gid_t gid,
struct p9_qid *qid); struct p9_qid *qid);
int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode,
gid_t gid, struct p9_qid *qid);
int p9_client_clunk(struct p9_fid *fid); int p9_client_clunk(struct p9_fid *fid);
int p9_client_remove(struct p9_fid *fid); int p9_client_remove(struct p9_fid *fid);
int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, int p9_client_read(struct p9_fid *fid, char *data, char __user *udata,
......
...@@ -1050,6 +1050,50 @@ int p9_client_open(struct p9_fid *fid, int mode) ...@@ -1050,6 +1050,50 @@ int p9_client_open(struct p9_fid *fid, int mode)
} }
EXPORT_SYMBOL(p9_client_open); EXPORT_SYMBOL(p9_client_open);
int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode,
gid_t gid, struct p9_qid *qid)
{
int err = 0;
struct p9_client *clnt;
struct p9_req_t *req;
int iounit;
P9_DPRINTK(P9_DEBUG_9P,
">>> TLCREATE fid %d name %s flags %d mode %d gid %d\n",
ofid->fid, name, flags, mode, gid);
clnt = ofid->clnt;
if (ofid->mode != -1)
return -EINVAL;
req = p9_client_rpc(clnt, P9_TLCREATE, "dsddd", ofid->fid, name, flags,
mode, gid);
if (IS_ERR(req)) {
err = PTR_ERR(req);
goto error;
}
err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", qid, &iounit);
if (err) {
p9pdu_dump(1, req->rc);
goto free_and_error;
}
P9_DPRINTK(P9_DEBUG_9P, "<<< RLCREATE qid %x.%llx.%x iounit %x\n",
qid->type,
(unsigned long long)qid->path,
qid->version, iounit);
ofid->mode = mode;
ofid->iounit = iounit;
free_and_error:
p9_free_req(clnt, req);
error:
return err;
}
EXPORT_SYMBOL(p9_client_create_dotl);
int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
char *extension) char *extension)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment