]> Pileus Git - ~andy/linux/blobdiff - fs/9p/vfs_inode.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable
[~andy/linux] / fs / 9p / vfs_inode.c
index 68f02973c338823ae58437b16b6ce5049b1ace98..34bf71b56542dd739887968246c2764205b81722 100644 (file)
@@ -55,6 +55,10 @@ 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;
 
+static int
+v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode,
+                   dev_t rdev);
+
 /**
  * unixmode2p9mode - convert unix mode bits to plan 9
  * @v9ses: v9fs session information
@@ -560,13 +564,6 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
        return retval;
 }
 
-static int
-v9fs_open_created(struct inode *inode, struct file *file)
-{
-       return 0;
-}
-
-
 /**
  * v9fs_create - Create a file
  * @v9ses: session information
@@ -681,8 +678,14 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
        v9ses = v9fs_inode2v9ses(dir);
        if (nd && nd->flags & LOOKUP_OPEN)
                flags = nd->intent.open.flags - 1;
-       else
-               flags = O_RDWR;
+       else {
+               /*
+                * create call without LOOKUP_OPEN is due
+                * to mknod of regular files. So use mknod
+                * operation.
+                */
+               return v9fs_vfs_mknod_dotl(dir, dentry, omode, 0);
+       }
 
        name = (char *) dentry->d_name.name;
        P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_create_dotl: name:%s flags:0x%x "
@@ -765,7 +768,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
 
        /* 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);
+               filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
                if (IS_ERR(filp)) {
                        p9_client_clunk(ofid);
                        return PTR_ERR(filp);
@@ -824,7 +827,7 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
 
        /* 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);
+               filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
                if (IS_ERR(filp)) {
                        err = PTR_ERR(filp);
                        goto error;
@@ -1027,7 +1030,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
 
        result = v9fs_fid_add(dentry, fid);
        if (result < 0)
-               goto error;
+               goto error_iput;
 
 inst_out:
        if (v9ses->cache)
@@ -1038,6 +1041,8 @@ inst_out:
        d_add(dentry, inode);
        return NULL;
 
+error_iput:
+       iput(inode);
 error:
        p9_client_clunk(fid);
 
@@ -1527,7 +1532,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
        if (IS_ERR(fid))
                return PTR_ERR(fid);
 
-       if (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses))
+       if (!v9fs_proto_dotu(v9ses))
                return -EBADF;
 
        st = p9_client_stat(fid);
@@ -1995,6 +2000,60 @@ error:
        return err;
 }
 
+static int
+v9fs_vfs_readlink_dotl(struct dentry *dentry, char *buffer, int buflen)
+{
+       int retval;
+       struct p9_fid *fid;
+       char *target = NULL;
+
+       P9_DPRINTK(P9_DEBUG_VFS, " %s\n", dentry->d_name.name);
+       retval = -EPERM;
+       fid = v9fs_fid_lookup(dentry);
+       if (IS_ERR(fid))
+               return PTR_ERR(fid);
+
+       retval = p9_client_readlink(fid, &target);
+       if (retval < 0)
+               return retval;
+
+       strncpy(buffer, target, buflen);
+       P9_DPRINTK(P9_DEBUG_VFS, "%s -> %s\n", dentry->d_name.name, buffer);
+
+       retval = strnlen(buffer, buflen);
+       return retval;
+}
+
+/**
+ * v9fs_vfs_follow_link_dotl - follow a symlink path
+ * @dentry: dentry for symlink
+ * @nd: nameidata
+ *
+ */
+
+static void *
+v9fs_vfs_follow_link_dotl(struct dentry *dentry, struct nameidata *nd)
+{
+       int len = 0;
+       char *link = __getname();
+
+       P9_DPRINTK(P9_DEBUG_VFS, "%s n", dentry->d_name.name);
+
+       if (!link)
+               link = ERR_PTR(-ENOMEM);
+       else {
+               len = v9fs_vfs_readlink_dotl(dentry, link, PATH_MAX);
+               if (len < 0) {
+                       __putname(link);
+                       link = ERR_PTR(len);
+               } else
+                       link[min(len, PATH_MAX-1)] = 0;
+       }
+       nd_set_link(nd, link);
+
+       return NULL;
+}
+
 static const struct inode_operations v9fs_dir_inode_operations_dotu = {
        .create = v9fs_vfs_create,
        .lookup = v9fs_vfs_lookup,
@@ -2064,8 +2123,8 @@ static const struct inode_operations v9fs_symlink_inode_operations = {
 };
 
 static const struct inode_operations v9fs_symlink_inode_operations_dotl = {
-       .readlink = generic_readlink,
-       .follow_link = v9fs_vfs_follow_link,
+       .readlink = v9fs_vfs_readlink_dotl,
+       .follow_link = v9fs_vfs_follow_link_dotl,
        .put_link = v9fs_vfs_put_link,
        .getattr = v9fs_vfs_getattr_dotl,
        .setattr = v9fs_vfs_setattr_dotl,