diff options
author | Christoph Hellwig <hch@lst.de> | 2018-06-19 18:10:55 -0400 |
---|---|---|
committer | Darrick J. Wong <darrick.wong@oracle.com> | 2018-06-19 18:10:55 -0400 |
commit | a6d639da63aeb838d5c0b7dc50598f2eac4014a0 (patch) | |
tree | 172b65dd27e3bade9b2d99c50433786c9688132e | |
parent | ce397d215ccd07b8ae3f71db689aedb85d56ab40 (diff) |
fs: factor out a __generic_write_end helper
Bits of the buffer.c based write_end implementations that don't know
about buffer_heads and can be reused by other implementations.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
-rw-r--r-- | fs/buffer.c | 67 | ||||
-rw-r--r-- | fs/internal.h | 2 |
2 files changed, 37 insertions, 32 deletions
diff --git a/fs/buffer.c b/fs/buffer.c index cabc045f483d..aba2a948b235 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
@@ -2076,6 +2076,40 @@ int block_write_begin(struct address_space *mapping, loff_t pos, unsigned len, | |||
2076 | } | 2076 | } |
2077 | EXPORT_SYMBOL(block_write_begin); | 2077 | EXPORT_SYMBOL(block_write_begin); |
2078 | 2078 | ||
2079 | int __generic_write_end(struct inode *inode, loff_t pos, unsigned copied, | ||
2080 | struct page *page) | ||
2081 | { | ||
2082 | loff_t old_size = inode->i_size; | ||
2083 | bool i_size_changed = false; | ||
2084 | |||
2085 | /* | ||
2086 | * No need to use i_size_read() here, the i_size cannot change under us | ||
2087 | * because we hold i_rwsem. | ||
2088 | * | ||
2089 | * But it's important to update i_size while still holding page lock: | ||
2090 | * page writeout could otherwise come in and zero beyond i_size. | ||
2091 | */ | ||
2092 | if (pos + copied > inode->i_size) { | ||
2093 | i_size_write(inode, pos + copied); | ||
2094 | i_size_changed = true; | ||
2095 | } | ||
2096 | |||
2097 | unlock_page(page); | ||
2098 | put_page(page); | ||
2099 | |||
2100 | if (old_size < pos) | ||
2101 | pagecache_isize_extended(inode, old_size, pos); | ||
2102 | /* | ||
2103 | * Don't mark the inode dirty under page lock. First, it unnecessarily | ||
2104 | * makes the holding time of page lock longer. Second, it forces lock | ||
2105 | * ordering of page lock and transaction start for journaling | ||
2106 | * filesystems. | ||
2107 | */ | ||
2108 | if (i_size_changed) | ||
2109 | mark_inode_dirty(inode); | ||
2110 | return copied; | ||
2111 | } | ||
2112 | |||
2079 | int block_write_end(struct file *file, struct address_space *mapping, | 2113 | int block_write_end(struct file *file, struct address_space *mapping, |
2080 | loff_t pos, unsigned len, unsigned copied, | 2114 | loff_t pos, unsigned len, unsigned copied, |
2081 | struct page *page, void *fsdata) | 2115 | struct page *page, void *fsdata) |
@@ -2116,39 +2150,8 @@ int generic_write_end(struct file *file, struct address_space *mapping, | |||
2116 | loff_t pos, unsigned len, unsigned copied, | 2150 | loff_t pos, unsigned len, unsigned copied, |
2117 | struct page *page, void *fsdata) | 2151 | struct page *page, void *fsdata) |
2118 | { | 2152 | { |
2119 | struct inode *inode = mapping->host; | ||
2120 | loff_t old_size = inode->i_size; | ||
2121 | int i_size_changed = 0; | ||
2122 | |||
2123 | copied = block_write_end(file, mapping, pos, len, copied, page, fsdata); | 2153 | copied = block_write_end(file, mapping, pos, len, copied, page, fsdata); |
2124 | 2154 | return __generic_write_end(mapping->host, pos, copied, page); | |
2125 | /* | ||
2126 | * No need to use i_size_read() here, the i_size | ||
2127 | * cannot change under us because we hold i_mutex. | ||
2128 | * | ||
2129 | * But it's important to update i_size while still holding page lock: | ||
2130 | * page writeout could otherwise come in and zero beyond i_size. | ||
2131 | */ | ||
2132 | if (pos+copied > inode->i_size) { | ||
2133 | i_size_write(inode, pos+copied); | ||
2134 | i_size_changed = 1; | ||
2135 | } | ||
2136 | |||
2137 | unlock_page(page); | ||
2138 | put_page(page); | ||
2139 | |||
2140 | if (old_size < pos) | ||
2141 | pagecache_isize_extended(inode, old_size, pos); | ||
2142 | /* | ||
2143 | * Don't mark the inode dirty under page lock. First, it unnecessarily | ||
2144 | * makes the holding time of page lock longer. Second, it forces lock | ||
2145 | * ordering of page lock and transaction start for journaling | ||
2146 | * filesystems. | ||
2147 | */ | ||
2148 | if (i_size_changed) | ||
2149 | mark_inode_dirty(inode); | ||
2150 | |||
2151 | return copied; | ||
2152 | } | 2155 | } |
2153 | EXPORT_SYMBOL(generic_write_end); | 2156 | EXPORT_SYMBOL(generic_write_end); |
2154 | 2157 | ||
diff --git a/fs/internal.h b/fs/internal.h index 980d005b21b4..4a18bdbd2214 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
@@ -43,6 +43,8 @@ static inline int __sync_blockdev(struct block_device *bdev, int wait) | |||
43 | extern void guard_bio_eod(int rw, struct bio *bio); | 43 | extern void guard_bio_eod(int rw, struct bio *bio); |
44 | extern int __block_write_begin_int(struct page *page, loff_t pos, unsigned len, | 44 | extern int __block_write_begin_int(struct page *page, loff_t pos, unsigned len, |
45 | get_block_t *get_block, struct iomap *iomap); | 45 | get_block_t *get_block, struct iomap *iomap); |
46 | int __generic_write_end(struct inode *inode, loff_t pos, unsigned copied, | ||
47 | struct page *page); | ||
46 | 48 | ||
47 | /* | 49 | /* |
48 | * char_dev.c | 50 | * char_dev.c |