aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/ops_address.c
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2006-02-08 06:50:51 -0500
committerSteven Whitehouse <swhiteho@redhat.com>2006-02-08 06:50:51 -0500
commit18ec7d5c3f434aed9661ed10a9e1f48cdeb4981d (patch)
treea7161a4c4b3592052e6772e1c23849de16cac649 /fs/gfs2/ops_address.c
parent257f9b4e97e9a6cceeb247cead92119a4396d37b (diff)
[GFS2] Make journaled data files identical to normal files on disk
This is a very large patch, with a few still to be resolved issues so you might want to check out the previous head of the tree since this is known to be unstable. Fixes for the various bugs will be forthcoming shortly. This patch removes the special data format which has been used up till now for journaled data files. Directories still retain the old format so that they will remain on disk compatible with earlier releases. As a result you can now do the following with journaled data files: 1) mmap them 2) export them over NFS 3) convert to/from normal files whenever you want to (the zero length restriction is gone) In addition the level at which GFS' locking is done has changed for all files (since they all now use the page cache) such that the locking is done at the page cache level rather than the level of the fs operations. This should mean that things like loopback mounts and other things which touch the page cache directly should now work. Current known issues: 1. There is a lock mode inversion problem related to the resource group hold function which needs to be resolved. 2. Any significant amount of I/O causes an oops with an offset of hex 320 (NULL pointer dereference) which appears to be related to a journaled data buffer appearing on a list where it shouldn't be. 3. Direct I/O writes are disabled for the time being (will reappear later) 4. There is probably a deadlock between the page lock and GFS' locks under certain combinations of mmap and fs operation I/O. 5. Issue relating to ref counting on internally used inodes causes a hang on umount (discovered before this patch, and not fixed by it) 6. One part of the directory metadata is different from GFS1 and will need to be resolved before next release. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/ops_address.c')
-rw-r--r--fs/gfs2/ops_address.c260
1 files changed, 169 insertions, 91 deletions
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
index d611b2ad2e97..b14357e89421 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.c
@@ -20,13 +20,13 @@
20#include "bmap.h" 20#include "bmap.h"
21#include "glock.h" 21#include "glock.h"
22#include "inode.h" 22#include "inode.h"
23#include "jdata.h"
24#include "log.h" 23#include "log.h"
25#include "meta_io.h" 24#include "meta_io.h"
26#include "ops_address.h" 25#include "ops_address.h"
27#include "page.h" 26#include "page.h"
28#include "quota.h" 27#include "quota.h"
29#include "trans.h" 28#include "trans.h"
29#include "rgrp.h"
30 30
31/** 31/**
32 * gfs2_get_block - Fills in a buffer head with details about a block 32 * gfs2_get_block - Fills in a buffer head with details about a block
@@ -149,33 +149,55 @@ static int get_blocks_noalloc(struct inode *inode, sector_t lblock,
149 * 149 *
150 * Returns: errno 150 * Returns: errno
151 * 151 *
152 * Use Linux VFS block_write_full_page() to write one page, 152 * Some of this is copied from block_write_full_page() although we still
153 * using GFS2's get_block_noalloc to find which blocks to write. 153 * call it to do most of the work.
154 */ 154 */
155 155
156static int gfs2_writepage(struct page *page, struct writeback_control *wbc) 156static int gfs2_writepage(struct page *page, struct writeback_control *wbc)
157{ 157{
158 struct inode *inode = page->mapping->host;
158 struct gfs2_inode *ip = get_v2ip(page->mapping->host); 159 struct gfs2_inode *ip = get_v2ip(page->mapping->host);
159 struct gfs2_sbd *sdp = ip->i_sbd; 160 struct gfs2_sbd *sdp = ip->i_sbd;
161 loff_t i_size = i_size_read(inode);
162 pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
163 unsigned offset;
160 int error; 164 int error;
165 int done_trans = 0;
161 166
162 atomic_inc(&sdp->sd_ops_address); 167 atomic_inc(&sdp->sd_ops_address);
163
164 if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl))) { 168 if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl))) {
165 unlock_page(page); 169 unlock_page(page);
166 return -EIO; 170 return -EIO;
167 } 171 }
168 if (get_transaction) { 172 if (get_transaction)
169 redirty_page_for_writepage(wbc, page); 173 goto out_ignore;
174
175 /* Is the page fully outside i_size? (truncate in progress) */
176 offset = i_size & (PAGE_CACHE_SIZE-1);
177 if (page->index >= end_index+1 || !offset) {
178 page->mapping->a_ops->invalidatepage(page, 0);
170 unlock_page(page); 179 unlock_page(page);
171 return 0; 180 return 0; /* don't care */
172 } 181 }
173 182
174 error = block_write_full_page(page, get_block_noalloc, wbc); 183 if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) {
184 error = gfs2_trans_begin(sdp, RES_DINODE + 1, 0);
185 if (error)
186 goto out_ignore;
187 gfs2_page_add_databufs(ip, page, 0, sdp->sd_vfs->s_blocksize-1);
188 done_trans = 1;
189 }
175 190
191 error = block_write_full_page(page, get_block_noalloc, wbc);
192 if (done_trans)
193 gfs2_trans_end(sdp);
176 gfs2_meta_cache_flush(ip); 194 gfs2_meta_cache_flush(ip);
177
178 return error; 195 return error;
196
197out_ignore:
198 redirty_page_for_writepage(wbc, page);
199 unlock_page(page);
200 return 0;
179} 201}
180 202
181/** 203/**
@@ -227,40 +249,9 @@ static int zero_readpage(struct page *page)
227} 249}
228 250
229/** 251/**
230 * jdata_readpage - readpage that goes through gfs2_jdata_read_mem()
231 * @ip:
232 * @page: The page to read
233 *
234 * Returns: errno
235 */
236
237static int jdata_readpage(struct gfs2_inode *ip, struct page *page)
238{
239 void *kaddr;
240 int ret;
241
242 kaddr = kmap(page);
243
244 ret = gfs2_jdata_read_mem(ip, kaddr,
245 (uint64_t)page->index << PAGE_CACHE_SHIFT,
246 PAGE_CACHE_SIZE);
247 if (ret >= 0) {
248 if (ret < PAGE_CACHE_SIZE)
249 memset(kaddr + ret, 0, PAGE_CACHE_SIZE - ret);
250 SetPageUptodate(page);
251 ret = 0;
252 }
253
254 kunmap(page);
255
256 unlock_page(page);
257
258 return ret;
259}
260
261/**
262 * gfs2_readpage - readpage with locking 252 * gfs2_readpage - readpage with locking
263 * @file: The file to read a page for 253 * @file: The file to read a page for. N.B. This may be NULL if we are
254 * reading an internal file.
264 * @page: The page to read 255 * @page: The page to read
265 * 256 *
266 * Returns: errno 257 * Returns: errno
@@ -270,31 +261,35 @@ static int gfs2_readpage(struct file *file, struct page *page)
270{ 261{
271 struct gfs2_inode *ip = get_v2ip(page->mapping->host); 262 struct gfs2_inode *ip = get_v2ip(page->mapping->host);
272 struct gfs2_sbd *sdp = ip->i_sbd; 263 struct gfs2_sbd *sdp = ip->i_sbd;
264 struct gfs2_holder gh;
273 int error; 265 int error;
274 266
275 atomic_inc(&sdp->sd_ops_address); 267 atomic_inc(&sdp->sd_ops_address);
276 268
277 if (gfs2_assert_warn(sdp, gfs2_glock_is_locked_by_me(ip->i_gl))) { 269 gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh);
278 unlock_page(page); 270 error = gfs2_glock_nq_m_atime(1, &gh);
279 return -EOPNOTSUPP; 271 if (error)
280 } 272 goto out_unlock;
281 273
282 if (!gfs2_is_jdata(ip)) { 274 if (gfs2_is_stuffed(ip)) {
283 if (gfs2_is_stuffed(ip)) { 275 if (!page->index) {
284 if (!page->index) { 276 error = stuffed_readpage(ip, page);
285 error = stuffed_readpage(ip, page); 277 unlock_page(page);
286 unlock_page(page);
287 } else
288 error = zero_readpage(page);
289 } else 278 } else
290 error = mpage_readpage(page, gfs2_get_block); 279 error = zero_readpage(page);
291 } else 280 } else
292 error = jdata_readpage(ip, page); 281 error = mpage_readpage(page, gfs2_get_block);
293 282
294 if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) 283 if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
295 error = -EIO; 284 error = -EIO;
296 285
286 gfs2_glock_dq_m(1, &gh);
287 gfs2_holder_uninit(&gh);
288out:
297 return error; 289 return error;
290out_unlock:
291 unlock_page(page);
292 goto out;
298} 293}
299 294
300/** 295/**
@@ -312,28 +307,82 @@ static int gfs2_prepare_write(struct file *file, struct page *page,
312{ 307{
313 struct gfs2_inode *ip = get_v2ip(page->mapping->host); 308 struct gfs2_inode *ip = get_v2ip(page->mapping->host);
314 struct gfs2_sbd *sdp = ip->i_sbd; 309 struct gfs2_sbd *sdp = ip->i_sbd;
310 unsigned int data_blocks, ind_blocks, rblocks;
311 int alloc_required;
315 int error = 0; 312 int error = 0;
313 loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + from;
314 loff_t end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
315 struct gfs2_alloc *al;
316 316
317 atomic_inc(&sdp->sd_ops_address); 317 atomic_inc(&sdp->sd_ops_address);
318 318
319 if (gfs2_assert_warn(sdp, gfs2_glock_is_locked_by_me(ip->i_gl))) 319 gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME, &ip->i_gh);
320 return -EOPNOTSUPP; 320 error = gfs2_glock_nq_m_atime(1, &ip->i_gh);
321 if (error)
322 goto out_uninit;
321 323
322 if (gfs2_is_stuffed(ip)) { 324 gfs2_write_calc_reserv(ip, to - from, &data_blocks, &ind_blocks);
323 uint64_t file_size; 325
324 file_size = ((uint64_t)page->index << PAGE_CACHE_SHIFT) + to; 326 error = gfs2_write_alloc_required(ip, pos, from - to, &alloc_required);
327 if (error)
328 goto out_unlock;
325 329
326 if (file_size > sdp->sd_sb.sb_bsize - 330
327 sizeof(struct gfs2_dinode)) { 331 if (alloc_required) {
328 error = gfs2_unstuff_dinode(ip, gfs2_unstuffer_page, 332 al = gfs2_alloc_get(ip);
329 page); 333
330 if (!error) 334 error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
331 error = block_prepare_write(page, from, to, 335 if (error)
332 gfs2_get_block); 336 goto out_alloc_put;
333 } else if (!PageUptodate(page)) 337
338 error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid);
339 if (error)
340 goto out_qunlock;
341
342 al->al_requested = data_blocks + ind_blocks;
343 error = gfs2_inplace_reserve(ip);
344 if (error)
345 goto out_qunlock;
346 }
347
348 rblocks = RES_DINODE + ind_blocks;
349 if (gfs2_is_jdata(ip))
350 rblocks += data_blocks ? data_blocks : 1;
351 if (ind_blocks || data_blocks)
352 rblocks += RES_STATFS + RES_QUOTA;
353
354 error = gfs2_trans_begin(sdp, rblocks, 0);
355 if (error)
356 goto out;
357
358 if (gfs2_is_stuffed(ip)) {
359 if (end > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) {
360 error = gfs2_unstuff_dinode(ip, gfs2_unstuffer_page, page);
361 if (error)
362 goto out;
363 } else if (!PageUptodate(page)) {
334 error = stuffed_readpage(ip, page); 364 error = stuffed_readpage(ip, page);
335 } else 365 goto out;
336 error = block_prepare_write(page, from, to, gfs2_get_block); 366 }
367 }
368
369 error = block_prepare_write(page, from, to, gfs2_get_block);
370
371out:
372 if (error) {
373 gfs2_trans_end(sdp);
374 if (alloc_required) {
375 gfs2_inplace_release(ip);
376out_qunlock:
377 gfs2_quota_unlock(ip);
378out_alloc_put:
379 gfs2_alloc_put(ip);
380 }
381out_unlock:
382 gfs2_glock_dq_m(1, &ip->i_gh);
383out_uninit:
384 gfs2_holder_uninit(&ip->i_gh);
385 }
337 386
338 return error; 387 return error;
339} 388}
@@ -354,48 +403,73 @@ static int gfs2_commit_write(struct file *file, struct page *page,
354 struct inode *inode = page->mapping->host; 403 struct inode *inode = page->mapping->host;
355 struct gfs2_inode *ip = get_v2ip(inode); 404 struct gfs2_inode *ip = get_v2ip(inode);
356 struct gfs2_sbd *sdp = ip->i_sbd; 405 struct gfs2_sbd *sdp = ip->i_sbd;
357 int error; 406 int error = -EOPNOTSUPP;
407 struct buffer_head *dibh;
408 struct gfs2_alloc *al = &ip->i_alloc;;
358 409
359 atomic_inc(&sdp->sd_ops_address); 410 atomic_inc(&sdp->sd_ops_address);
360 411
412
413 if (gfs2_assert_withdraw(sdp, gfs2_glock_is_locked_by_me(ip->i_gl)))
414 goto fail_nounlock;
415
416 error = gfs2_meta_inode_buffer(ip, &dibh);
417 if (error)
418 goto fail_endtrans;
419
420 gfs2_trans_add_bh(ip->i_gl, dibh, 1);
421
361 if (gfs2_is_stuffed(ip)) { 422 if (gfs2_is_stuffed(ip)) {
362 struct buffer_head *dibh;
363 uint64_t file_size; 423 uint64_t file_size;
364 void *kaddr; 424 void *kaddr;
365 425
366 file_size = ((uint64_t)page->index << PAGE_CACHE_SHIFT) + to; 426 file_size = ((uint64_t)page->index << PAGE_CACHE_SHIFT) + to;
367 427
368 error = gfs2_meta_inode_buffer(ip, &dibh); 428 kaddr = kmap_atomic(page, KM_USER0);
369 if (error)
370 goto fail;
371
372 gfs2_trans_add_bh(ip->i_gl, dibh, 1);
373
374 kaddr = kmap(page);
375 memcpy(dibh->b_data + sizeof(struct gfs2_dinode) + from, 429 memcpy(dibh->b_data + sizeof(struct gfs2_dinode) + from,
376 (char *)kaddr + from, 430 (char *)kaddr + from, to - from);
377 to - from); 431 kunmap_atomic(page, KM_USER0);
378 kunmap(page);
379
380 brelse(dibh);
381 432
382 SetPageUptodate(page); 433 SetPageUptodate(page);
383 434
384 if (inode->i_size < file_size) 435 if (inode->i_size < file_size)
385 i_size_write(inode, file_size); 436 i_size_write(inode, file_size);
386 } else { 437 } else {
387 if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED) 438 if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
388 gfs2_page_add_databufs(ip, page, from, to); 439 gfs2_page_add_databufs(ip, page, from, to);
389 error = generic_commit_write(file, page, from, to); 440 error = generic_commit_write(file, page, from, to);
390 if (error) 441 if (error)
391 goto fail; 442 goto fail;
392 } 443 }
393 444
445 if (ip->i_di.di_size < inode->i_size)
446 ip->i_di.di_size = inode->i_size;
447
448 gfs2_dinode_out(&ip->i_di, dibh->b_data);
449 brelse(dibh);
450 gfs2_trans_end(sdp);
451 if (al->al_requested) {
452 gfs2_inplace_release(ip);
453 gfs2_quota_unlock(ip);
454 gfs2_alloc_put(ip);
455 }
456 gfs2_glock_dq_m(1, &ip->i_gh);
457 gfs2_holder_uninit(&ip->i_gh);
394 return 0; 458 return 0;
395 459
396 fail: 460fail:
461 brelse(dibh);
462fail_endtrans:
463 gfs2_trans_end(sdp);
464 if (al->al_requested) {
465 gfs2_inplace_release(ip);
466 gfs2_quota_unlock(ip);
467 gfs2_alloc_put(ip);
468 }
469 gfs2_glock_dq_m(1, &ip->i_gh);
470 gfs2_holder_uninit(&ip->i_gh);
471fail_nounlock:
397 ClearPageUptodate(page); 472 ClearPageUptodate(page);
398
399 return error; 473 return error;
400} 474}
401 475
@@ -492,12 +566,16 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *io
492 566
493 atomic_inc(&sdp->sd_ops_address); 567 atomic_inc(&sdp->sd_ops_address);
494 568
495 if (gfs2_assert_warn(sdp, gfs2_glock_is_locked_by_me(ip->i_gl)) || 569 if (gfs2_is_jdata(ip))
496 gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip)))
497 return -EINVAL; 570 return -EINVAL;
498 571
499 if (rw == WRITE && !get_transaction) 572 if (rw == WRITE) {
500 gb = get_blocks_noalloc; 573 return -EOPNOTSUPP; /* for now */
574 } else {
575 if (gfs2_assert_warn(sdp, gfs2_glock_is_locked_by_me(ip->i_gl)) ||
576 gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip)))
577 return -EINVAL;
578 }
501 579
502 return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, 580 return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
503 offset, nr_segs, gb, NULL); 581 offset, nr_segs, gb, NULL);