|
@@ -203,26 +203,25 @@ v9fs_blank_wstat(struct p9_wstat *wstat)
|
|
|
wstat->extension = NULL;
|
|
|
}
|
|
|
|
|
|
-#ifdef CONFIG_9P_FSCACHE
|
|
|
/**
|
|
|
* v9fs_alloc_inode - helper function to allocate an inode
|
|
|
- * This callback is executed before setting up the inode so that we
|
|
|
- * can associate a vcookie with each inode.
|
|
|
*
|
|
|
*/
|
|
|
-
|
|
|
struct inode *v9fs_alloc_inode(struct super_block *sb)
|
|
|
{
|
|
|
- struct v9fs_cookie *vcookie;
|
|
|
- vcookie = (struct v9fs_cookie *)kmem_cache_alloc(vcookie_cache,
|
|
|
- GFP_KERNEL);
|
|
|
- if (!vcookie)
|
|
|
+ struct v9fs_inode *v9inode;
|
|
|
+ v9inode = (struct v9fs_inode *)kmem_cache_alloc(v9fs_inode_cache,
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!v9inode)
|
|
|
return NULL;
|
|
|
-
|
|
|
- vcookie->fscache = NULL;
|
|
|
- vcookie->qid = NULL;
|
|
|
- spin_lock_init(&vcookie->lock);
|
|
|
- return &vcookie->inode;
|
|
|
+#ifdef CONFIG_9P_FSCACHE
|
|
|
+ v9inode->fscache = NULL;
|
|
|
+ v9inode->fscache_key = NULL;
|
|
|
+ spin_lock_init(&v9inode->fscache_lock);
|
|
|
+#endif
|
|
|
+ v9inode->writeback_fid = NULL;
|
|
|
+ v9inode->cache_validity = 0;
|
|
|
+ return &v9inode->vfs_inode;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -234,35 +233,18 @@ static void v9fs_i_callback(struct rcu_head *head)
|
|
|
{
|
|
|
struct inode *inode = container_of(head, struct inode, i_rcu);
|
|
|
INIT_LIST_HEAD(&inode->i_dentry);
|
|
|
- kmem_cache_free(vcookie_cache, v9fs_inode2cookie(inode));
|
|
|
+ kmem_cache_free(v9fs_inode_cache, V9FS_I(inode));
|
|
|
}
|
|
|
|
|
|
void v9fs_destroy_inode(struct inode *inode)
|
|
|
{
|
|
|
call_rcu(&inode->i_rcu, v9fs_i_callback);
|
|
|
}
|
|
|
-#endif
|
|
|
|
|
|
-/**
|
|
|
- * v9fs_get_inode - helper function to setup an inode
|
|
|
- * @sb: superblock
|
|
|
- * @mode: mode to setup inode with
|
|
|
- *
|
|
|
- */
|
|
|
-
|
|
|
-struct inode *v9fs_get_inode(struct super_block *sb, int mode)
|
|
|
+int v9fs_init_inode(struct v9fs_session_info *v9ses,
|
|
|
+ struct inode *inode, int mode)
|
|
|
{
|
|
|
- int err;
|
|
|
- struct inode *inode;
|
|
|
- struct v9fs_session_info *v9ses = sb->s_fs_info;
|
|
|
-
|
|
|
- P9_DPRINTK(P9_DEBUG_VFS, "super block: %p mode: %o\n", sb, mode);
|
|
|
-
|
|
|
- inode = new_inode(sb);
|
|
|
- if (!inode) {
|
|
|
- P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n");
|
|
|
- return ERR_PTR(-ENOMEM);
|
|
|
- }
|
|
|
+ int err = 0;
|
|
|
|
|
|
inode_init_owner(inode, NULL, mode);
|
|
|
inode->i_blocks = 0;
|
|
@@ -292,14 +274,20 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
|
|
|
case S_IFREG:
|
|
|
if (v9fs_proto_dotl(v9ses)) {
|
|
|
inode->i_op = &v9fs_file_inode_operations_dotl;
|
|
|
- inode->i_fop = &v9fs_file_operations_dotl;
|
|
|
+ if (v9ses->cache)
|
|
|
+ inode->i_fop =
|
|
|
+ &v9fs_cached_file_operations_dotl;
|
|
|
+ else
|
|
|
+ inode->i_fop = &v9fs_file_operations_dotl;
|
|
|
} else {
|
|
|
inode->i_op = &v9fs_file_inode_operations;
|
|
|
- inode->i_fop = &v9fs_file_operations;
|
|
|
+ if (v9ses->cache)
|
|
|
+ inode->i_fop = &v9fs_cached_file_operations;
|
|
|
+ else
|
|
|
+ inode->i_fop = &v9fs_file_operations;
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
-
|
|
|
case S_IFLNK:
|
|
|
if (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)) {
|
|
|
P9_DPRINTK(P9_DEBUG_ERROR, "extended modes used with "
|
|
@@ -335,12 +323,37 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
|
|
|
err = -EINVAL;
|
|
|
goto error;
|
|
|
}
|
|
|
+error:
|
|
|
+ return err;
|
|
|
|
|
|
- return inode;
|
|
|
+}
|
|
|
|
|
|
-error:
|
|
|
- iput(inode);
|
|
|
- return ERR_PTR(err);
|
|
|
+/**
|
|
|
+ * v9fs_get_inode - helper function to setup an inode
|
|
|
+ * @sb: superblock
|
|
|
+ * @mode: mode to setup inode with
|
|
|
+ *
|
|
|
+ */
|
|
|
+
|
|
|
+struct inode *v9fs_get_inode(struct super_block *sb, int mode)
|
|
|
+{
|
|
|
+ int err;
|
|
|
+ struct inode *inode;
|
|
|
+ struct v9fs_session_info *v9ses = sb->s_fs_info;
|
|
|
+
|
|
|
+ P9_DPRINTK(P9_DEBUG_VFS, "super block: %p mode: %o\n", sb, mode);
|
|
|
+
|
|
|
+ inode = new_inode(sb);
|
|
|
+ if (!inode) {
|
|
|
+ P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n");
|
|
|
+ return ERR_PTR(-ENOMEM);
|
|
|
+ }
|
|
|
+ err = v9fs_init_inode(v9ses, inode, mode);
|
|
|
+ if (err) {
|
|
|
+ iput(inode);
|
|
|
+ return ERR_PTR(err);
|
|
|
+ }
|
|
|
+ return inode;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -403,6 +416,8 @@ error:
|
|
|
*/
|
|
|
void v9fs_evict_inode(struct inode *inode)
|
|
|
{
|
|
|
+ struct v9fs_inode *v9inode = V9FS_I(inode);
|
|
|
+
|
|
|
truncate_inode_pages(inode->i_mapping, 0);
|
|
|
end_writeback(inode);
|
|
|
filemap_fdatawrite(inode->i_mapping);
|
|
@@ -410,41 +425,67 @@ void v9fs_evict_inode(struct inode *inode)
|
|
|
#ifdef CONFIG_9P_FSCACHE
|
|
|
v9fs_cache_inode_put_cookie(inode);
|
|
|
#endif
|
|
|
+ /* clunk the fid stashed in writeback_fid */
|
|
|
+ if (v9inode->writeback_fid) {
|
|
|
+ p9_client_clunk(v9inode->writeback_fid);
|
|
|
+ v9inode->writeback_fid = NULL;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-struct inode *
|
|
|
-v9fs_inode(struct v9fs_session_info *v9ses, struct p9_fid *fid,
|
|
|
- struct super_block *sb)
|
|
|
+static struct inode *v9fs_qid_iget(struct super_block *sb,
|
|
|
+ struct p9_qid *qid,
|
|
|
+ struct p9_wstat *st)
|
|
|
{
|
|
|
- int err, umode;
|
|
|
- struct inode *ret = NULL;
|
|
|
- struct p9_wstat *st;
|
|
|
-
|
|
|
- st = p9_client_stat(fid);
|
|
|
- if (IS_ERR(st))
|
|
|
- return ERR_CAST(st);
|
|
|
+ int retval, umode;
|
|
|
+ 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.
|
|
|
+ */
|
|
|
umode = p9mode2unixmode(v9ses, st->mode);
|
|
|
- ret = v9fs_get_inode(sb, umode);
|
|
|
- if (IS_ERR(ret)) {
|
|
|
- err = PTR_ERR(ret);
|
|
|
+ retval = v9fs_init_inode(v9ses, inode, umode);
|
|
|
+ if (retval)
|
|
|
goto error;
|
|
|
- }
|
|
|
-
|
|
|
- v9fs_stat2inode(st, ret, sb);
|
|
|
- ret->i_ino = v9fs_qid2ino(&st->qid);
|
|
|
|
|
|
+ v9fs_stat2inode(st, inode, sb);
|
|
|
#ifdef CONFIG_9P_FSCACHE
|
|
|
- v9fs_vcookie_set_qid(ret, &st->qid);
|
|
|
- v9fs_cache_inode_get_cookie(ret);
|
|
|
+ v9fs_fscache_set_key(inode, &st->qid);
|
|
|
+ v9fs_cache_inode_get_cookie(inode);
|
|
|
#endif
|
|
|
- p9stat_free(st);
|
|
|
- kfree(st);
|
|
|
- return ret;
|
|
|
+ unlock_new_inode(inode);
|
|
|
+ return inode;
|
|
|
error:
|
|
|
+ unlock_new_inode(inode);
|
|
|
+ iput(inode);
|
|
|
+ return ERR_PTR(retval);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+struct inode *
|
|
|
+v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
|
|
|
+ struct super_block *sb)
|
|
|
+{
|
|
|
+ struct p9_wstat *st;
|
|
|
+ struct inode *inode = NULL;
|
|
|
+
|
|
|
+ st = p9_client_stat(fid);
|
|
|
+ if (IS_ERR(st))
|
|
|
+ return ERR_CAST(st);
|
|
|
+
|
|
|
+ inode = v9fs_qid_iget(sb, &st->qid, st);
|
|
|
p9stat_free(st);
|
|
|
kfree(st);
|
|
|
- return ERR_PTR(err);
|
|
|
+ return inode;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -458,8 +499,8 @@ error:
|
|
|
static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
|
|
|
{
|
|
|
int retval;
|
|
|
- struct inode *file_inode;
|
|
|
struct p9_fid *v9fid;
|
|
|
+ struct inode *file_inode;
|
|
|
|
|
|
P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file,
|
|
|
rmdir);
|
|
@@ -470,8 +511,20 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
|
|
|
return PTR_ERR(v9fid);
|
|
|
|
|
|
retval = p9_client_remove(v9fid);
|
|
|
- if (!retval)
|
|
|
- drop_nlink(file_inode);
|
|
|
+ if (!retval) {
|
|
|
+ /*
|
|
|
+ * directories on unlink should have zero
|
|
|
+ * link count
|
|
|
+ */
|
|
|
+ if (rmdir) {
|
|
|
+ clear_nlink(file_inode);
|
|
|
+ drop_nlink(dir);
|
|
|
+ } else
|
|
|
+ drop_nlink(file_inode);
|
|
|
+
|
|
|
+ v9fs_invalidate_inode_attr(file_inode);
|
|
|
+ v9fs_invalidate_inode_attr(dir);
|
|
|
+ }
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
@@ -531,7 +584,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
|
|
|
}
|
|
|
|
|
|
/* instantiate inode and assign the unopened fid to the 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", err);
|
|
@@ -570,9 +623,10 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
|
|
|
int err;
|
|
|
u32 perm;
|
|
|
int flags;
|
|
|
- struct v9fs_session_info *v9ses;
|
|
|
- struct p9_fid *fid;
|
|
|
struct file *filp;
|
|
|
+ struct v9fs_inode *v9inode;
|
|
|
+ struct v9fs_session_info *v9ses;
|
|
|
+ struct p9_fid *fid, *inode_fid;
|
|
|
|
|
|
err = 0;
|
|
|
fid = NULL;
|
|
@@ -592,8 +646,25 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
|
+ v9fs_invalidate_inode_attr(dir);
|
|
|
/* if we are opening a file, assign the open fid to the file */
|
|
|
if (nd && nd->flags & LOOKUP_OPEN) {
|
|
|
+ v9inode = V9FS_I(dentry->d_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;
|
|
|
+ }
|
|
|
filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
|
|
|
if (IS_ERR(filp)) {
|
|
|
err = PTR_ERR(filp);
|
|
@@ -601,6 +672,10 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
|
|
|
}
|
|
|
|
|
|
filp->private_data = fid;
|
|
|
+#ifdef CONFIG_9P_FSCACHE
|
|
|
+ if (v9ses->cache)
|
|
|
+ v9fs_cache_inode_set_cookie(dentry->d_inode, filp);
|
|
|
+#endif
|
|
|
} else
|
|
|
p9_client_clunk(fid);
|
|
|
|
|
@@ -625,8 +700,8 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
|
|
|
{
|
|
|
int err;
|
|
|
u32 perm;
|
|
|
- struct v9fs_session_info *v9ses;
|
|
|
struct p9_fid *fid;
|
|
|
+ struct v9fs_session_info *v9ses;
|
|
|
|
|
|
P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
|
|
|
err = 0;
|
|
@@ -636,6 +711,9 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
|
|
|
if (IS_ERR(fid)) {
|
|
|
err = PTR_ERR(fid);
|
|
|
fid = NULL;
|
|
|
+ } else {
|
|
|
+ inc_nlink(dir);
|
|
|
+ v9fs_invalidate_inode_attr(dir);
|
|
|
}
|
|
|
|
|
|
if (fid)
|
|
@@ -687,7 +765,7 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
|
|
|
return ERR_PTR(result);
|
|
|
}
|
|
|
|
|
|
- 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)) {
|
|
|
result = PTR_ERR(inode);
|
|
|
inode = NULL;
|
|
@@ -747,17 +825,19 @@ int
|
|
|
v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|
|
struct inode *new_dir, struct dentry *new_dentry)
|
|
|
{
|
|
|
+ int retval;
|
|
|
struct inode *old_inode;
|
|
|
+ struct inode *new_inode;
|
|
|
struct v9fs_session_info *v9ses;
|
|
|
struct p9_fid *oldfid;
|
|
|
struct p9_fid *olddirfid;
|
|
|
struct p9_fid *newdirfid;
|
|
|
struct p9_wstat wstat;
|
|
|
- int retval;
|
|
|
|
|
|
P9_DPRINTK(P9_DEBUG_VFS, "\n");
|
|
|
retval = 0;
|
|
|
old_inode = old_dentry->d_inode;
|
|
|
+ new_inode = new_dentry->d_inode;
|
|
|
v9ses = v9fs_inode2v9ses(old_inode);
|
|
|
oldfid = v9fs_fid_lookup(old_dentry);
|
|
|
if (IS_ERR(oldfid))
|
|
@@ -798,9 +878,30 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|
|
retval = p9_client_wstat(oldfid, &wstat);
|
|
|
|
|
|
clunk_newdir:
|
|
|
- if (!retval)
|
|
|
+ if (!retval) {
|
|
|
+ if (new_inode) {
|
|
|
+ if (S_ISDIR(new_inode->i_mode))
|
|
|
+ clear_nlink(new_inode);
|
|
|
+ else
|
|
|
+ drop_nlink(new_inode);
|
|
|
+ /*
|
|
|
+ * Work around vfs rename rehash bug with
|
|
|
+ * FS_RENAME_DOES_D_MOVE
|
|
|
+ */
|
|
|
+ v9fs_invalidate_inode_attr(new_inode);
|
|
|
+ }
|
|
|
+ if (S_ISDIR(old_inode->i_mode)) {
|
|
|
+ if (!new_inode)
|
|
|
+ inc_nlink(new_dir);
|
|
|
+ drop_nlink(old_dir);
|
|
|
+ }
|
|
|
+ v9fs_invalidate_inode_attr(old_inode);
|
|
|
+ v9fs_invalidate_inode_attr(old_dir);
|
|
|
+ v9fs_invalidate_inode_attr(new_dir);
|
|
|
+
|
|
|
/* successful rename */
|
|
|
d_move(old_dentry, new_dentry);
|
|
|
+ }
|
|
|
up_write(&v9ses->rename_sem);
|
|
|
p9_client_clunk(newdirfid);
|
|
|
|
|
@@ -831,9 +932,10 @@ v9fs_vfs_getattr(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);
|
|
@@ -891,17 +993,20 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
|
|
|
if (iattr->ia_valid & ATTR_GID)
|
|
|
wstat.n_gid = iattr->ia_gid;
|
|
|
}
|
|
|
-
|
|
|
- retval = p9_client_wstat(fid, &wstat);
|
|
|
- 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_wstat(fid, &wstat);
|
|
|
+ if (retval < 0)
|
|
|
+ return retval;
|
|
|
+ v9fs_invalidate_inode_attr(dentry->d_inode);
|
|
|
|
|
|
setattr_copy(dentry->d_inode, iattr);
|
|
|
mark_inode_dirty(dentry->d_inode);
|
|
@@ -924,6 +1029,7 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
|
|
|
char tag_name[14];
|
|
|
unsigned int i_nlink;
|
|
|
struct v9fs_session_info *v9ses = sb->s_fs_info;
|
|
|
+ struct v9fs_inode *v9inode = V9FS_I(inode);
|
|
|
|
|
|
inode->i_nlink = 1;
|
|
|
|
|
@@ -983,6 +1089,7 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
|
|
|
|
|
|
/* not real number of blocks, but 512 byte ones ... */
|
|
|
inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9;
|
|
|
+ v9inode->cache_validity &= ~V9FS_INO_INVALID_ATTR;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1115,8 +1222,8 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
|
|
|
int mode, const char *extension)
|
|
|
{
|
|
|
u32 perm;
|
|
|
- struct v9fs_session_info *v9ses;
|
|
|
struct p9_fid *fid;
|
|
|
+ struct v9fs_session_info *v9ses;
|
|
|
|
|
|
v9ses = v9fs_inode2v9ses(dir);
|
|
|
if (!v9fs_proto_dotu(v9ses)) {
|
|
@@ -1130,6 +1237,7 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
|
|
|
if (IS_ERR(fid))
|
|
|
return PTR_ERR(fid);
|
|
|
|
|
|
+ v9fs_invalidate_inode_attr(dir);
|
|
|
p9_client_clunk(fid);
|
|
|
return 0;
|
|
|
}
|
|
@@ -1166,8 +1274,8 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
|
|
|
struct dentry *dentry)
|
|
|
{
|
|
|
int retval;
|
|
|
- struct p9_fid *oldfid;
|
|
|
char *name;
|
|
|
+ struct p9_fid *oldfid;
|
|
|
|
|
|
P9_DPRINTK(P9_DEBUG_VFS,
|
|
|
" %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
|
|
@@ -1186,7 +1294,10 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
|
|
|
sprintf(name, "%d\n", oldfid->fid);
|
|
|
retval = v9fs_vfs_mkspecial(dir, dentry, P9_DMLINK, name);
|
|
|
__putname(name);
|
|
|
-
|
|
|
+ if (!retval) {
|
|
|
+ v9fs_refresh_inode(oldfid, old_dentry->d_inode);
|
|
|
+ v9fs_invalidate_inode_attr(dir);
|
|
|
+ }
|
|
|
clunk_fid:
|
|
|
p9_client_clunk(oldfid);
|
|
|
return retval;
|
|
@@ -1237,6 +1348,32 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
|
+int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode)
|
|
|
+{
|
|
|
+ loff_t i_size;
|
|
|
+ struct p9_wstat *st;
|
|
|
+ struct v9fs_session_info *v9ses;
|
|
|
+
|
|
|
+ v9ses = v9fs_inode2v9ses(inode);
|
|
|
+ st = p9_client_stat(fid);
|
|
|
+ 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(st, inode, inode->i_sb);
|
|
|
+ if (v9ses->cache)
|
|
|
+ inode->i_size = i_size;
|
|
|
+ spin_unlock(&inode->i_lock);
|
|
|
+ p9stat_free(st);
|
|
|
+ kfree(st);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static const struct inode_operations v9fs_dir_inode_operations_dotu = {
|
|
|
.create = v9fs_vfs_create,
|
|
|
.lookup = v9fs_vfs_lookup,
|