diff options
author | Matthew Wilcox <matthew.r.wilcox@intel.com> | 2015-02-16 18:58:56 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-16 20:56:03 -0500 |
commit | d475c6346a38aef3058eba96867bfa726a3cc940 (patch) | |
tree | 4d69d0f50a4a8e649a751dca8f710485848c0249 /mm | |
parent | fbbbad4bc2101e452b24e6e65d3d5e11314a0b5f (diff) |
dax,ext2: replace XIP read and write with DAX I/O
Use the generic AIO infrastructure instead of custom read and write
methods. In addition to giving us support for AIO, this adds the missing
locking between read() and truncate().
Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
Reviewed-by: Ross Zwisler <ross.zwisler@linux.intel.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Cc: Andreas Dilger <andreas.dilger@intel.com>
Cc: Boaz Harrosh <boaz@plexistor.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/filemap.c | 6 | ||||
-rw-r--r-- | mm/filemap_xip.c | 234 |
2 files changed, 2 insertions, 238 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 1578c224285e..ad7242043bdb 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -1695,8 +1695,7 @@ generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter) | |||
1695 | loff_t *ppos = &iocb->ki_pos; | 1695 | loff_t *ppos = &iocb->ki_pos; |
1696 | loff_t pos = *ppos; | 1696 | loff_t pos = *ppos; |
1697 | 1697 | ||
1698 | /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ | 1698 | if (io_is_direct(file)) { |
1699 | if (file->f_flags & O_DIRECT) { | ||
1700 | struct address_space *mapping = file->f_mapping; | 1699 | struct address_space *mapping = file->f_mapping; |
1701 | struct inode *inode = mapping->host; | 1700 | struct inode *inode = mapping->host; |
1702 | size_t count = iov_iter_count(iter); | 1701 | size_t count = iov_iter_count(iter); |
@@ -2584,8 +2583,7 @@ ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
2584 | if (err) | 2583 | if (err) |
2585 | goto out; | 2584 | goto out; |
2586 | 2585 | ||
2587 | /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ | 2586 | if (io_is_direct(file)) { |
2588 | if (unlikely(file->f_flags & O_DIRECT)) { | ||
2589 | loff_t endbyte; | 2587 | loff_t endbyte; |
2590 | 2588 | ||
2591 | written = generic_file_direct_write(iocb, from, pos); | 2589 | written = generic_file_direct_write(iocb, from, pos); |
diff --git a/mm/filemap_xip.c b/mm/filemap_xip.c index 59e1c5585748..9c869f402c07 100644 --- a/mm/filemap_xip.c +++ b/mm/filemap_xip.c | |||
@@ -43,119 +43,6 @@ static struct page *xip_sparse_page(void) | |||
43 | } | 43 | } |
44 | 44 | ||
45 | /* | 45 | /* |
46 | * This is a file read routine for execute in place files, and uses | ||
47 | * the mapping->a_ops->get_xip_mem() function for the actual low-level | ||
48 | * stuff. | ||
49 | * | ||
50 | * Note the struct file* is not used at all. It may be NULL. | ||
51 | */ | ||
52 | static ssize_t | ||
53 | do_xip_mapping_read(struct address_space *mapping, | ||
54 | struct file_ra_state *_ra, | ||
55 | struct file *filp, | ||
56 | char __user *buf, | ||
57 | size_t len, | ||
58 | loff_t *ppos) | ||
59 | { | ||
60 | struct inode *inode = mapping->host; | ||
61 | pgoff_t index, end_index; | ||
62 | unsigned long offset; | ||
63 | loff_t isize, pos; | ||
64 | size_t copied = 0, error = 0; | ||
65 | |||
66 | BUG_ON(!mapping->a_ops->get_xip_mem); | ||
67 | |||
68 | pos = *ppos; | ||
69 | index = pos >> PAGE_CACHE_SHIFT; | ||
70 | offset = pos & ~PAGE_CACHE_MASK; | ||
71 | |||
72 | isize = i_size_read(inode); | ||
73 | if (!isize) | ||
74 | goto out; | ||
75 | |||
76 | end_index = (isize - 1) >> PAGE_CACHE_SHIFT; | ||
77 | do { | ||
78 | unsigned long nr, left; | ||
79 | void *xip_mem; | ||
80 | unsigned long xip_pfn; | ||
81 | int zero = 0; | ||
82 | |||
83 | /* nr is the maximum number of bytes to copy from this page */ | ||
84 | nr = PAGE_CACHE_SIZE; | ||
85 | if (index >= end_index) { | ||
86 | if (index > end_index) | ||
87 | goto out; | ||
88 | nr = ((isize - 1) & ~PAGE_CACHE_MASK) + 1; | ||
89 | if (nr <= offset) { | ||
90 | goto out; | ||
91 | } | ||
92 | } | ||
93 | nr = nr - offset; | ||
94 | if (nr > len - copied) | ||
95 | nr = len - copied; | ||
96 | |||
97 | error = mapping->a_ops->get_xip_mem(mapping, index, 0, | ||
98 | &xip_mem, &xip_pfn); | ||
99 | if (unlikely(error)) { | ||
100 | if (error == -ENODATA) { | ||
101 | /* sparse */ | ||
102 | zero = 1; | ||
103 | } else | ||
104 | goto out; | ||
105 | } | ||
106 | |||
107 | /* If users can be writing to this page using arbitrary | ||
108 | * virtual addresses, take care about potential aliasing | ||
109 | * before reading the page on the kernel side. | ||
110 | */ | ||
111 | if (mapping_writably_mapped(mapping)) | ||
112 | /* address based flush */ ; | ||
113 | |||
114 | /* | ||
115 | * Ok, we have the mem, so now we can copy it to user space... | ||
116 | * | ||
117 | * The actor routine returns how many bytes were actually used.. | ||
118 | * NOTE! This may not be the same as how much of a user buffer | ||
119 | * we filled up (we may be padding etc), so we can only update | ||
120 | * "pos" here (the actor routine has to update the user buffer | ||
121 | * pointers and the remaining count). | ||
122 | */ | ||
123 | if (!zero) | ||
124 | left = __copy_to_user(buf+copied, xip_mem+offset, nr); | ||
125 | else | ||
126 | left = __clear_user(buf + copied, nr); | ||
127 | |||
128 | if (left) { | ||
129 | error = -EFAULT; | ||
130 | goto out; | ||
131 | } | ||
132 | |||
133 | copied += (nr - left); | ||
134 | offset += (nr - left); | ||
135 | index += offset >> PAGE_CACHE_SHIFT; | ||
136 | offset &= ~PAGE_CACHE_MASK; | ||
137 | } while (copied < len); | ||
138 | |||
139 | out: | ||
140 | *ppos = pos + copied; | ||
141 | if (filp) | ||
142 | file_accessed(filp); | ||
143 | |||
144 | return (copied ? copied : error); | ||
145 | } | ||
146 | |||
147 | ssize_t | ||
148 | xip_file_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) | ||
149 | { | ||
150 | if (!access_ok(VERIFY_WRITE, buf, len)) | ||
151 | return -EFAULT; | ||
152 | |||
153 | return do_xip_mapping_read(filp->f_mapping, &filp->f_ra, filp, | ||
154 | buf, len, ppos); | ||
155 | } | ||
156 | EXPORT_SYMBOL_GPL(xip_file_read); | ||
157 | |||
158 | /* | ||
159 | * __xip_unmap is invoked from xip_unmap and xip_write | 46 | * __xip_unmap is invoked from xip_unmap and xip_write |
160 | * | 47 | * |
161 | * This function walks all vmas of the address_space and unmaps the | 48 | * This function walks all vmas of the address_space and unmaps the |
@@ -341,127 +228,6 @@ int xip_file_mmap(struct file * file, struct vm_area_struct * vma) | |||
341 | } | 228 | } |
342 | EXPORT_SYMBOL_GPL(xip_file_mmap); | 229 | EXPORT_SYMBOL_GPL(xip_file_mmap); |
343 | 230 | ||
344 | static ssize_t | ||
345 | __xip_file_write(struct file *filp, const char __user *buf, | ||
346 | size_t count, loff_t pos, loff_t *ppos) | ||
347 | { | ||
348 | struct address_space * mapping = filp->f_mapping; | ||
349 | const struct address_space_operations *a_ops = mapping->a_ops; | ||
350 | struct inode *inode = mapping->host; | ||
351 | long status = 0; | ||
352 | size_t bytes; | ||
353 | ssize_t written = 0; | ||
354 | |||
355 | BUG_ON(!mapping->a_ops->get_xip_mem); | ||
356 | |||
357 | do { | ||
358 | unsigned long index; | ||
359 | unsigned long offset; | ||
360 | size_t copied; | ||
361 | void *xip_mem; | ||
362 | unsigned long xip_pfn; | ||
363 | |||
364 | offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */ | ||
365 | index = pos >> PAGE_CACHE_SHIFT; | ||
366 | bytes = PAGE_CACHE_SIZE - offset; | ||
367 | if (bytes > count) | ||
368 | bytes = count; | ||
369 | |||
370 | status = a_ops->get_xip_mem(mapping, index, 0, | ||
371 | &xip_mem, &xip_pfn); | ||
372 | if (status == -ENODATA) { | ||
373 | /* we allocate a new page unmap it */ | ||
374 | mutex_lock(&xip_sparse_mutex); | ||
375 | status = a_ops->get_xip_mem(mapping, index, 1, | ||
376 | &xip_mem, &xip_pfn); | ||
377 | mutex_unlock(&xip_sparse_mutex); | ||
378 | if (!status) | ||
379 | /* unmap page at pgoff from all other vmas */ | ||
380 | __xip_unmap(mapping, index); | ||
381 | } | ||
382 | |||
383 | if (status) | ||
384 | break; | ||
385 | |||
386 | copied = bytes - | ||
387 | __copy_from_user_nocache(xip_mem + offset, buf, bytes); | ||
388 | |||
389 | if (likely(copied > 0)) { | ||
390 | status = copied; | ||
391 | |||
392 | if (status >= 0) { | ||
393 | written += status; | ||
394 | count -= status; | ||
395 | pos += status; | ||
396 | buf += status; | ||
397 | } | ||
398 | } | ||
399 | if (unlikely(copied != bytes)) | ||
400 | if (status >= 0) | ||
401 | status = -EFAULT; | ||
402 | if (status < 0) | ||
403 | break; | ||
404 | } while (count); | ||
405 | *ppos = pos; | ||
406 | /* | ||
407 | * No need to use i_size_read() here, the i_size | ||
408 | * cannot change under us because we hold i_mutex. | ||
409 | */ | ||
410 | if (pos > inode->i_size) { | ||
411 | i_size_write(inode, pos); | ||
412 | mark_inode_dirty(inode); | ||
413 | } | ||
414 | |||
415 | return written ? written : status; | ||
416 | } | ||
417 | |||
418 | ssize_t | ||
419 | xip_file_write(struct file *filp, const char __user *buf, size_t len, | ||
420 | loff_t *ppos) | ||
421 | { | ||
422 | struct address_space *mapping = filp->f_mapping; | ||
423 | struct inode *inode = mapping->host; | ||
424 | size_t count; | ||
425 | loff_t pos; | ||
426 | ssize_t ret; | ||
427 | |||
428 | mutex_lock(&inode->i_mutex); | ||
429 | |||
430 | if (!access_ok(VERIFY_READ, buf, len)) { | ||
431 | ret=-EFAULT; | ||
432 | goto out_up; | ||
433 | } | ||
434 | |||
435 | pos = *ppos; | ||
436 | count = len; | ||
437 | |||
438 | /* We can write back this queue in page reclaim */ | ||
439 | current->backing_dev_info = inode_to_bdi(inode); | ||
440 | |||
441 | ret = generic_write_checks(filp, &pos, &count, S_ISBLK(inode->i_mode)); | ||
442 | if (ret) | ||
443 | goto out_backing; | ||
444 | if (count == 0) | ||
445 | goto out_backing; | ||
446 | |||
447 | ret = file_remove_suid(filp); | ||
448 | if (ret) | ||
449 | goto out_backing; | ||
450 | |||
451 | ret = file_update_time(filp); | ||
452 | if (ret) | ||
453 | goto out_backing; | ||
454 | |||
455 | ret = __xip_file_write (filp, buf, count, pos, ppos); | ||
456 | |||
457 | out_backing: | ||
458 | current->backing_dev_info = NULL; | ||
459 | out_up: | ||
460 | mutex_unlock(&inode->i_mutex); | ||
461 | return ret; | ||
462 | } | ||
463 | EXPORT_SYMBOL_GPL(xip_file_write); | ||
464 | |||
465 | /* | 231 | /* |
466 | * truncate a page used for execute in place | 232 | * truncate a page used for execute in place |
467 | * functionality is analog to block_truncate_page but does use get_xip_mem | 233 | * functionality is analog to block_truncate_page but does use get_xip_mem |