diff options
| author | Hugh Dickins <hugh@veritas.com> | 2008-02-05 01:28:44 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-05 12:44:15 -0500 |
| commit | 5402b976ae0be96b3a32f3508ab7308c380d6477 (patch) | |
| tree | d2c0900086033ea1fdeb3e1540e733d962cd177c /mm/shmem.c | |
| parent | d3602444e1e3485890eea5f61366e19a287c00c4 (diff) | |
shmem_file_write is redundant
With the old aops, writing to a tmpfs file had to use its own special method:
the generic method would pass in a fresh page to prepare_write when the right
page was there in swapcache - which was inefficient to handle, even once we'd
concocted the code to handle it.
With the new aops, the generic method uses shmem_write_end, which lets
shmem_getpage find the right page: so now abandon shmem_file_write in favour
of the generic method. Yes, that does do several things that tmpfs hasn't
really needed (notably balance_dirty_pages_ratelimited, which ramfs also
calls); but more use of common code is preferable.
Signed-off-by: Hugh Dickins <hugh@veritas.com>
Cc: Nick Piggin <nickpiggin@yahoo.com.au>
Acked-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/shmem.c')
| -rw-r--r-- | mm/shmem.c | 109 |
1 files changed, 3 insertions, 106 deletions
diff --git a/mm/shmem.c b/mm/shmem.c index 43d071922b..5dfe79048f 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
| @@ -1106,7 +1106,7 @@ static int shmem_getpage(struct inode *inode, unsigned long idx, | |||
| 1106 | * Normally, filepage is NULL on entry, and either found | 1106 | * Normally, filepage is NULL on entry, and either found |
| 1107 | * uptodate immediately, or allocated and zeroed, or read | 1107 | * uptodate immediately, or allocated and zeroed, or read |
| 1108 | * in under swappage, which is then assigned to filepage. | 1108 | * in under swappage, which is then assigned to filepage. |
| 1109 | * But shmem_readpage and shmem_write_begin pass in a locked | 1109 | * But shmem_readpage (required for splice) passes in a locked |
| 1110 | * filepage, which may be found not uptodate by other callers | 1110 | * filepage, which may be found not uptodate by other callers |
| 1111 | * too, and may need to be copied from the swappage read in. | 1111 | * too, and may need to be copied from the swappage read in. |
| 1112 | */ | 1112 | */ |
| @@ -1476,110 +1476,6 @@ shmem_write_end(struct file *file, struct address_space *mapping, | |||
| 1476 | return copied; | 1476 | return copied; |
| 1477 | } | 1477 | } |
| 1478 | 1478 | ||
| 1479 | static ssize_t | ||
| 1480 | shmem_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | ||
| 1481 | { | ||
| 1482 | struct inode *inode = file->f_path.dentry->d_inode; | ||
| 1483 | loff_t pos; | ||
| 1484 | unsigned long written; | ||
| 1485 | ssize_t err; | ||
| 1486 | |||
| 1487 | if ((ssize_t) count < 0) | ||
| 1488 | return -EINVAL; | ||
| 1489 | |||
| 1490 | if (!access_ok(VERIFY_READ, buf, count)) | ||
| 1491 | return -EFAULT; | ||
| 1492 | |||
| 1493 | mutex_lock(&inode->i_mutex); | ||
| 1494 | |||
| 1495 | pos = *ppos; | ||
| 1496 | written = 0; | ||
| 1497 | |||
| 1498 | err = generic_write_checks(file, &pos, &count, 0); | ||
| 1499 | if (err || !count) | ||
| 1500 | goto out; | ||
| 1501 | |||
| 1502 | err = remove_suid(file->f_path.dentry); | ||
| 1503 | if (err) | ||
| 1504 | goto out; | ||
| 1505 | |||
| 1506 | inode->i_ctime = inode->i_mtime = CURRENT_TIME; | ||
| 1507 | |||
| 1508 | do { | ||
| 1509 | struct page *page = NULL; | ||
| 1510 | unsigned long bytes, index, offset; | ||
| 1511 | char *kaddr; | ||
| 1512 | int left; | ||
| 1513 | |||
| 1514 | offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */ | ||
| 1515 | index = pos >> PAGE_CACHE_SHIFT; | ||
| 1516 | bytes = PAGE_CACHE_SIZE - offset; | ||
| 1517 | if (bytes > count) | ||
| 1518 | bytes = count; | ||
| 1519 | |||
| 1520 | /* | ||
| 1521 | * We don't hold page lock across copy from user - | ||
| 1522 | * what would it guard against? - so no deadlock here. | ||
| 1523 | * But it still may be a good idea to prefault below. | ||
| 1524 | */ | ||
| 1525 | |||
| 1526 | err = shmem_getpage(inode, index, &page, SGP_WRITE, NULL); | ||
| 1527 | if (err) | ||
| 1528 | break; | ||
| 1529 | |||
| 1530 | unlock_page(page); | ||
| 1531 | left = bytes; | ||
| 1532 | if (PageHighMem(page)) { | ||
| 1533 | volatile unsigned char dummy; | ||
| 1534 | __get_user(dummy, buf); | ||
| 1535 | __get_user(dummy, buf + bytes - 1); | ||
| 1536 | |||
| 1537 | kaddr = kmap_atomic(page, KM_USER0); | ||
| 1538 | left = __copy_from_user_inatomic(kaddr + offset, | ||
| 1539 | buf, bytes); | ||
| 1540 | kunmap_atomic(kaddr, KM_USER0); | ||
| 1541 | } | ||
| 1542 | if (left) { | ||
| 1543 | kaddr = kmap(page); | ||
| 1544 | left = __copy_from_user(kaddr + offset, buf, bytes); | ||
| 1545 | kunmap(page); | ||
| 1546 | } | ||
| 1547 | |||
| 1548 | written += bytes; | ||
| 1549 | count -= bytes; | ||
| 1550 | pos += bytes; | ||
| 1551 | buf += bytes; | ||
| 1552 | if (pos > inode->i_size) | ||
| 1553 | i_size_write(inode, pos); | ||
| 1554 | |||
| 1555 | flush_dcache_page(page); | ||
| 1556 | set_page_dirty(page); | ||
| 1557 | mark_page_accessed(page); | ||
| 1558 | page_cache_release(page); | ||
| 1559 | |||
| 1560 | if (left) { | ||
| 1561 | pos -= left; | ||
| 1562 | written -= left; | ||
| 1563 | err = -EFAULT; | ||
| 1564 | break; | ||
| 1565 | } | ||
| 1566 | |||
| 1567 | /* | ||
| 1568 | * Our dirty pages are not counted in nr_dirty, | ||
| 1569 | * and we do not attempt to balance dirty pages. | ||
| 1570 | */ | ||
| 1571 | |||
| 1572 | cond_resched(); | ||
| 1573 | } while (count); | ||
| 1574 | |||
| 1575 | *ppos = pos; | ||
| 1576 | if (written) | ||
| 1577 | err = written; | ||
| 1578 | out: | ||
| 1579 | mutex_unlock(&inode->i_mutex); | ||
| 1580 | return err; | ||
| 1581 | } | ||
| 1582 | |||
| 1583 | static void do_shmem_file_read(struct file *filp, loff_t *ppos, read_descriptor_t *desc, read_actor_t actor) | 1479 | static void do_shmem_file_read(struct file *filp, loff_t *ppos, read_descriptor_t *desc, read_actor_t actor) |
| 1584 | { | 1480 | { |
| 1585 | struct inode *inode = filp->f_path.dentry->d_inode; | 1481 | struct inode *inode = filp->f_path.dentry->d_inode; |
| @@ -2354,7 +2250,8 @@ static const struct file_operations shmem_file_operations = { | |||
| 2354 | #ifdef CONFIG_TMPFS | 2250 | #ifdef CONFIG_TMPFS |
| 2355 | .llseek = generic_file_llseek, | 2251 | .llseek = generic_file_llseek, |
| 2356 | .read = shmem_file_read, | 2252 | .read = shmem_file_read, |
| 2357 | .write = shmem_file_write, | 2253 | .write = do_sync_write, |
| 2254 | .aio_write = generic_file_aio_write, | ||
| 2358 | .fsync = simple_sync_file, | 2255 | .fsync = simple_sync_file, |
| 2359 | .splice_read = generic_file_splice_read, | 2256 | .splice_read = generic_file_splice_read, |
| 2360 | .splice_write = generic_file_splice_write, | 2257 | .splice_write = generic_file_splice_write, |
