From 60448b1d6db4e82946ff9a2ac88df341f5fa87a2 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 8 May 2007 00:35:13 -0700 Subject: udf: use sector_t and loff_t for file offsets Use sector_t and loff_t for file offsets in UDF filesystem. Otherwise an overflow may occur for long files. Also make inode_bmap() return offset in the extent in number of blocks instead of number of bytes - for most callers this is more convenient. Signed-off-by: Jan Kara Acked-by: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/udf/inode.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'fs/udf/inode.c') diff --git a/fs/udf/inode.c b/fs/udf/inode.c index ae21a0e59e95..6b094250d805 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -49,7 +49,7 @@ MODULE_LICENSE("GPL"); static mode_t udf_convert_permissions(struct fileEntry *); static int udf_update_inode(struct inode *, int); static void udf_fill_inode(struct inode *, struct buffer_head *); -static struct buffer_head *inode_getblk(struct inode *, long, int *, +static struct buffer_head *inode_getblk(struct inode *, sector_t, int *, long *, int *); static int8_t udf_insert_aext(struct inode *, kernel_lb_addr, int, kernel_lb_addr, uint32_t, struct buffer_head *); @@ -354,7 +354,7 @@ udf_getblk(struct inode *inode, long block, int create, int *err) return NULL; } -static struct buffer_head * inode_getblk(struct inode * inode, long block, +static struct buffer_head * inode_getblk(struct inode * inode, sector_t block, int *err, long *phys, int *new) { struct buffer_head *pbh = NULL, *cbh = NULL, *nbh = NULL, *result = NULL; @@ -364,14 +364,15 @@ static struct buffer_head * inode_getblk(struct inode * inode, long block, uint32_t elen = 0; kernel_lb_addr eloc, pbloc, cbloc, nbloc; int c = 1; - uint64_t lbcount = 0, b_off = 0; - uint32_t newblocknum, newblock, offset = 0; + loff_t lbcount = 0, b_off = 0; + uint32_t newblocknum, newblock; + sector_t offset = 0; int8_t etype; int goal = 0, pgoal = UDF_I_LOCATION(inode).logicalBlockNum; char lastblock = 0; pextoffset = cextoffset = nextoffset = udf_file_entry_alloc_offset(inode); - b_off = (uint64_t)block << inode->i_sb->s_blocksize_bits; + b_off = (loff_t)block << inode->i_sb->s_blocksize_bits; pbloc = cbloc = nbloc = UDF_I_LOCATION(inode); /* find the extent which contains the block we are looking for. @@ -1948,10 +1949,10 @@ int8_t udf_delete_aext(struct inode *inode, kernel_lb_addr nbloc, int nextoffset return (elen >> 30); } -int8_t inode_bmap(struct inode *inode, int block, kernel_lb_addr *bloc, uint32_t *extoffset, - kernel_lb_addr *eloc, uint32_t *elen, uint32_t *offset, struct buffer_head **bh) +int8_t inode_bmap(struct inode *inode, sector_t block, kernel_lb_addr *bloc, uint32_t *extoffset, + kernel_lb_addr *eloc, uint32_t *elen, sector_t *offset, struct buffer_head **bh) { - uint64_t lbcount = 0, bcount = (uint64_t)block << inode->i_sb->s_blocksize_bits; + loff_t lbcount = 0, bcount = (loff_t)block << inode->i_sb->s_blocksize_bits; int8_t etype; if (block < 0) @@ -1968,29 +1969,30 @@ int8_t inode_bmap(struct inode *inode, int block, kernel_lb_addr *bloc, uint32_t { if ((etype = udf_next_aext(inode, bloc, extoffset, eloc, elen, bh, 1)) == -1) { - *offset = bcount - lbcount; + *offset = (bcount - lbcount) >> inode->i_sb->s_blocksize_bits; UDF_I_LENEXTENTS(inode) = lbcount; return -1; } lbcount += *elen; } while (lbcount <= bcount); - *offset = bcount + *elen - lbcount; + *offset = (bcount + *elen - lbcount) >> inode->i_sb->s_blocksize_bits; return etype; } -long udf_block_map(struct inode *inode, long block) +long udf_block_map(struct inode *inode, sector_t block) { kernel_lb_addr eloc, bloc; - uint32_t offset, extoffset, elen; + uint32_t extoffset, elen; + sector_t offset; struct buffer_head *bh = NULL; int ret; lock_kernel(); if (inode_bmap(inode, block, &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30)) - ret = udf_get_lb_pblock(inode->i_sb, eloc, offset >> inode->i_sb->s_blocksize_bits); + ret = udf_get_lb_pblock(inode->i_sb, eloc, offset); else ret = 0; -- cgit v1.2.1 From ff116fc8d1d43927c7651b91d5aec41eb30c4429 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 8 May 2007 00:35:14 -0700 Subject: UDF: introduce struct extent_position Introduce a structure extent_position to store a position of an extent and the corresponding buffer_head in one place. Signed-off-by: Jan Kara Acked-by: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/udf/inode.c | 343 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 169 insertions(+), 174 deletions(-) (limited to 'fs/udf/inode.c') diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 6b094250d805..a106acb58292 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -51,8 +51,8 @@ static int udf_update_inode(struct inode *, int); static void udf_fill_inode(struct inode *, struct buffer_head *); static struct buffer_head *inode_getblk(struct inode *, sector_t, int *, long *, int *); -static int8_t udf_insert_aext(struct inode *, kernel_lb_addr, int, - kernel_lb_addr, uint32_t, struct buffer_head *); +static int8_t udf_insert_aext(struct inode *, struct extent_position, + kernel_lb_addr, uint32_t); static void udf_split_extents(struct inode *, int *, int, int, kernel_long_ad [EXTENT_MERGE_SIZE], int *); static void udf_prealloc_extents(struct inode *, int, int, @@ -61,7 +61,7 @@ static void udf_merge_extents(struct inode *, kernel_long_ad [EXTENT_MERGE_SIZE], int *); static void udf_update_extents(struct inode *, kernel_long_ad [EXTENT_MERGE_SIZE], int, int, - kernel_lb_addr, uint32_t, struct buffer_head **); + struct extent_position *); static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int); /* @@ -194,10 +194,11 @@ void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err) struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int *err) { int newblock; - struct buffer_head *sbh = NULL, *dbh = NULL; - kernel_lb_addr bloc, eloc; - uint32_t elen, extoffset; + struct buffer_head *dbh = NULL; + kernel_lb_addr eloc; + uint32_t elen; uint8_t alloctype; + struct extent_position epos; struct udf_fileident_bh sfibh, dfibh; loff_t f_pos = udf_ext0_offset(inode) >> 2; @@ -237,13 +238,13 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int mark_buffer_dirty_inode(dbh, inode); sfibh.soffset = sfibh.eoffset = (f_pos & ((inode->i_sb->s_blocksize - 1) >> 2)) << 2; - sbh = sfibh.sbh = sfibh.ebh = NULL; + sfibh.sbh = sfibh.ebh = NULL; dfibh.soffset = dfibh.eoffset = 0; dfibh.sbh = dfibh.ebh = dbh; while ( (f_pos < size) ) { UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB; - sfi = udf_fileident_read(inode, &f_pos, &sfibh, &cfi, NULL, NULL, NULL, NULL, NULL, NULL); + sfi = udf_fileident_read(inode, &f_pos, &sfibh, &cfi, NULL, NULL, NULL, NULL); if (!sfi) { udf_release_data(dbh); @@ -266,16 +267,17 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), 0, UDF_I_LENALLOC(inode)); UDF_I_LENALLOC(inode) = 0; - bloc = UDF_I_LOCATION(inode); eloc.logicalBlockNum = *block; eloc.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum; elen = inode->i_size; UDF_I_LENEXTENTS(inode) = elen; - extoffset = udf_file_entry_alloc_offset(inode); - udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &sbh, 0); + epos.bh = NULL; + epos.block = UDF_I_LOCATION(inode); + epos.offset = udf_file_entry_alloc_offset(inode); + udf_add_aext(inode, &epos, eloc, elen, 0); /* UniqueID stuff */ - udf_release_data(sbh); + udf_release_data(epos.bh); mark_inode_dirty(inode); return dbh; } @@ -357,12 +359,12 @@ udf_getblk(struct inode *inode, long block, int create, int *err) static struct buffer_head * inode_getblk(struct inode * inode, sector_t block, int *err, long *phys, int *new) { - struct buffer_head *pbh = NULL, *cbh = NULL, *nbh = NULL, *result = NULL; + struct buffer_head *result = NULL; kernel_long_ad laarr[EXTENT_MERGE_SIZE]; - uint32_t pextoffset = 0, cextoffset = 0, nextoffset = 0; + struct extent_position prev_epos, cur_epos, next_epos; int count = 0, startnum = 0, endnum = 0; uint32_t elen = 0; - kernel_lb_addr eloc, pbloc, cbloc, nbloc; + kernel_lb_addr eloc; int c = 1; loff_t lbcount = 0, b_off = 0; uint32_t newblocknum, newblock; @@ -371,37 +373,39 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block, int goal = 0, pgoal = UDF_I_LOCATION(inode).logicalBlockNum; char lastblock = 0; - pextoffset = cextoffset = nextoffset = udf_file_entry_alloc_offset(inode); + prev_epos.offset = udf_file_entry_alloc_offset(inode); + prev_epos.block = UDF_I_LOCATION(inode); + prev_epos.bh = NULL; + cur_epos = next_epos = prev_epos; b_off = (loff_t)block << inode->i_sb->s_blocksize_bits; - pbloc = cbloc = nbloc = UDF_I_LOCATION(inode); /* find the extent which contains the block we are looking for. alternate between laarr[0] and laarr[1] for locations of the current extent, and the previous extent */ do { - if (pbh != cbh) + if (prev_epos.bh != cur_epos.bh) { - udf_release_data(pbh); - atomic_inc(&cbh->b_count); - pbh = cbh; + udf_release_data(prev_epos.bh); + atomic_inc(&cur_epos.bh->b_count); + prev_epos.bh = cur_epos.bh; } - if (cbh != nbh) + if (cur_epos.bh != next_epos.bh) { - udf_release_data(cbh); - atomic_inc(&nbh->b_count); - cbh = nbh; + udf_release_data(cur_epos.bh); + atomic_inc(&next_epos.bh->b_count); + cur_epos.bh = next_epos.bh; } lbcount += elen; - pbloc = cbloc; - cbloc = nbloc; + prev_epos.block = cur_epos.block; + cur_epos.block = next_epos.block; - pextoffset = cextoffset; - cextoffset = nextoffset; + prev_epos.offset = cur_epos.offset; + cur_epos.offset = next_epos.offset; - if ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) == -1) + if ((etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 1)) == -1) break; c = !c; @@ -430,11 +434,11 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block, elen = EXT_RECORDED_ALLOCATED | ((elen + inode->i_sb->s_blocksize - 1) & ~(inode->i_sb->s_blocksize - 1)); - etype = udf_write_aext(inode, nbloc, &cextoffset, eloc, elen, nbh, 1); + etype = udf_write_aext(inode, &cur_epos, eloc, elen, 1); } - udf_release_data(pbh); - udf_release_data(cbh); - udf_release_data(nbh); + udf_release_data(prev_epos.bh); + udf_release_data(cur_epos.bh); + udf_release_data(next_epos.bh); newblock = udf_get_lb_pblock(inode->i_sb, eloc, offset); *phys = newblock; return NULL; @@ -477,7 +481,7 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block, /* if the current block is located in a extent, read the next extent */ if (etype != -1) { - if ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 0)) != -1) + if ((etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 0)) != -1) { laarr[c+1].extLength = (etype << 30) | elen; laarr[c+1].extLocation = eloc; @@ -488,8 +492,8 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block, else lastblock = 1; } - udf_release_data(cbh); - udf_release_data(nbh); + udf_release_data(cur_epos.bh); + udf_release_data(next_epos.bh); /* if the current extent is not recorded but allocated, get the block in the extent corresponding to the requested block */ @@ -509,7 +513,7 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block, if (!(newblocknum = udf_new_block(inode->i_sb, inode, UDF_I_LOCATION(inode).partitionReferenceNum, goal, err))) { - udf_release_data(pbh); + udf_release_data(prev_epos.bh); *err = -ENOSPC; return NULL; } @@ -532,9 +536,9 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block, /* write back the new extents, inserting new extents if the new number of extents is greater than the old number, and deleting extents if the new number of extents is less than the old number */ - udf_update_extents(inode, laarr, startnum, endnum, pbloc, pextoffset, &pbh); + udf_update_extents(inode, laarr, startnum, endnum, &prev_epos); - udf_release_data(pbh); + udf_release_data(prev_epos.bh); if (!(newblock = udf_get_pblock(inode->i_sb, newblocknum, UDF_I_LOCATION(inode).partitionReferenceNum, 0))) @@ -796,7 +800,7 @@ static void udf_merge_extents(struct inode *inode, static void udf_update_extents(struct inode *inode, kernel_long_ad laarr[EXTENT_MERGE_SIZE], int startnum, int endnum, - kernel_lb_addr pbloc, uint32_t pextoffset, struct buffer_head **pbh) + struct extent_position *epos) { int start = 0, i; kernel_lb_addr tmploc; @@ -805,28 +809,26 @@ static void udf_update_extents(struct inode *inode, if (startnum > endnum) { for (i=0; i<(startnum-endnum); i++) - { - udf_delete_aext(inode, pbloc, pextoffset, laarr[i].extLocation, - laarr[i].extLength, *pbh); - } + udf_delete_aext(inode, *epos, laarr[i].extLocation, + laarr[i].extLength); } else if (startnum < endnum) { for (i=0; i<(endnum-startnum); i++) { - udf_insert_aext(inode, pbloc, pextoffset, laarr[i].extLocation, - laarr[i].extLength, *pbh); - udf_next_aext(inode, &pbloc, &pextoffset, &laarr[i].extLocation, - &laarr[i].extLength, pbh, 1); + udf_insert_aext(inode, *epos, laarr[i].extLocation, + laarr[i].extLength); + udf_next_aext(inode, epos, &laarr[i].extLocation, + &laarr[i].extLength, 1); start ++; } } for (i=start; ibh) + ptr = UDF_I_DATA(inode) + epos->offset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode); else - ptr = (*bh)->b_data + *extoffset; + ptr = epos->bh->b_data + epos->offset; if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) adsize = sizeof(short_ad); @@ -1579,20 +1581,20 @@ int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset, else return -1; - if (*extoffset + (2 * adsize) > inode->i_sb->s_blocksize) + if (epos->offset + (2 * adsize) > inode->i_sb->s_blocksize) { char *sptr, *dptr; struct buffer_head *nbh; int err, loffset; - kernel_lb_addr obloc = *bloc; + kernel_lb_addr obloc = epos->block; - if (!(bloc->logicalBlockNum = udf_new_block(inode->i_sb, NULL, + if (!(epos->block.logicalBlockNum = udf_new_block(inode->i_sb, NULL, obloc.partitionReferenceNum, obloc.logicalBlockNum, &err))) { return -1; } if (!(nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb, - *bloc, 0)))) + epos->block, 0)))) { return -1; } @@ -1605,25 +1607,25 @@ int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset, aed = (struct allocExtDesc *)(nbh->b_data); if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT)) aed->previousAllocExtLocation = cpu_to_le32(obloc.logicalBlockNum); - if (*extoffset + adsize > inode->i_sb->s_blocksize) + if (epos->offset + adsize > inode->i_sb->s_blocksize) { - loffset = *extoffset; + loffset = epos->offset; aed->lengthAllocDescs = cpu_to_le32(adsize); sptr = ptr - adsize; dptr = nbh->b_data + sizeof(struct allocExtDesc); memcpy(dptr, sptr, adsize); - *extoffset = sizeof(struct allocExtDesc) + adsize; + epos->offset = sizeof(struct allocExtDesc) + adsize; } else { - loffset = *extoffset + adsize; + loffset = epos->offset + adsize; aed->lengthAllocDescs = cpu_to_le32(0); sptr = ptr; - *extoffset = sizeof(struct allocExtDesc); + epos->offset = sizeof(struct allocExtDesc); - if (*bh) + if (epos->bh) { - aed = (struct allocExtDesc *)(*bh)->b_data; + aed = (struct allocExtDesc *)epos->bh->b_data; aed->lengthAllocDescs = cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize); } @@ -1635,10 +1637,10 @@ int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset, } if (UDF_SB_UDFREV(inode->i_sb) >= 0x0200) udf_new_tag(nbh->b_data, TAG_IDENT_AED, 3, 1, - bloc->logicalBlockNum, sizeof(tag)); + epos->block.logicalBlockNum, sizeof(tag)); else udf_new_tag(nbh->b_data, TAG_IDENT_AED, 2, 1, - bloc->logicalBlockNum, sizeof(tag)); + epos->block.logicalBlockNum, sizeof(tag)); switch (UDF_I_ALLOCTYPE(inode)) { case ICBTAG_FLAG_AD_SHORT: @@ -1647,7 +1649,7 @@ int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset, sad->extLength = cpu_to_le32( EXT_NEXT_EXTENT_ALLOCDECS | inode->i_sb->s_blocksize); - sad->extPosition = cpu_to_le32(bloc->logicalBlockNum); + sad->extPosition = cpu_to_le32(epos->block.logicalBlockNum); break; } case ICBTAG_FLAG_AD_LONG: @@ -1656,60 +1658,57 @@ int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset, lad->extLength = cpu_to_le32( EXT_NEXT_EXTENT_ALLOCDECS | inode->i_sb->s_blocksize); - lad->extLocation = cpu_to_lelb(*bloc); + lad->extLocation = cpu_to_lelb(epos->block); memset(lad->impUse, 0x00, sizeof(lad->impUse)); break; } } - if (*bh) + if (epos->bh) { if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) - udf_update_tag((*bh)->b_data, loffset); + udf_update_tag(epos->bh->b_data, loffset); else - udf_update_tag((*bh)->b_data, sizeof(struct allocExtDesc)); - mark_buffer_dirty_inode(*bh, inode); - udf_release_data(*bh); + udf_update_tag(epos->bh->b_data, sizeof(struct allocExtDesc)); + mark_buffer_dirty_inode(epos->bh, inode); + udf_release_data(epos->bh); } else mark_inode_dirty(inode); - *bh = nbh; + epos->bh = nbh; } - etype = udf_write_aext(inode, *bloc, extoffset, eloc, elen, *bh, inc); + etype = udf_write_aext(inode, epos, eloc, elen, inc); - if (!*bh) + if (!epos->bh) { UDF_I_LENALLOC(inode) += adsize; mark_inode_dirty(inode); } else { - aed = (struct allocExtDesc *)(*bh)->b_data; + aed = (struct allocExtDesc *)epos->bh->b_data; aed->lengthAllocDescs = cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize); if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) - udf_update_tag((*bh)->b_data, *extoffset + (inc ? 0 : adsize)); + udf_update_tag(epos->bh->b_data, epos->offset + (inc ? 0 : adsize)); else - udf_update_tag((*bh)->b_data, sizeof(struct allocExtDesc)); - mark_buffer_dirty_inode(*bh, inode); + udf_update_tag(epos->bh->b_data, sizeof(struct allocExtDesc)); + mark_buffer_dirty_inode(epos->bh, inode); } return etype; } -int8_t udf_write_aext(struct inode *inode, kernel_lb_addr bloc, int *extoffset, - kernel_lb_addr eloc, uint32_t elen, struct buffer_head *bh, int inc) +int8_t udf_write_aext(struct inode *inode, struct extent_position *epos, + kernel_lb_addr eloc, uint32_t elen, int inc) { int adsize; uint8_t *ptr; - if (!bh) - ptr = UDF_I_DATA(inode) + *extoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode); + if (!epos->bh) + ptr = UDF_I_DATA(inode) + epos->offset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode); else - { - ptr = bh->b_data + *extoffset; - atomic_inc(&bh->b_count); - } + ptr = epos->bh->b_data + epos->offset; switch (UDF_I_ALLOCTYPE(inode)) { @@ -1734,40 +1733,39 @@ int8_t udf_write_aext(struct inode *inode, kernel_lb_addr bloc, int *extoffset, return -1; } - if (bh) + if (epos->bh) { if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) { - struct allocExtDesc *aed = (struct allocExtDesc *)(bh)->b_data; - udf_update_tag((bh)->b_data, + struct allocExtDesc *aed = (struct allocExtDesc *)epos->bh->b_data; + udf_update_tag(epos->bh->b_data, le32_to_cpu(aed->lengthAllocDescs) + sizeof(struct allocExtDesc)); } - mark_buffer_dirty_inode(bh, inode); - udf_release_data(bh); + mark_buffer_dirty_inode(epos->bh, inode); } else mark_inode_dirty(inode); if (inc) - *extoffset += adsize; + epos->offset += adsize; return (elen >> 30); } -int8_t udf_next_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset, - kernel_lb_addr *eloc, uint32_t *elen, struct buffer_head **bh, int inc) +int8_t udf_next_aext(struct inode *inode, struct extent_position *epos, + kernel_lb_addr *eloc, uint32_t *elen, int inc) { int8_t etype; - while ((etype = udf_current_aext(inode, bloc, extoffset, eloc, elen, bh, inc)) == + while ((etype = udf_current_aext(inode, epos, eloc, elen, inc)) == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) { - *bloc = *eloc; - *extoffset = sizeof(struct allocExtDesc); - udf_release_data(*bh); - if (!(*bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, *bloc, 0)))) + epos->block = *eloc; + epos->offset = sizeof(struct allocExtDesc); + udf_release_data(epos->bh); + if (!(epos->bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, epos->block, 0)))) { udf_debug("reading block %d failed!\n", - udf_get_lb_pblock(inode->i_sb, *bloc, 0)); + udf_get_lb_pblock(inode->i_sb, epos->block, 0)); return -1; } } @@ -1775,26 +1773,26 @@ int8_t udf_next_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset, return etype; } -int8_t udf_current_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset, - kernel_lb_addr *eloc, uint32_t *elen, struct buffer_head **bh, int inc) +int8_t udf_current_aext(struct inode *inode, struct extent_position *epos, + kernel_lb_addr *eloc, uint32_t *elen, int inc) { int alen; int8_t etype; uint8_t *ptr; - if (!*bh) + if (!epos->bh) { - if (!(*extoffset)) - *extoffset = udf_file_entry_alloc_offset(inode); - ptr = UDF_I_DATA(inode) + *extoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode); + if (!epos->offset) + epos->offset = udf_file_entry_alloc_offset(inode); + ptr = UDF_I_DATA(inode) + epos->offset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode); alen = udf_file_entry_alloc_offset(inode) + UDF_I_LENALLOC(inode); } else { - if (!(*extoffset)) - *extoffset = sizeof(struct allocExtDesc); - ptr = (*bh)->b_data + *extoffset; - alen = sizeof(struct allocExtDesc) + le32_to_cpu(((struct allocExtDesc *)(*bh)->b_data)->lengthAllocDescs); + if (!epos->offset) + epos->offset = sizeof(struct allocExtDesc); + ptr = epos->bh->b_data + epos->offset; + alen = sizeof(struct allocExtDesc) + le32_to_cpu(((struct allocExtDesc *)epos->bh->b_data)->lengthAllocDescs); } switch (UDF_I_ALLOCTYPE(inode)) @@ -1803,7 +1801,7 @@ int8_t udf_current_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffse { short_ad *sad; - if (!(sad = udf_get_fileshortad(ptr, alen, extoffset, inc))) + if (!(sad = udf_get_fileshortad(ptr, alen, &epos->offset, inc))) return -1; etype = le32_to_cpu(sad->extLength) >> 30; @@ -1816,7 +1814,7 @@ int8_t udf_current_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffse { long_ad *lad; - if (!(lad = udf_get_filelongad(ptr, alen, extoffset, inc))) + if (!(lad = udf_get_filelongad(ptr, alen, &epos->offset, inc))) return -1; etype = le32_to_cpu(lad->extLength) >> 30; @@ -1835,41 +1833,40 @@ int8_t udf_current_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffse } static int8_t -udf_insert_aext(struct inode *inode, kernel_lb_addr bloc, int extoffset, - kernel_lb_addr neloc, uint32_t nelen, struct buffer_head *bh) +udf_insert_aext(struct inode *inode, struct extent_position epos, + kernel_lb_addr neloc, uint32_t nelen) { kernel_lb_addr oeloc; uint32_t oelen; int8_t etype; - if (bh) - atomic_inc(&bh->b_count); + if (epos.bh) + atomic_inc(&epos.bh->b_count); - while ((etype = udf_next_aext(inode, &bloc, &extoffset, &oeloc, &oelen, &bh, 0)) != -1) + while ((etype = udf_next_aext(inode, &epos, &oeloc, &oelen, 0)) != -1) { - udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 1); + udf_write_aext(inode, &epos, neloc, nelen, 1); neloc = oeloc; nelen = (etype << 30) | oelen; } - udf_add_aext(inode, &bloc, &extoffset, neloc, nelen, &bh, 1); - udf_release_data(bh); + udf_add_aext(inode, &epos, neloc, nelen, 1); + udf_release_data(epos.bh); return (nelen >> 30); } -int8_t udf_delete_aext(struct inode *inode, kernel_lb_addr nbloc, int nextoffset, - kernel_lb_addr eloc, uint32_t elen, struct buffer_head *nbh) +int8_t udf_delete_aext(struct inode *inode, struct extent_position epos, + kernel_lb_addr eloc, uint32_t elen) { - struct buffer_head *obh; - kernel_lb_addr obloc; - int oextoffset, adsize; + struct extent_position oepos; + int adsize; int8_t etype; struct allocExtDesc *aed; - if (nbh) + if (epos.bh) { - atomic_inc(&nbh->b_count); - atomic_inc(&nbh->b_count); + atomic_inc(&epos.bh->b_count); + atomic_inc(&epos.bh->b_count); } if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) @@ -1879,78 +1876,75 @@ int8_t udf_delete_aext(struct inode *inode, kernel_lb_addr nbloc, int nextoffset else adsize = 0; - obh = nbh; - obloc = nbloc; - oextoffset = nextoffset; - - if (udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1) == -1) + oepos = epos; + if (udf_next_aext(inode, &epos, &eloc, &elen, 1) == -1) return -1; - while ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) != -1) + while ((etype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) { - udf_write_aext(inode, obloc, &oextoffset, eloc, (etype << 30) | elen, obh, 1); - if (obh != nbh) + udf_write_aext(inode, &oepos, eloc, (etype << 30) | elen, 1); + if (oepos.bh != epos.bh) { - obloc = nbloc; - udf_release_data(obh); - atomic_inc(&nbh->b_count); - obh = nbh; - oextoffset = nextoffset - adsize; + oepos.block = epos.block; + udf_release_data(oepos.bh); + atomic_inc(&epos.bh->b_count); + oepos.bh = epos.bh; + oepos.offset = epos.offset - adsize; } } memset(&eloc, 0x00, sizeof(kernel_lb_addr)); elen = 0; - if (nbh != obh) + if (epos.bh != oepos.bh) { - udf_free_blocks(inode->i_sb, inode, nbloc, 0, 1); - udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1); - udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1); - if (!obh) + udf_free_blocks(inode->i_sb, inode, epos.block, 0, 1); + udf_write_aext(inode, &oepos, eloc, elen, 1); + udf_write_aext(inode, &oepos, eloc, elen, 1); + if (!oepos.bh) { UDF_I_LENALLOC(inode) -= (adsize * 2); mark_inode_dirty(inode); } else { - aed = (struct allocExtDesc *)(obh)->b_data; + aed = (struct allocExtDesc *)oepos.bh->b_data; aed->lengthAllocDescs = cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - (2*adsize)); if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) - udf_update_tag((obh)->b_data, oextoffset - (2*adsize)); + udf_update_tag(oepos.bh->b_data, oepos.offset - (2*adsize)); else - udf_update_tag((obh)->b_data, sizeof(struct allocExtDesc)); - mark_buffer_dirty_inode(obh, inode); + udf_update_tag(oepos.bh->b_data, sizeof(struct allocExtDesc)); + mark_buffer_dirty_inode(oepos.bh, inode); } } else { - udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1); - if (!obh) + udf_write_aext(inode, &oepos, eloc, elen, 1); + if (!oepos.bh) { UDF_I_LENALLOC(inode) -= adsize; mark_inode_dirty(inode); } else { - aed = (struct allocExtDesc *)(obh)->b_data; + aed = (struct allocExtDesc *)oepos.bh->b_data; aed->lengthAllocDescs = cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - adsize); if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) - udf_update_tag((obh)->b_data, oextoffset - adsize); + udf_update_tag(oepos.bh->b_data, epos.offset - adsize); else - udf_update_tag((obh)->b_data, sizeof(struct allocExtDesc)); - mark_buffer_dirty_inode(obh, inode); + udf_update_tag(oepos.bh->b_data, sizeof(struct allocExtDesc)); + mark_buffer_dirty_inode(oepos.bh, inode); } } - udf_release_data(nbh); - udf_release_data(obh); + udf_release_data(epos.bh); + udf_release_data(oepos.bh); return (elen >> 30); } -int8_t inode_bmap(struct inode *inode, sector_t block, kernel_lb_addr *bloc, uint32_t *extoffset, - kernel_lb_addr *eloc, uint32_t *elen, sector_t *offset, struct buffer_head **bh) +int8_t inode_bmap(struct inode *inode, sector_t block, struct extent_position *pos, + kernel_lb_addr *eloc, uint32_t *elen, sector_t *offset) { loff_t lbcount = 0, bcount = (loff_t)block << inode->i_sb->s_blocksize_bits; int8_t etype; @@ -1961,13 +1955,14 @@ int8_t inode_bmap(struct inode *inode, sector_t block, kernel_lb_addr *bloc, uin return -1; } - *extoffset = 0; + pos->offset = 0; + pos->block = UDF_I_LOCATION(inode); + pos->bh = NULL; *elen = 0; - *bloc = UDF_I_LOCATION(inode); do { - if ((etype = udf_next_aext(inode, bloc, extoffset, eloc, elen, bh, 1)) == -1) + if ((etype = udf_next_aext(inode, pos, eloc, elen, 1)) == -1) { *offset = (bcount - lbcount) >> inode->i_sb->s_blocksize_bits; UDF_I_LENEXTENTS(inode) = lbcount; @@ -1983,21 +1978,21 @@ int8_t inode_bmap(struct inode *inode, sector_t block, kernel_lb_addr *bloc, uin long udf_block_map(struct inode *inode, sector_t block) { - kernel_lb_addr eloc, bloc; - uint32_t extoffset, elen; + kernel_lb_addr eloc; + uint32_t elen; sector_t offset; - struct buffer_head *bh = NULL; + struct extent_position epos = { NULL, 0, { 0, 0}}; int ret; lock_kernel(); - if (inode_bmap(inode, block, &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30)) + if (inode_bmap(inode, block, &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30)) ret = udf_get_lb_pblock(inode->i_sb, eloc, offset); else ret = 0; unlock_kernel(); - udf_release_data(bh); + udf_release_data(epos.bh); if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_VARCONV)) return udf_fixed_to_variable(ret); -- cgit v1.2.1 From 3bf25cb40d899eeb5a471f497e56ddfe2c96c019 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 8 May 2007 00:35:16 -0700 Subject: udf: use get_bh() Make UDF use get_bh() instead of directly accessing b_count and use brelse() instead of udf_release_data() which does just brelse()... Signed-off-by: Jan Kara Acked-by: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/udf/inode.c | 74 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) (limited to 'fs/udf/inode.c') diff --git a/fs/udf/inode.c b/fs/udf/inode.c index a106acb58292..2171bcfeec20 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -247,7 +247,7 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int sfi = udf_fileident_read(inode, &f_pos, &sfibh, &cfi, NULL, NULL, NULL, NULL); if (!sfi) { - udf_release_data(dbh); + brelse(dbh); return NULL; } UDF_I_ALLOCTYPE(inode) = alloctype; @@ -259,7 +259,7 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int sfi->fileIdent + le16_to_cpu(sfi->lengthOfImpUse))) { UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB; - udf_release_data(dbh); + brelse(dbh); return NULL; } } @@ -277,7 +277,7 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int udf_add_aext(inode, &epos, eloc, elen, 0); /* UniqueID stuff */ - udf_release_data(epos.bh); + brelse(epos.bh); mark_inode_dirty(inode); return dbh; } @@ -386,14 +386,14 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block, { if (prev_epos.bh != cur_epos.bh) { - udf_release_data(prev_epos.bh); - atomic_inc(&cur_epos.bh->b_count); + brelse(prev_epos.bh); + get_bh(cur_epos.bh); prev_epos.bh = cur_epos.bh; } if (cur_epos.bh != next_epos.bh) { - udf_release_data(cur_epos.bh); - atomic_inc(&next_epos.bh->b_count); + brelse(cur_epos.bh); + get_bh(next_epos.bh); cur_epos.bh = next_epos.bh; } @@ -436,9 +436,9 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block, ~(inode->i_sb->s_blocksize - 1)); etype = udf_write_aext(inode, &cur_epos, eloc, elen, 1); } - udf_release_data(prev_epos.bh); - udf_release_data(cur_epos.bh); - udf_release_data(next_epos.bh); + brelse(prev_epos.bh); + brelse(cur_epos.bh); + brelse(next_epos.bh); newblock = udf_get_lb_pblock(inode->i_sb, eloc, offset); *phys = newblock; return NULL; @@ -492,8 +492,8 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block, else lastblock = 1; } - udf_release_data(cur_epos.bh); - udf_release_data(next_epos.bh); + brelse(cur_epos.bh); + brelse(next_epos.bh); /* if the current extent is not recorded but allocated, get the block in the extent corresponding to the requested block */ @@ -513,7 +513,7 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block, if (!(newblocknum = udf_new_block(inode->i_sb, inode, UDF_I_LOCATION(inode).partitionReferenceNum, goal, err))) { - udf_release_data(prev_epos.bh); + brelse(prev_epos.bh); *err = -ENOSPC; return NULL; } @@ -538,7 +538,7 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block, the new number of extents is less than the old number */ udf_update_extents(inode, laarr, startnum, endnum, &prev_epos); - udf_release_data(prev_epos.bh); + brelse(prev_epos.bh); if (!(newblock = udf_get_pblock(inode->i_sb, newblocknum, UDF_I_LOCATION(inode).partitionReferenceNum, 0))) @@ -934,7 +934,7 @@ __udf_read_inode(struct inode *inode) { printk(KERN_ERR "udf: udf_read_inode(ino %ld) failed ident=%d\n", inode->i_ino, ident); - udf_release_data(bh); + brelse(bh); make_bad_inode(inode); return; } @@ -963,35 +963,35 @@ __udf_read_inode(struct inode *inode) ident == TAG_IDENT_EFE) { memcpy(&UDF_I_LOCATION(inode), &loc, sizeof(kernel_lb_addr)); - udf_release_data(bh); - udf_release_data(ibh); - udf_release_data(nbh); + brelse(bh); + brelse(ibh); + brelse(nbh); __udf_read_inode(inode); return; } else { - udf_release_data(nbh); - udf_release_data(ibh); + brelse(nbh); + brelse(ibh); } } else - udf_release_data(ibh); + brelse(ibh); } } else - udf_release_data(ibh); + brelse(ibh); } else if (le16_to_cpu(fe->icbTag.strategyType) != 4) { printk(KERN_ERR "udf: unsupported strategy type: %d\n", le16_to_cpu(fe->icbTag.strategyType)); - udf_release_data(bh); + brelse(bh); make_bad_inode(inode); return; } udf_fill_inode(inode, bh); - udf_release_data(bh); + brelse(bh); } static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) @@ -1334,7 +1334,7 @@ udf_update_inode(struct inode *inode, int do_sync) use->descTag.tagChecksum += ((uint8_t *)&(use->descTag))[i]; mark_buffer_dirty(bh); - udf_release_data(bh); + brelse(bh); return err; } @@ -1523,7 +1523,7 @@ udf_update_inode(struct inode *inode, int do_sync) err = -EIO; } } - udf_release_data(bh); + brelse(bh); return err; } @@ -1670,7 +1670,7 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos, else udf_update_tag(epos->bh->b_data, sizeof(struct allocExtDesc)); mark_buffer_dirty_inode(epos->bh, inode); - udf_release_data(epos->bh); + brelse(epos->bh); } else mark_inode_dirty(inode); @@ -1761,7 +1761,7 @@ int8_t udf_next_aext(struct inode *inode, struct extent_position *epos, { epos->block = *eloc; epos->offset = sizeof(struct allocExtDesc); - udf_release_data(epos->bh); + brelse(epos->bh); if (!(epos->bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, epos->block, 0)))) { udf_debug("reading block %d failed!\n", @@ -1841,7 +1841,7 @@ udf_insert_aext(struct inode *inode, struct extent_position epos, int8_t etype; if (epos.bh) - atomic_inc(&epos.bh->b_count); + get_bh(epos.bh); while ((etype = udf_next_aext(inode, &epos, &oeloc, &oelen, 0)) != -1) { @@ -1851,7 +1851,7 @@ udf_insert_aext(struct inode *inode, struct extent_position epos, nelen = (etype << 30) | oelen; } udf_add_aext(inode, &epos, neloc, nelen, 1); - udf_release_data(epos.bh); + brelse(epos.bh); return (nelen >> 30); } @@ -1865,8 +1865,8 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos, if (epos.bh) { - atomic_inc(&epos.bh->b_count); - atomic_inc(&epos.bh->b_count); + get_bh(epos.bh); + get_bh(epos.bh); } if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) @@ -1886,8 +1886,8 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos, if (oepos.bh != epos.bh) { oepos.block = epos.block; - udf_release_data(oepos.bh); - atomic_inc(&epos.bh->b_count); + brelse(oepos.bh); + get_bh(epos.bh); oepos.bh = epos.bh; oepos.offset = epos.offset - adsize; } @@ -1938,8 +1938,8 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos, } } - udf_release_data(epos.bh); - udf_release_data(oepos.bh); + brelse(epos.bh); + brelse(oepos.bh); return (elen >> 30); } @@ -1992,7 +1992,7 @@ long udf_block_map(struct inode *inode, sector_t block) ret = 0; unlock_kernel(); - udf_release_data(epos.bh); + brelse(epos.bh); if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_VARCONV)) return udf_fixed_to_variable(ret); -- cgit v1.2.1 From 31170b6ad4ebe6c43c1cc3b8112274cf59474de0 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 8 May 2007 00:35:21 -0700 Subject: udf: support files larger than 1G Make UDF work correctly for files larger than 1GB. As no extent can be longer than (1<<30)-blocksize bytes, we have to create several extents if a big hole is being created. As a side-effect, we now don't discard preallocated blocks when creating a hole. Signed-off-by: Jan Kara Acked-by: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/udf/inode.c | 192 ++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 157 insertions(+), 35 deletions(-) (limited to 'fs/udf/inode.c') diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 2171bcfeec20..c8461551e108 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -356,9 +356,106 @@ udf_getblk(struct inode *inode, long block, int create, int *err) return NULL; } +/* Extend the file by 'blocks' blocks, return the number of extents added */ +int udf_extend_file(struct inode *inode, struct extent_position *last_pos, + kernel_long_ad *last_ext, sector_t blocks) +{ + sector_t add; + int count = 0, fake = !(last_ext->extLength & UDF_EXTENT_LENGTH_MASK); + struct super_block *sb = inode->i_sb; + kernel_lb_addr prealloc_loc = {0, 0}; + int prealloc_len = 0; + + /* The previous extent is fake and we should not extend by anything + * - there's nothing to do... */ + if (!blocks && fake) + return 0; + /* Round the last extent up to a multiple of block size */ + if (last_ext->extLength & (sb->s_blocksize - 1)) { + last_ext->extLength = + (last_ext->extLength & UDF_EXTENT_FLAG_MASK) | + (((last_ext->extLength & UDF_EXTENT_LENGTH_MASK) + + sb->s_blocksize - 1) & ~(sb->s_blocksize - 1)); + UDF_I_LENEXTENTS(inode) = + (UDF_I_LENEXTENTS(inode) + sb->s_blocksize - 1) & + ~(sb->s_blocksize - 1); + } + /* Last extent are just preallocated blocks? */ + if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) == EXT_NOT_RECORDED_ALLOCATED) { + /* Save the extent so that we can reattach it to the end */ + prealloc_loc = last_ext->extLocation; + prealloc_len = last_ext->extLength; + /* Mark the extent as a hole */ + last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | + (last_ext->extLength & UDF_EXTENT_LENGTH_MASK); + last_ext->extLocation.logicalBlockNum = 0; + last_ext->extLocation.partitionReferenceNum = 0; + } + /* Can we merge with the previous extent? */ + if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) == EXT_NOT_RECORDED_NOT_ALLOCATED) { + add = ((1<<30) - sb->s_blocksize - (last_ext->extLength & + UDF_EXTENT_LENGTH_MASK)) >> sb->s_blocksize_bits; + if (add > blocks) + add = blocks; + blocks -= add; + last_ext->extLength += add << sb->s_blocksize_bits; + } + + if (fake) { + udf_add_aext(inode, last_pos, last_ext->extLocation, + last_ext->extLength, 1); + count++; + } + else + udf_write_aext(inode, last_pos, last_ext->extLocation, last_ext->extLength, 1); + /* Managed to do everything necessary? */ + if (!blocks) + goto out; + + /* All further extents will be NOT_RECORDED_NOT_ALLOCATED */ + last_ext->extLocation.logicalBlockNum = 0; + last_ext->extLocation.partitionReferenceNum = 0; + add = (1 << (30-sb->s_blocksize_bits)) - 1; + last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | (add << sb->s_blocksize_bits); + /* Create enough extents to cover the whole hole */ + while (blocks > add) { + blocks -= add; + if (udf_add_aext(inode, last_pos, last_ext->extLocation, + last_ext->extLength, 1) == -1) + return -1; + count++; + } + if (blocks) { + last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | + (blocks << sb->s_blocksize_bits); + if (udf_add_aext(inode, last_pos, last_ext->extLocation, + last_ext->extLength, 1) == -1) + return -1; + count++; + } +out: + /* Do we have some preallocated blocks saved? */ + if (prealloc_len) { + if (udf_add_aext(inode, last_pos, prealloc_loc, prealloc_len, 1) == -1) + return -1; + last_ext->extLocation = prealloc_loc; + last_ext->extLength = prealloc_len; + count++; + } + /* last_pos should point to the last written extent... */ + if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) + last_pos->offset -= sizeof(short_ad); + else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG) + last_pos->offset -= sizeof(long_ad); + else + return -1; + return count; +} + static struct buffer_head * inode_getblk(struct inode * inode, sector_t block, int *err, long *phys, int *new) { + static sector_t last_block; struct buffer_head *result = NULL; kernel_long_ad laarr[EXTENT_MERGE_SIZE]; struct extent_position prev_epos, cur_epos, next_epos; @@ -371,7 +468,7 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block, sector_t offset = 0; int8_t etype; int goal = 0, pgoal = UDF_I_LOCATION(inode).logicalBlockNum; - char lastblock = 0; + int lastblock = 0; prev_epos.offset = udf_file_entry_alloc_offset(inode); prev_epos.block = UDF_I_LOCATION(inode); @@ -423,6 +520,8 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block, b_off -= lbcount; offset = b_off >> inode->i_sb->s_blocksize_bits; + /* Move into indirect extent if we are at a pointer to it */ + udf_next_aext(inode, &prev_epos, &eloc, &elen, 0); /* if the extent is allocated and recorded, return the block if the extent is not a multiple of the blocksize, round up */ @@ -444,43 +543,66 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block, return NULL; } + last_block = block; + /* Are we beyond EOF? */ if (etype == -1) { - endnum = startnum = ((count > 1) ? 1 : count); - if (laarr[c].extLength & (inode->i_sb->s_blocksize - 1)) - { - laarr[c].extLength = - (laarr[c].extLength & UDF_EXTENT_FLAG_MASK) | - (((laarr[c].extLength & UDF_EXTENT_LENGTH_MASK) + - inode->i_sb->s_blocksize - 1) & - ~(inode->i_sb->s_blocksize - 1)); - UDF_I_LENEXTENTS(inode) = - (UDF_I_LENEXTENTS(inode) + inode->i_sb->s_blocksize - 1) & - ~(inode->i_sb->s_blocksize - 1); + int ret; + + if (count) { + if (c) + laarr[0] = laarr[1]; + startnum = 1; + } + else { + /* Create a fake extent when there's not one */ + memset(&laarr[0].extLocation, 0x00, sizeof(kernel_lb_addr)); + laarr[0].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED; + /* Will udf_extend_file() create real extent from a fake one? */ + startnum = (offset > 0); + } + /* Create extents for the hole between EOF and offset */ + ret = udf_extend_file(inode, &prev_epos, laarr, offset); + if (ret == -1) { + brelse(prev_epos.bh); + brelse(cur_epos.bh); + brelse(next_epos.bh); + /* We don't really know the error here so we just make + * something up */ + *err = -ENOSPC; + return NULL; } - c = !c; - laarr[c].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | - ((offset + 1) << inode->i_sb->s_blocksize_bits); - memset(&laarr[c].extLocation, 0x00, sizeof(kernel_lb_addr)); - count ++; - endnum ++; + c = 0; + offset = 0; + count += ret; + /* We are not covered by a preallocated extent? */ + if ((laarr[0].extLength & UDF_EXTENT_FLAG_MASK) != EXT_NOT_RECORDED_ALLOCATED) { + /* Is there any real extent? - otherwise we overwrite + * the fake one... */ + if (count) + c = !c; + laarr[c].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | + inode->i_sb->s_blocksize; + memset(&laarr[c].extLocation, 0x00, sizeof(kernel_lb_addr)); + count ++; + endnum ++; + } + endnum = c+1; lastblock = 1; } - else + else { endnum = startnum = ((count > 2) ? 2 : count); - /* if the current extent is in position 0, swap it with the previous */ - if (!c && count != 1) - { - laarr[2] = laarr[0]; - laarr[0] = laarr[1]; - laarr[1] = laarr[2]; - c = 1; - } + /* if the current extent is in position 0, swap it with the previous */ + if (!c && count != 1) + { + laarr[2] = laarr[0]; + laarr[0] = laarr[1]; + laarr[1] = laarr[2]; + c = 1; + } - /* if the current block is located in a extent, read the next extent */ - if (etype != -1) - { + /* if the current block is located in an extent, read the next extent */ if ((etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 0)) != -1) { laarr[c+1].extLength = (etype << 30) | elen; @@ -489,11 +611,10 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block, startnum ++; endnum ++; } - else + else { lastblock = 1; + } } - brelse(cur_epos.bh); - brelse(next_epos.bh); /* if the current extent is not recorded but allocated, get the block in the extent corresponding to the requested block */ @@ -534,8 +655,8 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block, udf_merge_extents(inode, laarr, &endnum); /* write back the new extents, inserting new extents if the new number - of extents is greater than the old number, and deleting extents if - the new number of extents is less than the old number */ + of extents is greater than the old number, and deleting extents if + the new number of extents is less than the old number */ udf_update_extents(inode, laarr, startnum, endnum, &prev_epos); brelse(prev_epos.bh); @@ -991,6 +1112,7 @@ __udf_read_inode(struct inode *inode) return; } udf_fill_inode(inode, bh); + brelse(bh); } -- cgit v1.2.1