diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext3/inode.c | 163 |
1 files changed, 115 insertions, 48 deletions
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index de4e3161e479..2f2b6864db10 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
@@ -1147,51 +1147,68 @@ static int do_journal_get_write_access(handle_t *handle, | |||
1147 | return ext3_journal_get_write_access(handle, bh); | 1147 | return ext3_journal_get_write_access(handle, bh); |
1148 | } | 1148 | } |
1149 | 1149 | ||
1150 | static int ext3_prepare_write(struct file *file, struct page *page, | 1150 | static int ext3_write_begin(struct file *file, struct address_space *mapping, |
1151 | unsigned from, unsigned to) | 1151 | loff_t pos, unsigned len, unsigned flags, |
1152 | struct page **pagep, void **fsdata) | ||
1152 | { | 1153 | { |
1153 | struct inode *inode = page->mapping->host; | 1154 | struct inode *inode = mapping->host; |
1154 | int ret, needed_blocks = ext3_writepage_trans_blocks(inode); | 1155 | int ret, needed_blocks = ext3_writepage_trans_blocks(inode); |
1155 | handle_t *handle; | 1156 | handle_t *handle; |
1156 | int retries = 0; | 1157 | int retries = 0; |
1158 | struct page *page; | ||
1159 | pgoff_t index; | ||
1160 | unsigned from, to; | ||
1161 | |||
1162 | index = pos >> PAGE_CACHE_SHIFT; | ||
1163 | from = pos & (PAGE_CACHE_SIZE - 1); | ||
1164 | to = from + len; | ||
1157 | 1165 | ||
1158 | retry: | 1166 | retry: |
1167 | page = __grab_cache_page(mapping, index); | ||
1168 | if (!page) | ||
1169 | return -ENOMEM; | ||
1170 | *pagep = page; | ||
1171 | |||
1159 | handle = ext3_journal_start(inode, needed_blocks); | 1172 | handle = ext3_journal_start(inode, needed_blocks); |
1160 | if (IS_ERR(handle)) { | 1173 | if (IS_ERR(handle)) { |
1174 | unlock_page(page); | ||
1175 | page_cache_release(page); | ||
1161 | ret = PTR_ERR(handle); | 1176 | ret = PTR_ERR(handle); |
1162 | goto out; | 1177 | goto out; |
1163 | } | 1178 | } |
1164 | if (test_opt(inode->i_sb, NOBH) && ext3_should_writeback_data(inode)) | 1179 | ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, |
1165 | ret = nobh_prepare_write(page, from, to, ext3_get_block); | 1180 | ext3_get_block); |
1166 | else | ||
1167 | ret = block_prepare_write(page, from, to, ext3_get_block); | ||
1168 | if (ret) | 1181 | if (ret) |
1169 | goto prepare_write_failed; | 1182 | goto write_begin_failed; |
1170 | 1183 | ||
1171 | if (ext3_should_journal_data(inode)) { | 1184 | if (ext3_should_journal_data(inode)) { |
1172 | ret = walk_page_buffers(handle, page_buffers(page), | 1185 | ret = walk_page_buffers(handle, page_buffers(page), |
1173 | from, to, NULL, do_journal_get_write_access); | 1186 | from, to, NULL, do_journal_get_write_access); |
1174 | } | 1187 | } |
1175 | prepare_write_failed: | 1188 | write_begin_failed: |
1176 | if (ret) | 1189 | if (ret) { |
1177 | ext3_journal_stop(handle); | 1190 | ext3_journal_stop(handle); |
1191 | unlock_page(page); | ||
1192 | page_cache_release(page); | ||
1193 | } | ||
1178 | if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) | 1194 | if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) |
1179 | goto retry; | 1195 | goto retry; |
1180 | out: | 1196 | out: |
1181 | return ret; | 1197 | return ret; |
1182 | } | 1198 | } |
1183 | 1199 | ||
1200 | |||
1184 | int ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh) | 1201 | int ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh) |
1185 | { | 1202 | { |
1186 | int err = journal_dirty_data(handle, bh); | 1203 | int err = journal_dirty_data(handle, bh); |
1187 | if (err) | 1204 | if (err) |
1188 | ext3_journal_abort_handle(__FUNCTION__, __FUNCTION__, | 1205 | ext3_journal_abort_handle(__FUNCTION__, __FUNCTION__, |
1189 | bh, handle,err); | 1206 | bh, handle, err); |
1190 | return err; | 1207 | return err; |
1191 | } | 1208 | } |
1192 | 1209 | ||
1193 | /* For commit_write() in data=journal mode */ | 1210 | /* For write_end() in data=journal mode */ |
1194 | static int commit_write_fn(handle_t *handle, struct buffer_head *bh) | 1211 | static int write_end_fn(handle_t *handle, struct buffer_head *bh) |
1195 | { | 1212 | { |
1196 | if (!buffer_mapped(bh) || buffer_freed(bh)) | 1213 | if (!buffer_mapped(bh) || buffer_freed(bh)) |
1197 | return 0; | 1214 | return 0; |
@@ -1200,84 +1217,130 @@ static int commit_write_fn(handle_t *handle, struct buffer_head *bh) | |||
1200 | } | 1217 | } |
1201 | 1218 | ||
1202 | /* | 1219 | /* |
1220 | * Generic write_end handler for ordered and writeback ext3 journal modes. | ||
1221 | * We can't use generic_write_end, because that unlocks the page and we need to | ||
1222 | * unlock the page after ext3_journal_stop, but ext3_journal_stop must run | ||
1223 | * after block_write_end. | ||
1224 | */ | ||
1225 | static int ext3_generic_write_end(struct file *file, | ||
1226 | struct address_space *mapping, | ||
1227 | loff_t pos, unsigned len, unsigned copied, | ||
1228 | struct page *page, void *fsdata) | ||
1229 | { | ||
1230 | struct inode *inode = file->f_mapping->host; | ||
1231 | |||
1232 | copied = block_write_end(file, mapping, pos, len, copied, page, fsdata); | ||
1233 | |||
1234 | if (pos+copied > inode->i_size) { | ||
1235 | i_size_write(inode, pos+copied); | ||
1236 | mark_inode_dirty(inode); | ||
1237 | } | ||
1238 | |||
1239 | return copied; | ||
1240 | } | ||
1241 | |||
1242 | /* | ||
1203 | * We need to pick up the new inode size which generic_commit_write gave us | 1243 | * We need to pick up the new inode size which generic_commit_write gave us |
1204 | * `file' can be NULL - eg, when called from page_symlink(). | 1244 | * `file' can be NULL - eg, when called from page_symlink(). |
1205 | * | 1245 | * |
1206 | * ext3 never places buffers on inode->i_mapping->private_list. metadata | 1246 | * ext3 never places buffers on inode->i_mapping->private_list. metadata |
1207 | * buffers are managed internally. | 1247 | * buffers are managed internally. |
1208 | */ | 1248 | */ |
1209 | static int ext3_ordered_commit_write(struct file *file, struct page *page, | 1249 | static int ext3_ordered_write_end(struct file *file, |
1210 | unsigned from, unsigned to) | 1250 | struct address_space *mapping, |
1251 | loff_t pos, unsigned len, unsigned copied, | ||
1252 | struct page *page, void *fsdata) | ||
1211 | { | 1253 | { |
1212 | handle_t *handle = ext3_journal_current_handle(); | 1254 | handle_t *handle = ext3_journal_current_handle(); |
1213 | struct inode *inode = page->mapping->host; | 1255 | struct inode *inode = file->f_mapping->host; |
1256 | unsigned from, to; | ||
1214 | int ret = 0, ret2; | 1257 | int ret = 0, ret2; |
1215 | 1258 | ||
1259 | from = pos & (PAGE_CACHE_SIZE - 1); | ||
1260 | to = from + len; | ||
1261 | |||
1216 | ret = walk_page_buffers(handle, page_buffers(page), | 1262 | ret = walk_page_buffers(handle, page_buffers(page), |
1217 | from, to, NULL, ext3_journal_dirty_data); | 1263 | from, to, NULL, ext3_journal_dirty_data); |
1218 | 1264 | ||
1219 | if (ret == 0) { | 1265 | if (ret == 0) { |
1220 | /* | 1266 | /* |
1221 | * generic_commit_write() will run mark_inode_dirty() if i_size | 1267 | * generic_write_end() will run mark_inode_dirty() if i_size |
1222 | * changes. So let's piggyback the i_disksize mark_inode_dirty | 1268 | * changes. So let's piggyback the i_disksize mark_inode_dirty |
1223 | * into that. | 1269 | * into that. |
1224 | */ | 1270 | */ |
1225 | loff_t new_i_size; | 1271 | loff_t new_i_size; |
1226 | 1272 | ||
1227 | new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; | 1273 | new_i_size = pos + copied; |
1228 | if (new_i_size > EXT3_I(inode)->i_disksize) | 1274 | if (new_i_size > EXT3_I(inode)->i_disksize) |
1229 | EXT3_I(inode)->i_disksize = new_i_size; | 1275 | EXT3_I(inode)->i_disksize = new_i_size; |
1230 | ret = generic_commit_write(file, page, from, to); | 1276 | copied = ext3_generic_write_end(file, mapping, pos, len, copied, |
1277 | page, fsdata); | ||
1278 | if (copied < 0) | ||
1279 | ret = copied; | ||
1231 | } | 1280 | } |
1232 | ret2 = ext3_journal_stop(handle); | 1281 | ret2 = ext3_journal_stop(handle); |
1233 | if (!ret) | 1282 | if (!ret) |
1234 | ret = ret2; | 1283 | ret = ret2; |
1235 | return ret; | 1284 | unlock_page(page); |
1285 | page_cache_release(page); | ||
1286 | |||
1287 | return ret ? ret : copied; | ||
1236 | } | 1288 | } |
1237 | 1289 | ||
1238 | static int ext3_writeback_commit_write(struct file *file, struct page *page, | 1290 | static int ext3_writeback_write_end(struct file *file, |
1239 | unsigned from, unsigned to) | 1291 | struct address_space *mapping, |
1292 | loff_t pos, unsigned len, unsigned copied, | ||
1293 | struct page *page, void *fsdata) | ||
1240 | { | 1294 | { |
1241 | handle_t *handle = ext3_journal_current_handle(); | 1295 | handle_t *handle = ext3_journal_current_handle(); |
1242 | struct inode *inode = page->mapping->host; | 1296 | struct inode *inode = file->f_mapping->host; |
1243 | int ret = 0, ret2; | 1297 | int ret = 0, ret2; |
1244 | loff_t new_i_size; | 1298 | loff_t new_i_size; |
1245 | 1299 | ||
1246 | new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; | 1300 | new_i_size = pos + copied; |
1247 | if (new_i_size > EXT3_I(inode)->i_disksize) | 1301 | if (new_i_size > EXT3_I(inode)->i_disksize) |
1248 | EXT3_I(inode)->i_disksize = new_i_size; | 1302 | EXT3_I(inode)->i_disksize = new_i_size; |
1249 | 1303 | ||
1250 | if (test_opt(inode->i_sb, NOBH) && ext3_should_writeback_data(inode)) | 1304 | copied = ext3_generic_write_end(file, mapping, pos, len, copied, |
1251 | ret = nobh_commit_write(file, page, from, to); | 1305 | page, fsdata); |
1252 | else | 1306 | if (copied < 0) |
1253 | ret = generic_commit_write(file, page, from, to); | 1307 | ret = copied; |
1254 | 1308 | ||
1255 | ret2 = ext3_journal_stop(handle); | 1309 | ret2 = ext3_journal_stop(handle); |
1256 | if (!ret) | 1310 | if (!ret) |
1257 | ret = ret2; | 1311 | ret = ret2; |
1258 | return ret; | 1312 | unlock_page(page); |
1313 | page_cache_release(page); | ||
1314 | |||
1315 | return ret ? ret : copied; | ||
1259 | } | 1316 | } |
1260 | 1317 | ||
1261 | static int ext3_journalled_commit_write(struct file *file, | 1318 | static int ext3_journalled_write_end(struct file *file, |
1262 | struct page *page, unsigned from, unsigned to) | 1319 | struct address_space *mapping, |
1320 | loff_t pos, unsigned len, unsigned copied, | ||
1321 | struct page *page, void *fsdata) | ||
1263 | { | 1322 | { |
1264 | handle_t *handle = ext3_journal_current_handle(); | 1323 | handle_t *handle = ext3_journal_current_handle(); |
1265 | struct inode *inode = page->mapping->host; | 1324 | struct inode *inode = mapping->host; |
1266 | int ret = 0, ret2; | 1325 | int ret = 0, ret2; |
1267 | int partial = 0; | 1326 | int partial = 0; |
1268 | loff_t pos; | 1327 | unsigned from, to; |
1269 | 1328 | ||
1270 | /* | 1329 | from = pos & (PAGE_CACHE_SIZE - 1); |
1271 | * Here we duplicate the generic_commit_write() functionality | 1330 | to = from + len; |
1272 | */ | 1331 | |
1273 | pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; | 1332 | if (copied < len) { |
1333 | if (!PageUptodate(page)) | ||
1334 | copied = 0; | ||
1335 | page_zero_new_buffers(page, from+copied, to); | ||
1336 | } | ||
1274 | 1337 | ||
1275 | ret = walk_page_buffers(handle, page_buffers(page), from, | 1338 | ret = walk_page_buffers(handle, page_buffers(page), from, |
1276 | to, &partial, commit_write_fn); | 1339 | to, &partial, write_end_fn); |
1277 | if (!partial) | 1340 | if (!partial) |
1278 | SetPageUptodate(page); | 1341 | SetPageUptodate(page); |
1279 | if (pos > inode->i_size) | 1342 | if (pos+copied > inode->i_size) |
1280 | i_size_write(inode, pos); | 1343 | i_size_write(inode, pos+copied); |
1281 | EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; | 1344 | EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; |
1282 | if (inode->i_size > EXT3_I(inode)->i_disksize) { | 1345 | if (inode->i_size > EXT3_I(inode)->i_disksize) { |
1283 | EXT3_I(inode)->i_disksize = inode->i_size; | 1346 | EXT3_I(inode)->i_disksize = inode->i_size; |
@@ -1285,10 +1348,14 @@ static int ext3_journalled_commit_write(struct file *file, | |||
1285 | if (!ret) | 1348 | if (!ret) |
1286 | ret = ret2; | 1349 | ret = ret2; |
1287 | } | 1350 | } |
1351 | |||
1288 | ret2 = ext3_journal_stop(handle); | 1352 | ret2 = ext3_journal_stop(handle); |
1289 | if (!ret) | 1353 | if (!ret) |
1290 | ret = ret2; | 1354 | ret = ret2; |
1291 | return ret; | 1355 | unlock_page(page); |
1356 | page_cache_release(page); | ||
1357 | |||
1358 | return ret ? ret : copied; | ||
1292 | } | 1359 | } |
1293 | 1360 | ||
1294 | /* | 1361 | /* |
@@ -1546,7 +1613,7 @@ static int ext3_journalled_writepage(struct page *page, | |||
1546 | PAGE_CACHE_SIZE, NULL, do_journal_get_write_access); | 1613 | PAGE_CACHE_SIZE, NULL, do_journal_get_write_access); |
1547 | 1614 | ||
1548 | err = walk_page_buffers(handle, page_buffers(page), 0, | 1615 | err = walk_page_buffers(handle, page_buffers(page), 0, |
1549 | PAGE_CACHE_SIZE, NULL, commit_write_fn); | 1616 | PAGE_CACHE_SIZE, NULL, write_end_fn); |
1550 | if (ret == 0) | 1617 | if (ret == 0) |
1551 | ret = err; | 1618 | ret = err; |
1552 | EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; | 1619 | EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; |
@@ -1706,8 +1773,8 @@ static const struct address_space_operations ext3_ordered_aops = { | |||
1706 | .readpages = ext3_readpages, | 1773 | .readpages = ext3_readpages, |
1707 | .writepage = ext3_ordered_writepage, | 1774 | .writepage = ext3_ordered_writepage, |
1708 | .sync_page = block_sync_page, | 1775 | .sync_page = block_sync_page, |
1709 | .prepare_write = ext3_prepare_write, | 1776 | .write_begin = ext3_write_begin, |
1710 | .commit_write = ext3_ordered_commit_write, | 1777 | .write_end = ext3_ordered_write_end, |
1711 | .bmap = ext3_bmap, | 1778 | .bmap = ext3_bmap, |
1712 | .invalidatepage = ext3_invalidatepage, | 1779 | .invalidatepage = ext3_invalidatepage, |
1713 | .releasepage = ext3_releasepage, | 1780 | .releasepage = ext3_releasepage, |
@@ -1720,8 +1787,8 @@ static const struct address_space_operations ext3_writeback_aops = { | |||
1720 | .readpages = ext3_readpages, | 1787 | .readpages = ext3_readpages, |
1721 | .writepage = ext3_writeback_writepage, | 1788 | .writepage = ext3_writeback_writepage, |
1722 | .sync_page = block_sync_page, | 1789 | .sync_page = block_sync_page, |
1723 | .prepare_write = ext3_prepare_write, | 1790 | .write_begin = ext3_write_begin, |
1724 | .commit_write = ext3_writeback_commit_write, | 1791 | .write_end = ext3_writeback_write_end, |
1725 | .bmap = ext3_bmap, | 1792 | .bmap = ext3_bmap, |
1726 | .invalidatepage = ext3_invalidatepage, | 1793 | .invalidatepage = ext3_invalidatepage, |
1727 | .releasepage = ext3_releasepage, | 1794 | .releasepage = ext3_releasepage, |
@@ -1734,8 +1801,8 @@ static const struct address_space_operations ext3_journalled_aops = { | |||
1734 | .readpages = ext3_readpages, | 1801 | .readpages = ext3_readpages, |
1735 | .writepage = ext3_journalled_writepage, | 1802 | .writepage = ext3_journalled_writepage, |
1736 | .sync_page = block_sync_page, | 1803 | .sync_page = block_sync_page, |
1737 | .prepare_write = ext3_prepare_write, | 1804 | .write_begin = ext3_write_begin, |
1738 | .commit_write = ext3_journalled_commit_write, | 1805 | .write_end = ext3_journalled_write_end, |
1739 | .set_page_dirty = ext3_journalled_set_page_dirty, | 1806 | .set_page_dirty = ext3_journalled_set_page_dirty, |
1740 | .bmap = ext3_bmap, | 1807 | .bmap = ext3_bmap, |
1741 | .invalidatepage = ext3_invalidatepage, | 1808 | .invalidatepage = ext3_invalidatepage, |