aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/ext3/inode.c163
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
1150static int ext3_prepare_write(struct file *file, struct page *page, 1150static 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
1158retry: 1166retry:
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 }
1175prepare_write_failed: 1188write_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;
1180out: 1196out:
1181 return ret; 1197 return ret;
1182} 1198}
1183 1199
1200
1184int ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh) 1201int 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 */
1194static int commit_write_fn(handle_t *handle, struct buffer_head *bh) 1211static 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 */
1225static 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 */
1209static int ext3_ordered_commit_write(struct file *file, struct page *page, 1249static 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
1238static int ext3_writeback_commit_write(struct file *file, struct page *page, 1290static 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
1261static int ext3_journalled_commit_write(struct file *file, 1318static 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,