Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 95028
b: refs/heads/master
c: 093a088
h: refs/heads/master
v: v3
  • Loading branch information
Aneesh Kumar K.V authored and Theodore Ts'o committed Apr 29, 2008
1 parent f7a7cea commit 3e2dba6
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 8 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: 35802c0b2bab71695f131f981d95fcea7432c99b
refs/heads/master: 093a088b76352e0a6fdca84eb78b3aa65fbe6dd1
106 changes: 99 additions & 7 deletions trunk/fs/ext4/extents.c
Original file line number Diff line number Diff line change
Expand Up @@ -2138,6 +2138,80 @@ void ext4_ext_release(struct super_block *sb)
#endif
}

static void bi_complete(struct bio *bio, int error)
{
complete((struct completion *)bio->bi_private);
}

/* FIXME!! we need to try to merge to left or right after zero-out */
static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
{
int ret = -EIO;
struct bio *bio;
int blkbits, blocksize;
sector_t ee_pblock;
struct completion event;
unsigned int ee_len, len, done, offset;


blkbits = inode->i_blkbits;
blocksize = inode->i_sb->s_blocksize;
ee_len = ext4_ext_get_actual_len(ex);
ee_pblock = ext_pblock(ex);

/* convert ee_pblock to 512 byte sectors */
ee_pblock = ee_pblock << (blkbits - 9);

while (ee_len > 0) {

if (ee_len > BIO_MAX_PAGES)
len = BIO_MAX_PAGES;
else
len = ee_len;

bio = bio_alloc(GFP_NOIO, len);
if (!bio)
return -ENOMEM;
bio->bi_sector = ee_pblock;
bio->bi_bdev = inode->i_sb->s_bdev;

done = 0;
offset = 0;
while (done < len) {
ret = bio_add_page(bio, ZERO_PAGE(0),
blocksize, offset);
if (ret != blocksize) {
/*
* We can't add any more pages because of
* hardware limitations. Start a new bio.
*/
break;
}
done++;
offset += blocksize;
if (offset >= PAGE_CACHE_SIZE)
offset = 0;
}

init_completion(&event);
bio->bi_private = &event;
bio->bi_end_io = bi_complete;
submit_bio(WRITE, bio);
wait_for_completion(&event);

if (test_bit(BIO_UPTODATE, &bio->bi_flags))
ret = 0;
else {
ret = -EIO;
break;
}
bio_put(bio);
ee_len -= done;
ee_pblock += done << (blkbits - 9);
}
return ret;
}

/*
* This function is called by ext4_ext_get_blocks() if someone tries to write
* to an uninitialized extent. It may result in splitting the uninitialized
Expand Down Expand Up @@ -2204,14 +2278,19 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
ex3->ee_len = cpu_to_le16(allocated - max_blocks);
ext4_ext_mark_uninitialized(ex3);
err = ext4_ext_insert_extent(handle, inode, path, ex3);
if (err) {
if (err == -ENOSPC) {
err = ext4_ext_zeroout(inode, &orig_ex);
if (err)
goto fix_extent_len;
/* update the extent length and mark as initialized */
ex->ee_block = orig_ex.ee_block;
ex->ee_len = orig_ex.ee_len;
ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
ext4_ext_mark_uninitialized(ex);
ext4_ext_dirty(handle, inode, path + depth);
goto out;
}
return le16_to_cpu(ex->ee_len);

} else if (err)
goto fix_extent_len;
/*
* The depth, and hence eh & ex might change
* as part of the insert above.
Expand Down Expand Up @@ -2297,15 +2376,28 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
goto out;
insert:
err = ext4_ext_insert_extent(handle, inode, path, &newex);
if (err) {
if (err == -ENOSPC) {
err = ext4_ext_zeroout(inode, &orig_ex);
if (err)
goto fix_extent_len;
/* update the extent length and mark as initialized */
ex->ee_block = orig_ex.ee_block;
ex->ee_len = orig_ex.ee_len;
ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
ext4_ext_mark_uninitialized(ex);
ext4_ext_dirty(handle, inode, path + depth);
}
return le16_to_cpu(ex->ee_len);
} else if (err)
goto fix_extent_len;
out:
return err ? err : allocated;

fix_extent_len:
ex->ee_block = orig_ex.ee_block;
ex->ee_len = orig_ex.ee_len;
ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
ext4_ext_mark_uninitialized(ex);
ext4_ext_dirty(handle, inode, path + depth);
return err;
}

/*
Expand Down

0 comments on commit 3e2dba6

Please sign in to comment.