diff options
Diffstat (limited to 'fs/fuse')
-rw-r--r-- | fs/fuse/dir.c | 3 | ||||
-rw-r--r-- | fs/fuse/file.c | 60 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 2 |
3 files changed, 48 insertions, 17 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index fdff346e96fd..8b8eebc5614b 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -224,7 +224,7 @@ static int invalid_nodeid(u64 nodeid) | |||
224 | return !nodeid || nodeid == FUSE_ROOT_ID; | 224 | return !nodeid || nodeid == FUSE_ROOT_ID; |
225 | } | 225 | } |
226 | 226 | ||
227 | struct dentry_operations fuse_dentry_operations = { | 227 | const struct dentry_operations fuse_dentry_operations = { |
228 | .d_revalidate = fuse_dentry_revalidate, | 228 | .d_revalidate = fuse_dentry_revalidate, |
229 | }; | 229 | }; |
230 | 230 | ||
@@ -1032,6 +1032,7 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) | |||
1032 | fuse_put_request(fc, req); | 1032 | fuse_put_request(fc, req); |
1033 | return -ENOMEM; | 1033 | return -ENOMEM; |
1034 | } | 1034 | } |
1035 | req->out.argpages = 1; | ||
1035 | req->num_pages = 1; | 1036 | req->num_pages = 1; |
1036 | req->pages[0] = page; | 1037 | req->pages[0] = page; |
1037 | fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR); | 1038 | fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR); |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index d9fdb7cec538..2b25133524a3 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -386,7 +386,6 @@ void fuse_read_fill(struct fuse_req *req, struct file *file, | |||
386 | req->in.numargs = 1; | 386 | req->in.numargs = 1; |
387 | req->in.args[0].size = sizeof(struct fuse_read_in); | 387 | req->in.args[0].size = sizeof(struct fuse_read_in); |
388 | req->in.args[0].value = inarg; | 388 | req->in.args[0].value = inarg; |
389 | req->out.argpages = 1; | ||
390 | req->out.argvar = 1; | 389 | req->out.argvar = 1; |
391 | req->out.numargs = 1; | 390 | req->out.numargs = 1; |
392 | req->out.args[0].size = count; | 391 | req->out.args[0].size = count; |
@@ -453,6 +452,7 @@ static int fuse_readpage(struct file *file, struct page *page) | |||
453 | attr_ver = fuse_get_attr_version(fc); | 452 | attr_ver = fuse_get_attr_version(fc); |
454 | 453 | ||
455 | req->out.page_zeroing = 1; | 454 | req->out.page_zeroing = 1; |
455 | req->out.argpages = 1; | ||
456 | req->num_pages = 1; | 456 | req->num_pages = 1; |
457 | req->pages[0] = page; | 457 | req->pages[0] = page; |
458 | num_read = fuse_send_read(req, file, inode, pos, count, NULL); | 458 | num_read = fuse_send_read(req, file, inode, pos, count, NULL); |
@@ -510,6 +510,8 @@ static void fuse_send_readpages(struct fuse_req *req, struct file *file, | |||
510 | struct fuse_conn *fc = get_fuse_conn(inode); | 510 | struct fuse_conn *fc = get_fuse_conn(inode); |
511 | loff_t pos = page_offset(req->pages[0]); | 511 | loff_t pos = page_offset(req->pages[0]); |
512 | size_t count = req->num_pages << PAGE_CACHE_SHIFT; | 512 | size_t count = req->num_pages << PAGE_CACHE_SHIFT; |
513 | |||
514 | req->out.argpages = 1; | ||
513 | req->out.page_zeroing = 1; | 515 | req->out.page_zeroing = 1; |
514 | fuse_read_fill(req, file, inode, pos, count, FUSE_READ); | 516 | fuse_read_fill(req, file, inode, pos, count, FUSE_READ); |
515 | req->misc.read.attr_ver = fuse_get_attr_version(fc); | 517 | req->misc.read.attr_ver = fuse_get_attr_version(fc); |
@@ -621,7 +623,6 @@ static void fuse_write_fill(struct fuse_req *req, struct file *file, | |||
621 | inarg->flags = file ? file->f_flags : 0; | 623 | inarg->flags = file ? file->f_flags : 0; |
622 | req->in.h.opcode = FUSE_WRITE; | 624 | req->in.h.opcode = FUSE_WRITE; |
623 | req->in.h.nodeid = get_node_id(inode); | 625 | req->in.h.nodeid = get_node_id(inode); |
624 | req->in.argpages = 1; | ||
625 | req->in.numargs = 2; | 626 | req->in.numargs = 2; |
626 | if (fc->minor < 9) | 627 | if (fc->minor < 9) |
627 | req->in.args[0].size = FUSE_COMPAT_WRITE_IN_SIZE; | 628 | req->in.args[0].size = FUSE_COMPAT_WRITE_IN_SIZE; |
@@ -695,6 +696,7 @@ static int fuse_buffered_write(struct file *file, struct inode *inode, | |||
695 | if (IS_ERR(req)) | 696 | if (IS_ERR(req)) |
696 | return PTR_ERR(req); | 697 | return PTR_ERR(req); |
697 | 698 | ||
699 | req->in.argpages = 1; | ||
698 | req->num_pages = 1; | 700 | req->num_pages = 1; |
699 | req->pages[0] = page; | 701 | req->pages[0] = page; |
700 | req->page_offset = offset; | 702 | req->page_offset = offset; |
@@ -771,6 +773,7 @@ static ssize_t fuse_fill_write_pages(struct fuse_req *req, | |||
771 | size_t count = 0; | 773 | size_t count = 0; |
772 | int err; | 774 | int err; |
773 | 775 | ||
776 | req->in.argpages = 1; | ||
774 | req->page_offset = offset; | 777 | req->page_offset = offset; |
775 | 778 | ||
776 | do { | 779 | do { |
@@ -935,21 +938,28 @@ static void fuse_release_user_pages(struct fuse_req *req, int write) | |||
935 | } | 938 | } |
936 | 939 | ||
937 | static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf, | 940 | static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf, |
938 | unsigned nbytes, int write) | 941 | unsigned *nbytesp, int write) |
939 | { | 942 | { |
943 | unsigned nbytes = *nbytesp; | ||
940 | unsigned long user_addr = (unsigned long) buf; | 944 | unsigned long user_addr = (unsigned long) buf; |
941 | unsigned offset = user_addr & ~PAGE_MASK; | 945 | unsigned offset = user_addr & ~PAGE_MASK; |
942 | int npages; | 946 | int npages; |
943 | 947 | ||
944 | /* This doesn't work with nfsd */ | 948 | /* Special case for kernel I/O: can copy directly into the buffer */ |
945 | if (!current->mm) | 949 | if (segment_eq(get_fs(), KERNEL_DS)) { |
946 | return -EPERM; | 950 | if (write) |
951 | req->in.args[1].value = (void *) user_addr; | ||
952 | else | ||
953 | req->out.args[0].value = (void *) user_addr; | ||
954 | |||
955 | return 0; | ||
956 | } | ||
947 | 957 | ||
948 | nbytes = min(nbytes, (unsigned) FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT); | 958 | nbytes = min(nbytes, (unsigned) FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT); |
949 | npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT; | 959 | npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT; |
950 | npages = clamp(npages, 1, FUSE_MAX_PAGES_PER_REQ); | 960 | npages = clamp(npages, 1, FUSE_MAX_PAGES_PER_REQ); |
951 | down_read(¤t->mm->mmap_sem); | 961 | down_read(¤t->mm->mmap_sem); |
952 | npages = get_user_pages(current, current->mm, user_addr, npages, write, | 962 | npages = get_user_pages(current, current->mm, user_addr, npages, !write, |
953 | 0, req->pages, NULL); | 963 | 0, req->pages, NULL); |
954 | up_read(¤t->mm->mmap_sem); | 964 | up_read(¤t->mm->mmap_sem); |
955 | if (npages < 0) | 965 | if (npages < 0) |
@@ -957,6 +967,15 @@ static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf, | |||
957 | 967 | ||
958 | req->num_pages = npages; | 968 | req->num_pages = npages; |
959 | req->page_offset = offset; | 969 | req->page_offset = offset; |
970 | |||
971 | if (write) | ||
972 | req->in.argpages = 1; | ||
973 | else | ||
974 | req->out.argpages = 1; | ||
975 | |||
976 | nbytes = (req->num_pages << PAGE_SHIFT) - req->page_offset; | ||
977 | *nbytesp = min(*nbytesp, nbytes); | ||
978 | |||
960 | return 0; | 979 | return 0; |
961 | } | 980 | } |
962 | 981 | ||
@@ -979,15 +998,13 @@ static ssize_t fuse_direct_io(struct file *file, const char __user *buf, | |||
979 | 998 | ||
980 | while (count) { | 999 | while (count) { |
981 | size_t nres; | 1000 | size_t nres; |
982 | size_t nbytes_limit = min(count, nmax); | 1001 | size_t nbytes = min(count, nmax); |
983 | size_t nbytes; | 1002 | int err = fuse_get_user_pages(req, buf, &nbytes, write); |
984 | int err = fuse_get_user_pages(req, buf, nbytes_limit, !write); | ||
985 | if (err) { | 1003 | if (err) { |
986 | res = err; | 1004 | res = err; |
987 | break; | 1005 | break; |
988 | } | 1006 | } |
989 | nbytes = (req->num_pages << PAGE_SHIFT) - req->page_offset; | 1007 | |
990 | nbytes = min(nbytes_limit, nbytes); | ||
991 | if (write) | 1008 | if (write) |
992 | nres = fuse_send_write(req, file, inode, pos, nbytes, | 1009 | nres = fuse_send_write(req, file, inode, pos, nbytes, |
993 | current->files); | 1010 | current->files); |
@@ -1163,6 +1180,7 @@ static int fuse_writepage_locked(struct page *page) | |||
1163 | fuse_write_fill(req, NULL, ff, inode, page_offset(page), 0, 1); | 1180 | fuse_write_fill(req, NULL, ff, inode, page_offset(page), 0, 1); |
1164 | 1181 | ||
1165 | copy_highpage(tmp_page, page); | 1182 | copy_highpage(tmp_page, page); |
1183 | req->in.argpages = 1; | ||
1166 | req->num_pages = 1; | 1184 | req->num_pages = 1; |
1167 | req->pages[0] = tmp_page; | 1185 | req->pages[0] = tmp_page; |
1168 | req->page_offset = 0; | 1186 | req->page_offset = 0; |
@@ -1234,8 +1252,9 @@ static void fuse_vma_close(struct vm_area_struct *vma) | |||
1234 | * - sync(2) | 1252 | * - sync(2) |
1235 | * - try_to_free_pages() with order > PAGE_ALLOC_COSTLY_ORDER | 1253 | * - try_to_free_pages() with order > PAGE_ALLOC_COSTLY_ORDER |
1236 | */ | 1254 | */ |
1237 | static int fuse_page_mkwrite(struct vm_area_struct *vma, struct page *page) | 1255 | static int fuse_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) |
1238 | { | 1256 | { |
1257 | struct page *page = vmf->page; | ||
1239 | /* | 1258 | /* |
1240 | * Don't use page->mapping as it may become NULL from a | 1259 | * Don't use page->mapping as it may become NULL from a |
1241 | * concurrent truncate. | 1260 | * concurrent truncate. |
@@ -1273,6 +1292,15 @@ static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma) | |||
1273 | return 0; | 1292 | return 0; |
1274 | } | 1293 | } |
1275 | 1294 | ||
1295 | static int fuse_direct_mmap(struct file *file, struct vm_area_struct *vma) | ||
1296 | { | ||
1297 | /* Can't provide the coherency needed for MAP_SHARED */ | ||
1298 | if (vma->vm_flags & VM_MAYSHARE) | ||
1299 | return -ENODEV; | ||
1300 | |||
1301 | return generic_file_mmap(file, vma); | ||
1302 | } | ||
1303 | |||
1276 | static int convert_fuse_file_lock(const struct fuse_file_lock *ffl, | 1304 | static int convert_fuse_file_lock(const struct fuse_file_lock *ffl, |
1277 | struct file_lock *fl) | 1305 | struct file_lock *fl) |
1278 | { | 1306 | { |
@@ -1465,7 +1493,7 @@ static loff_t fuse_file_llseek(struct file *file, loff_t offset, int origin) | |||
1465 | case SEEK_END: | 1493 | case SEEK_END: |
1466 | retval = fuse_update_attributes(inode, NULL, file, NULL); | 1494 | retval = fuse_update_attributes(inode, NULL, file, NULL); |
1467 | if (retval) | 1495 | if (retval) |
1468 | return retval; | 1496 | goto exit; |
1469 | offset += i_size_read(inode); | 1497 | offset += i_size_read(inode); |
1470 | break; | 1498 | break; |
1471 | case SEEK_CUR: | 1499 | case SEEK_CUR: |
@@ -1479,6 +1507,7 @@ static loff_t fuse_file_llseek(struct file *file, loff_t offset, int origin) | |||
1479 | } | 1507 | } |
1480 | retval = offset; | 1508 | retval = offset; |
1481 | } | 1509 | } |
1510 | exit: | ||
1482 | mutex_unlock(&inode->i_mutex); | 1511 | mutex_unlock(&inode->i_mutex); |
1483 | return retval; | 1512 | return retval; |
1484 | } | 1513 | } |
@@ -1906,6 +1935,7 @@ static const struct file_operations fuse_direct_io_file_operations = { | |||
1906 | .llseek = fuse_file_llseek, | 1935 | .llseek = fuse_file_llseek, |
1907 | .read = fuse_direct_read, | 1936 | .read = fuse_direct_read, |
1908 | .write = fuse_direct_write, | 1937 | .write = fuse_direct_write, |
1938 | .mmap = fuse_direct_mmap, | ||
1909 | .open = fuse_open, | 1939 | .open = fuse_open, |
1910 | .flush = fuse_flush, | 1940 | .flush = fuse_flush, |
1911 | .release = fuse_release, | 1941 | .release = fuse_release, |
@@ -1915,7 +1945,7 @@ static const struct file_operations fuse_direct_io_file_operations = { | |||
1915 | .unlocked_ioctl = fuse_file_ioctl, | 1945 | .unlocked_ioctl = fuse_file_ioctl, |
1916 | .compat_ioctl = fuse_file_compat_ioctl, | 1946 | .compat_ioctl = fuse_file_compat_ioctl, |
1917 | .poll = fuse_file_poll, | 1947 | .poll = fuse_file_poll, |
1918 | /* no mmap and splice_read */ | 1948 | /* no splice_read */ |
1919 | }; | 1949 | }; |
1920 | 1950 | ||
1921 | static const struct address_space_operations fuse_file_aops = { | 1951 | static const struct address_space_operations fuse_file_aops = { |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 5e64b815a5a1..6fc5aedaa0d5 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -493,7 +493,7 @@ static inline u64 get_node_id(struct inode *inode) | |||
493 | /** Device operations */ | 493 | /** Device operations */ |
494 | extern const struct file_operations fuse_dev_operations; | 494 | extern const struct file_operations fuse_dev_operations; |
495 | 495 | ||
496 | extern struct dentry_operations fuse_dentry_operations; | 496 | extern const struct dentry_operations fuse_dentry_operations; |
497 | 497 | ||
498 | /** | 498 | /** |
499 | * Get a filled in inode | 499 | * Get a filled in inode |