]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/udf/inode.c
Merge branch 'drm-patches' of ssh://master.kernel.org/pub/scm/linux/kernel/git/airlie...
[linux-2.6-omap-h63xx.git] / fs / udf / inode.c
index 605f5111b6d86a100430897877f170c2b59248e7..5b82e489af7851f476ad2ecf381c6466b77edf48 100644 (file)
@@ -49,10 +49,11 @@ 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 int udf_alloc_i_data(struct inode *inode, size_t size);
+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 +62,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);
 
 /*
@@ -100,14 +101,23 @@ no_delete:
        clear_inode(inode);
 }
 
+/*
+ * If we are going to release inode from memory, we discard preallocation and
+ * truncate last inode extent to proper length. We could use drop_inode() but
+ * it's called under inode_lock and thus we cannot mark inode dirty there.  We
+ * use clear_inode() but we have to make sure to write inode as it's not written
+ * automatically.
+ */
 void udf_clear_inode(struct inode *inode)
 {
        if (!(inode->i_sb->s_flags & MS_RDONLY)) {
                lock_kernel();
+               /* Discard preallocation for directories, symlinks, etc. */
                udf_discard_prealloc(inode);
+               udf_truncate_tail_extent(inode);
                unlock_kernel();
+               write_inode_now(inode, 1);
        }
-
        kfree(UDF_I_DATA(inode));
        UDF_I_DATA(inode) = NULL;
 }
@@ -194,10 +204,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,16 +248,16 @@ 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);
+                       brelse(dbh);
                        return NULL;
                }
                UDF_I_ALLOCTYPE(inode) = alloctype;
@@ -258,7 +269,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;
                }
        }
@@ -266,16 +277,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);
+       brelse(epos.bh);
        mark_inode_dirty(inode);
        return dbh;
 }
@@ -354,53 +366,153 @@ udf_getblk(struct inode *inode, long block, int create, int *err)
        return NULL;
 }
 
-static struct buffer_head * inode_getblk(struct inode * inode, long block,
+/* 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)
 {
-       struct buffer_head *pbh = NULL, *cbh = NULL, *nbh = NULL, *result = NULL;
+       static sector_t last_block;
+       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;
+       uint32_t elen = 0, tmpelen;
+       kernel_lb_addr eloc, tmpeloc;
        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;
+       int lastblock = 0;
 
-       pextoffset = cextoffset = nextoffset = udf_file_entry_alloc_offset(inode);
-       b_off = (uint64_t)block << inode->i_sb->s_blocksize_bits;
-       pbloc = cbloc = nbloc = UDF_I_LOCATION(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;
 
        /* 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;
+                       brelse(prev_epos.bh);
+                       get_bh(cur_epos.bh);
+                       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;
+                       brelse(cur_epos.bh);
+                       get_bh(next_epos.bh);
+                       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;
@@ -418,6 +530,12 @@ static struct buffer_head * inode_getblk(struct inode * inode, long block,
 
        b_off -= lbcount;
        offset = b_off >> inode->i_sb->s_blocksize_bits;
+       /*
+        * Move prev_epos and cur_epos into indirect extent if we are at
+        * the pointer to it
+        */
+       udf_next_aext(inode, &prev_epos, &tmpeloc, &tmpelen, 0);
+       udf_next_aext(inode, &cur_epos, &tmpeloc, &tmpelen, 0);
 
        /* if the extent is allocated and recorded, return the block
        if the extent is not a multiple of the blocksize, round up */
@@ -429,54 +547,77 @@ static struct buffer_head * inode_getblk(struct inode * inode, long 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);
+               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;
        }
 
+       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 ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 0)) != -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;
                        laarr[c+1].extLocation = eloc;
@@ -484,11 +625,10 @@ static struct buffer_head * inode_getblk(struct inode * inode, long block,
                        startnum ++;
                        endnum ++;
                }
-               else
+               else {
                        lastblock = 1;
+               }
        }
-       udf_release_data(cbh);
-       udf_release_data(nbh);
 
        /* if the current extent is not recorded but allocated, get the
                block in the extent corresponding to the requested block */
@@ -508,7 +648,7 @@ static struct buffer_head * inode_getblk(struct inode * inode, long block,
                if (!(newblocknum = udf_new_block(inode->i_sb, inode,
                        UDF_I_LOCATION(inode).partitionReferenceNum, goal, err)))
                {
-                       udf_release_data(pbh);
+                       brelse(prev_epos.bh);
                        *err = -ENOSPC;
                        return NULL;
                }
@@ -529,11 +669,11 @@ static struct buffer_head * inode_getblk(struct inode * inode, long 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 */
-       udf_update_extents(inode, laarr, startnum, endnum, pbloc, pextoffset, &pbh);
+       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);
 
-       udf_release_data(pbh);
+       brelse(prev_epos.bh);
 
        if (!(newblock = udf_get_pblock(inode->i_sb, newblocknum,
                UDF_I_LOCATION(inode).partitionReferenceNum, 0)))
@@ -595,7 +735,7 @@ static void udf_split_extents(struct inode *inode, int *c, int offset, int newbl
                        (*c) ++;
                        (*endnum) ++;
                }
-               
+
                laarr[curr].extLocation.logicalBlockNum = newblocknum;
                if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
                        laarr[curr].extLocation.partitionReferenceNum =
@@ -697,7 +837,7 @@ static void udf_prealloc_extents(struct inode *inode, int c, int lastblock,
                                {
                                        numalloc -= elen;
                                        if (*endnum > (i+1))
-                                               memmove(&laarr[i], &laarr[i+1], 
+                                               memmove(&laarr[i], &laarr[i+1],
                                                        sizeof(long_ad) * (*endnum - (i+1)));
                                        i --;
                                        (*endnum) --;
@@ -795,7 +935,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;
@@ -804,28 +944,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; i<endnum; i++)
        {
-               udf_next_aext(inode, &pbloc, &pextoffset, &tmploc, &tmplen, pbh, 0);
-               udf_write_aext(inode, pbloc, &pextoffset, laarr[i].extLocation,
-                       laarr[i].extLength, *pbh, 1);
+               udf_next_aext(inode, epos, &tmploc, &tmplen, 0);
+               udf_write_aext(inode, epos, laarr[i].extLocation,
+                       laarr[i].extLength, 1);
        }
 }
 
@@ -887,7 +1025,7 @@ void udf_truncate(struct inode * inode)
        {
                block_truncate_page(inode->i_mapping, inode->i_size, udf_get_block);
                udf_truncate_extents(inode);
-       }       
+       }
 
        inode->i_mtime = inode->i_ctime = current_fs_time(inode->i_sb);
        if (IS_SYNC(inode))
@@ -916,8 +1054,6 @@ __udf_read_inode(struct inode *inode)
         *      i_nlink = 1
         *      i_op = NULL;
         */
-       inode->i_blksize = PAGE_SIZE;
-
        bh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 0, &ident);
 
        if (!bh)
@@ -933,7 +1069,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;
        }
@@ -952,45 +1088,46 @@ __udf_read_inode(struct inode *inode)
                        {
                                kernel_lb_addr loc;
                                ie = (struct indirectEntry *)ibh->b_data;
-       
+
                                loc = lelb_to_cpu(ie->indirectICB.extLocation);
-       
-                               if (ie->indirectICB.extLength && 
+
+                               if (ie->indirectICB.extLength &&
                                        (nbh = udf_read_ptagged(inode->i_sb, loc, 0, &ident)))
                                {
                                        if (ident == TAG_IDENT_FE ||
                                                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)
@@ -1020,14 +1157,22 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
        {
                UDF_I_EFE(inode) = 1;
                UDF_I_USE(inode) = 0;
-               UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry), GFP_KERNEL);
+               if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry)))
+               {
+                       make_bad_inode(inode);
+                       return;
+               }
                memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct extendedFileEntry), inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry));
        }
        else if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_FE)
        {
                UDF_I_EFE(inode) = 0;
                UDF_I_USE(inode) = 0;
-               UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct fileEntry), GFP_KERNEL);
+               if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize - sizeof(struct fileEntry)))
+               {
+                       make_bad_inode(inode);
+                       return;
+               }
                memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct fileEntry), inode->i_sb->s_blocksize - sizeof(struct fileEntry));
        }
        else if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_USE)
@@ -1037,7 +1182,11 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
                UDF_I_LENALLOC(inode) =
                        le32_to_cpu(
                                ((struct unallocSpaceEntry *)bh->b_data)->lengthAllocDescs);
-               UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry), GFP_KERNEL);
+               if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry)))
+               {
+                       make_bad_inode(inode);
+                       return;
+               }
                memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct unallocSpaceEntry), inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry));
                return;
        }
@@ -1055,7 +1204,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
        inode->i_nlink = le16_to_cpu(fe->fileLinkCount);
        if (!inode->i_nlink)
                inode->i_nlink = 1;
-       
+
        inode->i_size = le64_to_cpu(fe->informationLength);
        UDF_I_LENEXTENTS(inode) = inode->i_size;
 
@@ -1107,7 +1256,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
        }
        else
        {
-               inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) << 
+               inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) <<
                        (inode->i_sb->s_blocksize_bits - 9);
 
                if ( udf_stamp_to_time(&convtime, &convtime_usec,
@@ -1167,7 +1316,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
                        inode->i_op = &udf_dir_inode_operations;
                        inode->i_fop = &udf_dir_operations;
                        inode->i_mode |= S_IFDIR;
-                       inode->i_nlink ++;
+                       inc_nlink(inode);
                        break;
                }
                case ICBTAG_FILE_TYPE_REALTIME:
@@ -1238,6 +1387,20 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
        }
 }
 
+static int udf_alloc_i_data(struct inode *inode, size_t size)
+{
+       UDF_I_DATA(inode) = kmalloc(size, GFP_KERNEL);
+
+       if (!UDF_I_DATA(inode))
+       {
+               printk(KERN_ERR "udf:udf_alloc_i_data (ino %ld) no free memory\n",
+                      inode->i_ino);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
 static mode_t
 udf_convert_permissions(struct fileEntry *fe)
 {
@@ -1333,7 +1496,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;
        }
 
@@ -1522,7 +1685,7 @@ udf_update_inode(struct inode *inode, int do_sync)
                        err = -EIO;
                }
        }
-       udf_release_data(bh);
+       brelse(bh);
        return err;
 }
 
@@ -1558,8 +1721,8 @@ udf_iget(struct super_block *sb, kernel_lb_addr ino)
        return NULL;
 }
 
-int8_t udf_add_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_add_aext(struct inode *inode, struct extent_position *epos,
+       kernel_lb_addr eloc, uint32_t elen, int inc)
 {
        int adsize;
        short_ad *sad = NULL;
@@ -1568,10 +1731,10 @@ int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,
        int8_t etype;
        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;
+               ptr = epos->bh->b_data + epos->offset;
 
        if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
                adsize = sizeof(short_ad);
@@ -1580,20 +1743,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;
                }
@@ -1606,25 +1769,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);
                        }
@@ -1636,10 +1799,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:
@@ -1648,7 +1811,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:
@@ -1657,60 +1820,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);
+                       brelse(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))
        {
@@ -1735,40 +1895,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);
+               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",
-                               udf_get_lb_pblock(inode->i_sb, *bloc, 0));
+                               udf_get_lb_pblock(inode->i_sb, epos->block, 0));
                        return -1;
                }
        }
@@ -1776,26 +1935,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))
@@ -1804,7 +1963,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;
@@ -1817,7 +1976,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;
@@ -1836,41 +1995,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)
+               get_bh(epos.bh);
 
-       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);
+       brelse(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);
+               get_bh(epos.bh);
+               get_bh(epos.bh);
        }
 
        if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
@@ -1880,80 +2038,77 @@ 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;
+                       brelse(oepos.bh);
+                       get_bh(epos.bh);
+                       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);
+
+       brelse(epos.bh);
+       brelse(oepos.bh);
        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, struct extent_position *pos,
+       kernel_lb_addr *eloc, uint32_t *elen, sector_t *offset)
 {
-       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)
@@ -1962,42 +2117,44 @@ int8_t inode_bmap(struct inode *inode, int block, kernel_lb_addr *bloc, uint32_t
                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;
+                       *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;
-       struct buffer_head *bh = NULL;
+       kernel_lb_addr eloc;
+       uint32_t elen;
+       sector_t offset;
+       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))
-               ret = udf_get_lb_pblock(inode->i_sb, eloc, offset >> inode->i_sb->s_blocksize_bits);
+       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);
+       brelse(epos.bh);
 
        if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_VARCONV))
                return udf_fixed_to_variable(ret);