diff options
author | Nick Piggin <npiggin@suse.de> | 2007-10-16 04:25:05 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 12:42:55 -0400 |
commit | bfc1af650a8f36feba6b90a6c398325f885c00bc (patch) | |
tree | c7db5bbfad01d2c18533e7a128027e26d1992a42 /fs | |
parent | f4fc66a894546bdc88a775d0e83ad20a65210bcb (diff) |
ext4: convert to new aops
Convert ext4 to use write_begin()/write_end() methods.
Signed-off-by: Badari Pulavarty <pbadari@us.ibm.com>
Signed-off-by: Nick Piggin <npiggin@suse.de>
Cc: Dmitriy Monakhov <dmonakhov@sw.ru>
Cc: Mark Fasheh <mark.fasheh@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/inode.c | 174 |
1 files changed, 120 insertions, 54 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index a4848e04a5ed..0df2b1e06d0b 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -1146,34 +1146,50 @@ static int do_journal_get_write_access(handle_t *handle, | |||
1146 | return ext4_journal_get_write_access(handle, bh); | 1146 | return ext4_journal_get_write_access(handle, bh); |
1147 | } | 1147 | } |
1148 | 1148 | ||
1149 | static int ext4_prepare_write(struct file *file, struct page *page, | 1149 | static int ext4_write_begin(struct file *file, struct address_space *mapping, |
1150 | unsigned from, unsigned to) | 1150 | loff_t pos, unsigned len, unsigned flags, |
1151 | struct page **pagep, void **fsdata) | ||
1151 | { | 1152 | { |
1152 | struct inode *inode = page->mapping->host; | 1153 | struct inode *inode = mapping->host; |
1153 | int ret, needed_blocks = ext4_writepage_trans_blocks(inode); | 1154 | int ret, needed_blocks = ext4_writepage_trans_blocks(inode); |
1154 | handle_t *handle; | 1155 | handle_t *handle; |
1155 | int retries = 0; | 1156 | int retries = 0; |
1157 | struct page *page; | ||
1158 | pgoff_t index; | ||
1159 | unsigned from, to; | ||
1160 | |||
1161 | index = pos >> PAGE_CACHE_SHIFT; | ||
1162 | from = pos & (PAGE_CACHE_SIZE - 1); | ||
1163 | to = from + len; | ||
1156 | 1164 | ||
1157 | retry: | 1165 | retry: |
1158 | handle = ext4_journal_start(inode, needed_blocks); | 1166 | page = __grab_cache_page(mapping, index); |
1159 | if (IS_ERR(handle)) { | 1167 | if (!page) |
1160 | ret = PTR_ERR(handle); | 1168 | return -ENOMEM; |
1161 | goto out; | 1169 | *pagep = page; |
1170 | |||
1171 | handle = ext4_journal_start(inode, needed_blocks); | ||
1172 | if (IS_ERR(handle)) { | ||
1173 | unlock_page(page); | ||
1174 | page_cache_release(page); | ||
1175 | ret = PTR_ERR(handle); | ||
1176 | goto out; | ||
1162 | } | 1177 | } |
1163 | if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode)) | ||
1164 | ret = nobh_prepare_write(page, from, to, ext4_get_block); | ||
1165 | else | ||
1166 | ret = block_prepare_write(page, from, to, ext4_get_block); | ||
1167 | if (ret) | ||
1168 | goto prepare_write_failed; | ||
1169 | 1178 | ||
1170 | if (ext4_should_journal_data(inode)) { | 1179 | ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, |
1180 | ext4_get_block); | ||
1181 | |||
1182 | if (!ret && ext4_should_journal_data(inode)) { | ||
1171 | ret = walk_page_buffers(handle, page_buffers(page), | 1183 | ret = walk_page_buffers(handle, page_buffers(page), |
1172 | from, to, NULL, do_journal_get_write_access); | 1184 | from, to, NULL, do_journal_get_write_access); |
1173 | } | 1185 | } |
1174 | prepare_write_failed: | 1186 | |
1175 | if (ret) | 1187 | if (ret) { |
1176 | ext4_journal_stop(handle); | 1188 | ext4_journal_stop(handle); |
1189 | unlock_page(page); | ||
1190 | page_cache_release(page); | ||
1191 | } | ||
1192 | |||
1177 | if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) | 1193 | if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) |
1178 | goto retry; | 1194 | goto retry; |
1179 | out: | 1195 | out: |
@@ -1185,12 +1201,12 @@ int ext4_journal_dirty_data(handle_t *handle, struct buffer_head *bh) | |||
1185 | int err = jbd2_journal_dirty_data(handle, bh); | 1201 | int err = jbd2_journal_dirty_data(handle, bh); |
1186 | if (err) | 1202 | if (err) |
1187 | ext4_journal_abort_handle(__FUNCTION__, __FUNCTION__, | 1203 | ext4_journal_abort_handle(__FUNCTION__, __FUNCTION__, |
1188 | bh, handle,err); | 1204 | bh, handle, err); |
1189 | return err; | 1205 | return err; |
1190 | } | 1206 | } |
1191 | 1207 | ||
1192 | /* For commit_write() in data=journal mode */ | 1208 | /* For write_end() in data=journal mode */ |
1193 | static int commit_write_fn(handle_t *handle, struct buffer_head *bh) | 1209 | static int write_end_fn(handle_t *handle, struct buffer_head *bh) |
1194 | { | 1210 | { |
1195 | if (!buffer_mapped(bh) || buffer_freed(bh)) | 1211 | if (!buffer_mapped(bh) || buffer_freed(bh)) |
1196 | return 0; | 1212 | return 0; |
@@ -1199,84 +1215,130 @@ static int commit_write_fn(handle_t *handle, struct buffer_head *bh) | |||
1199 | } | 1215 | } |
1200 | 1216 | ||
1201 | /* | 1217 | /* |
1218 | * Generic write_end handler for ordered and writeback ext4 journal modes. | ||
1219 | * We can't use generic_write_end, because that unlocks the page and we need to | ||
1220 | * unlock the page after ext4_journal_stop, but ext4_journal_stop must run | ||
1221 | * after block_write_end. | ||
1222 | */ | ||
1223 | static int ext4_generic_write_end(struct file *file, | ||
1224 | struct address_space *mapping, | ||
1225 | loff_t pos, unsigned len, unsigned copied, | ||
1226 | struct page *page, void *fsdata) | ||
1227 | { | ||
1228 | struct inode *inode = file->f_mapping->host; | ||
1229 | |||
1230 | copied = block_write_end(file, mapping, pos, len, copied, page, fsdata); | ||
1231 | |||
1232 | if (pos+copied > inode->i_size) { | ||
1233 | i_size_write(inode, pos+copied); | ||
1234 | mark_inode_dirty(inode); | ||
1235 | } | ||
1236 | |||
1237 | return copied; | ||
1238 | } | ||
1239 | |||
1240 | /* | ||
1202 | * We need to pick up the new inode size which generic_commit_write gave us | 1241 | * We need to pick up the new inode size which generic_commit_write gave us |
1203 | * `file' can be NULL - eg, when called from page_symlink(). | 1242 | * `file' can be NULL - eg, when called from page_symlink(). |
1204 | * | 1243 | * |
1205 | * ext4 never places buffers on inode->i_mapping->private_list. metadata | 1244 | * ext4 never places buffers on inode->i_mapping->private_list. metadata |
1206 | * buffers are managed internally. | 1245 | * buffers are managed internally. |
1207 | */ | 1246 | */ |
1208 | static int ext4_ordered_commit_write(struct file *file, struct page *page, | 1247 | static int ext4_ordered_write_end(struct file *file, |
1209 | unsigned from, unsigned to) | 1248 | struct address_space *mapping, |
1249 | loff_t pos, unsigned len, unsigned copied, | ||
1250 | struct page *page, void *fsdata) | ||
1210 | { | 1251 | { |
1211 | handle_t *handle = ext4_journal_current_handle(); | 1252 | handle_t *handle = ext4_journal_current_handle(); |
1212 | struct inode *inode = page->mapping->host; | 1253 | struct inode *inode = file->f_mapping->host; |
1254 | unsigned from, to; | ||
1213 | int ret = 0, ret2; | 1255 | int ret = 0, ret2; |
1214 | 1256 | ||
1257 | from = pos & (PAGE_CACHE_SIZE - 1); | ||
1258 | to = from + len; | ||
1259 | |||
1215 | ret = walk_page_buffers(handle, page_buffers(page), | 1260 | ret = walk_page_buffers(handle, page_buffers(page), |
1216 | from, to, NULL, ext4_journal_dirty_data); | 1261 | from, to, NULL, ext4_journal_dirty_data); |
1217 | 1262 | ||
1218 | if (ret == 0) { | 1263 | if (ret == 0) { |
1219 | /* | 1264 | /* |
1220 | * generic_commit_write() will run mark_inode_dirty() if i_size | 1265 | * generic_write_end() will run mark_inode_dirty() if i_size |
1221 | * changes. So let's piggyback the i_disksize mark_inode_dirty | 1266 | * changes. So let's piggyback the i_disksize mark_inode_dirty |
1222 | * into that. | 1267 | * into that. |
1223 | */ | 1268 | */ |
1224 | loff_t new_i_size; | 1269 | loff_t new_i_size; |
1225 | 1270 | ||
1226 | new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; | 1271 | new_i_size = pos + copied; |
1227 | if (new_i_size > EXT4_I(inode)->i_disksize) | 1272 | if (new_i_size > EXT4_I(inode)->i_disksize) |
1228 | EXT4_I(inode)->i_disksize = new_i_size; | 1273 | EXT4_I(inode)->i_disksize = new_i_size; |
1229 | ret = generic_commit_write(file, page, from, to); | 1274 | copied = ext4_generic_write_end(file, mapping, pos, len, copied, |
1275 | page, fsdata); | ||
1276 | if (copied < 0) | ||
1277 | ret = copied; | ||
1230 | } | 1278 | } |
1231 | ret2 = ext4_journal_stop(handle); | 1279 | ret2 = ext4_journal_stop(handle); |
1232 | if (!ret) | 1280 | if (!ret) |
1233 | ret = ret2; | 1281 | ret = ret2; |
1234 | return ret; | 1282 | unlock_page(page); |
1283 | page_cache_release(page); | ||
1284 | |||
1285 | return ret ? ret : copied; | ||
1235 | } | 1286 | } |
1236 | 1287 | ||
1237 | static int ext4_writeback_commit_write(struct file *file, struct page *page, | 1288 | static int ext4_writeback_write_end(struct file *file, |
1238 | unsigned from, unsigned to) | 1289 | struct address_space *mapping, |
1290 | loff_t pos, unsigned len, unsigned copied, | ||
1291 | struct page *page, void *fsdata) | ||
1239 | { | 1292 | { |
1240 | handle_t *handle = ext4_journal_current_handle(); | 1293 | handle_t *handle = ext4_journal_current_handle(); |
1241 | struct inode *inode = page->mapping->host; | 1294 | struct inode *inode = file->f_mapping->host; |
1242 | int ret = 0, ret2; | 1295 | int ret = 0, ret2; |
1243 | loff_t new_i_size; | 1296 | loff_t new_i_size; |
1244 | 1297 | ||
1245 | new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; | 1298 | new_i_size = pos + copied; |
1246 | if (new_i_size > EXT4_I(inode)->i_disksize) | 1299 | if (new_i_size > EXT4_I(inode)->i_disksize) |
1247 | EXT4_I(inode)->i_disksize = new_i_size; | 1300 | EXT4_I(inode)->i_disksize = new_i_size; |
1248 | 1301 | ||
1249 | if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode)) | 1302 | copied = ext4_generic_write_end(file, mapping, pos, len, copied, |
1250 | ret = nobh_commit_write(file, page, from, to); | 1303 | page, fsdata); |
1251 | else | 1304 | if (copied < 0) |
1252 | ret = generic_commit_write(file, page, from, to); | 1305 | ret = copied; |
1253 | 1306 | ||
1254 | ret2 = ext4_journal_stop(handle); | 1307 | ret2 = ext4_journal_stop(handle); |
1255 | if (!ret) | 1308 | if (!ret) |
1256 | ret = ret2; | 1309 | ret = ret2; |
1257 | return ret; | 1310 | unlock_page(page); |
1311 | page_cache_release(page); | ||
1312 | |||
1313 | return ret ? ret : copied; | ||
1258 | } | 1314 | } |
1259 | 1315 | ||
1260 | static int ext4_journalled_commit_write(struct file *file, | 1316 | static int ext4_journalled_write_end(struct file *file, |
1261 | struct page *page, unsigned from, unsigned to) | 1317 | struct address_space *mapping, |
1318 | loff_t pos, unsigned len, unsigned copied, | ||
1319 | struct page *page, void *fsdata) | ||
1262 | { | 1320 | { |
1263 | handle_t *handle = ext4_journal_current_handle(); | 1321 | handle_t *handle = ext4_journal_current_handle(); |
1264 | struct inode *inode = page->mapping->host; | 1322 | struct inode *inode = mapping->host; |
1265 | int ret = 0, ret2; | 1323 | int ret = 0, ret2; |
1266 | int partial = 0; | 1324 | int partial = 0; |
1267 | loff_t pos; | 1325 | unsigned from, to; |
1268 | 1326 | ||
1269 | /* | 1327 | from = pos & (PAGE_CACHE_SIZE - 1); |
1270 | * Here we duplicate the generic_commit_write() functionality | 1328 | to = from + len; |
1271 | */ | 1329 | |
1272 | pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; | 1330 | if (copied < len) { |
1331 | if (!PageUptodate(page)) | ||
1332 | copied = 0; | ||
1333 | page_zero_new_buffers(page, from+copied, to); | ||
1334 | } | ||
1273 | 1335 | ||
1274 | ret = walk_page_buffers(handle, page_buffers(page), from, | 1336 | ret = walk_page_buffers(handle, page_buffers(page), from, |
1275 | to, &partial, commit_write_fn); | 1337 | to, &partial, write_end_fn); |
1276 | if (!partial) | 1338 | if (!partial) |
1277 | SetPageUptodate(page); | 1339 | SetPageUptodate(page); |
1278 | if (pos > inode->i_size) | 1340 | if (pos+copied > inode->i_size) |
1279 | i_size_write(inode, pos); | 1341 | i_size_write(inode, pos+copied); |
1280 | EXT4_I(inode)->i_state |= EXT4_STATE_JDATA; | 1342 | EXT4_I(inode)->i_state |= EXT4_STATE_JDATA; |
1281 | if (inode->i_size > EXT4_I(inode)->i_disksize) { | 1343 | if (inode->i_size > EXT4_I(inode)->i_disksize) { |
1282 | EXT4_I(inode)->i_disksize = inode->i_size; | 1344 | EXT4_I(inode)->i_disksize = inode->i_size; |
@@ -1284,10 +1346,14 @@ static int ext4_journalled_commit_write(struct file *file, | |||
1284 | if (!ret) | 1346 | if (!ret) |
1285 | ret = ret2; | 1347 | ret = ret2; |
1286 | } | 1348 | } |
1349 | |||
1287 | ret2 = ext4_journal_stop(handle); | 1350 | ret2 = ext4_journal_stop(handle); |
1288 | if (!ret) | 1351 | if (!ret) |
1289 | ret = ret2; | 1352 | ret = ret2; |
1290 | return ret; | 1353 | unlock_page(page); |
1354 | page_cache_release(page); | ||
1355 | |||
1356 | return ret ? ret : copied; | ||
1291 | } | 1357 | } |
1292 | 1358 | ||
1293 | /* | 1359 | /* |
@@ -1545,7 +1611,7 @@ static int ext4_journalled_writepage(struct page *page, | |||
1545 | PAGE_CACHE_SIZE, NULL, do_journal_get_write_access); | 1611 | PAGE_CACHE_SIZE, NULL, do_journal_get_write_access); |
1546 | 1612 | ||
1547 | err = walk_page_buffers(handle, page_buffers(page), 0, | 1613 | err = walk_page_buffers(handle, page_buffers(page), 0, |
1548 | PAGE_CACHE_SIZE, NULL, commit_write_fn); | 1614 | PAGE_CACHE_SIZE, NULL, write_end_fn); |
1549 | if (ret == 0) | 1615 | if (ret == 0) |
1550 | ret = err; | 1616 | ret = err; |
1551 | EXT4_I(inode)->i_state |= EXT4_STATE_JDATA; | 1617 | EXT4_I(inode)->i_state |= EXT4_STATE_JDATA; |
@@ -1705,8 +1771,8 @@ static const struct address_space_operations ext4_ordered_aops = { | |||
1705 | .readpages = ext4_readpages, | 1771 | .readpages = ext4_readpages, |
1706 | .writepage = ext4_ordered_writepage, | 1772 | .writepage = ext4_ordered_writepage, |
1707 | .sync_page = block_sync_page, | 1773 | .sync_page = block_sync_page, |
1708 | .prepare_write = ext4_prepare_write, | 1774 | .write_begin = ext4_write_begin, |
1709 | .commit_write = ext4_ordered_commit_write, | 1775 | .write_end = ext4_ordered_write_end, |
1710 | .bmap = ext4_bmap, | 1776 | .bmap = ext4_bmap, |
1711 | .invalidatepage = ext4_invalidatepage, | 1777 | .invalidatepage = ext4_invalidatepage, |
1712 | .releasepage = ext4_releasepage, | 1778 | .releasepage = ext4_releasepage, |
@@ -1719,8 +1785,8 @@ static const struct address_space_operations ext4_writeback_aops = { | |||
1719 | .readpages = ext4_readpages, | 1785 | .readpages = ext4_readpages, |
1720 | .writepage = ext4_writeback_writepage, | 1786 | .writepage = ext4_writeback_writepage, |
1721 | .sync_page = block_sync_page, | 1787 | .sync_page = block_sync_page, |
1722 | .prepare_write = ext4_prepare_write, | 1788 | .write_begin = ext4_write_begin, |
1723 | .commit_write = ext4_writeback_commit_write, | 1789 | .write_end = ext4_writeback_write_end, |
1724 | .bmap = ext4_bmap, | 1790 | .bmap = ext4_bmap, |
1725 | .invalidatepage = ext4_invalidatepage, | 1791 | .invalidatepage = ext4_invalidatepage, |
1726 | .releasepage = ext4_releasepage, | 1792 | .releasepage = ext4_releasepage, |
@@ -1733,8 +1799,8 @@ static const struct address_space_operations ext4_journalled_aops = { | |||
1733 | .readpages = ext4_readpages, | 1799 | .readpages = ext4_readpages, |
1734 | .writepage = ext4_journalled_writepage, | 1800 | .writepage = ext4_journalled_writepage, |
1735 | .sync_page = block_sync_page, | 1801 | .sync_page = block_sync_page, |
1736 | .prepare_write = ext4_prepare_write, | 1802 | .write_begin = ext4_write_begin, |
1737 | .commit_write = ext4_journalled_commit_write, | 1803 | .write_end = ext4_journalled_write_end, |
1738 | .set_page_dirty = ext4_journalled_set_page_dirty, | 1804 | .set_page_dirty = ext4_journalled_set_page_dirty, |
1739 | .bmap = ext4_bmap, | 1805 | .bmap = ext4_bmap, |
1740 | .invalidatepage = ext4_invalidatepage, | 1806 | .invalidatepage = ext4_invalidatepage, |