From b85f7d92d7bd7e3298159e8b1eed8cb8cbbb0348 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Wed, 13 Jul 2011 19:12:18 -0500 Subject: [PATCH 01/14] net/9p: fix client code to fail more gracefully on protocol error There was a BUG_ON to protect against a bad id which could be dealt with more gracefully. Reported-by: Natalie Orlin Signed-off-by: Eric Van Hensbergen --- net/9p/client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/9p/client.c b/net/9p/client.c index 9e3b0e640da1..81e667b6bbbd 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -280,7 +280,8 @@ struct p9_req_t *p9_tag_lookup(struct p9_client *c, u16 tag) * buffer to read the data into */ tag++; - BUG_ON(tag >= c->max_tag); + if(tag >= c->max_tag) + return NULL; row = tag / P9_ROW_MAXTAG; col = tag % P9_ROW_MAXTAG; From 2053d67c5451d92a3ddf58d944e1d6b0efc9c419 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Mon, 6 Jun 2011 18:01:47 +0000 Subject: [PATCH 02/14] fs/9p: remove rename work around in 9p Now that VFS does the right thing remove the work around. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Eric Van Hensbergen --- fs/9p/vfs_inode.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 7f9976a866e9..a5a95372cd68 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -889,11 +889,6 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, 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) From e660a828f017991468ce322742586e8ebb047ae6 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Sun, 19 Jun 2011 16:38:21 -0500 Subject: [PATCH 03/14] 9p: clean up packet dump code Switch to generic kernel hexdump library and cleanup macros to be more consistent with the way we do normal debug prints. Signed-off-by: Eric Van Hensbergen --- include/net/9p/9p.h | 6 ++++++ net/9p/client.c | 39 ++++++++++++++++++++------------------- net/9p/protocol.c | 42 ++++++++++++++++-------------------------- 3 files changed, 42 insertions(+), 45 deletions(-) diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h index 008711e8e78f..1abbfd87a951 100644 --- a/include/net/9p/9p.h +++ b/include/net/9p/9p.h @@ -40,6 +40,7 @@ * @P9_DEBUG_FID: fid allocation/deallocation tracking * @P9_DEBUG_PKT: packet marshalling/unmarshalling * @P9_DEBUG_FSC: FS-cache tracing + * @P9_DEBUG_VPKT: Verbose packet debugging (full packet dump) * * These flags are passed at mount time to turn on various levels of * verbosity and tracing which will be output to the system logs. @@ -57,6 +58,7 @@ enum p9_debug_flags { P9_DEBUG_FID = (1<<9), P9_DEBUG_PKT = (1<<10), P9_DEBUG_FSC = (1<<11), + P9_DEBUG_VPKT = (1<<12), }; #ifdef CONFIG_NET_9P_DEBUG @@ -74,10 +76,14 @@ do { \ } \ } while (0) +#define P9_DUMP_PKT(way, pdu) p9pdu_dump(way, pdu) + #else #define P9_DPRINTK(level, format, arg...) do { } while (0) +#define P9_DUMP_PKT(way, pdu) do { } while (0) #endif + #define P9_EPRINTK(level, format, arg...) \ do { \ printk(level "9p: %s (%d): " \ diff --git a/net/9p/client.c b/net/9p/client.c index 81e667b6bbbd..332f97e0385e 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -750,7 +750,7 @@ static int p9_client_version(struct p9_client *c) err = p9pdu_readf(req->rc, c->proto_version, "ds", &msize, &version); if (err) { P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err); - p9pdu_dump(1, req->rc); + P9_DUMP_PKT(1, req->rc); goto error; } @@ -912,7 +912,7 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid); if (err) { - p9pdu_dump(1, req->rc); + P9_DUMP_PKT(1, req->rc); p9_free_req(clnt, req); goto error; } @@ -972,7 +972,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname, err = p9pdu_readf(req->rc, clnt->proto_version, "R", &nwqids, &wqids); if (err) { - p9pdu_dump(1, req->rc); + P9_DUMP_PKT(1, req->rc); p9_free_req(clnt, req); goto clunk_fid; } @@ -1039,7 +1039,7 @@ int p9_client_open(struct p9_fid *fid, int mode) err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit); if (err) { - p9pdu_dump(1, req->rc); + P9_DUMP_PKT(1, req->rc); goto free_and_error; } @@ -1082,7 +1082,7 @@ int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode, err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", qid, &iounit); if (err) { - p9pdu_dump(1, req->rc); + P9_DUMP_PKT(1, req->rc); goto free_and_error; } @@ -1127,7 +1127,7 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit); if (err) { - p9pdu_dump(1, req->rc); + P9_DUMP_PKT(1, req->rc); goto free_and_error; } @@ -1166,7 +1166,7 @@ int p9_client_symlink(struct p9_fid *dfid, char *name, char *symtgt, gid_t gid, err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid); if (err) { - p9pdu_dump(1, req->rc); + P9_DUMP_PKT(1, req->rc); goto free_and_error; } @@ -1319,11 +1319,12 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr); if (err) { - p9pdu_dump(1, req->rc); + P9_DUMP_PKT(1, req->rc); goto free_and_error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count); + P9_DUMP_PKT(1, req->rc); if (!req->tc->pbuf_size) { if (data) { @@ -1387,7 +1388,7 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count); if (err) { - p9pdu_dump(1, req->rc); + P9_DUMP_PKT(1, req->rc); goto free_and_error; } @@ -1427,7 +1428,7 @@ struct p9_wstat *p9_client_stat(struct p9_fid *fid) err = p9pdu_readf(req->rc, clnt->proto_version, "wS", &ignored, ret); if (err) { - p9pdu_dump(1, req->rc); + P9_DUMP_PKT(1, req->rc); p9_free_req(clnt, req); goto error; } @@ -1478,7 +1479,7 @@ struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid, err = p9pdu_readf(req->rc, clnt->proto_version, "A", ret); if (err) { - p9pdu_dump(1, req->rc); + P9_DUMP_PKT(1, req->rc); p9_free_req(clnt, req); goto error; } @@ -1626,7 +1627,7 @@ int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb) &sb->bsize, &sb->blocks, &sb->bfree, &sb->bavail, &sb->files, &sb->ffree, &sb->fsid, &sb->namelen); if (err) { - p9pdu_dump(1, req->rc); + P9_DUMP_PKT(1, req->rc); p9_free_req(clnt, req); goto error; } @@ -1702,7 +1703,7 @@ struct p9_fid *p9_client_xattrwalk(struct p9_fid *file_fid, } err = p9pdu_readf(req->rc, clnt->proto_version, "q", attr_size); if (err) { - p9pdu_dump(1, req->rc); + P9_DUMP_PKT(1, req->rc); p9_free_req(clnt, req); goto clunk_fid; } @@ -1781,7 +1782,7 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr); if (err) { - p9pdu_dump(1, req->rc); + P9_DUMP_PKT(1, req->rc); goto free_and_error; } @@ -1818,7 +1819,7 @@ int p9_client_mknod_dotl(struct p9_fid *fid, char *name, int mode, err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid); if (err) { - p9pdu_dump(1, req->rc); + P9_DUMP_PKT(1, req->rc); goto error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RMKNOD qid %x.%llx.%x\n", qid->type, @@ -1849,7 +1850,7 @@ int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode, err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid); if (err) { - p9pdu_dump(1, req->rc); + P9_DUMP_PKT(1, req->rc); goto error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RMKDIR qid %x.%llx.%x\n", qid->type, @@ -1884,7 +1885,7 @@ int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status) err = p9pdu_readf(req->rc, clnt->proto_version, "b", status); if (err) { - p9pdu_dump(1, req->rc); + P9_DUMP_PKT(1, req->rc); goto error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RLOCK status %i\n", *status); @@ -1917,7 +1918,7 @@ int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *glock) &glock->start, &glock->length, &glock->proc_id, &glock->client_id); if (err) { - p9pdu_dump(1, req->rc); + P9_DUMP_PKT(1, req->rc); goto error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RGETLOCK type %i start %lld length %lld " @@ -1945,7 +1946,7 @@ int p9_client_readlink(struct p9_fid *fid, char **target) err = p9pdu_readf(req->rc, clnt->proto_version, "s", target); if (err) { - p9pdu_dump(1, req->rc); + P9_DUMP_PKT(1, req->rc); goto error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RREADLINK target %s\n", *target); diff --git a/net/9p/protocol.c b/net/9p/protocol.c index a873277cb996..df58375ea6b3 100644 --- a/net/9p/protocol.c +++ b/net/9p/protocol.c @@ -44,30 +44,24 @@ p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...); void p9pdu_dump(int way, struct p9_fcall *pdu) { - int i, n; - u8 *data = pdu->sdata; - int datalen = pdu->size; - char buf[255]; - int buflen = 255; + int len = pdu->size; - i = n = 0; - if (datalen > (buflen-16)) - datalen = buflen-16; - while (i < datalen) { - n += scnprintf(buf + n, buflen - n, "%02x ", data[i]); - if (i%4 == 3) - n += scnprintf(buf + n, buflen - n, " "); - if (i%32 == 31) - n += scnprintf(buf + n, buflen - n, "\n"); - - i++; + if ((p9_debug_level & P9_DEBUG_VPKT) != P9_DEBUG_VPKT) { + if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT) { + if (len > 32) + len = 32; + } else { + /* shouldn't happen */ + return; + } } - n += scnprintf(buf + n, buflen - n, "\n"); if (way) - P9_DPRINTK(P9_DEBUG_PKT, "[[[(%d) %s\n", datalen, buf); + print_hex_dump_bytes("[9P] ", DUMP_PREFIX_OFFSET, pdu->sdata, + len); else - P9_DPRINTK(P9_DEBUG_PKT, "]]](%d) %s\n", datalen, buf); + print_hex_dump_bytes("]9P[ ", DUMP_PREFIX_OFFSET, pdu->sdata, + len); } #else void @@ -610,7 +604,7 @@ int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version) ret = p9pdu_readf(&fake_pdu, proto_version, "S", st); if (ret) { P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret); - p9pdu_dump(1, &fake_pdu); + P9_DUMP_PKT(0, &fake_pdu); } return ret; @@ -632,11 +626,7 @@ int p9pdu_finalize(struct p9_fcall *pdu) err = p9pdu_writef(pdu, 0, "d", size); pdu->size = size; -#ifdef CONFIG_NET_9P_DEBUG - if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT) - p9pdu_dump(0, pdu); -#endif - + P9_DUMP_PKT(0, pdu); P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size, pdu->id, pdu->tag); @@ -669,7 +659,7 @@ int p9dirent_read(char *buf, int len, struct p9_dirent *dirent, &dirent->d_off, &dirent->d_type, &nameptr); if (ret) { P9_DPRINTK(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret); - p9pdu_dump(1, &fake_pdu); + P9_DUMP_PKT(1, &fake_pdu); goto out; } From 114e6f3a5ede73d5b56e145f04680c61c3dd67c4 Mon Sep 17 00:00:00 2001 From: jvrao Date: Thu, 30 Jun 2011 23:18:39 +0000 Subject: [PATCH 04/14] Fix the size of receive buffer packing onto VirtIO ring. Signed-off-by: Venkateswararao Jujjuri " Reviewed-by: Aneesh Kumar K.V Signed-off-by: Eric Van Hensbergen --- net/9p/trans_virtio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index 244e70742183..0ec5423b409e 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -367,7 +367,7 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req) in += inp; } else { in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, rdata, - client->msize); + req->rc->capacity); } err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc); From 7f781679dd596c8abde8336b4d0d166d6a4aad04 Mon Sep 17 00:00:00 2001 From: jvrao Date: Thu, 30 Jun 2011 23:18:41 +0000 Subject: [PATCH 05/14] VirtIO can transfer VIRTQUEUE_NUM of pages. Signed-off-by: Venkateswararao Jujjuri " Reviewed-by: Aneesh Kumar K.V Signed-off-by: Eric Van Hensbergen --- net/9p/trans_virtio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index 0ec5423b409e..175b5135bdcf 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -592,7 +592,7 @@ static struct p9_trans_module p9_virtio_trans = { .close = p9_virtio_close, .request = p9_virtio_request, .cancel = p9_virtio_cancel, - .maxsize = PAGE_SIZE*16, + .maxsize = PAGE_SIZE*VIRTQUEUE_NUM, .pref = P9_TRANS_PREF_PAYLOAD_SEP, .def = 0, .owner = THIS_MODULE, From 52c14ab3b51d000ca534e58f7f34e2dd53408b0a Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Thu, 7 Jul 2011 08:44:03 +0000 Subject: [PATCH 06/14] net/9p: Remove structure not used in the code Signed-off-by: Aneesh Kumar K.V Signed-off-by: Eric Van Hensbergen --- include/net/9p/9p.h | 183 ++------------------------------------------ 1 file changed, 5 insertions(+), 178 deletions(-) diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h index 1abbfd87a951..160193e6dddd 100644 --- a/include/net/9p/9p.h +++ b/include/net/9p/9p.h @@ -326,21 +326,6 @@ enum p9_qid_t { /* Room for readdir header */ #define P9_READDIRHDRSZ 24 -/** - * struct p9_str - length prefixed string type - * @len: length of the string - * @str: the string - * - * The protocol uses length prefixed strings for all - * string data, so we replicate that for our internal - * string members. - */ - -struct p9_str { - u16 len; - char *str; -}; - /** * struct p9_qid - file system entity information * @type: 8-bit type &p9_qid_t @@ -377,11 +362,11 @@ struct p9_qid { * @atime: Last access/read time * @mtime: Last modify/write time * @length: file length - * @name: last element of path (aka filename) in type &p9_str - * @uid: owner name in type &p9_str - * @gid: group owner in type &p9_str - * @muid: last modifier in type &p9_str - * @extension: area used to encode extended UNIX support in type &p9_str + * @name: last element of path (aka filename) + * @uid: owner name + * @gid: group owner + * @muid: last modifier + * @extension: area used to encode extended UNIX support * @n_uid: numeric user id of owner (part of 9p2000.u extension) * @n_gid: numeric group id (part of 9p2000.u extension) * @n_muid: numeric user id of laster modifier (part of 9p2000.u extension) @@ -518,11 +503,6 @@ struct p9_getlock { char *client_id; }; -/* Structures for Protocol Operations */ -struct p9_tstatfs { - u32 fid; -}; - struct p9_rstatfs { u32 type; u32 bsize; @@ -535,159 +515,6 @@ struct p9_rstatfs { u32 namelen; }; -struct p9_trename { - u32 fid; - u32 newdirfid; - struct p9_str name; -}; - -struct p9_rrename { -}; - -struct p9_tversion { - u32 msize; - struct p9_str version; -}; - -struct p9_rversion { - u32 msize; - struct p9_str version; -}; - -struct p9_tauth { - u32 afid; - struct p9_str uname; - struct p9_str aname; - u32 n_uname; /* 9P2000.u extensions */ -}; - -struct p9_rauth { - struct p9_qid qid; -}; - -struct p9_rerror { - struct p9_str error; - u32 errno; /* 9p2000.u extension */ -}; - -struct p9_tflush { - u16 oldtag; -}; - -struct p9_rflush { -}; - -struct p9_tattach { - u32 fid; - u32 afid; - struct p9_str uname; - struct p9_str aname; - u32 n_uname; /* 9P2000.u extensions */ -}; - -struct p9_rattach { - struct p9_qid qid; -}; - -struct p9_twalk { - u32 fid; - u32 newfid; - u16 nwname; - struct p9_str wnames[16]; -}; - -struct p9_rwalk { - u16 nwqid; - struct p9_qid wqids[16]; -}; - -struct p9_topen { - u32 fid; - u8 mode; -}; - -struct p9_ropen { - struct p9_qid qid; - u32 iounit; -}; - -struct p9_tcreate { - u32 fid; - struct p9_str name; - u32 perm; - u8 mode; - struct p9_str extension; -}; - -struct p9_rcreate { - struct p9_qid qid; - u32 iounit; -}; - -struct p9_tread { - u32 fid; - u64 offset; - u32 count; -}; - -struct p9_rread { - u32 count; - u8 *data; -}; - -struct p9_twrite { - u32 fid; - u64 offset; - u32 count; - u8 *data; -}; - -struct p9_rwrite { - u32 count; -}; - -struct p9_treaddir { - u32 fid; - u64 offset; - u32 count; -}; - -struct p9_rreaddir { - u32 count; - u8 *data; -}; - - -struct p9_tclunk { - u32 fid; -}; - -struct p9_rclunk { -}; - -struct p9_tremove { - u32 fid; -}; - -struct p9_rremove { -}; - -struct p9_tstat { - u32 fid; -}; - -struct p9_rstat { - struct p9_wstat stat; -}; - -struct p9_twstat { - u32 fid; - struct p9_wstat stat; -}; - -struct p9_rwstat { -}; - /** * struct p9_fcall - primary packet structure * @size: prefixed length of the structure From 5034990e28efb2d232ee82443a9edd62defd17ba Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Mon, 11 Jul 2011 16:40:58 +0000 Subject: [PATCH 07/14] fs/9p: Fid is not valid after a failed clunk. free the fid even in case of failed clunk. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Eric Van Hensbergen --- net/9p/client.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/9p/client.c b/net/9p/client.c index 332f97e0385e..7dd4e78878d6 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -1250,9 +1250,11 @@ int p9_client_clunk(struct p9_fid *fid) P9_DPRINTK(P9_DEBUG_9P, "<<< RCLUNK fid %d\n", fid->fid); p9_free_req(clnt, req); - p9_fid_destroy(fid); - error: + /* + * Fid is not valid even after a failed clunk + */ + p9_fid_destroy(fid); return err; } EXPORT_SYMBOL(p9_client_clunk); From fd2421f54423f307ecd31bdebdca6bc317e0c492 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Mon, 11 Jul 2011 16:40:59 +0000 Subject: [PATCH 08/14] fs/9p: When doing inode lookup compare qid details and inode mode bits. This make sure we don't use wrong inode from the inode hash. The inode number of the file deleted is reused by the next file system object created and if we only use inode number for inode hash lookup we could end up with wrong struct inode. Also compare inode generation number. Not all Linux file system provide st_gen in userspace. So it could be 0; Signed-off-by: Aneesh Kumar K.V Signed-off-by: Eric Van Hensbergen --- fs/9p/cache.c | 20 +++++++++----------- fs/9p/cache.h | 9 --------- fs/9p/v9fs.c | 2 +- fs/9p/v9fs.h | 2 +- fs/9p/vfs_inode.c | 36 +++++++++++++++++++++++++++++++++--- fs/9p/vfs_inode_dotl.c | 41 +++++++++++++++++++++++++++++++++++++---- 6 files changed, 81 insertions(+), 29 deletions(-) diff --git a/fs/9p/cache.c b/fs/9p/cache.c index 5b335c5086a1..945aa5f02f9b 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 049507a5b01c..40cc54ced5d9 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 c82b017f51f3..8b7c6be2450b 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -487,8 +487,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 e5ebedfc5ed8..5d7392ead24b 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; diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index a5a95372cd68..3d8a18ee78e6 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -216,7 +216,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; @@ -433,6 +432,37 @@ void v9fs_evict_inode(struct inode *inode) } } +static int v9fs_test_inode(struct inode *inode, void *data) +{ + int umode; + 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->mode); + /* 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_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) @@ -443,7 +473,7 @@ static struct inode *v9fs_qid_iget(struct super_block *sb, struct v9fs_session_info *v9ses = sb->s_fs_info; i_ino = v9fs_qid2ino(qid); - inode = iget_locked(sb, i_ino); + inode = iget5_locked(sb, i_ino, v9fs_test_inode, v9fs_set_inode, st); if (!inode) return ERR_PTR(-ENOMEM); if (!(inode->i_state & I_NEW)) @@ -453,6 +483,7 @@ static struct inode *v9fs_qid_iget(struct super_block *sb, * FIXME!! we may need support for stale inodes * later. */ + inode->i_ino = i_ino; umode = p9mode2unixmode(v9ses, st->mode); retval = v9fs_init_inode(v9ses, inode, umode); if (retval) @@ -460,7 +491,6 @@ static struct inode *v9fs_qid_iget(struct super_block *sb, 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); diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index 32bbbe5aa689..dc9e7de38202 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -86,6 +86,38 @@ static struct dentry *v9fs_dentry_from_dir_inode(struct inode *inode) return dentry; } +static int v9fs_test_inode_dotl(struct inode *inode, void *data) +{ + struct v9fs_inode *v9inode = V9FS_I(inode); + struct p9_stat_dotl *st = (struct p9_stat_dotl *)data; + + /* don't match inode of different type */ + if ((inode->i_mode & S_IFMT) != (st->st_mode & S_IFMT)) + return 0; + + if (inode->i_generation != st->st_gen) + 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_set_inode_dotl(struct inode *inode, void *data) +{ + struct v9fs_inode *v9inode = V9FS_I(inode); + struct p9_stat_dotl *st = (struct p9_stat_dotl *)data; + + memcpy(&v9inode->qid, &st->qid, sizeof(st->qid)); + inode->i_generation = st->st_gen; + return 0; +} + static struct inode *v9fs_qid_iget_dotl(struct super_block *sb, struct p9_qid *qid, struct p9_fid *fid, @@ -97,7 +129,8 @@ static struct inode *v9fs_qid_iget_dotl(struct super_block *sb, struct v9fs_session_info *v9ses = sb->s_fs_info; i_ino = v9fs_qid2ino(qid); - inode = iget_locked(sb, i_ino); + inode = iget5_locked(sb, i_ino, v9fs_test_inode_dotl, + v9fs_set_inode_dotl, st); if (!inode) return ERR_PTR(-ENOMEM); if (!(inode->i_state & I_NEW)) @@ -107,13 +140,13 @@ static struct inode *v9fs_qid_iget_dotl(struct super_block *sb, * FIXME!! we may need support for stale inodes * later. */ + inode->i_ino = i_ino; 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); @@ -136,7 +169,7 @@ v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid, struct p9_stat_dotl *st; struct inode *inode = NULL; - st = p9_client_getattr_dotl(fid, P9_STATS_BASIC); + st = p9_client_getattr_dotl(fid, P9_STATS_BASIC | P9_STATS_GEN); if (IS_ERR(st)) return ERR_CAST(st); @@ -547,7 +580,7 @@ v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode) inode->i_blocks = stat->st_blocks; } if (stat->st_result_mask & P9_STATS_GEN) - inode->i_generation = stat->st_gen; + inode->i_generation = stat->st_gen; /* Currently we don't support P9_STATS_BTIME and P9_STATS_DATA_VERSION * because the inode structure does not have fields for them. From a2dd43bb0d7b9ce28f8a39254c25840c0730498e Mon Sep 17 00:00:00 2001 From: Prem Karat Date: Fri, 6 May 2011 18:24:18 +0530 Subject: [PATCH 09/14] fs/9p: Fix invalid mount options/args Without this fix, if any invalid mount options/args are passed while mouting the 9p fs, no error (-EINVAL) is returned and default arg value is assigned. This fix returns -EINVAL when an invalid arguement is found while parsing mount options. Signed-off-by: Prem Karat Signed-off-by: Aneesh Kumar K.V Signed-off-by: Eric Van Hensbergen --- fs/9p/v9fs.c | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 8b7c6be2450b..ef9661886112 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 @@ -171,13 +190,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 +219,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; From 4d63055fa9657aa402da25575045c23f37c3da05 Mon Sep 17 00:00:00 2001 From: Prem Karat Date: Fri, 6 May 2011 18:35:32 +0530 Subject: [PATCH 10/14] fs/9p: Clean-up get_protocol_version() to use strcmp Signed-off-by: Prem Karat Signed-off-by: Aneesh Kumar K.V Signed-off-by: Eric Van Hensbergen --- include/net/9p/client.h | 6 ++--- include/net/9p/transport.h | 2 +- net/9p/client.c | 47 ++++++++++++++++++++++++++------------ net/9p/mod.c | 4 ++-- 4 files changed, 39 insertions(+), 20 deletions(-) diff --git a/include/net/9p/client.h b/include/net/9p/client.h index d26d5e98a173..f7a8d036f803 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -36,9 +36,9 @@ */ enum p9_proto_versions{ - p9_proto_legacy = 0, - p9_proto_2000u = 1, - p9_proto_2000L = 2, + p9_proto_legacy, + p9_proto_2000u, + p9_proto_2000L, }; diff --git a/include/net/9p/transport.h b/include/net/9p/transport.h index d8549fb9c742..83531ebeee99 100644 --- a/include/net/9p/transport.h +++ b/include/net/9p/transport.h @@ -67,7 +67,7 @@ struct p9_trans_module { void v9fs_register_trans(struct p9_trans_module *m); void v9fs_unregister_trans(struct p9_trans_module *m); -struct p9_trans_module *v9fs_get_trans_by_name(const substring_t *name); +struct p9_trans_module *v9fs_get_trans_by_name(char *s); struct p9_trans_module *v9fs_get_default_trans(void); void v9fs_put_trans(struct p9_trans_module *m); #endif /* NET_9P_TRANSPORT_H */ diff --git a/net/9p/client.c b/net/9p/client.c index 7dd4e78878d6..431eaef697c7 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -72,23 +72,22 @@ inline int p9_is_proto_dotu(struct p9_client *clnt) EXPORT_SYMBOL(p9_is_proto_dotu); /* Interpret mount option for protocol version */ -static int get_protocol_version(const substring_t *name) +static int get_protocol_version(char *s) { int version = -EINVAL; - if (!strncmp("9p2000", name->from, name->to-name->from)) { + if (!strcmp(s, "9p2000")) { version = p9_proto_legacy; P9_DPRINTK(P9_DEBUG_9P, "Protocol version: Legacy\n"); - } else if (!strncmp("9p2000.u", name->from, name->to-name->from)) { + } else if (!strcmp(s, "9p2000.u")) { version = p9_proto_2000u; P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2000.u\n"); - } else if (!strncmp("9p2000.L", name->from, name->to-name->from)) { + } else if (!strcmp(s, "9p2000.L")) { version = p9_proto_2000L; P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2000.L\n"); - } else { - P9_DPRINTK(P9_DEBUG_ERROR, "Unknown protocol version %s. ", - name->from); - } + } else + printk(KERN_INFO "9p: Unknown protocol version %s.\n", s); + return version; } @@ -106,6 +105,7 @@ static int parse_opts(char *opts, struct p9_client *clnt) char *p; substring_t args[MAX_OPT_ARGS]; int option; + char *s; int ret = 0; clnt->proto_version = p9_proto_2000u; @@ -141,22 +141,41 @@ static int parse_opts(char *opts, struct p9_client *clnt) clnt->msize = option; break; case Opt_trans: - clnt->trans_mod = v9fs_get_trans_by_name(&args[0]); - if(clnt->trans_mod == NULL) { + s = match_strdup(&args[0]); + if (!s) { + ret = -ENOMEM; P9_DPRINTK(P9_DEBUG_ERROR, - "Could not find request transport: %s\n", - (char *) &args[0]); + "problem allocating copy of trans arg\n"); + goto free_and_return; + } + clnt->trans_mod = v9fs_get_trans_by_name(s); + if (clnt->trans_mod == NULL) { + printk(KERN_INFO + "9p: Could not find " + "request transport: %s\n", s); ret = -EINVAL; + kfree(s); goto free_and_return; } + kfree(s); break; case Opt_legacy: clnt->proto_version = p9_proto_legacy; break; case Opt_version: - ret = get_protocol_version(&args[0]); - if (ret == -EINVAL) + s = match_strdup(&args[0]); + if (!s) { + ret = -ENOMEM; + P9_DPRINTK(P9_DEBUG_ERROR, + "problem allocating copy of version arg\n"); goto free_and_return; + } + ret = get_protocol_version(s); + if (ret == -EINVAL) { + kfree(s); + goto free_and_return; + } + kfree(s); clnt->proto_version = ret; break; default: diff --git a/net/9p/mod.c b/net/9p/mod.c index 72c398275051..2664d1292291 100644 --- a/net/9p/mod.c +++ b/net/9p/mod.c @@ -80,14 +80,14 @@ EXPORT_SYMBOL(v9fs_unregister_trans); * @name: string identifying transport * */ -struct p9_trans_module *v9fs_get_trans_by_name(const substring_t *name) +struct p9_trans_module *v9fs_get_trans_by_name(char *s) { struct p9_trans_module *t, *found = NULL; spin_lock(&v9fs_trans_lock); list_for_each_entry(t, &v9fs_trans_list, list) - if (strncmp(t->name, name->from, name->to-name->from) == 0 && + if (strcmp(t->name, s) == 0 && try_module_get(t->owner)) { found = t; break; From ed80fcfac2565fa866d93ba14f0e75de17a8223e Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Wed, 6 Jul 2011 16:32:31 +0530 Subject: [PATCH 11/14] fs/9p: Always ask new inode in create This make sure we don't end up reusing the unlinked inode object. The ideal way is to use inode i_generation. But i_generation is not available in userspace always. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Eric Van Hensbergen --- fs/9p/v9fs.h | 27 +++++++++++++++++++++++---- fs/9p/vfs_inode.c | 22 +++++++++++++++++----- fs/9p/vfs_inode_dotl.c | 30 +++++++++++++++++++++--------- 3 files changed, 61 insertions(+), 18 deletions(-) diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h index 5d7392ead24b..e78956cbd702 100644 --- a/fs/9p/v9fs.h +++ b/fs/9p/v9fs.h @@ -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/vfs_inode.c b/fs/9p/vfs_inode.c index 3d8a18ee78e6..3bbf705634b2 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -454,6 +454,11 @@ static int v9fs_test_inode(struct inode *inode, void *data) 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); @@ -465,15 +470,22 @@ static int v9fs_set_inode(struct inode *inode, void *data) static struct inode *v9fs_qid_iget(struct super_block *sb, struct p9_qid *qid, - struct p9_wstat *st) + struct p9_wstat *st, + int new) { 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 = iget5_locked(sb, i_ino, v9fs_test_inode, v9fs_set_inode, st); + inode = iget5_locked(sb, i_ino, test, v9fs_set_inode, st); if (!inode) return ERR_PTR(-ENOMEM); if (!(inode->i_state & I_NEW)) @@ -504,7 +516,7 @@ static struct inode *v9fs_qid_iget(struct super_block *sb, 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; @@ -513,7 +525,7 @@ 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; @@ -615,7 +627,7 @@ 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); diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index dc9e7de38202..276f4a69ecd4 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -108,6 +108,12 @@ static int v9fs_test_inode_dotl(struct inode *inode, void *data) return 1; } +/* Always get a new inode */ +static int v9fs_test_new_inode_dotl(struct inode *inode, void *data) +{ + return 0; +} + static int v9fs_set_inode_dotl(struct inode *inode, void *data) { struct v9fs_inode *v9inode = V9FS_I(inode); @@ -121,16 +127,22 @@ static int v9fs_set_inode_dotl(struct inode *inode, void *data) static struct inode *v9fs_qid_iget_dotl(struct super_block *sb, struct p9_qid *qid, struct p9_fid *fid, - struct p9_stat_dotl *st) + struct p9_stat_dotl *st, + int new) { int retval; 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_dotl; + else + test = v9fs_test_inode_dotl; i_ino = v9fs_qid2ino(qid); - inode = iget5_locked(sb, i_ino, v9fs_test_inode_dotl, - v9fs_set_inode_dotl, st); + inode = iget5_locked(sb, i_ino, test, v9fs_set_inode_dotl, st); if (!inode) return ERR_PTR(-ENOMEM); if (!(inode->i_state & I_NEW)) @@ -164,7 +176,7 @@ static struct inode *v9fs_qid_iget_dotl(struct super_block *sb, 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) { struct p9_stat_dotl *st; struct inode *inode = NULL; @@ -173,7 +185,7 @@ v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid, if (IS_ERR(st)) return ERR_CAST(st); - inode = v9fs_qid_iget_dotl(sb, &st->qid, fid, st); + inode = v9fs_qid_iget_dotl(sb, &st->qid, fid, st, new); kfree(st); return inode; } @@ -263,7 +275,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, fid = NULL; goto error; } - 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); @@ -383,7 +395,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, goto error; } - 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", @@ -636,7 +648,7 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry, } /* instantiate inode and assign the unopened fid to 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", @@ -789,7 +801,7 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode, goto error; } - 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", From 9e8fb38e7d7a00e5f63bbb331f0ea4c02286d5e6 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 28 Jun 2011 15:41:16 +0530 Subject: [PATCH 12/14] fs/9p: add 9P2000.L renameat operation renameat - change name of file or directory size[4] Trenameat tag[2] olddirfid[4] oldname[s] newdirfid[4] newname[s] size[4] Rrenameat tag[2] older Trename have the below request format size[4] Trename tag[2] fid[4] newdirfid[4] name[s] The rename message is used to change the name of a file, possibly moving it to a new directory. The rename opreation is actually a directory opertation and should ideally have olddirfid, if not we cannot represent the fid on server with anything other than name. We will have to derive the old directory name from fid in the Trename request. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Eric Van Hensbergen --- fs/9p/vfs_inode.c | 9 ++++++--- include/net/9p/9p.h | 2 ++ include/net/9p/client.h | 5 ++++- net/9p/client.c | 33 ++++++++++++++++++++++++++++++++- 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 3bbf705634b2..bce66f56c62c 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -904,9 +904,12 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, down_write(&v9ses->rename_sem); if (v9fs_proto_dotl(v9ses)) { - retval = p9_client_rename(oldfid, newdirfid, - (char *) new_dentry->d_name.name); - if (retval != -ENOSYS) + retval = p9_client_renameat(olddirfid, old_dentry->d_name.name, + newdirfid, new_dentry->d_name.name); + if (retval == -EOPNOTSUPP) + retval = p9_client_rename(oldfid, newdirfid, + new_dentry->d_name.name); + if (retval != -EOPNOTSUPP) goto clunk_newdir; } if (old_dentry->d_parent != new_dentry->d_parent) { diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h index 160193e6dddd..61156207c98c 100644 --- a/include/net/9p/9p.h +++ b/include/net/9p/9p.h @@ -181,6 +181,8 @@ enum p9_msg_t { P9_RLINK, P9_TMKDIR = 72, P9_RMKDIR, + P9_TRENAMEAT = 74, + P9_RRENAMEAT, P9_TVERSION = 100, P9_RVERSION, P9_TAUTH = 102, diff --git a/include/net/9p/client.h b/include/net/9p/client.h index f7a8d036f803..62ceddf9994a 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -211,7 +211,10 @@ struct p9_dirent { }; int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb); -int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, char *name); +int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, + const char *name); +int p9_client_renameat(struct p9_fid *olddirfid, const char *old_name, + struct p9_fid *newdirfid, const char *new_name); struct p9_client *p9_client_create(const char *dev_name, char *options); void p9_client_destroy(struct p9_client *clnt); void p9_client_disconnect(struct p9_client *clnt); diff --git a/net/9p/client.c b/net/9p/client.c index 431eaef697c7..c4b77f383582 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -1666,7 +1666,8 @@ int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb) } EXPORT_SYMBOL(p9_client_statfs); -int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, char *name) +int p9_client_rename(struct p9_fid *fid, + struct p9_fid *newdirfid, const char *name) { int err; struct p9_req_t *req; @@ -1693,6 +1694,36 @@ int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, char *name) } EXPORT_SYMBOL(p9_client_rename); +int p9_client_renameat(struct p9_fid *olddirfid, const char *old_name, + struct p9_fid *newdirfid, const char *new_name) +{ + int err; + struct p9_req_t *req; + struct p9_client *clnt; + + err = 0; + clnt = olddirfid->clnt; + + P9_DPRINTK(P9_DEBUG_9P, ">>> TRENAMEAT olddirfid %d old name %s" + " newdirfid %d new name %s\n", olddirfid->fid, old_name, + newdirfid->fid, new_name); + + req = p9_client_rpc(clnt, P9_TRENAMEAT, "dsds", olddirfid->fid, + old_name, newdirfid->fid, new_name); + if (IS_ERR(req)) { + err = PTR_ERR(req); + goto error; + } + + P9_DPRINTK(P9_DEBUG_9P, "<<< RRENAMEAT newdirfid %d new name %s\n", + newdirfid->fid, new_name); + + p9_free_req(clnt, req); +error: + return err; +} +EXPORT_SYMBOL(p9_client_renameat); + /* * An xattrwalk without @attr_name gives the fid for the lisxattr namespace */ From 48e370ff93769ee6e592ddef3bb38686b8147c67 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 28 Jun 2011 15:41:18 +0530 Subject: [PATCH 13/14] fs/9p: add 9P2000.L unlinkat operation unlinkat - Remove a directory entry size[4] Tunlinkat tag[2] dirfid[4] name[s] flag[4] size[4] Runlinkat tag[2] older Tremove have the below request format size[4] Tremove tag[2] fid[4] The remove message is used to remove a directory entry either file or directory The remove opreation is actually a directory opertation and should ideally have dirfid, if not we cannot represent the fid on server with anything other than name. We will have to derive the directory name from fid in the Tremove request. NOTE: The operation doesn't clunk the unlink fid. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Eric Van Hensbergen --- fs/9p/vfs_inode.c | 48 +++++++++++++++++++++++++---------------- include/net/9p/9p.h | 2 ++ include/net/9p/client.h | 1 + net/9p/client.c | 23 ++++++++++++++++++++ 4 files changed, 56 insertions(+), 18 deletions(-) diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index bce66f56c62c..8bb5507e822f 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -534,38 +534,50 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, /** * 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; + struct inode *inode; + int retval = -EOPNOTSUPP; + struct p9_fid *v9fid, *dfid; + struct v9fs_session_info *v9ses; - P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file, - rmdir); + P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %x\n", + dir, dentry, flags); - file_inode = file->d_inode; - v9fid = v9fs_fid_clone(file); - if (IS_ERR(v9fid)) - return PTR_ERR(v9fid); - - 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, 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; @@ -856,7 +868,7 @@ int v9fs_vfs_unlink(struct inode *i, struct dentry *d) int v9fs_vfs_rmdir(struct inode *i, struct dentry *d) { - return v9fs_remove(i, d, 1); + return v9fs_remove(i, d, AT_REMOVEDIR); } /** diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h index 61156207c98c..342dcf13d039 100644 --- a/include/net/9p/9p.h +++ b/include/net/9p/9p.h @@ -183,6 +183,8 @@ enum p9_msg_t { P9_RMKDIR, P9_TRENAMEAT = 74, P9_RRENAMEAT, + P9_TUNLINKAT = 76, + P9_RUNLINKAT, P9_TVERSION = 100, P9_RVERSION, P9_TAUTH = 102, diff --git a/include/net/9p/client.h b/include/net/9p/client.h index 62ceddf9994a..55ce72ce9861 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -234,6 +234,7 @@ int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode, int p9_client_clunk(struct p9_fid *fid); int p9_client_fsync(struct p9_fid *fid, int datasync); int p9_client_remove(struct p9_fid *fid); +int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags); int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, u32 count); int p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, diff --git a/net/9p/client.c b/net/9p/client.c index c4b77f383582..a953baa3624e 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -1303,6 +1303,29 @@ int p9_client_remove(struct p9_fid *fid) } EXPORT_SYMBOL(p9_client_remove); +int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags) +{ + int err = 0; + struct p9_req_t *req; + struct p9_client *clnt; + + P9_DPRINTK(P9_DEBUG_9P, ">>> TUNLINKAT fid %d %s %d\n", + dfid->fid, name, flags); + + clnt = dfid->clnt; + req = p9_client_rpc(clnt, P9_TUNLINKAT, "dsd", dfid->fid, name, flags); + if (IS_ERR(req)) { + err = PTR_ERR(req); + goto error; + } + P9_DPRINTK(P9_DEBUG_9P, "<<< RUNLINKAT fid %d %s\n", dfid->fid, name); + + p9_free_req(clnt, req); +error: + return err; +} +EXPORT_SYMBOL(p9_client_unlinkat); + int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, u32 count) From c9ffb05ca5b5098d6ea468c909dd384d90da7d54 Mon Sep 17 00:00:00 2001 From: "Venkateswararao Jujjuri (JV)" Date: Wed, 29 Jun 2011 18:06:33 -0700 Subject: [PATCH 14/14] net/9p: Fix the msize calculation. msize represents the maximum PDU size that includes P9_IOHDRSZ. Signed-off-by: Venkateswararao Jujjuri " Signed-off-by: Aneesh Kumar K.V Signed-off-by: Eric Van Hensbergen --- net/9p/client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/9p/client.c b/net/9p/client.c index a953baa3624e..0505a03c374c 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -841,8 +841,8 @@ struct p9_client *p9_client_create(const char *dev_name, char *options) if (err) goto destroy_fidpool; - if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize) - clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ; + if (clnt->msize > clnt->trans_mod->maxsize) + clnt->msize = clnt->trans_mod->maxsize; err = p9_client_version(clnt); if (err)