diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-28 12:25:11 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-28 12:25:11 -0400 |
commit | 90a2b69c14d0f0b6cbd124caf429ae9033f0615c (patch) | |
tree | 9aa18ac045eec9515ed225f900717e8a5f4fd8d6 /net | |
parent | e430426654c6a99fb1977bae71d4844e876c4a52 (diff) | |
parent | f6ac55b6c156cebf750376dc08e06ffdade82717 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs: (28 commits)
net/9p: Return error on read with NULL buffer
9p: Add datasync to client side TFSYNC/RFSYNC for dotl
net/9p: Return error if we fail to encode protocol data
fs/9p: Use generic_file_open with lookup_instantiate_filp
fs/9p: Add missing iput in v9fs_vfs_lookup
fs/9p: Use mknod 9p operation on create without open request
net/9p: Add waitq to VirtIO transport.
[net/9p]Serialize virtqueue operations to make VirtIO transport SMP safe.
9p: Implement TREADLINK operation for 9p2000.L
9p: Use V9FS_MAGIC in statfs
9p: Implement TGETLOCK
9p: Implement TLOCK
[9p] Introduce client side TFSYNC/RFSYNC for dotl.
[fs/9p] Add file_operations for cached mode in dotl protocol.
fs/9p: Add access = client option to opt in acl evaluation.
fs/9p: Implement create time inheritance
fs/9p: Update ACL on chmod
fs/9p: Implement setting posix acl
fs/9p: Add xattr callbacks for POSIX ACL
fs/9p: Implement POSIX ACL permission checking function
...
Diffstat (limited to 'net')
-rw-r--r-- | net/9p/client.c | 178 | ||||
-rw-r--r-- | net/9p/protocol.c | 5 | ||||
-rw-r--r-- | net/9p/trans_virtio.c | 76 |
3 files changed, 220 insertions, 39 deletions
diff --git a/net/9p/client.c b/net/9p/client.c index 83bf0541d66f..a848bca9fbff 100644 --- a/net/9p/client.c +++ b/net/9p/client.c | |||
@@ -450,32 +450,43 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req) | |||
450 | return err; | 450 | return err; |
451 | } | 451 | } |
452 | 452 | ||
453 | if (type == P9_RERROR) { | 453 | if (type == P9_RERROR || type == P9_RLERROR) { |
454 | int ecode; | 454 | int ecode; |
455 | char *ename; | ||
456 | 455 | ||
457 | err = p9pdu_readf(req->rc, c->proto_version, "s?d", | 456 | if (!p9_is_proto_dotl(c)) { |
458 | &ename, &ecode); | 457 | char *ename; |
459 | if (err) { | ||
460 | P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", | ||
461 | err); | ||
462 | return err; | ||
463 | } | ||
464 | 458 | ||
465 | if (p9_is_proto_dotu(c) || | 459 | err = p9pdu_readf(req->rc, c->proto_version, "s?d", |
466 | p9_is_proto_dotl(c)) | 460 | &ename, &ecode); |
467 | err = -ecode; | 461 | if (err) |
462 | goto out_err; | ||
463 | |||
464 | if (p9_is_proto_dotu(c)) | ||
465 | err = -ecode; | ||
466 | |||
467 | if (!err || !IS_ERR_VALUE(err)) { | ||
468 | err = p9_errstr2errno(ename, strlen(ename)); | ||
469 | |||
470 | P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename); | ||
468 | 471 | ||
469 | if (!err || !IS_ERR_VALUE(err)) | 472 | kfree(ename); |
470 | err = p9_errstr2errno(ename, strlen(ename)); | 473 | } |
474 | } else { | ||
475 | err = p9pdu_readf(req->rc, c->proto_version, "d", &ecode); | ||
476 | err = -ecode; | ||
471 | 477 | ||
472 | P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename); | 478 | P9_DPRINTK(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode); |
479 | } | ||
473 | 480 | ||
474 | kfree(ename); | ||
475 | } else | 481 | } else |
476 | err = 0; | 482 | err = 0; |
477 | 483 | ||
478 | return err; | 484 | return err; |
485 | |||
486 | out_err: | ||
487 | P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", err); | ||
488 | |||
489 | return err; | ||
479 | } | 490 | } |
480 | 491 | ||
481 | /** | 492 | /** |
@@ -568,11 +579,14 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) | |||
568 | va_start(ap, fmt); | 579 | va_start(ap, fmt); |
569 | err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap); | 580 | err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap); |
570 | va_end(ap); | 581 | va_end(ap); |
582 | if (err) | ||
583 | goto reterr; | ||
571 | p9pdu_finalize(req->tc); | 584 | p9pdu_finalize(req->tc); |
572 | 585 | ||
573 | err = c->trans_mod->request(c, req); | 586 | err = c->trans_mod->request(c, req); |
574 | if (err < 0) { | 587 | if (err < 0) { |
575 | c->status = Disconnected; | 588 | if (err != -ERESTARTSYS) |
589 | c->status = Disconnected; | ||
576 | goto reterr; | 590 | goto reterr; |
577 | } | 591 | } |
578 | 592 | ||
@@ -1151,12 +1165,44 @@ int p9_client_link(struct p9_fid *dfid, struct p9_fid *oldfid, char *newname) | |||
1151 | } | 1165 | } |
1152 | EXPORT_SYMBOL(p9_client_link); | 1166 | EXPORT_SYMBOL(p9_client_link); |
1153 | 1167 | ||
1168 | int p9_client_fsync(struct p9_fid *fid, int datasync) | ||
1169 | { | ||
1170 | int err; | ||
1171 | struct p9_client *clnt; | ||
1172 | struct p9_req_t *req; | ||
1173 | |||
1174 | P9_DPRINTK(P9_DEBUG_9P, ">>> TFSYNC fid %d datasync:%d\n", | ||
1175 | fid->fid, datasync); | ||
1176 | err = 0; | ||
1177 | clnt = fid->clnt; | ||
1178 | |||
1179 | req = p9_client_rpc(clnt, P9_TFSYNC, "dd", fid->fid, datasync); | ||
1180 | if (IS_ERR(req)) { | ||
1181 | err = PTR_ERR(req); | ||
1182 | goto error; | ||
1183 | } | ||
1184 | |||
1185 | P9_DPRINTK(P9_DEBUG_9P, "<<< RFSYNC fid %d\n", fid->fid); | ||
1186 | |||
1187 | p9_free_req(clnt, req); | ||
1188 | |||
1189 | error: | ||
1190 | return err; | ||
1191 | } | ||
1192 | EXPORT_SYMBOL(p9_client_fsync); | ||
1193 | |||
1154 | int p9_client_clunk(struct p9_fid *fid) | 1194 | int p9_client_clunk(struct p9_fid *fid) |
1155 | { | 1195 | { |
1156 | int err; | 1196 | int err; |
1157 | struct p9_client *clnt; | 1197 | struct p9_client *clnt; |
1158 | struct p9_req_t *req; | 1198 | struct p9_req_t *req; |
1159 | 1199 | ||
1200 | if (!fid) { | ||
1201 | P9_EPRINTK(KERN_WARNING, "Trying to clunk with NULL fid\n"); | ||
1202 | dump_stack(); | ||
1203 | return 0; | ||
1204 | } | ||
1205 | |||
1160 | P9_DPRINTK(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid); | 1206 | P9_DPRINTK(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid); |
1161 | err = 0; | 1207 | err = 0; |
1162 | clnt = fid->clnt; | 1208 | clnt = fid->clnt; |
@@ -1240,16 +1286,13 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, | |||
1240 | 1286 | ||
1241 | if (data) { | 1287 | if (data) { |
1242 | memmove(data, dataptr, count); | 1288 | memmove(data, dataptr, count); |
1243 | } | 1289 | } else { |
1244 | |||
1245 | if (udata) { | ||
1246 | err = copy_to_user(udata, dataptr, count); | 1290 | err = copy_to_user(udata, dataptr, count); |
1247 | if (err) { | 1291 | if (err) { |
1248 | err = -EFAULT; | 1292 | err = -EFAULT; |
1249 | goto free_and_error; | 1293 | goto free_and_error; |
1250 | } | 1294 | } |
1251 | } | 1295 | } |
1252 | |||
1253 | p9_free_req(clnt, req); | 1296 | p9_free_req(clnt, req); |
1254 | return count; | 1297 | return count; |
1255 | 1298 | ||
@@ -1761,3 +1804,96 @@ error: | |||
1761 | 1804 | ||
1762 | } | 1805 | } |
1763 | EXPORT_SYMBOL(p9_client_mkdir_dotl); | 1806 | EXPORT_SYMBOL(p9_client_mkdir_dotl); |
1807 | |||
1808 | int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status) | ||
1809 | { | ||
1810 | int err; | ||
1811 | struct p9_client *clnt; | ||
1812 | struct p9_req_t *req; | ||
1813 | |||
1814 | err = 0; | ||
1815 | clnt = fid->clnt; | ||
1816 | P9_DPRINTK(P9_DEBUG_9P, ">>> TLOCK fid %d type %i flags %d " | ||
1817 | "start %lld length %lld proc_id %d client_id %s\n", | ||
1818 | fid->fid, flock->type, flock->flags, flock->start, | ||
1819 | flock->length, flock->proc_id, flock->client_id); | ||
1820 | |||
1821 | req = p9_client_rpc(clnt, P9_TLOCK, "dbdqqds", fid->fid, flock->type, | ||
1822 | flock->flags, flock->start, flock->length, | ||
1823 | flock->proc_id, flock->client_id); | ||
1824 | |||
1825 | if (IS_ERR(req)) | ||
1826 | return PTR_ERR(req); | ||
1827 | |||
1828 | err = p9pdu_readf(req->rc, clnt->proto_version, "b", status); | ||
1829 | if (err) { | ||
1830 | p9pdu_dump(1, req->rc); | ||
1831 | goto error; | ||
1832 | } | ||
1833 | P9_DPRINTK(P9_DEBUG_9P, "<<< RLOCK status %i\n", *status); | ||
1834 | error: | ||
1835 | p9_free_req(clnt, req); | ||
1836 | return err; | ||
1837 | |||
1838 | } | ||
1839 | EXPORT_SYMBOL(p9_client_lock_dotl); | ||
1840 | |||
1841 | int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *glock) | ||
1842 | { | ||
1843 | int err; | ||
1844 | struct p9_client *clnt; | ||
1845 | struct p9_req_t *req; | ||
1846 | |||
1847 | err = 0; | ||
1848 | clnt = fid->clnt; | ||
1849 | P9_DPRINTK(P9_DEBUG_9P, ">>> TGETLOCK fid %d, type %i start %lld " | ||
1850 | "length %lld proc_id %d client_id %s\n", fid->fid, glock->type, | ||
1851 | glock->start, glock->length, glock->proc_id, glock->client_id); | ||
1852 | |||
1853 | req = p9_client_rpc(clnt, P9_TGETLOCK, "dbqqds", fid->fid, glock->type, | ||
1854 | glock->start, glock->length, glock->proc_id, glock->client_id); | ||
1855 | |||
1856 | if (IS_ERR(req)) | ||
1857 | return PTR_ERR(req); | ||
1858 | |||
1859 | err = p9pdu_readf(req->rc, clnt->proto_version, "bqqds", &glock->type, | ||
1860 | &glock->start, &glock->length, &glock->proc_id, | ||
1861 | &glock->client_id); | ||
1862 | if (err) { | ||
1863 | p9pdu_dump(1, req->rc); | ||
1864 | goto error; | ||
1865 | } | ||
1866 | P9_DPRINTK(P9_DEBUG_9P, "<<< RGETLOCK type %i start %lld length %lld " | ||
1867 | "proc_id %d client_id %s\n", glock->type, glock->start, | ||
1868 | glock->length, glock->proc_id, glock->client_id); | ||
1869 | error: | ||
1870 | p9_free_req(clnt, req); | ||
1871 | return err; | ||
1872 | } | ||
1873 | EXPORT_SYMBOL(p9_client_getlock_dotl); | ||
1874 | |||
1875 | int p9_client_readlink(struct p9_fid *fid, char **target) | ||
1876 | { | ||
1877 | int err; | ||
1878 | struct p9_client *clnt; | ||
1879 | struct p9_req_t *req; | ||
1880 | |||
1881 | err = 0; | ||
1882 | clnt = fid->clnt; | ||
1883 | P9_DPRINTK(P9_DEBUG_9P, ">>> TREADLINK fid %d\n", fid->fid); | ||
1884 | |||
1885 | req = p9_client_rpc(clnt, P9_TREADLINK, "d", fid->fid); | ||
1886 | if (IS_ERR(req)) | ||
1887 | return PTR_ERR(req); | ||
1888 | |||
1889 | err = p9pdu_readf(req->rc, clnt->proto_version, "s", target); | ||
1890 | if (err) { | ||
1891 | p9pdu_dump(1, req->rc); | ||
1892 | goto error; | ||
1893 | } | ||
1894 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREADLINK target %s\n", *target); | ||
1895 | error: | ||
1896 | p9_free_req(clnt, req); | ||
1897 | return err; | ||
1898 | } | ||
1899 | EXPORT_SYMBOL(p9_client_readlink); | ||
diff --git a/net/9p/protocol.c b/net/9p/protocol.c index 3acd3afb20c8..45c15f491401 100644 --- a/net/9p/protocol.c +++ b/net/9p/protocol.c | |||
@@ -122,9 +122,8 @@ static size_t | |||
122 | pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size) | 122 | pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size) |
123 | { | 123 | { |
124 | size_t len = MIN(pdu->capacity - pdu->size, size); | 124 | size_t len = MIN(pdu->capacity - pdu->size, size); |
125 | int err = copy_from_user(&pdu->sdata[pdu->size], udata, len); | 125 | if (copy_from_user(&pdu->sdata[pdu->size], udata, len)) |
126 | if (err) | 126 | len = 0; |
127 | printk(KERN_WARNING "pdu_write_u returning: %d\n", err); | ||
128 | 127 | ||
129 | pdu->size += len; | 128 | pdu->size += len; |
130 | return size - len; | 129 | return size - len; |
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index b88515936e4b..c8f3f72ab20e 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c | |||
@@ -75,6 +75,8 @@ struct virtio_chan { | |||
75 | struct p9_client *client; | 75 | struct p9_client *client; |
76 | struct virtio_device *vdev; | 76 | struct virtio_device *vdev; |
77 | struct virtqueue *vq; | 77 | struct virtqueue *vq; |
78 | int ring_bufs_avail; | ||
79 | wait_queue_head_t *vc_wq; | ||
78 | 80 | ||
79 | /* Scatterlist: can be too big for stack. */ | 81 | /* Scatterlist: can be too big for stack. */ |
80 | struct scatterlist sg[VIRTQUEUE_NUM]; | 82 | struct scatterlist sg[VIRTQUEUE_NUM]; |
@@ -134,16 +136,30 @@ static void req_done(struct virtqueue *vq) | |||
134 | struct p9_fcall *rc; | 136 | struct p9_fcall *rc; |
135 | unsigned int len; | 137 | unsigned int len; |
136 | struct p9_req_t *req; | 138 | struct p9_req_t *req; |
139 | unsigned long flags; | ||
137 | 140 | ||
138 | P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n"); | 141 | P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n"); |
139 | 142 | ||
140 | while ((rc = virtqueue_get_buf(chan->vq, &len)) != NULL) { | 143 | do { |
141 | P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc); | 144 | spin_lock_irqsave(&chan->lock, flags); |
142 | P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag); | 145 | rc = virtqueue_get_buf(chan->vq, &len); |
143 | req = p9_tag_lookup(chan->client, rc->tag); | 146 | |
144 | req->status = REQ_STATUS_RCVD; | 147 | if (rc != NULL) { |
145 | p9_client_cb(chan->client, req); | 148 | if (!chan->ring_bufs_avail) { |
146 | } | 149 | chan->ring_bufs_avail = 1; |
150 | wake_up(chan->vc_wq); | ||
151 | } | ||
152 | spin_unlock_irqrestore(&chan->lock, flags); | ||
153 | P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc); | ||
154 | P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", | ||
155 | rc->tag); | ||
156 | req = p9_tag_lookup(chan->client, rc->tag); | ||
157 | req->status = REQ_STATUS_RCVD; | ||
158 | p9_client_cb(chan->client, req); | ||
159 | } else { | ||
160 | spin_unlock_irqrestore(&chan->lock, flags); | ||
161 | } | ||
162 | } while (rc != NULL); | ||
147 | } | 163 | } |
148 | 164 | ||
149 | /** | 165 | /** |
@@ -199,23 +215,43 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req) | |||
199 | int in, out; | 215 | int in, out; |
200 | struct virtio_chan *chan = client->trans; | 216 | struct virtio_chan *chan = client->trans; |
201 | char *rdata = (char *)req->rc+sizeof(struct p9_fcall); | 217 | char *rdata = (char *)req->rc+sizeof(struct p9_fcall); |
218 | unsigned long flags; | ||
219 | int err; | ||
202 | 220 | ||
203 | P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n"); | 221 | P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n"); |
204 | 222 | ||
223 | req_retry: | ||
224 | req->status = REQ_STATUS_SENT; | ||
225 | |||
226 | spin_lock_irqsave(&chan->lock, flags); | ||
205 | out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, req->tc->sdata, | 227 | out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, req->tc->sdata, |
206 | req->tc->size); | 228 | req->tc->size); |
207 | in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata, | 229 | in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata, |
208 | client->msize); | 230 | client->msize); |
209 | 231 | ||
210 | req->status = REQ_STATUS_SENT; | 232 | err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc); |
211 | 233 | if (err < 0) { | |
212 | if (virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc) < 0) { | 234 | if (err == -ENOSPC) { |
213 | P9_DPRINTK(P9_DEBUG_TRANS, | 235 | chan->ring_bufs_avail = 0; |
214 | "9p debug: virtio rpc add_buf returned failure"); | 236 | spin_unlock_irqrestore(&chan->lock, flags); |
215 | return -EIO; | 237 | err = wait_event_interruptible(*chan->vc_wq, |
238 | chan->ring_bufs_avail); | ||
239 | if (err == -ERESTARTSYS) | ||
240 | return err; | ||
241 | |||
242 | P9_DPRINTK(P9_DEBUG_TRANS, "9p:Retry virtio request\n"); | ||
243 | goto req_retry; | ||
244 | } else { | ||
245 | spin_unlock_irqrestore(&chan->lock, flags); | ||
246 | P9_DPRINTK(P9_DEBUG_TRANS, | ||
247 | "9p debug: " | ||
248 | "virtio rpc add_buf returned failure"); | ||
249 | return -EIO; | ||
250 | } | ||
216 | } | 251 | } |
217 | 252 | ||
218 | virtqueue_kick(chan->vq); | 253 | virtqueue_kick(chan->vq); |
254 | spin_unlock_irqrestore(&chan->lock, flags); | ||
219 | 255 | ||
220 | P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n"); | 256 | P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n"); |
221 | return 0; | 257 | return 0; |
@@ -290,14 +326,23 @@ static int p9_virtio_probe(struct virtio_device *vdev) | |||
290 | chan->tag_len = tag_len; | 326 | chan->tag_len = tag_len; |
291 | err = sysfs_create_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr); | 327 | err = sysfs_create_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr); |
292 | if (err) { | 328 | if (err) { |
293 | kfree(tag); | 329 | goto out_free_tag; |
294 | goto out_free_vq; | ||
295 | } | 330 | } |
331 | chan->vc_wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL); | ||
332 | if (!chan->vc_wq) { | ||
333 | err = -ENOMEM; | ||
334 | goto out_free_tag; | ||
335 | } | ||
336 | init_waitqueue_head(chan->vc_wq); | ||
337 | chan->ring_bufs_avail = 1; | ||
338 | |||
296 | mutex_lock(&virtio_9p_lock); | 339 | mutex_lock(&virtio_9p_lock); |
297 | list_add_tail(&chan->chan_list, &virtio_chan_list); | 340 | list_add_tail(&chan->chan_list, &virtio_chan_list); |
298 | mutex_unlock(&virtio_9p_lock); | 341 | mutex_unlock(&virtio_9p_lock); |
299 | return 0; | 342 | return 0; |
300 | 343 | ||
344 | out_free_tag: | ||
345 | kfree(tag); | ||
301 | out_free_vq: | 346 | out_free_vq: |
302 | vdev->config->del_vqs(vdev); | 347 | vdev->config->del_vqs(vdev); |
303 | kfree(chan); | 348 | kfree(chan); |
@@ -371,6 +416,7 @@ static void p9_virtio_remove(struct virtio_device *vdev) | |||
371 | mutex_unlock(&virtio_9p_lock); | 416 | mutex_unlock(&virtio_9p_lock); |
372 | sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr); | 417 | sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr); |
373 | kfree(chan->tag); | 418 | kfree(chan->tag); |
419 | kfree(chan->vc_wq); | ||
374 | kfree(chan); | 420 | kfree(chan); |
375 | 421 | ||
376 | } | 422 | } |