aboutsummaryrefslogtreecommitdiff
path: root/fs/9p
diff options
context:
space:
mode:
Diffstat (limited to 'fs/9p')
-rw-r--r--fs/9p/acl.c75
-rw-r--r--fs/9p/acl.h14
-rw-r--r--fs/9p/cache.c20
-rw-r--r--fs/9p/cache.h9
-rw-r--r--fs/9p/v9fs.c78
-rw-r--r--fs/9p/v9fs.h29
-rw-r--r--fs/9p/v9fs_vfs.h9
-rw-r--r--fs/9p/vfs_dir.c14
-rw-r--r--fs/9p/vfs_file.c58
-rw-r--r--fs/9p/vfs_inode.c265
-rw-r--r--fs/9p/vfs_inode_dotl.c180
-rw-r--r--fs/9p/vfs_super.c2
12 files changed, 507 insertions, 246 deletions
diff --git a/fs/9p/acl.c b/fs/9p/acl.c
index 535ab6eccb1..9a1d4263075 100644
--- a/fs/9p/acl.c
+++ b/fs/9p/acl.c
@@ -96,14 +96,10 @@ static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type)
return acl;
}
-int v9fs_check_acl(struct inode *inode, int mask, unsigned int flags)
+struct posix_acl *v9fs_iop_get_acl(struct inode *inode, int type)
{
- struct posix_acl *acl;
struct v9fs_session_info *v9ses;
- if (flags & IPERM_FLAG_RCU)
- return -ECHILD;
-
v9ses = v9fs_inode2v9ses(inode);
if (((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) ||
((v9ses->flags & V9FS_ACL_MASK) != V9FS_POSIX_ACL)) {
@@ -111,18 +107,10 @@ int v9fs_check_acl(struct inode *inode, int mask, unsigned int flags)
* On access = client and acl = on mode get the acl
* values from the server
*/
- return 0;
+ return NULL;
}
- acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS);
+ return v9fs_get_cached_acl(inode, type);
- if (IS_ERR(acl))
- return PTR_ERR(acl);
- if (acl) {
- int error = posix_acl_permission(inode, acl, mask);
- posix_acl_release(acl);
- return error;
- }
- return -EAGAIN;
}
static int v9fs_set_acl(struct dentry *dentry, int type, struct posix_acl *acl)
@@ -165,40 +153,40 @@ err_free_out:
int v9fs_acl_chmod(struct dentry *dentry)
{
int retval = 0;
- struct posix_acl *acl, *clone;
+ struct posix_acl *acl;
struct inode *inode = dentry->d_inode;
if (S_ISLNK(inode->i_mode))
return -EOPNOTSUPP;
acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS);
if (acl) {
- clone = posix_acl_clone(acl, GFP_KERNEL);
+ retval = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
+ if (retval)
+ return retval;
+ retval = v9fs_set_acl(dentry, ACL_TYPE_ACCESS, acl);
posix_acl_release(acl);
- if (!clone)
- return -ENOMEM;
- retval = posix_acl_chmod_masq(clone, inode->i_mode);
- if (!retval)
- retval = v9fs_set_acl(dentry, ACL_TYPE_ACCESS, clone);
- posix_acl_release(clone);
}
return retval;
}
int v9fs_set_create_acl(struct dentry *dentry,
- struct posix_acl *dpacl, struct posix_acl *pacl)
+ struct posix_acl **dpacl, struct posix_acl **pacl)
{
- v9fs_set_acl(dentry, ACL_TYPE_DEFAULT, dpacl);
- v9fs_set_acl(dentry, ACL_TYPE_ACCESS, pacl);
- posix_acl_release(dpacl);
- posix_acl_release(pacl);
+ if (dentry) {
+ v9fs_set_acl(dentry, ACL_TYPE_DEFAULT, *dpacl);
+ v9fs_set_acl(dentry, ACL_TYPE_ACCESS, *pacl);
+ }
+ posix_acl_release(*dpacl);
+ posix_acl_release(*pacl);
+ *dpacl = *pacl = NULL;
return 0;
}
-int v9fs_acl_mode(struct inode *dir, mode_t *modep,
+int v9fs_acl_mode(struct inode *dir, umode_t *modep,
struct posix_acl **dpacl, struct posix_acl **pacl)
{
int retval = 0;
- mode_t mode = *modep;
+ umode_t mode = *modep;
struct posix_acl *acl = NULL;
if (!S_ISLNK(mode)) {
@@ -209,29 +197,18 @@ int v9fs_acl_mode(struct inode *dir, mode_t *modep,
mode &= ~current_umask();
}
if (acl) {
- struct posix_acl *clone;
-
if (S_ISDIR(mode))
- *dpacl = acl;
- clone = posix_acl_clone(acl, GFP_NOFS);
- retval = -ENOMEM;
- if (!clone)
- goto cleanup;
-
- retval = posix_acl_create_masq(clone, &mode);
- if (retval < 0) {
- posix_acl_release(clone);
- goto cleanup;
- }
+ *dpacl = posix_acl_dup(acl);
+ retval = posix_acl_create(&acl, GFP_NOFS, &mode);
+ if (retval < 0)
+ return retval;
if (retval > 0)
- *pacl = clone;
+ *pacl = acl;
+ else
+ posix_acl_release(acl);
}
*modep = mode;
return 0;
-cleanup:
- posix_acl_release(acl);
- return retval;
-
}
static int v9fs_remote_get_acl(struct dentry *dentry, const char *name,
@@ -342,7 +319,7 @@ static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
case ACL_TYPE_ACCESS:
name = POSIX_ACL_XATTR_ACCESS;
if (acl) {
- mode_t mode = inode->i_mode;
+ umode_t mode = inode->i_mode;
retval = posix_acl_equiv_mode(acl, &mode);
if (retval < 0)
goto err_out;
diff --git a/fs/9p/acl.h b/fs/9p/acl.h
index 7ef3ac9f6d9..55955641196 100644
--- a/fs/9p/acl.h
+++ b/fs/9p/acl.h
@@ -16,14 +16,14 @@
#ifdef CONFIG_9P_FS_POSIX_ACL
extern int v9fs_get_acl(struct inode *, struct p9_fid *);
-extern int v9fs_check_acl(struct inode *inode, int mask, unsigned int flags);
+extern struct posix_acl *v9fs_iop_get_acl(struct inode *inode, int type);
extern int v9fs_acl_chmod(struct dentry *);
extern int v9fs_set_create_acl(struct dentry *,
- struct posix_acl *, struct posix_acl *);
-extern int v9fs_acl_mode(struct inode *dir, mode_t *modep,
+ struct posix_acl **, struct posix_acl **);
+extern int v9fs_acl_mode(struct inode *dir, umode_t *modep,
struct posix_acl **dpacl, struct posix_acl **pacl);
#else
-#define v9fs_check_acl NULL
+#define v9fs_iop_get_acl NULL
static inline int v9fs_get_acl(struct inode *inode, struct p9_fid *fid)
{
return 0;
@@ -33,12 +33,12 @@ static inline int v9fs_acl_chmod(struct dentry *dentry)
return 0;
}
static inline int v9fs_set_create_acl(struct dentry *dentry,
- struct posix_acl *dpacl,
- struct posix_acl *pacl)
+ struct posix_acl **dpacl,
+ struct posix_acl **pacl)
{
return 0;
}
-static inline int v9fs_acl_mode(struct inode *dir, mode_t *modep,
+static inline int v9fs_acl_mode(struct inode *dir, umode_t *modep,
struct posix_acl **dpacl,
struct posix_acl **pacl)
{
diff --git a/fs/9p/cache.c b/fs/9p/cache.c
index 5b335c5086a..945aa5f02f9 100644
--- a/fs/9p/cache.c
+++ b/fs/9p/cache.c
@@ -108,11 +108,10 @@ static uint16_t v9fs_cache_inode_get_key(const void *cookie_netfs_data,
void *buffer, uint16_t bufmax)
{
const struct v9fs_inode *v9inode = cookie_netfs_data;
- memcpy(buffer, &v9inode->fscache_key->path,
- sizeof(v9inode->fscache_key->path));
+ memcpy(buffer, &v9inode->qid.path, sizeof(v9inode->qid.path));
P9_DPRINTK(P9_DEBUG_FSC, "inode %p get key %llu", &v9inode->vfs_inode,
- v9inode->fscache_key->path);
- return sizeof(v9inode->fscache_key->path);
+ v9inode->qid.path);
+ return sizeof(v9inode->qid.path);
}
static void v9fs_cache_inode_get_attr(const void *cookie_netfs_data,
@@ -129,11 +128,10 @@ static uint16_t v9fs_cache_inode_get_aux(const void *cookie_netfs_data,
void *buffer, uint16_t buflen)
{
const struct v9fs_inode *v9inode = cookie_netfs_data;
- memcpy(buffer, &v9inode->fscache_key->version,
- sizeof(v9inode->fscache_key->version));
+ memcpy(buffer, &v9inode->qid.version, sizeof(v9inode->qid.version));
P9_DPRINTK(P9_DEBUG_FSC, "inode %p get aux %u", &v9inode->vfs_inode,
- v9inode->fscache_key->version);
- return sizeof(v9inode->fscache_key->version);
+ v9inode->qid.version);
+ return sizeof(v9inode->qid.version);
}
static enum
@@ -143,11 +141,11 @@ fscache_checkaux v9fs_cache_inode_check_aux(void *cookie_netfs_data,
{
const struct v9fs_inode *v9inode = cookie_netfs_data;
- if (buflen != sizeof(v9inode->fscache_key->version))
+ if (buflen != sizeof(v9inode->qid.version))
return FSCACHE_CHECKAUX_OBSOLETE;
- if (memcmp(buffer, &v9inode->fscache_key->version,
- sizeof(v9inode->fscache_key->version)))
+ if (memcmp(buffer, &v9inode->qid.version,
+ sizeof(v9inode->qid.version)))
return FSCACHE_CHECKAUX_OBSOLETE;
return FSCACHE_CHECKAUX_OKAY;
diff --git a/fs/9p/cache.h b/fs/9p/cache.h
index 049507a5b01..40cc54ced5d 100644
--- a/fs/9p/cache.h
+++ b/fs/9p/cache.h
@@ -93,15 +93,6 @@ static inline void v9fs_uncache_page(struct inode *inode, struct page *page)
BUG_ON(PageFsCache(page));
}
-static inline void v9fs_fscache_set_key(struct inode *inode,
- struct p9_qid *qid)
-{
- struct v9fs_inode *v9inode = V9FS_I(inode);
- spin_lock(&v9inode->fscache_lock);
- v9inode->fscache_key = qid;
- spin_unlock(&v9inode->fscache_lock);
-}
-
static inline void v9fs_fscache_wait_on_page_write(struct inode *inode,
struct page *page)
{
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index c82b017f51f..2b78014a124 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -78,6 +78,25 @@ static const match_table_t tokens = {
{Opt_err, NULL}
};
+/* Interpret mount options for cache mode */
+static int get_cache_mode(char *s)
+{
+ int version = -EINVAL;
+
+ if (!strcmp(s, "loose")) {
+ version = CACHE_LOOSE;
+ P9_DPRINTK(P9_DEBUG_9P, "Cache mode: loose\n");
+ } else if (!strcmp(s, "fscache")) {
+ version = CACHE_FSCACHE;
+ P9_DPRINTK(P9_DEBUG_9P, "Cache mode: fscache\n");
+ } else if (!strcmp(s, "none")) {
+ version = CACHE_NONE;
+ P9_DPRINTK(P9_DEBUG_9P, "Cache mode: none\n");
+ } else
+ printk(KERN_INFO "9p: Unknown Cache mode %s.\n", s);
+ return version;
+}
+
/**
* v9fs_parse_options - parse mount options into session structure
* @v9ses: existing v9fs session information
@@ -97,7 +116,7 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
/* setup defaults */
v9ses->afid = ~0;
v9ses->debug = 0;
- v9ses->cache = 0;
+ v9ses->cache = CACHE_NONE;
#ifdef CONFIG_9P_FSCACHE
v9ses->cachetag = NULL;
#endif
@@ -113,21 +132,19 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
options = tmp_options;
while ((p = strsep(&options, ",")) != NULL) {
- int token;
+ int token, r;
if (!*p)
continue;
token = match_token(p, tokens, args);
- if (token < Opt_uname) {
- int r = match_int(&args[0], &option);
+ switch (token) {
+ case Opt_debug:
+ r = match_int(&args[0], &option);
if (r < 0) {
P9_DPRINTK(P9_DEBUG_ERROR,
- "integer field, but no integer?\n");
+ "integer field, but no integer?\n");
ret = r;
continue;
}
- }
- switch (token) {
- case Opt_debug:
v9ses->debug = option;
#ifdef CONFIG_NET_9P_DEBUG
p9_debug_level = option;
@@ -135,12 +152,33 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
break;
case Opt_dfltuid:
+ r = match_int(&args[0], &option);
+ if (r < 0) {
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "integer field, but no integer?\n");
+ ret = r;
+ continue;
+ }
v9ses->dfltuid = option;
break;
case Opt_dfltgid:
+ r = match_int(&args[0], &option);
+ if (r < 0) {
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "integer field, but no integer?\n");
+ ret = r;
+ continue;
+ }
v9ses->dfltgid = option;
break;
case Opt_afid:
+ r = match_int(&args[0], &option);
+ if (r < 0) {
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "integer field, but no integer?\n");
+ ret = r;
+ continue;
+ }
v9ses->afid = option;
break;
case Opt_uname:
@@ -171,13 +209,13 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
"problem allocating copy of cache arg\n");
goto free_and_return;
}
+ ret = get_cache_mode(s);
+ if (ret == -EINVAL) {
+ kfree(s);
+ goto free_and_return;
+ }
- if (strcmp(s, "loose") == 0)
- v9ses->cache = CACHE_LOOSE;
- else if (strcmp(s, "fscache") == 0)
- v9ses->cache = CACHE_FSCACHE;
- else
- v9ses->cache = CACHE_NONE;
+ v9ses->cache = ret;
kfree(s);
break;
@@ -200,9 +238,15 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
} else {
v9ses->flags |= V9FS_ACCESS_SINGLE;
v9ses->uid = simple_strtoul(s, &e, 10);
- if (*e != '\0')
- v9ses->uid = ~0;
+ if (*e != '\0') {
+ ret = -EINVAL;
+ printk(KERN_INFO "9p: Unknown access "
+ "argument %s.\n", s);
+ kfree(s);
+ goto free_and_return;
+ }
}
+
kfree(s);
break;
@@ -487,8 +531,8 @@ static void v9fs_inode_init_once(void *foo)
struct v9fs_inode *v9inode = (struct v9fs_inode *)foo;
#ifdef CONFIG_9P_FSCACHE
v9inode->fscache = NULL;
- v9inode->fscache_key = NULL;
#endif
+ memset(&v9inode->qid, 0, sizeof(v9inode->qid));
inode_init_once(&v9inode->vfs_inode);
}
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index e5ebedfc5ed..e78956cbd70 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -125,8 +125,8 @@ struct v9fs_inode {
#ifdef CONFIG_9P_FSCACHE
spinlock_t fscache_lock;
struct fscache_cookie *fscache;
- struct p9_qid *fscache_key;
#endif
+ struct p9_qid qid;
unsigned int cache_validity;
struct p9_fid *writeback_fid;
struct mutex v_mutex;
@@ -153,13 +153,13 @@ extern void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd,
void *p);
extern struct inode *v9fs_inode_from_fid(struct v9fs_session_info *v9ses,
struct p9_fid *fid,
- struct super_block *sb);
+ struct super_block *sb, int new);
extern const struct inode_operations v9fs_dir_inode_operations_dotl;
extern const struct inode_operations v9fs_file_inode_operations_dotl;
extern const struct inode_operations v9fs_symlink_inode_operations_dotl;
extern struct inode *v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses,
struct p9_fid *fid,
- struct super_block *sb);
+ struct super_block *sb, int new);
/* other default globals */
#define V9FS_PORT 564
@@ -201,8 +201,27 @@ v9fs_get_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
struct super_block *sb)
{
if (v9fs_proto_dotl(v9ses))
- return v9fs_inode_from_fid_dotl(v9ses, fid, sb);
+ return v9fs_inode_from_fid_dotl(v9ses, fid, sb, 0);
else
- return v9fs_inode_from_fid(v9ses, fid, sb);
+ return v9fs_inode_from_fid(v9ses, fid, sb, 0);
}
+
+/**
+ * v9fs_get_new_inode_from_fid - Helper routine to populate an inode by
+ * issuing a attribute request
+ * @v9ses: session information
+ * @fid: fid to issue attribute request for
+ * @sb: superblock on which to create inode
+ *
+ */
+static inline struct inode *
+v9fs_get_new_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
+ struct super_block *sb)
+{
+ if (v9fs_proto_dotl(v9ses))
+ return v9fs_inode_from_fid_dotl(v9ses, fid, sb, 1);
+ else
+ return v9fs_inode_from_fid(v9ses, fid, sb, 1);
+}
+
#endif
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index 4014160903a..410ffd6ceb5 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -54,9 +54,9 @@ extern struct kmem_cache *v9fs_inode_cache;
struct inode *v9fs_alloc_inode(struct super_block *sb);
void v9fs_destroy_inode(struct inode *inode);
-struct inode *v9fs_get_inode(struct super_block *sb, int mode);
+struct inode *v9fs_get_inode(struct super_block *sb, int mode, dev_t);
int v9fs_init_inode(struct v9fs_session_info *v9ses,
- struct inode *inode, int mode);
+ struct inode *inode, int mode, dev_t);
void v9fs_evict_inode(struct inode *inode);
ino_t v9fs_qid2ino(struct p9_qid *qid);
void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *);
@@ -70,7 +70,8 @@ ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64);
ssize_t v9fs_fid_readn(struct p9_fid *, char *, char __user *, u32, u64);
void v9fs_blank_wstat(struct p9_wstat *wstat);
int v9fs_vfs_setattr_dotl(struct dentry *, struct iattr *);
-int v9fs_file_fsync_dotl(struct file *filp, int datasync);
+int v9fs_file_fsync_dotl(struct file *filp, loff_t start, loff_t end,
+ int datasync);
ssize_t v9fs_file_write_internal(struct inode *, struct p9_fid *,
const char __user *, size_t, loff_t *, int);
int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode);
@@ -82,4 +83,6 @@ static inline void v9fs_invalidate_inode_attr(struct inode *inode)
v9inode->cache_validity |= V9FS_INO_INVALID_ATTR;
return;
}
+
+int v9fs_open_to_dotl_flags(int flags);
#endif
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index 9c2bdda5cd9..598fff1a54e 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -165,9 +165,8 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
while (rdir->head < rdir->tail) {
p9stat_init(&st);
- err = p9stat_read(rdir->buf + rdir->head,
- rdir->tail - rdir->head, &st,
- fid->clnt->proto_version);
+ err = p9stat_read(fid->clnt, rdir->buf + rdir->head,
+ rdir->tail - rdir->head, &st);
if (err) {
P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
err = -EIO;
@@ -231,7 +230,7 @@ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
while (err == 0) {
if (rdir->tail == rdir->head) {
err = p9_client_readdir(fid, rdir->buf, buflen,
- filp->f_pos);
+ filp->f_pos);
if (err <= 0)
goto unlock_and_exit;
@@ -241,10 +240,9 @@ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
while (rdir->head < rdir->tail) {
- err = p9dirent_read(rdir->buf + rdir->head,
- rdir->tail - rdir->head,
- &curdirent,
- fid->clnt->proto_version);
+ err = p9dirent_read(fid->clnt, rdir->buf + rdir->head,
+ rdir->tail - rdir->head,
+ &curdirent);
if (err < 0) {
P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
err = -EIO;
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index ffed55817f0..62857a810a7 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -65,7 +65,7 @@ int v9fs_file_open(struct inode *inode, struct file *file)
v9inode = V9FS_I(inode);
v9ses = v9fs_inode2v9ses(inode);
if (v9fs_proto_dotl(v9ses))
- omode = file->f_flags;
+ omode = v9fs_open_to_dotl_flags(file->f_flags);
else
omode = v9fs_uflags2omode(file->f_flags,
v9fs_proto_dotu(v9ses));
@@ -169,7 +169,18 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
/* convert posix lock to p9 tlock args */
memset(&flock, 0, sizeof(flock));
- flock.type = fl->fl_type;
+ /* map the lock type */
+ switch (fl->fl_type) {
+ case F_RDLCK:
+ flock.type = P9_LOCK_TYPE_RDLCK;
+ break;
+ case F_WRLCK:
+ flock.type = P9_LOCK_TYPE_WRLCK;
+ break;
+ case F_UNLCK:
+ flock.type = P9_LOCK_TYPE_UNLCK;
+ break;
+ }
flock.start = fl->fl_start;
if (fl->fl_end == OFFSET_MAX)
flock.length = 0;
@@ -245,7 +256,7 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
/* convert posix lock to p9 tgetlock args */
memset(&glock, 0, sizeof(glock));
- glock.type = fl->fl_type;
+ glock.type = P9_LOCK_TYPE_UNLCK;
glock.start = fl->fl_start;
if (fl->fl_end == OFFSET_MAX)
glock.length = 0;
@@ -257,17 +268,26 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
res = p9_client_getlock_dotl(fid, &glock);
if (res < 0)
return res;
- if (glock.type != F_UNLCK) {
- fl->fl_type = glock.type;
+ /* map 9p lock type to os lock type */
+ switch (glock.type) {
+ case P9_LOCK_TYPE_RDLCK:
+ fl->fl_type = F_RDLCK;
+ break;
+ case P9_LOCK_TYPE_WRLCK:
+ fl->fl_type = F_WRLCK;
+ break;
+ case P9_LOCK_TYPE_UNLCK:
+ fl->fl_type = F_UNLCK;
+ break;
+ }
+ if (glock.type != P9_LOCK_TYPE_UNLCK) {
fl->fl_start = glock.start;
if (glock.length == 0)
fl->fl_end = OFFSET_MAX;
else
fl->fl_end = glock.start + glock.length - 1;
fl->fl_pid = glock.proc_id;
- } else
- fl->fl_type = F_UNLCK;
-
+ }
return res;
}
@@ -519,32 +539,50 @@ out:
}
-static int v9fs_file_fsync(struct file *filp, int datasync)
+static int v9fs_file_fsync(struct file *filp, loff_t start, loff_t end,
+ int datasync)
{
struct p9_fid *fid;
+ struct inode *inode = filp->f_mapping->host;
struct p9_wstat wstat;
int retval;
+ retval = filemap_write_and_wait_range(inode->i_mapping, start, end);
+ if (retval)
+ return retval;
+
+ mutex_lock(&inode->i_mutex);
P9_DPRINTK(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync);
fid = filp->private_data;
v9fs_blank_wstat(&wstat);
retval = p9_client_wstat(fid, &wstat);
+ mutex_unlock(&inode->i_mutex);
+
return retval;
}
-int v9fs_file_fsync_dotl(struct file *filp, int datasync)
+int v9fs_file_fsync_dotl(struct file *filp, loff_t start, loff_t end,
+ int datasync)
{
struct p9_fid *fid;
+ struct inode *inode = filp->f_mapping->host;
int retval;
+ retval = filemap_write_and_wait_range(inode->i_mapping, start, end);
+ if (retval)
+ return retval;
+
+ mutex_lock(&inode->i_mutex);
P9_DPRINTK(P9_DEBUG_VFS, "v9fs_file_fsync_dotl: filp %p datasync %x\n",
filp, datasync);
fid = filp->private_data;
retval = p9_client_fsync(fid, datasync);
+ mutex_unlock(&inode->i_mutex);
+
return retval;
}
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 7f6c6770319..879ed885173 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -95,15 +95,18 @@ static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode)
/**
* p9mode2unixmode- convert plan9 mode bits to unix mode bits
* @v9ses: v9fs session information
- * @mode: mode to convert
+ * @stat: p9_wstat from which mode need to be derived
+ * @rdev: major number, minor number in case of device files.
*
*/
-
-static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
+static int p9mode2unixmode(struct v9fs_session_info *v9ses,
+ struct p9_wstat *stat, dev_t *rdev)
{
int res;
+ int mode = stat->mode;
- res = mode & 0777;
+ res = mode & S_IALLUGO;
+ *rdev = 0;
if ((mode & P9_DMDIR) == P9_DMDIR)
res |= S_IFDIR;
@@ -116,9 +119,26 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
&& (v9ses->nodev == 0))
res |= S_IFIFO;
else if ((mode & P9_DMDEVICE) && (v9fs_proto_dotu(v9ses))
- && (v9ses->nodev == 0))
- res |= S_IFBLK;
- else
+ && (v9ses->nodev == 0)) {
+ char type = 0, ext[32];
+ int major = -1, minor = -1;
+
+ strncpy(ext, stat->extension, sizeof(ext));
+ sscanf(ext, "%c %u %u", &type, &major, &minor);
+ switch (type) {
+ case 'c':
+ res |= S_IFCHR;
+ break;
+ case 'b':
+ res |= S_IFBLK;
+ break;
+ default:
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "Unknown special type %c %s\n", type,
+ stat->extension);
+ };
+ *rdev = MKDEV(major, minor);
+ } else
res |= S_IFREG;
if (v9fs_proto_dotu(v9ses)) {
@@ -131,7 +151,6 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
if ((mode & P9_DMSETVTX) == P9_DMSETVTX)
res |= S_ISVTX;
}
-
return res;
}
@@ -216,7 +235,6 @@ struct inode *v9fs_alloc_inode(struct super_block *sb)
return NULL;
#ifdef CONFIG_9P_FSCACHE
v9inode->fscache = NULL;
- v9inode->fscache_key = NULL;
spin_lock_init(&v9inode->fscache_lock);
#endif
v9inode->writeback_fid = NULL;
@@ -243,13 +261,13 @@ void v9fs_destroy_inode(struct inode *inode)
}
int v9fs_init_inode(struct v9fs_session_info *v9ses,
- struct inode *inode, int mode)
+ struct inode *inode, int mode, dev_t rdev)
{
int err = 0;
inode_init_owner(inode, NULL, mode);
inode->i_blocks = 0;
- inode->i_rdev = 0;
+ inode->i_rdev = rdev;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_mapping->a_ops = &v9fs_addr_operations;
@@ -260,10 +278,8 @@ int v9fs_init_inode(struct v9fs_session_info *v9ses,
case S_IFSOCK:
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");
@@ -336,7 +352,7 @@ error:
*
*/
-struct inode *v9fs_get_inode(struct super_block *sb, int mode)
+struct inode *v9fs_get_inode(struct super_block *sb, int mode, dev_t rdev)
{
int err;
struct inode *inode;
@@ -349,7 +365,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n");
return ERR_PTR(-ENOMEM);
}
- err = v9fs_init_inode(v9ses, inode, mode);
+ err = v9fs_init_inode(v9ses, inode, mode, rdev);
if (err) {
iput(inode);
return ERR_PTR(err);
@@ -433,17 +449,62 @@ void v9fs_evict_inode(struct inode *inode)
}
}
+static int v9fs_test_inode(struct inode *inode, void *data)
+{
+ int umode;
+ dev_t rdev;
+ struct v9fs_inode *v9inode = V9FS_I(inode);
+ struct p9_wstat *st = (struct p9_wstat *)data;
+ struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
+
+ umode = p9mode2unixmode(v9ses, st, &rdev);
+ /* don't match inode of different type */
+ if ((inode->i_mode & S_IFMT) != (umode & S_IFMT))
+ return 0;
+
+ /* compare qid details */
+ if (memcmp(&v9inode->qid.version,
+ &st->qid.version, sizeof(v9inode->qid.version)))
+ return 0;
+
+ if (v9inode->qid.type != st->qid.type)
+ return 0;
+ return 1;
+}
+
+static int v9fs_test_new_inode(struct inode *inode, void *data)
+{
+ return 0;
+}
+
+static int v9fs_set_inode(struct inode *inode, void *data)
+{
+ struct v9fs_inode *v9inode = V9FS_I(inode);
+ struct p9_wstat *st = (struct p9_wstat *)data;
+
+ memcpy(&v9inode->qid, &st->qid, sizeof(st->qid));
+ return 0;
+}
+
static struct inode *v9fs_qid_iget(struct super_block *sb,
struct p9_qid *qid,
- struct p9_wstat *st)
+ struct p9_wstat *st,
+ int new)
{
+ dev_t rdev;
int retval, umode;
unsigned long i_ino;
struct inode *inode;
struct v9fs_session_info *v9ses = sb->s_fs_info;
+ int (*test)(struct inode *, void *);
+
+ if (new)
+ test = v9fs_test_new_inode;
+ else
+ test = v9fs_test_inode;
i_ino = v9fs_qid2ino(qid);
- inode = iget_locked(sb, i_ino);
+ inode = iget5_locked(sb, i_ino, test, v9fs_set_inode, st);
if (!inode)
return ERR_PTR(-ENOMEM);
if (!(inode->i_state & I_NEW))
@@ -453,14 +514,14 @@ static struct inode *v9fs_qid_iget(struct super_block *sb,
* FIXME!! we may need support for stale inodes
* later.
*/
- umode = p9mode2unixmode(v9ses, st->mode);
- retval = v9fs_init_inode(v9ses, inode, umode);
+ inode->i_ino = i_ino;
+ umode = p9mode2unixmode(v9ses, st, &rdev);
+ retval = v9fs_init_inode(v9ses, inode, umode, rdev);
if (retval)
goto error;
v9fs_stat2inode(st, inode, sb);
#ifdef CONFIG_9P_FSCACHE
- v9fs_fscache_set_key(inode, &st->qid);
v9fs_cache_inode_get_cookie(inode);
#endif
unlock_new_inode(inode);
@@ -474,7 +535,7 @@ error:
struct inode *
v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
- struct super_block *sb)
+ struct super_block *sb, int new)
{
struct p9_wstat *st;
struct inode *inode = NULL;
@@ -483,47 +544,73 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
if (IS_ERR(st))
return ERR_CAST(st);
- inode = v9fs_qid_iget(sb, &st->qid, st);
+ inode = v9fs_qid_iget(sb, &st->qid, st, new);
p9stat_free(st);
kfree(st);
return inode;
}
/**
+ * v9fs_at_to_dotl_flags- convert Linux specific AT flags to
+ * plan 9 AT flag.
+ * @flags: flags to convert
+ */
+static int v9fs_at_to_dotl_flags(int flags)
+{
+ int rflags = 0;
+ if (flags & AT_REMOVEDIR)
+ rflags |= P9_DOTL_AT_REMOVEDIR;
+ return rflags;
+}
+
+/**
* v9fs_remove - helper function to remove files and directories
* @dir: directory inode that is being deleted
- * @file: dentry that is being deleted
+ * @dentry: dentry that is being deleted
* @rmdir: removing a directory
*
*/
-static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
+static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags)
{
- int retval;
- struct p9_fid *v9fid;
- struct inode *file_inode;
-
- P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file,
- rmdir);
+ struct inode *inode;
+ int retval = -EOPNOTSUPP;
+ struct p9_fid *v9fid, *dfid;
+ struct v9fs_session_info *v9ses;
- file_inode = file->d_inode;
- v9fid = v9fs_fid_clone(file);
- if (IS_ERR(v9fid))
- return PTR_ERR(v9fid);
+ P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %x\n",
+ dir, dentry, flags);
- retval = p9_client_remove(v9fid);
+ v9ses = v9fs_inode2v9ses(dir);
+ inode = dentry->d_inode;
+ dfid = v9fs_fid_lookup(dentry->d_parent);
+ if (IS_ERR(dfid)) {
+ retval = PTR_ERR(dfid);
+ P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", retval);
+ return retval;
+ }
+ if (v9fs_proto_dotl(v9ses))
+ retval = p9_client_unlinkat(dfid, dentry->d_name.name,
+ v9fs_at_to_dotl_flags(flags));
+ if (retval == -EOPNOTSUPP) {
+ /* Try the one based on path */
+ v9fid = v9fs_fid_clone(dentry);
+ if (IS_ERR(v9fid))
+ return PTR_ERR(v9fid);
+ retval = p9_client_remove(v9fid);
+ }
if (!retval) {
/*
* directories on unlink should have zero
* link count
*/
- if (rmdir) {
- clear_nlink(file_inode);
+ if (flags & AT_REMOVEDIR) {
+ clear_nlink(inode);
drop_nlink(dir);
} else
- drop_nlink(file_inode);
+ drop_nlink(inode);
- v9fs_invalidate_inode_attr(file_inode);
+ v9fs_invalidate_inode_attr(inode);
v9fs_invalidate_inode_attr(dir);
}
return retval;
@@ -585,19 +672,17 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
}
/* instantiate inode and assign the unopened fid to the dentry */
- inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
+ inode = v9fs_get_new_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;
}
- d_instantiate(dentry, inode);
err = v9fs_fid_add(dentry, fid);
if (err < 0)
goto error;
-
+ d_instantiate(dentry, inode);
return ofid;
-
error:
if (ofid)
p9_client_clunk(ofid);
@@ -633,8 +718,8 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
fid = NULL;
v9ses = v9fs_inode2v9ses(dir);
perm = unixmode2p9mode(v9ses, mode);
- if (nd && nd->flags & LOOKUP_OPEN)
- flags = nd->intent.open.flags - 1;
+ if (nd)
+ flags = nd->intent.open.flags;
else
flags = O_RDWR;
@@ -649,7 +734,7 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
v9fs_invalidate_inode_attr(dir);
/* if we are opening a file, assign the open fid to the file */
- if (nd && nd->flags & LOOKUP_OPEN) {
+ if (nd) {
v9inode = V9FS_I(dentry->d_inode);
mutex_lock(&v9inode->v_mutex);
if (v9ses->cache && !v9inode->writeback_fid &&
@@ -738,6 +823,7 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nameidata)
{
+ struct dentry *res;
struct super_block *sb;
struct v9fs_session_info *v9ses;
struct p9_fid *dfid, *fid;
@@ -769,22 +855,35 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
return ERR_PTR(result);
}
-
- inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
+ /*
+ * Make sure we don't use a wrong inode due to parallel
+ * unlink. For cached mode create calls request for new
+ * inode. But with cache disabled, lookup should do this.
+ */
+ if (v9ses->cache)
+ inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
+ else
+ inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
if (IS_ERR(inode)) {
result = PTR_ERR(inode);
inode = NULL;
goto error;
}
-
result = v9fs_fid_add(dentry, fid);
if (result < 0)
goto error_iput;
-
inst_out:
- d_add(dentry, inode);
- return NULL;
-
+ /*
+ * If we had a rename on the server and a parallel lookup
+ * for the