Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 83625
b: refs/heads/master
c: bd1939d
h: refs/heads/master
i:
  83623: f9c4437
v: v3
  • Loading branch information
Jan Kara authored and Linus Torvalds committed Feb 6, 2008
1 parent 4e763b2 commit 7486d4d
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 55 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: d8fd66aaea7fe3e4f1ea044a563f129e3b9f05ff
refs/heads/master: bd1939de9061dbc5cac44ffb4425aaf4c9b894f1
106 changes: 52 additions & 54 deletions trunk/fs/ext3/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -939,55 +939,45 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
return err;
}

#define DIO_CREDITS (EXT3_RESERVE_TRANS_BLOCKS + 32)
/* Maximum number of blocks we map for direct IO at once. */
#define DIO_MAX_BLOCKS 4096
/*
* Number of credits we need for writing DIO_MAX_BLOCKS:
* We need sb + group descriptor + bitmap + inode -> 4
* For B blocks with A block pointers per block we need:
* 1 (triple ind.) + (B/A/A + 2) (doubly ind.) + (B/A + 2) (indirect).
* If we plug in 4096 for B and 256 for A (for 1KB block size), we get 25.
*/
#define DIO_CREDITS 25

static int ext3_get_block(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create)
{
handle_t *handle = ext3_journal_current_handle();
int ret = 0;
int ret = 0, started = 0;
unsigned max_blocks = bh_result->b_size >> inode->i_blkbits;

if (!create)
goto get_block; /* A read */

if (max_blocks == 1)
goto get_block; /* A single block get */

if (handle->h_transaction->t_state == T_LOCKED) {
/*
* Huge direct-io writes can hold off commits for long
* periods of time. Let this commit run.
*/
ext3_journal_stop(handle);
handle = ext3_journal_start(inode, DIO_CREDITS);
if (IS_ERR(handle))
if (create && !handle) { /* Direct IO write... */
if (max_blocks > DIO_MAX_BLOCKS)
max_blocks = DIO_MAX_BLOCKS;
handle = ext3_journal_start(inode, DIO_CREDITS +
2 * EXT3_QUOTA_TRANS_BLOCKS(inode->i_sb));
if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
goto get_block;
}

if (handle->h_buffer_credits <= EXT3_RESERVE_TRANS_BLOCKS) {
/*
* Getting low on buffer credits...
*/
ret = ext3_journal_extend(handle, DIO_CREDITS);
if (ret > 0) {
/*
* Couldn't extend the transaction. Start a new one.
*/
ret = ext3_journal_restart(handle, DIO_CREDITS);
goto out;
}
started = 1;
}

get_block:
if (ret == 0) {
ret = ext3_get_blocks_handle(handle, inode, iblock,
ret = ext3_get_blocks_handle(handle, inode, iblock,
max_blocks, bh_result, create, 0);
if (ret > 0) {
bh_result->b_size = (ret << inode->i_blkbits);
ret = 0;
}
if (ret > 0) {
bh_result->b_size = (ret << inode->i_blkbits);
ret = 0;
}
if (started)
ext3_journal_stop(handle);
out:
return ret;
}

Expand Down Expand Up @@ -1678,7 +1668,8 @@ static int ext3_releasepage(struct page *page, gfp_t wait)
* if the machine crashes during the write.
*
* If the O_DIRECT write is intantiating holes inside i_size and the machine
* crashes then stale disk data _may_ be exposed inside the file.
* crashes then stale disk data _may_ be exposed inside the file. But current
* VFS code falls back into buffered path in that case so we are safe.
*/
static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb,
const struct iovec *iov, loff_t offset,
Expand All @@ -1687,44 +1678,51 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb,
struct file *file = iocb->ki_filp;
struct inode *inode = file->f_mapping->host;
struct ext3_inode_info *ei = EXT3_I(inode);
handle_t *handle = NULL;
handle_t *handle;
ssize_t ret;
int orphan = 0;
size_t count = iov_length(iov, nr_segs);

if (rw == WRITE) {
loff_t final_size = offset + count;

handle = ext3_journal_start(inode, DIO_CREDITS);
if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
goto out;
}
if (final_size > inode->i_size) {
/* Credits for sb + inode write */
handle = ext3_journal_start(inode, 2);
if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
goto out;
}
ret = ext3_orphan_add(handle, inode);
if (ret)
goto out_stop;
if (ret) {
ext3_journal_stop(handle);
goto out;
}
orphan = 1;
ei->i_disksize = inode->i_size;
ext3_journal_stop(handle);
}
}

ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
offset, nr_segs,
ext3_get_block, NULL);

/*
* Reacquire the handle: ext3_get_block() can restart the transaction
*/
handle = ext3_journal_current_handle();

out_stop:
if (handle) {
if (orphan) {
int err;

if (orphan && inode->i_nlink)
/* Credits for sb + inode write */
handle = ext3_journal_start(inode, 2);
if (IS_ERR(handle)) {
/* This is really bad luck. We've written the data
* but cannot extend i_size. Bail out and pretend
* the write failed... */
ret = PTR_ERR(handle);
goto out;
}
if (inode->i_nlink)
ext3_orphan_del(handle, inode);
if (orphan && ret > 0) {
if (ret > 0) {
loff_t end = offset + ret;
if (end > inode->i_size) {
ei->i_disksize = end;
Expand Down

0 comments on commit 7486d4d

Please sign in to comment.