Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh...
[pandora-kernel.git] / fs / 9p / vfs_inode.c
index f2434fc..4331b3b 100644 (file)
 #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
@@ -253,9 +256,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
                return ERR_PTR(-ENOMEM);
        }
 
-       inode->i_mode = mode;
-       inode->i_uid = current_fsuid();
-       inode->i_gid = current_fsgid();
+       inode_init_owner(inode, NULL, mode);
        inode->i_blocks = 0;
        inode->i_rdev = 0;
        inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
@@ -275,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",
@@ -434,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);
@@ -484,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 */
@@ -497,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);
@@ -508,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);
@@ -538,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);
 
@@ -675,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);
@@ -693,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;
@@ -772,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,
@@ -1197,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;
@@ -1208,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,
@@ -1239,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,
@@ -1246,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,
+};