diff options
-rw-r--r-- | fs/fuse/dev.c | 229 | ||||
-rw-r--r-- | fs/fuse/file.c | 2 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 3 | ||||
-rw-r--r-- | include/linux/fuse.h | 34 |
4 files changed, 260 insertions, 8 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 9424796d6634..69ad053ffd78 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -239,7 +239,6 @@ static u64 fuse_get_unique(struct fuse_conn *fc) | |||
239 | 239 | ||
240 | static void queue_request(struct fuse_conn *fc, struct fuse_req *req) | 240 | static void queue_request(struct fuse_conn *fc, struct fuse_req *req) |
241 | { | 241 | { |
242 | req->in.h.unique = fuse_get_unique(fc); | ||
243 | req->in.h.len = sizeof(struct fuse_in_header) + | 242 | req->in.h.len = sizeof(struct fuse_in_header) + |
244 | len_args(req->in.numargs, (struct fuse_arg *) req->in.args); | 243 | len_args(req->in.numargs, (struct fuse_arg *) req->in.args); |
245 | list_add_tail(&req->list, &fc->pending); | 244 | list_add_tail(&req->list, &fc->pending); |
@@ -261,6 +260,7 @@ static void flush_bg_queue(struct fuse_conn *fc) | |||
261 | req = list_entry(fc->bg_queue.next, struct fuse_req, list); | 260 | req = list_entry(fc->bg_queue.next, struct fuse_req, list); |
262 | list_del(&req->list); | 261 | list_del(&req->list); |
263 | fc->active_background++; | 262 | fc->active_background++; |
263 | req->in.h.unique = fuse_get_unique(fc); | ||
264 | queue_request(fc, req); | 264 | queue_request(fc, req); |
265 | } | 265 | } |
266 | } | 266 | } |
@@ -398,6 +398,7 @@ void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req) | |||
398 | else if (fc->conn_error) | 398 | else if (fc->conn_error) |
399 | req->out.h.error = -ECONNREFUSED; | 399 | req->out.h.error = -ECONNREFUSED; |
400 | else { | 400 | else { |
401 | req->in.h.unique = fuse_get_unique(fc); | ||
401 | queue_request(fc, req); | 402 | queue_request(fc, req); |
402 | /* acquire extra reference, since request is still needed | 403 | /* acquire extra reference, since request is still needed |
403 | after request_end() */ | 404 | after request_end() */ |
@@ -450,6 +451,23 @@ void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req) | |||
450 | } | 451 | } |
451 | EXPORT_SYMBOL_GPL(fuse_request_send_background); | 452 | EXPORT_SYMBOL_GPL(fuse_request_send_background); |
452 | 453 | ||
454 | static int fuse_request_send_notify_reply(struct fuse_conn *fc, | ||
455 | struct fuse_req *req, u64 unique) | ||
456 | { | ||
457 | int err = -ENODEV; | ||
458 | |||
459 | req->isreply = 0; | ||
460 | req->in.h.unique = unique; | ||
461 | spin_lock(&fc->lock); | ||
462 | if (fc->connected) { | ||
463 | queue_request(fc, req); | ||
464 | err = 0; | ||
465 | } | ||
466 | spin_unlock(&fc->lock); | ||
467 | |||
468 | return err; | ||
469 | } | ||
470 | |||
453 | /* | 471 | /* |
454 | * Called under fc->lock | 472 | * Called under fc->lock |
455 | * | 473 | * |
@@ -535,13 +553,13 @@ static void fuse_copy_finish(struct fuse_copy_state *cs) | |||
535 | if (!cs->write) { | 553 | if (!cs->write) { |
536 | buf->ops->unmap(cs->pipe, buf, cs->mapaddr); | 554 | buf->ops->unmap(cs->pipe, buf, cs->mapaddr); |
537 | } else { | 555 | } else { |
538 | kunmap_atomic(cs->mapaddr, KM_USER0); | 556 | kunmap(buf->page); |
539 | buf->len = PAGE_SIZE - cs->len; | 557 | buf->len = PAGE_SIZE - cs->len; |
540 | } | 558 | } |
541 | cs->currbuf = NULL; | 559 | cs->currbuf = NULL; |
542 | cs->mapaddr = NULL; | 560 | cs->mapaddr = NULL; |
543 | } else if (cs->mapaddr) { | 561 | } else if (cs->mapaddr) { |
544 | kunmap_atomic(cs->mapaddr, KM_USER0); | 562 | kunmap(cs->pg); |
545 | if (cs->write) { | 563 | if (cs->write) { |
546 | flush_dcache_page(cs->pg); | 564 | flush_dcache_page(cs->pg); |
547 | set_page_dirty_lock(cs->pg); | 565 | set_page_dirty_lock(cs->pg); |
@@ -572,7 +590,7 @@ static int fuse_copy_fill(struct fuse_copy_state *cs) | |||
572 | 590 | ||
573 | BUG_ON(!cs->nr_segs); | 591 | BUG_ON(!cs->nr_segs); |
574 | cs->currbuf = buf; | 592 | cs->currbuf = buf; |
575 | cs->mapaddr = buf->ops->map(cs->pipe, buf, 1); | 593 | cs->mapaddr = buf->ops->map(cs->pipe, buf, 0); |
576 | cs->len = buf->len; | 594 | cs->len = buf->len; |
577 | cs->buf = cs->mapaddr + buf->offset; | 595 | cs->buf = cs->mapaddr + buf->offset; |
578 | cs->pipebufs++; | 596 | cs->pipebufs++; |
@@ -592,7 +610,7 @@ static int fuse_copy_fill(struct fuse_copy_state *cs) | |||
592 | buf->len = 0; | 610 | buf->len = 0; |
593 | 611 | ||
594 | cs->currbuf = buf; | 612 | cs->currbuf = buf; |
595 | cs->mapaddr = kmap_atomic(page, KM_USER0); | 613 | cs->mapaddr = kmap(page); |
596 | cs->buf = cs->mapaddr; | 614 | cs->buf = cs->mapaddr; |
597 | cs->len = PAGE_SIZE; | 615 | cs->len = PAGE_SIZE; |
598 | cs->pipebufs++; | 616 | cs->pipebufs++; |
@@ -611,7 +629,7 @@ static int fuse_copy_fill(struct fuse_copy_state *cs) | |||
611 | return err; | 629 | return err; |
612 | BUG_ON(err != 1); | 630 | BUG_ON(err != 1); |
613 | offset = cs->addr % PAGE_SIZE; | 631 | offset = cs->addr % PAGE_SIZE; |
614 | cs->mapaddr = kmap_atomic(cs->pg, KM_USER0); | 632 | cs->mapaddr = kmap(cs->pg); |
615 | cs->buf = cs->mapaddr + offset; | 633 | cs->buf = cs->mapaddr + offset; |
616 | cs->len = min(PAGE_SIZE - offset, cs->seglen); | 634 | cs->len = min(PAGE_SIZE - offset, cs->seglen); |
617 | cs->seglen -= cs->len; | 635 | cs->seglen -= cs->len; |
@@ -1231,6 +1249,199 @@ err: | |||
1231 | return err; | 1249 | return err; |
1232 | } | 1250 | } |
1233 | 1251 | ||
1252 | static int fuse_notify_store(struct fuse_conn *fc, unsigned int size, | ||
1253 | struct fuse_copy_state *cs) | ||
1254 | { | ||
1255 | struct fuse_notify_store_out outarg; | ||
1256 | struct inode *inode; | ||
1257 | struct address_space *mapping; | ||
1258 | u64 nodeid; | ||
1259 | int err; | ||
1260 | pgoff_t index; | ||
1261 | unsigned int offset; | ||
1262 | unsigned int num; | ||
1263 | loff_t file_size; | ||
1264 | loff_t end; | ||
1265 | |||
1266 | err = -EINVAL; | ||
1267 | if (size < sizeof(outarg)) | ||
1268 | goto out_finish; | ||
1269 | |||
1270 | err = fuse_copy_one(cs, &outarg, sizeof(outarg)); | ||
1271 | if (err) | ||
1272 | goto out_finish; | ||
1273 | |||
1274 | err = -EINVAL; | ||
1275 | if (size - sizeof(outarg) != outarg.size) | ||
1276 | goto out_finish; | ||
1277 | |||
1278 | nodeid = outarg.nodeid; | ||
1279 | |||
1280 | down_read(&fc->killsb); | ||
1281 | |||
1282 | err = -ENOENT; | ||
1283 | if (!fc->sb) | ||
1284 | goto out_up_killsb; | ||
1285 | |||
1286 | inode = ilookup5(fc->sb, nodeid, fuse_inode_eq, &nodeid); | ||
1287 | if (!inode) | ||
1288 | goto out_up_killsb; | ||
1289 | |||
1290 | mapping = inode->i_mapping; | ||
1291 | index = outarg.offset >> PAGE_CACHE_SHIFT; | ||
1292 | offset = outarg.offset & ~PAGE_CACHE_MASK; | ||
1293 | file_size = i_size_read(inode); | ||
1294 | end = outarg.offset + outarg.size; | ||
1295 | if (end > file_size) { | ||
1296 | file_size = end; | ||
1297 | fuse_write_update_size(inode, file_size); | ||
1298 | } | ||
1299 | |||
1300 | num = outarg.size; | ||
1301 | while (num) { | ||
1302 | struct page *page; | ||
1303 | unsigned int this_num; | ||
1304 | |||
1305 | err = -ENOMEM; | ||
1306 | page = find_or_create_page(mapping, index, | ||
1307 | mapping_gfp_mask(mapping)); | ||
1308 | if (!page) | ||
1309 | goto out_iput; | ||
1310 | |||
1311 | this_num = min_t(unsigned, num, PAGE_CACHE_SIZE - offset); | ||
1312 | err = fuse_copy_page(cs, &page, offset, this_num, 0); | ||
1313 | if (!err && offset == 0 && (num != 0 || file_size == end)) | ||
1314 | SetPageUptodate(page); | ||
1315 | unlock_page(page); | ||
1316 | page_cache_release(page); | ||
1317 | |||
1318 | if (err) | ||
1319 | goto out_iput; | ||
1320 | |||
1321 | num -= this_num; | ||
1322 | offset = 0; | ||
1323 | index++; | ||
1324 | } | ||
1325 | |||
1326 | err = 0; | ||
1327 | |||
1328 | out_iput: | ||
1329 | iput(inode); | ||
1330 | out_up_killsb: | ||
1331 | up_read(&fc->killsb); | ||
1332 | out_finish: | ||
1333 | fuse_copy_finish(cs); | ||
1334 | return err; | ||
1335 | } | ||
1336 | |||
1337 | static void fuse_retrieve_end(struct fuse_conn *fc, struct fuse_req *req) | ||
1338 | { | ||
1339 | int i; | ||
1340 | |||
1341 | for (i = 0; i < req->num_pages; i++) { | ||
1342 | struct page *page = req->pages[i]; | ||
1343 | page_cache_release(page); | ||
1344 | } | ||
1345 | } | ||
1346 | |||
1347 | static int fuse_retrieve(struct fuse_conn *fc, struct inode *inode, | ||
1348 | struct fuse_notify_retrieve_out *outarg) | ||
1349 | { | ||
1350 | int err; | ||
1351 | struct address_space *mapping = inode->i_mapping; | ||
1352 | struct fuse_req *req; | ||
1353 | pgoff_t index; | ||
1354 | loff_t file_size; | ||
1355 | unsigned int num; | ||
1356 | unsigned int offset; | ||
1357 | size_t total_len; | ||
1358 | |||
1359 | req = fuse_get_req(fc); | ||
1360 | if (IS_ERR(req)) | ||
1361 | return PTR_ERR(req); | ||
1362 | |||
1363 | offset = outarg->offset & ~PAGE_CACHE_MASK; | ||
1364 | |||
1365 | req->in.h.opcode = FUSE_NOTIFY_REPLY; | ||
1366 | req->in.h.nodeid = outarg->nodeid; | ||
1367 | req->in.numargs = 2; | ||
1368 | req->in.argpages = 1; | ||
1369 | req->page_offset = offset; | ||
1370 | req->end = fuse_retrieve_end; | ||
1371 | |||
1372 | index = outarg->offset >> PAGE_CACHE_SHIFT; | ||
1373 | file_size = i_size_read(inode); | ||
1374 | num = outarg->size; | ||
1375 | if (outarg->offset > file_size) | ||
1376 | num = 0; | ||
1377 | else if (outarg->offset + num > file_size) | ||
1378 | num = file_size - outarg->offset; | ||
1379 | |||
1380 | while (num) { | ||
1381 | struct page *page; | ||
1382 | unsigned int this_num; | ||
1383 | |||
1384 | page = find_get_page(mapping, index); | ||
1385 | if (!page) | ||
1386 | break; | ||
1387 | |||
1388 | this_num = min_t(unsigned, num, PAGE_CACHE_SIZE - offset); | ||
1389 | req->pages[req->num_pages] = page; | ||
1390 | req->num_pages++; | ||
1391 | |||
1392 | num -= this_num; | ||
1393 | total_len += this_num; | ||
1394 | } | ||
1395 | req->misc.retrieve_in.offset = outarg->offset; | ||
1396 | req->misc.retrieve_in.size = total_len; | ||
1397 | req->in.args[0].size = sizeof(req->misc.retrieve_in); | ||
1398 | req->in.args[0].value = &req->misc.retrieve_in; | ||
1399 | req->in.args[1].size = total_len; | ||
1400 | |||
1401 | err = fuse_request_send_notify_reply(fc, req, outarg->notify_unique); | ||
1402 | if (err) | ||
1403 | fuse_retrieve_end(fc, req); | ||
1404 | |||
1405 | return err; | ||
1406 | } | ||
1407 | |||
1408 | static int fuse_notify_retrieve(struct fuse_conn *fc, unsigned int size, | ||
1409 | struct fuse_copy_state *cs) | ||
1410 | { | ||
1411 | struct fuse_notify_retrieve_out outarg; | ||
1412 | struct inode *inode; | ||
1413 | int err; | ||
1414 | |||
1415 | err = -EINVAL; | ||
1416 | if (size != sizeof(outarg)) | ||
1417 | goto copy_finish; | ||
1418 | |||
1419 | err = fuse_copy_one(cs, &outarg, sizeof(outarg)); | ||
1420 | if (err) | ||
1421 | goto copy_finish; | ||
1422 | |||
1423 | fuse_copy_finish(cs); | ||
1424 | |||
1425 | down_read(&fc->killsb); | ||
1426 | err = -ENOENT; | ||
1427 | if (fc->sb) { | ||
1428 | u64 nodeid = outarg.nodeid; | ||
1429 | |||
1430 | inode = ilookup5(fc->sb, nodeid, fuse_inode_eq, &nodeid); | ||
1431 | if (inode) { | ||
1432 | err = fuse_retrieve(fc, inode, &outarg); | ||
1433 | iput(inode); | ||
1434 | } | ||
1435 | } | ||
1436 | up_read(&fc->killsb); | ||
1437 | |||
1438 | return err; | ||
1439 | |||
1440 | copy_finish: | ||
1441 | fuse_copy_finish(cs); | ||
1442 | return err; | ||
1443 | } | ||
1444 | |||
1234 | static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code, | 1445 | static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code, |
1235 | unsigned int size, struct fuse_copy_state *cs) | 1446 | unsigned int size, struct fuse_copy_state *cs) |
1236 | { | 1447 | { |
@@ -1244,6 +1455,12 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code, | |||
1244 | case FUSE_NOTIFY_INVAL_ENTRY: | 1455 | case FUSE_NOTIFY_INVAL_ENTRY: |
1245 | return fuse_notify_inval_entry(fc, size, cs); | 1456 | return fuse_notify_inval_entry(fc, size, cs); |
1246 | 1457 | ||
1458 | case FUSE_NOTIFY_STORE: | ||
1459 | return fuse_notify_store(fc, size, cs); | ||
1460 | |||
1461 | case FUSE_NOTIFY_RETRIEVE: | ||
1462 | return fuse_notify_retrieve(fc, size, cs); | ||
1463 | |||
1247 | default: | 1464 | default: |
1248 | fuse_copy_finish(cs); | 1465 | fuse_copy_finish(cs); |
1249 | return -EINVAL; | 1466 | return -EINVAL; |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index ada0adeb3bb5..147c1f71bdb9 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -706,7 +706,7 @@ static int fuse_write_begin(struct file *file, struct address_space *mapping, | |||
706 | return 0; | 706 | return 0; |
707 | } | 707 | } |
708 | 708 | ||
709 | static void fuse_write_update_size(struct inode *inode, loff_t pos) | 709 | void fuse_write_update_size(struct inode *inode, loff_t pos) |
710 | { | 710 | { |
711 | struct fuse_conn *fc = get_fuse_conn(inode); | 711 | struct fuse_conn *fc = get_fuse_conn(inode); |
712 | struct fuse_inode *fi = get_fuse_inode(inode); | 712 | struct fuse_inode *fi = get_fuse_inode(inode); |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 8f309f04064e..57d4a3a0f102 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -272,6 +272,7 @@ struct fuse_req { | |||
272 | struct fuse_write_in in; | 272 | struct fuse_write_in in; |
273 | struct fuse_write_out out; | 273 | struct fuse_write_out out; |
274 | } write; | 274 | } write; |
275 | struct fuse_notify_retrieve_in retrieve_in; | ||
275 | struct fuse_lk_in lk_in; | 276 | struct fuse_lk_in lk_in; |
276 | } misc; | 277 | } misc; |
277 | 278 | ||
@@ -748,4 +749,6 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, | |||
748 | unsigned fuse_file_poll(struct file *file, poll_table *wait); | 749 | unsigned fuse_file_poll(struct file *file, poll_table *wait); |
749 | int fuse_dev_release(struct inode *inode, struct file *file); | 750 | int fuse_dev_release(struct inode *inode, struct file *file); |
750 | 751 | ||
752 | void fuse_write_update_size(struct inode *inode, loff_t pos); | ||
753 | |||
751 | #endif /* _FS_FUSE_I_H */ | 754 | #endif /* _FS_FUSE_I_H */ |
diff --git a/include/linux/fuse.h b/include/linux/fuse.h index 88e0eb596919..c3c578e09833 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h | |||
@@ -37,6 +37,10 @@ | |||
37 | * | 37 | * |
38 | * 7.14 | 38 | * 7.14 |
39 | * - add splice support to fuse device | 39 | * - add splice support to fuse device |
40 | * | ||
41 | * 7.15 | ||
42 | * - add store notify | ||
43 | * - add retrieve notify | ||
40 | */ | 44 | */ |
41 | 45 | ||
42 | #ifndef _LINUX_FUSE_H | 46 | #ifndef _LINUX_FUSE_H |
@@ -68,7 +72,7 @@ | |||
68 | #define FUSE_KERNEL_VERSION 7 | 72 | #define FUSE_KERNEL_VERSION 7 |
69 | 73 | ||
70 | /** Minor version number of this interface */ | 74 | /** Minor version number of this interface */ |
71 | #define FUSE_KERNEL_MINOR_VERSION 14 | 75 | #define FUSE_KERNEL_MINOR_VERSION 15 |
72 | 76 | ||
73 | /** The node ID of the root inode */ | 77 | /** The node ID of the root inode */ |
74 | #define FUSE_ROOT_ID 1 | 78 | #define FUSE_ROOT_ID 1 |
@@ -251,6 +255,7 @@ enum fuse_opcode { | |||
251 | FUSE_DESTROY = 38, | 255 | FUSE_DESTROY = 38, |
252 | FUSE_IOCTL = 39, | 256 | FUSE_IOCTL = 39, |
253 | FUSE_POLL = 40, | 257 | FUSE_POLL = 40, |
258 | FUSE_NOTIFY_REPLY = 41, | ||
254 | 259 | ||
255 | /* CUSE specific operations */ | 260 | /* CUSE specific operations */ |
256 | CUSE_INIT = 4096, | 261 | CUSE_INIT = 4096, |
@@ -260,6 +265,8 @@ enum fuse_notify_code { | |||
260 | FUSE_NOTIFY_POLL = 1, | 265 | FUSE_NOTIFY_POLL = 1, |
261 | FUSE_NOTIFY_INVAL_INODE = 2, | 266 | FUSE_NOTIFY_INVAL_INODE = 2, |
262 | FUSE_NOTIFY_INVAL_ENTRY = 3, | 267 | FUSE_NOTIFY_INVAL_ENTRY = 3, |
268 | FUSE_NOTIFY_STORE = 4, | ||
269 | FUSE_NOTIFY_RETRIEVE = 5, | ||
263 | FUSE_NOTIFY_CODE_MAX, | 270 | FUSE_NOTIFY_CODE_MAX, |
264 | }; | 271 | }; |
265 | 272 | ||
@@ -568,4 +575,29 @@ struct fuse_notify_inval_entry_out { | |||
568 | __u32 padding; | 575 | __u32 padding; |
569 | }; | 576 | }; |
570 | 577 | ||
578 | struct fuse_notify_store_out { | ||
579 | __u64 nodeid; | ||
580 | __u64 offset; | ||
581 | __u32 size; | ||
582 | __u32 padding; | ||
583 | }; | ||
584 | |||
585 | struct fuse_notify_retrieve_out { | ||
586 | __u64 notify_unique; | ||
587 | __u64 nodeid; | ||
588 | __u64 offset; | ||
589 | __u32 size; | ||
590 | __u32 padding; | ||
591 | }; | ||
592 | |||
593 | /* Matches the size of fuse_write_in */ | ||
594 | struct fuse_notify_retrieve_in { | ||
595 | __u64 dummy1; | ||
596 | __u64 offset; | ||
597 | __u32 size; | ||
598 | __u32 dummy2; | ||
599 | __u64 dummy3; | ||
600 | __u64 dummy4; | ||
601 | }; | ||
602 | |||
571 | #endif /* _LINUX_FUSE_H */ | 603 | #endif /* _LINUX_FUSE_H */ |