Merge branch 'vhost-net-next' of git://git.kernel.org/pub/scm/linux/kernel/git/mst...
[pandora-kernel.git] / fs / 9p / vfs_inode_dotl.c
index fe3ffa9..67c138e 100644 (file)
@@ -86,40 +86,63 @@ static struct dentry *v9fs_dentry_from_dir_inode(struct inode *inode)
        return dentry;
 }
 
+static struct inode *v9fs_qid_iget_dotl(struct super_block *sb,
+                                       struct p9_qid *qid,
+                                       struct p9_fid *fid,
+                                       struct p9_stat_dotl *st)
+{
+       int retval;
+       unsigned long i_ino;
+       struct inode *inode;
+       struct v9fs_session_info *v9ses = sb->s_fs_info;
+
+       i_ino = v9fs_qid2ino(qid);
+       inode = iget_locked(sb, i_ino);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+       if (!(inode->i_state & I_NEW))
+               return inode;
+       /*
+        * initialize the inode with the stat info
+        * FIXME!! we may need support for stale inodes
+        * later.
+        */
+       retval = v9fs_init_inode(v9ses, inode, st->st_mode);
+       if (retval)
+               goto error;
+
+       v9fs_stat2inode_dotl(st, inode);
+#ifdef CONFIG_9P_FSCACHE
+       v9fs_fscache_set_key(inode, &st->qid);
+       v9fs_cache_inode_get_cookie(inode);
+#endif
+       retval = v9fs_get_acl(inode, fid);
+       if (retval)
+               goto error;
+
+       unlock_new_inode(inode);
+       return inode;
+error:
+       unlock_new_inode(inode);
+       iput(inode);
+       return ERR_PTR(retval);
+
+}
+
 struct inode *
-v9fs_inode_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid,
-       struct super_block *sb)
+v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid,
+                        struct super_block *sb)
 {
-       struct inode *ret = NULL;
-       int err;
        struct p9_stat_dotl *st;
+       struct inode *inode = NULL;
 
        st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
        if (IS_ERR(st))
                return ERR_CAST(st);
 
-       ret = v9fs_get_inode(sb, st->st_mode);
-       if (IS_ERR(ret)) {
-               err = PTR_ERR(ret);
-               goto error;
-       }
-
-       v9fs_stat2inode_dotl(st, ret);
-       ret->i_ino = v9fs_qid2ino(&st->qid);
-#ifdef CONFIG_9P_FSCACHE
-       v9fs_vcookie_set_qid(ret, &st->qid);
-       v9fs_cache_inode_get_cookie(ret);
-#endif
-       err = v9fs_get_acl(ret, fid);
-       if (err) {
-               iput(ret);
-               goto error;
-       }
-       kfree(st);
-       return ret;
-error:
+       inode = v9fs_qid_iget_dotl(sb, &st->qid, fid, st);
        kfree(st);
-       return ERR_PTR(err);
+       return inode;
 }
 
 /**
@@ -136,16 +159,17 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
                struct nameidata *nd)
 {
        int err = 0;
-       char *name = NULL;
        gid_t gid;
        int flags;
        mode_t mode;
-       struct v9fs_session_info *v9ses;
-       struct p9_fid *fid = NULL;
-       struct p9_fid *dfid, *ofid;
+       char *name = NULL;
        struct file *filp;
        struct p9_qid qid;
        struct inode *inode;
+       struct p9_fid *fid = NULL;
+       struct v9fs_inode *v9inode;
+       struct p9_fid *dfid, *ofid, *inode_fid;
+       struct v9fs_session_info *v9ses;
        struct posix_acl *pacl = NULL, *dacl = NULL;
 
        v9ses = v9fs_inode2v9ses(dir);
@@ -196,6 +220,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
                                err);
                goto error;
        }
+       v9fs_invalidate_inode_attr(dir);
 
        /* instantiate inode and assign the unopened fid to the dentry */
        fid = p9_client_walk(dfid, 1, &name, 1);
@@ -205,7 +230,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
                fid = NULL;
                goto error;
        }
-       inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
+       inode = v9fs_get_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);
@@ -219,6 +244,22 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
        /* Now set the ACL based on the default value */
        v9fs_set_create_acl(dentry, dacl, pacl);
 
+       v9inode = V9FS_I(inode);
+       if (v9ses->cache && !v9inode->writeback_fid) {
+               /*
+                * clone a fid and add it to writeback_fid
+                * we do it during open time instead of
+                * page dirty time via write_begin/page_mkwrite
+                * because we want write after unlink usecase
+                * to work.
+                */
+               inode_fid = v9fs_writeback_fid(dentry);
+               if (IS_ERR(inode_fid)) {
+                       err = PTR_ERR(inode_fid);
+                       goto error;
+               }
+               v9inode->writeback_fid = (void *) inode_fid;
+       }
        /* Since we are opening a file, assign the open fid to the file */
        filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
        if (IS_ERR(filp)) {
@@ -226,6 +267,10 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
                return PTR_ERR(filp);
        }
        filp->private_data = ofid;
+#ifdef CONFIG_9P_FSCACHE
+       if (v9ses->cache)
+               v9fs_cache_inode_set_cookie(inode, filp);
+#endif
        return 0;
 
 error:
@@ -300,7 +345,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
                        goto error;
                }
 
-               inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
+               inode = v9fs_get_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",
@@ -327,7 +372,8 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
        }
        /* Now set the ACL based on the default value */
        v9fs_set_create_acl(dentry, dacl, pacl);
-
+       inc_nlink(dir);
+       v9fs_invalidate_inode_attr(dir);
 error:
        if (fid)
                p9_client_clunk(fid);
@@ -346,9 +392,10 @@ v9fs_vfs_getattr_dotl(struct vfsmount *mnt, struct dentry *dentry,
        P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry);
        err = -EPERM;
        v9ses = v9fs_inode2v9ses(dentry->d_inode);
-       if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
-               return simple_getattr(mnt, dentry, stat);
-
+       if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
+               generic_fillattr(dentry->d_inode, stat);
+               return 0;
+       }
        fid = v9fs_fid_lookup(dentry);
        if (IS_ERR(fid))
                return PTR_ERR(fid);
@@ -406,16 +453,20 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
        if (IS_ERR(fid))
                return PTR_ERR(fid);
 
-       retval = p9_client_setattr(fid, &p9attr);
-       if (retval < 0)
-               return retval;
-
        if ((iattr->ia_valid & ATTR_SIZE) &&
            iattr->ia_size != i_size_read(dentry->d_inode)) {
                retval = vmtruncate(dentry->d_inode, iattr->ia_size);
                if (retval)
                        return retval;
        }
+       /* Write all dirty data */
+       if (S_ISREG(dentry->d_inode->i_mode))
+               filemap_write_and_wait(dentry->d_inode->i_mapping);
+
+       retval = p9_client_setattr(fid, &p9attr);
+       if (retval < 0)
+               return retval;
+       v9fs_invalidate_inode_attr(dentry->d_inode);
 
        setattr_copy(dentry->d_inode, iattr);
        mark_inode_dirty(dentry->d_inode);
@@ -439,6 +490,7 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
 void
 v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)
 {
+       struct v9fs_inode *v9inode = V9FS_I(inode);
 
        if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) {
                inode->i_atime.tv_sec = stat->st_atime_sec;
@@ -497,20 +549,21 @@ v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)
        /* Currently we don't support P9_STATS_BTIME and P9_STATS_DATA_VERSION
         * because the inode structure does not have fields for them.
         */
+       v9inode->cache_validity &= ~V9FS_INO_INVALID_ATTR;
 }
 
 static int
 v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
                const char *symname)
 {
-       struct v9fs_session_info *v9ses;
-       struct p9_fid *dfid;
-       struct p9_fid *fid = NULL;
-       struct inode *inode;
-       struct p9_qid qid;
-       char *name;
        int err;
        gid_t gid;
+       char *name;
+       struct p9_qid qid;
+       struct inode *inode;
+       struct p9_fid *dfid;
+       struct p9_fid *fid = NULL;
+       struct v9fs_session_info *v9ses;
 
        name = (char *) dentry->d_name.name;
        P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_symlink_dotl : %lu,%s,%s\n",
@@ -534,6 +587,7 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
                goto error;
        }
 
+       v9fs_invalidate_inode_attr(dir);
        if (v9ses->cache) {
                /* Now walk from the parent so we can get an unopened fid. */
                fid = p9_client_walk(dfid, 1, &name, 1);
@@ -546,7 +600,7 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
                }
 
                /* instantiate inode and assign the unopened fid to dentry */
-               inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
+               inode = v9fs_get_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",
@@ -588,10 +642,10 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
                struct dentry *dentry)
 {
        int err;
-       struct p9_fid *dfid, *oldfid;
        char *name;
-       struct v9fs_session_info *v9ses;
        struct dentry *dir_dentry;
+       struct p9_fid *dfid, *oldfid;
+       struct v9fs_session_info *v9ses;
 
        P9_DPRINTK(P9_DEBUG_VFS, "dir ino: %lu, old_name: %s, new_name: %s\n",
                        dir->i_ino, old_dentry->d_name.name,
@@ -616,29 +670,17 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
                return err;
        }
 
+       v9fs_invalidate_inode_attr(dir);
        if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
                /* Get the latest stat info from server. */
                struct p9_fid *fid;
-               struct p9_stat_dotl *st;
-
                fid = v9fs_fid_lookup(old_dentry);
                if (IS_ERR(fid))
                        return PTR_ERR(fid);
 
-               st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
-               if (IS_ERR(st))
-                       return PTR_ERR(st);
-
-               v9fs_stat2inode_dotl(st, old_dentry->d_inode);
-
-               kfree(st);
-       } else {
-               /* Caching disabled. No need to get upto date stat info.
-                * This dentry will be released immediately. So, just hold the
-                * inode
-                */
-               ihold(old_dentry->d_inode);
+               v9fs_refresh_inode_dotl(fid, old_dentry->d_inode);
        }
+       ihold(old_dentry->d_inode);
        d_instantiate(dentry, old_dentry->d_inode);
 
        return err;
@@ -657,12 +699,12 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode,
                dev_t rdev)
 {
        int err;
+       gid_t gid;
        char *name;
        mode_t mode;
        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_dentry;
        struct posix_acl *dacl = NULL, *pacl = NULL;
@@ -699,6 +741,7 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode,
        if (err < 0)
                goto error;
 
+       v9fs_invalidate_inode_attr(dir);
        /* 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);
@@ -710,7 +753,7 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode,
                        goto error;
                }
 
-               inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
+               inode = v9fs_get_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",
@@ -782,6 +825,31 @@ ndset:
        return NULL;
 }
 
+int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)
+{
+       loff_t i_size;
+       struct p9_stat_dotl *st;
+       struct v9fs_session_info *v9ses;
+
+       v9ses = v9fs_inode2v9ses(inode);
+       st = p9_client_getattr_dotl(fid, P9_STATS_ALL);
+       if (IS_ERR(st))
+               return PTR_ERR(st);
+
+       spin_lock(&inode->i_lock);
+       /*
+        * We don't want to refresh inode->i_size,
+        * because we may have cached data
+        */
+       i_size = inode->i_size;
+       v9fs_stat2inode_dotl(st, inode);
+       if (v9ses->cache)
+               inode->i_size = i_size;
+       spin_unlock(&inode->i_lock);
+       kfree(st);
+       return 0;
+}
+
 const struct inode_operations v9fs_dir_inode_operations_dotl = {
        .create = v9fs_vfs_create_dotl,
        .lookup = v9fs_vfs_lookup,