9p: Implement TMKNOD
M. Mohan Kumar [Wed, 16 Jun 2010 08:57:01 +0000 (13:57 +0530)]
Synopsis

    size[4] Tmknod tag[2] fid[4] name[s] mode[4] major[4] minor[4] gid[4]

    size[4] Rmknod tag[2] qid[13]

Description

    mknod asks the file server to create a device node with given major and
    minor number, mode and gid. The qid for the new device node is returned
    with the mknod reply message.

[sripathik@in.ibm.com: Fix error handling code]

Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
Signed-off-by: Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com>
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>

fs/9p/vfs_inode.c
include/net/9p/9p.h
include/net/9p/client.h
net/9p/client.c

index a731936..4d9f45e 100644 (file)
@@ -302,7 +302,13 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
        case S_IFBLK:
        case S_IFCHR:
        case S_IFSOCK:
-               if (!v9fs_proto_dotu(v9ses)) {
+               if (v9fs_proto_dotl(v9ses)) {
+                       inode->i_op = &v9fs_file_inode_operations_dotl;
+                       inode->i_fop = &v9fs_file_operations_dotl;
+               } else if (v9fs_proto_dotu(v9ses)) {
+                       inode->i_op = &v9fs_file_inode_operations;
+                       inode->i_fop = &v9fs_file_operations;
+               } else {
                        P9_DPRINTK(P9_DEBUG_ERROR,
                                   "special files without extended mode\n");
                        err = -EINVAL;
@@ -1616,6 +1622,100 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
        return retval;
 }
 
+/**
+ * v9fs_vfs_mknod_dotl - create a special file
+ * @dir: inode destination for new link
+ * @dentry: dentry for file
+ * @mode: mode for creation
+ * @rdev: device associated with special file
+ *
+ */
+static int
+v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int mode,
+               dev_t rdev)
+{
+       int err;
+       char *name;
+       struct v9fs_session_info *v9ses;
+       struct p9_fid *fid = NULL, *dfid = NULL;
+       struct inode *inode;
+       gid_t gid;
+       struct p9_qid qid;
+       struct dentry *dir_entry;
+
+       P9_DPRINTK(P9_DEBUG_VFS,
+               " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino,
+               dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev));
+
+       if (!new_valid_dev(rdev))
+               return -EINVAL;
+
+       v9ses = v9fs_inode2v9ses(dir);
+       dir_dentry = v9fs_dentry_from_dir_inode(dir);
+       dfid = v9fs_fid_lookup(dir_entry);
+       if (IS_ERR(dfid)) {
+               err = PTR_ERR(dfid);
+               P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
+               dfid = NULL;
+               goto error;
+       }
+
+       gid = v9fs_get_fsgid_for_create(dir);
+       if (gid < 0) {
+               P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_fsgid_for_create failed\n");
+               goto error;
+       }
+
+       name = (char *) dentry->d_name.name;
+
+       err = p9_client_mknod_dotl(dfid, name, mode, rdev, gid, &qid);
+       if (err < 0)
+               goto error;
+
+       /* instantiate inode and assign the unopened fid to the dentry */
+       if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
+               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;
+               }
+
+               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;
+               fid = NULL;
+       } else {
+               /*
+                * Not in cached mode. No need to populate inode with stat.
+                * socket syscall returns a fd, so we need instantiate
+                */
+               inode = v9fs_get_inode(dir->i_sb, mode);
+               if (IS_ERR(inode)) {
+                       err = PTR_ERR(inode);
+                       goto error;
+               }
+               dentry->d_op = &v9fs_dentry_operations;
+               d_instantiate(dentry, inode);
+       }
+
+error:
+       if (fid)
+               p9_client_clunk(fid);
+       return err;
+}
+
 static const struct inode_operations v9fs_dir_inode_operations_dotu = {
        .create = v9fs_vfs_create,
        .lookup = v9fs_vfs_lookup,
@@ -1624,7 +1724,7 @@ static const struct inode_operations v9fs_dir_inode_operations_dotu = {
        .unlink = v9fs_vfs_unlink,
        .mkdir = v9fs_vfs_mkdir,
        .rmdir = v9fs_vfs_rmdir,
-       .mknod = v9fs_vfs_mknod,
+       .mknod = v9fs_vfs_mknod_dotl,
        .rename = v9fs_vfs_rename,
        .getattr = v9fs_vfs_getattr,
        .setattr = v9fs_vfs_setattr,
@@ -1638,7 +1738,7 @@ static const struct inode_operations v9fs_dir_inode_operations_dotl = {
        .unlink = v9fs_vfs_unlink,
        .mkdir = v9fs_vfs_mkdir,
        .rmdir = v9fs_vfs_rmdir,
-       .mknod = v9fs_vfs_mknod,
+       .mknod = v9fs_vfs_mknod_dotl,
        .rename = v9fs_vfs_rename,
        .getattr = v9fs_vfs_getattr_dotl,
        .setattr = v9fs_vfs_setattr_dotl,
index 44a6883..ff32091 100644 (file)
@@ -90,6 +90,8 @@ do { \
  * @P9_RSTATFS: file system status response
  * @P9_TSYMLINK: make symlink request
  * @P9_RSYMLINK: make symlink response
+ * @P9_TMKNOD: create a special file object request
+ * @P9_RMKNOD: create a special file object response
  * @P9_TRENAME: rename request
  * @P9_RRENAME: rename response
  * @P9_TVERSION: version handshake request
@@ -135,6 +137,8 @@ enum p9_msg_t {
        P9_RSTATFS,
        P9_TSYMLINK = 16,
        P9_RSYMLINK,
+       P9_TMKNOD = 18,
+       P9_RMKNOD,
        P9_TRENAME = 20,
        P9_RRENAME,
        P9_TGETATTR = 24,
index 2e03973..6e70358 100644 (file)
@@ -245,6 +245,8 @@ int p9_client_setattr(struct p9_fid *fid, struct p9_iattr_dotl *attr);
 struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid,
                                                        u64 request_mask);
 
+int p9_client_mknod_dotl(struct p9_fid *oldfid, char *name, int mode,
+                       dev_t rdev, gid_t gid, struct p9_qid *);
 struct p9_req_t *p9_tag_lookup(struct p9_client *, u16);
 void p9_client_cb(struct p9_client *c, struct p9_req_t *req);
 
index e37e64c..cdfbd67 100644 (file)
@@ -1622,3 +1622,34 @@ error:
        return err;
 }
 EXPORT_SYMBOL(p9_client_readdir);
+
+int p9_client_mknod_dotl(struct p9_fid *fid, char *name, int mode,
+                       dev_t rdev, gid_t gid, struct p9_qid *qid)
+{
+       int err;
+       struct p9_client *clnt;
+       struct p9_req_t *req;
+
+       err = 0;
+       clnt = fid->clnt;
+       P9_DPRINTK(P9_DEBUG_9P, ">>> TMKNOD fid %d name %s mode %d major %d "
+               "minor %d\n", fid->fid, name, mode, MAJOR(rdev), MINOR(rdev));
+       req = p9_client_rpc(clnt, P9_TMKNOD, "dsdddd", fid->fid, name, mode,
+               MAJOR(rdev), MINOR(rdev), gid);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid);
+       if (err) {
+               p9pdu_dump(1, req->rc);
+               goto error;
+       }
+       P9_DPRINTK(P9_DEBUG_9P, "<<< RMKNOD qid %x.%llx.%x\n", qid->type,
+                               (unsigned long long)qid->path, qid->version);
+
+error:
+       p9_free_req(clnt, req);
+       return err;
+
+}
+EXPORT_SYMBOL(p9_client_mknod_dotl);