diff options
author | Jan Kara <jack@suse.cz> | 2015-12-23 08:21:13 -0500 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2015-12-23 12:04:52 -0500 |
commit | fcea62babc8100aee79c716c81203c6d105b2da0 (patch) | |
tree | 326aded5e99730a5f12b403339b36534f06fc28e /fs/udf | |
parent | b0918d9f476a8434b055e362b83fa4fd1d462c3f (diff) |
udf: Factor out code for creating indirect extent
Factor out code for creating indirect extent from udf_add_aext(). It was
mostly duplicated in two places. Also remove some opencoded versions
of udf_write_aext().
Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/udf')
-rw-r--r-- | fs/udf/balloc.c | 98 | ||||
-rw-r--r-- | fs/udf/inode.c | 217 | ||||
-rw-r--r-- | fs/udf/udfdecl.h | 4 |
3 files changed, 130 insertions, 189 deletions
diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c index 6d6a96b4e73f..e0fd65fe73e8 100644 --- a/fs/udf/balloc.c +++ b/fs/udf/balloc.c | |||
@@ -447,9 +447,6 @@ static void udf_table_free_blocks(struct super_block *sb, | |||
447 | */ | 447 | */ |
448 | 448 | ||
449 | int adsize; | 449 | int adsize; |
450 | struct short_ad *sad = NULL; | ||
451 | struct long_ad *lad = NULL; | ||
452 | struct allocExtDesc *aed; | ||
453 | 450 | ||
454 | eloc.logicalBlockNum = start; | 451 | eloc.logicalBlockNum = start; |
455 | elen = EXT_RECORDED_ALLOCATED | | 452 | elen = EXT_RECORDED_ALLOCATED | |
@@ -466,102 +463,17 @@ static void udf_table_free_blocks(struct super_block *sb, | |||
466 | } | 463 | } |
467 | 464 | ||
468 | if (epos.offset + (2 * adsize) > sb->s_blocksize) { | 465 | if (epos.offset + (2 * adsize) > sb->s_blocksize) { |
469 | unsigned char *sptr, *dptr; | ||
470 | int loffset; | ||
471 | |||
472 | brelse(oepos.bh); | ||
473 | oepos = epos; | ||
474 | |||
475 | /* Steal a block from the extent being free'd */ | 466 | /* Steal a block from the extent being free'd */ |
476 | epos.block.logicalBlockNum = eloc.logicalBlockNum; | 467 | udf_setup_indirect_aext(table, eloc.logicalBlockNum, |
468 | &epos); | ||
469 | |||
477 | eloc.logicalBlockNum++; | 470 | eloc.logicalBlockNum++; |
478 | elen -= sb->s_blocksize; | 471 | elen -= sb->s_blocksize; |
479 | |||
480 | epos.bh = udf_tread(sb, | ||
481 | udf_get_lb_pblock(sb, &epos.block, 0)); | ||
482 | if (!epos.bh) { | ||
483 | brelse(oepos.bh); | ||
484 | goto error_return; | ||
485 | } | ||
486 | aed = (struct allocExtDesc *)(epos.bh->b_data); | ||
487 | aed->previousAllocExtLocation = | ||
488 | cpu_to_le32(oepos.block.logicalBlockNum); | ||
489 | if (epos.offset + adsize > sb->s_blocksize) { | ||
490 | loffset = epos.offset; | ||
491 | aed->lengthAllocDescs = cpu_to_le32(adsize); | ||
492 | sptr = iinfo->i_ext.i_data + epos.offset | ||
493 | - adsize; | ||
494 | dptr = epos.bh->b_data + | ||
495 | sizeof(struct allocExtDesc); | ||
496 | memcpy(dptr, sptr, adsize); | ||
497 | epos.offset = sizeof(struct allocExtDesc) + | ||
498 | adsize; | ||
499 | } else { | ||
500 | loffset = epos.offset + adsize; | ||
501 | aed->lengthAllocDescs = cpu_to_le32(0); | ||
502 | if (oepos.bh) { | ||
503 | sptr = oepos.bh->b_data + epos.offset; | ||
504 | aed = (struct allocExtDesc *) | ||
505 | oepos.bh->b_data; | ||
506 | le32_add_cpu(&aed->lengthAllocDescs, | ||
507 | adsize); | ||
508 | } else { | ||
509 | sptr = iinfo->i_ext.i_data + | ||
510 | epos.offset; | ||
511 | iinfo->i_lenAlloc += adsize; | ||
512 | mark_inode_dirty(table); | ||
513 | } | ||
514 | epos.offset = sizeof(struct allocExtDesc); | ||
515 | } | ||
516 | if (sbi->s_udfrev >= 0x0200) | ||
517 | udf_new_tag(epos.bh->b_data, TAG_IDENT_AED, | ||
518 | 3, 1, epos.block.logicalBlockNum, | ||
519 | sizeof(struct tag)); | ||
520 | else | ||
521 | udf_new_tag(epos.bh->b_data, TAG_IDENT_AED, | ||
522 | 2, 1, epos.block.logicalBlockNum, | ||
523 | sizeof(struct tag)); | ||
524 | |||
525 | switch (iinfo->i_alloc_type) { | ||
526 | case ICBTAG_FLAG_AD_SHORT: | ||
527 | sad = (struct short_ad *)sptr; | ||
528 | sad->extLength = cpu_to_le32( | ||
529 | EXT_NEXT_EXTENT_ALLOCDECS | | ||
530 | sb->s_blocksize); | ||
531 | sad->extPosition = | ||
532 | cpu_to_le32(epos.block.logicalBlockNum); | ||
533 | break; | ||
534 | case ICBTAG_FLAG_AD_LONG: | ||
535 | lad = (struct long_ad *)sptr; | ||
536 | lad->extLength = cpu_to_le32( | ||
537 | EXT_NEXT_EXTENT_ALLOCDECS | | ||
538 | sb->s_blocksize); | ||
539 | lad->extLocation = | ||
540 | cpu_to_lelb(epos.block); | ||
541 | break; | ||
542 | } | ||
543 | if (oepos.bh) { | ||
544 | udf_update_tag(oepos.bh->b_data, loffset); | ||
545 | mark_buffer_dirty(oepos.bh); | ||
546 | } else { | ||
547 | mark_inode_dirty(table); | ||
548 | } | ||
549 | } | 472 | } |
550 | 473 | ||
551 | /* It's possible that stealing the block emptied the extent */ | 474 | /* It's possible that stealing the block emptied the extent */ |
552 | if (elen) { | 475 | if (elen) |
553 | udf_write_aext(table, &epos, &eloc, elen, 1); | 476 | __udf_add_aext(table, &epos, &eloc, elen, 1); |
554 | |||
555 | if (!epos.bh) { | ||
556 | iinfo->i_lenAlloc += adsize; | ||
557 | mark_inode_dirty(table); | ||
558 | } else { | ||
559 | aed = (struct allocExtDesc *)epos.bh->b_data; | ||
560 | le32_add_cpu(&aed->lengthAllocDescs, adsize); | ||
561 | udf_update_tag(epos.bh->b_data, epos.offset); | ||
562 | mark_buffer_dirty(epos.bh); | ||
563 | } | ||
564 | } | ||
565 | } | 477 | } |
566 | 478 | ||
567 | brelse(epos.bh); | 479 | brelse(epos.bh); |
diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 566df9b5a6cb..34c2d2b79594 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c | |||
@@ -1866,112 +1866,102 @@ struct inode *__udf_iget(struct super_block *sb, struct kernel_lb_addr *ino, | |||
1866 | return inode; | 1866 | return inode; |
1867 | } | 1867 | } |
1868 | 1868 | ||
1869 | int udf_add_aext(struct inode *inode, struct extent_position *epos, | 1869 | int udf_setup_indirect_aext(struct inode *inode, int block, |
1870 | struct kernel_lb_addr *eloc, uint32_t elen, int inc) | 1870 | struct extent_position *epos) |
1871 | { | 1871 | { |
1872 | int adsize; | 1872 | struct super_block *sb = inode->i_sb; |
1873 | struct short_ad *sad = NULL; | 1873 | struct buffer_head *bh; |
1874 | struct long_ad *lad = NULL; | ||
1875 | struct allocExtDesc *aed; | 1874 | struct allocExtDesc *aed; |
1876 | uint8_t *ptr; | 1875 | struct extent_position nepos; |
1877 | struct udf_inode_info *iinfo = UDF_I(inode); | 1876 | struct kernel_lb_addr neloc; |
1877 | int ver, adsize; | ||
1878 | 1878 | ||
1879 | if (!epos->bh) | 1879 | if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_SHORT) |
1880 | ptr = iinfo->i_ext.i_data + epos->offset - | 1880 | adsize = sizeof(struct short_ad); |
1881 | udf_file_entry_alloc_offset(inode) + | 1881 | else if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_LONG) |
1882 | iinfo->i_lenEAttr; | 1882 | adsize = sizeof(struct long_ad); |
1883 | |||
1884 | neloc.logicalBlockNum = block; | ||
1885 | neloc.partitionReferenceNum = epos->block.partitionReferenceNum; | ||
1886 | |||
1887 | bh = udf_tgetblk(sb, udf_get_lb_pblock(sb, &neloc, 0)); | ||
1888 | if (!bh) | ||
1889 | return -EIO; | ||
1890 | lock_buffer(bh); | ||
1891 | memset(bh->b_data, 0x00, sb->s_blocksize); | ||
1892 | set_buffer_uptodate(bh); | ||
1893 | unlock_buffer(bh); | ||
1894 | mark_buffer_dirty_inode(bh, inode); | ||
1895 | |||
1896 | aed = (struct allocExtDesc *)(bh->b_data); | ||
1897 | if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT)) { | ||
1898 | aed->previousAllocExtLocation = | ||
1899 | cpu_to_le32(epos->block.logicalBlockNum); | ||
1900 | } | ||
1901 | aed->lengthAllocDescs = cpu_to_le32(0); | ||
1902 | if (UDF_SB(sb)->s_udfrev >= 0x0200) | ||
1903 | ver = 3; | ||
1883 | else | 1904 | else |
1884 | ptr = epos->bh->b_data + epos->offset; | 1905 | ver = 2; |
1906 | udf_new_tag(bh->b_data, TAG_IDENT_AED, ver, 1, block, | ||
1907 | sizeof(struct tag)); | ||
1908 | |||
1909 | nepos.block = neloc; | ||
1910 | nepos.offset = sizeof(struct allocExtDesc); | ||
1911 | nepos.bh = bh; | ||
1912 | |||
1913 | /* | ||
1914 | * Do we have to copy current last extent to make space for indirect | ||
1915 | * one? | ||
1916 | */ | ||
1917 | if (epos->offset + adsize > sb->s_blocksize) { | ||
1918 | struct kernel_lb_addr cp_loc; | ||
1919 | uint32_t cp_len; | ||
1920 | int cp_type; | ||
1921 | |||
1922 | epos->offset -= adsize; | ||
1923 | cp_type = udf_current_aext(inode, epos, &cp_loc, &cp_len, 0); | ||
1924 | cp_len |= ((uint32_t)cp_type) << 30; | ||
1925 | |||
1926 | __udf_add_aext(inode, &nepos, &cp_loc, cp_len, 1); | ||
1927 | udf_write_aext(inode, epos, &nepos.block, | ||
1928 | sb->s_blocksize | EXT_NEXT_EXTENT_ALLOCDECS, 0); | ||
1929 | } else { | ||
1930 | __udf_add_aext(inode, epos, &nepos.block, | ||
1931 | sb->s_blocksize | EXT_NEXT_EXTENT_ALLOCDECS, 0); | ||
1932 | } | ||
1933 | |||
1934 | brelse(epos->bh); | ||
1935 | *epos = nepos; | ||
1936 | |||
1937 | return 0; | ||
1938 | } | ||
1939 | |||
1940 | /* | ||
1941 | * Append extent at the given position - should be the first free one in inode | ||
1942 | * / indirect extent. This function assumes there is enough space in the inode | ||
1943 | * or indirect extent. Use udf_add_aext() if you didn't check for this before. | ||
1944 | */ | ||
1945 | int __udf_add_aext(struct inode *inode, struct extent_position *epos, | ||
1946 | struct kernel_lb_addr *eloc, uint32_t elen, int inc) | ||
1947 | { | ||
1948 | struct udf_inode_info *iinfo = UDF_I(inode); | ||
1949 | struct allocExtDesc *aed; | ||
1950 | int adsize; | ||
1885 | 1951 | ||
1886 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) | 1952 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) |
1887 | adsize = sizeof(struct short_ad); | 1953 | adsize = sizeof(struct short_ad); |
1888 | else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG) | 1954 | else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG) |
1889 | adsize = sizeof(struct long_ad); | 1955 | adsize = sizeof(struct long_ad); |
1890 | else | ||
1891 | return -EIO; | ||
1892 | |||
1893 | if (epos->offset + (2 * adsize) > inode->i_sb->s_blocksize) { | ||
1894 | unsigned char *sptr, *dptr; | ||
1895 | struct buffer_head *nbh; | ||
1896 | int err, loffset; | ||
1897 | struct kernel_lb_addr obloc = epos->block; | ||
1898 | 1956 | ||
1899 | epos->block.logicalBlockNum = udf_new_block(inode->i_sb, NULL, | 1957 | if (!epos->bh) { |
1900 | obloc.partitionReferenceNum, | 1958 | WARN_ON(iinfo->i_lenAlloc != |
1901 | obloc.logicalBlockNum, &err); | 1959 | epos->offset - udf_file_entry_alloc_offset(inode)); |
1902 | if (!epos->block.logicalBlockNum) | 1960 | } else { |
1903 | return -ENOSPC; | 1961 | aed = (struct allocExtDesc *)epos->bh->b_data; |
1904 | nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb, | 1962 | WARN_ON(le32_to_cpu(aed->lengthAllocDescs) != |
1905 | &epos->block, | 1963 | epos->offset - sizeof(struct allocExtDesc)); |
1906 | 0)); | 1964 | WARN_ON(epos->offset + adsize > inode->i_sb->s_blocksize); |
1907 | if (!nbh) | ||
1908 | return -EIO; | ||
1909 | lock_buffer(nbh); | ||
1910 | memset(nbh->b_data, 0x00, inode->i_sb->s_blocksize); | ||
1911 | set_buffer_uptodate(nbh); | ||
1912 | unlock_buffer(nbh); | ||
1913 | mark_buffer_dirty_inode(nbh, inode); | ||
1914 | |||
1915 | aed = (struct allocExtDesc *)(nbh->b_data); | ||
1916 | if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT)) | ||
1917 | aed->previousAllocExtLocation = | ||
1918 | cpu_to_le32(obloc.logicalBlockNum); | ||
1919 | if (epos->offset + adsize > inode->i_sb->s_blocksize) { | ||
1920 | loffset = epos->offset; | ||
1921 | aed->lengthAllocDescs = cpu_to_le32(adsize); | ||
1922 | sptr = ptr - adsize; | ||
1923 | dptr = nbh->b_data + sizeof(struct allocExtDesc); | ||
1924 | memcpy(dptr, sptr, adsize); | ||
1925 | epos->offset = sizeof(struct allocExtDesc) + adsize; | ||
1926 | } else { | ||
1927 | loffset = epos->offset + adsize; | ||
1928 | aed->lengthAllocDescs = cpu_to_le32(0); | ||
1929 | sptr = ptr; | ||
1930 | epos->offset = sizeof(struct allocExtDesc); | ||
1931 | |||
1932 | if (epos->bh) { | ||
1933 | aed = (struct allocExtDesc *)epos->bh->b_data; | ||
1934 | le32_add_cpu(&aed->lengthAllocDescs, adsize); | ||
1935 | } else { | ||
1936 | iinfo->i_lenAlloc += adsize; | ||
1937 | mark_inode_dirty(inode); | ||
1938 | } | ||
1939 | } | ||
1940 | if (UDF_SB(inode->i_sb)->s_udfrev >= 0x0200) | ||
1941 | udf_new_tag(nbh->b_data, TAG_IDENT_AED, 3, 1, | ||
1942 | epos->block.logicalBlockNum, sizeof(struct tag)); | ||
1943 | else | ||
1944 | udf_new_tag(nbh->b_data, TAG_IDENT_AED, 2, 1, | ||
1945 | epos->block.logicalBlockNum, sizeof(struct tag)); | ||
1946 | switch (iinfo->i_alloc_type) { | ||
1947 | case ICBTAG_FLAG_AD_SHORT: | ||
1948 | sad = (struct short_ad *)sptr; | ||
1949 | sad->extLength = cpu_to_le32(EXT_NEXT_EXTENT_ALLOCDECS | | ||
1950 | inode->i_sb->s_blocksize); | ||
1951 | sad->extPosition = | ||
1952 | cpu_to_le32(epos->block.logicalBlockNum); | ||
1953 | break; | ||
1954 | case ICBTAG_FLAG_AD_LONG: | ||
1955 | lad = (struct long_ad *)sptr; | ||
1956 | lad->extLength = cpu_to_le32(EXT_NEXT_EXTENT_ALLOCDECS | | ||
1957 | inode->i_sb->s_blocksize); | ||
1958 | lad->extLocation = cpu_to_lelb(epos->block); | ||
1959 | memset(lad->impUse, 0x00, sizeof(lad->impUse)); | ||
1960 | break; | ||
1961 | } | ||
1962 | if (epos->bh) { | ||
1963 | if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || | ||
1964 | UDF_SB(inode->i_sb)->s_udfrev >= 0x0201) | ||
1965 | udf_update_tag(epos->bh->b_data, loffset); | ||
1966 | else | ||
1967 | udf_update_tag(epos->bh->b_data, | ||
1968 | sizeof(struct allocExtDesc)); | ||
1969 | mark_buffer_dirty_inode(epos->bh, inode); | ||
1970 | brelse(epos->bh); | ||
1971 | } else { | ||
1972 | mark_inode_dirty(inode); | ||
1973 | } | ||
1974 | epos->bh = nbh; | ||
1975 | } | 1965 | } |
1976 | 1966 | ||
1977 | udf_write_aext(inode, epos, eloc, elen, inc); | 1967 | udf_write_aext(inode, epos, eloc, elen, inc); |
@@ -1995,6 +1985,41 @@ int udf_add_aext(struct inode *inode, struct extent_position *epos, | |||
1995 | return 0; | 1985 | return 0; |
1996 | } | 1986 | } |
1997 | 1987 | ||
1988 | /* | ||
1989 | * Append extent at given position - should be the first free one in inode | ||
1990 | * / indirect extent. Takes care of allocating and linking indirect blocks. | ||
1991 | */ | ||
1992 | int udf_add_aext(struct inode *inode, struct extent_position *epos, | ||
1993 | struct kernel_lb_addr *eloc, uint32_t elen, int inc) | ||
1994 | { | ||
1995 | int adsize; | ||
1996 | struct super_block *sb = inode->i_sb; | ||
1997 | |||
1998 | if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_SHORT) | ||
1999 | adsize = sizeof(struct short_ad); | ||
2000 | else if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_LONG) | ||
2001 | adsize = sizeof(struct long_ad); | ||
2002 | else | ||
2003 | return -EIO; | ||
2004 | |||
2005 | if (epos->offset + (2 * adsize) > sb->s_blocksize) { | ||
2006 | int err; | ||
2007 | int new_block; | ||
2008 | |||
2009 | new_block = udf_new_block(sb, NULL, | ||
2010 | epos->block.partitionReferenceNum, | ||
2011 | epos->block.logicalBlockNum, &err); | ||
2012 | if (!new_block) | ||
2013 | return -ENOSPC; | ||
2014 | |||
2015 | err = udf_setup_indirect_aext(inode, new_block, epos); | ||
2016 | if (err) | ||
2017 | return err; | ||
2018 | } | ||
2019 | |||
2020 | return __udf_add_aext(inode, epos, eloc, elen, inc); | ||
2021 | } | ||
2022 | |||
1998 | void udf_write_aext(struct inode *inode, struct extent_position *epos, | 2023 | void udf_write_aext(struct inode *inode, struct extent_position *epos, |
1999 | struct kernel_lb_addr *eloc, uint32_t elen, int inc) | 2024 | struct kernel_lb_addr *eloc, uint32_t elen, int inc) |
2000 | { | 2025 | { |
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 47bb3f5ca360..269ad3fb2fab 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h | |||
@@ -159,6 +159,10 @@ extern int udf_write_inode(struct inode *, struct writeback_control *wbc); | |||
159 | extern long udf_block_map(struct inode *, sector_t); | 159 | extern long udf_block_map(struct inode *, sector_t); |
160 | extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *, | 160 | extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *, |
161 | struct kernel_lb_addr *, uint32_t *, sector_t *); | 161 | struct kernel_lb_addr *, uint32_t *, sector_t *); |
162 | extern int udf_setup_indirect_aext(struct inode *inode, int block, | ||
163 | struct extent_position *epos); | ||
164 | extern int __udf_add_aext(struct inode *inode, struct extent_position *epos, | ||
165 | struct kernel_lb_addr *eloc, uint32_t elen, int inc); | ||
162 | extern int udf_add_aext(struct inode *, struct extent_position *, | 166 | extern int udf_add_aext(struct inode *, struct extent_position *, |
163 | struct kernel_lb_addr *, uint32_t, int); | 167 | struct kernel_lb_addr *, uint32_t, int); |
164 | extern void udf_write_aext(struct inode *, struct extent_position *, | 168 | extern void udf_write_aext(struct inode *, struct extent_position *, |