diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-01-15 14:51:51 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-01-15 14:51:51 -0500 |
commit | 1d3671df72e0fe28d7cc686cb432e87c06f4accc (patch) | |
tree | 75bf9bdc327bd12d7ed0ca6ee5d1b0254c4753a4 | |
parent | 875fc4f5ddf35605581f9a5900c14afef48611f2 (diff) | |
parent | bb00c898ad1ce40c4bb422a8207ae562e9aea7ae (diff) |
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
Pull UDF fixes and quota cleanups from Jan Kara:
"Several UDF fixes and some minor quota cleanups"
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
udf: Check output buffer length when converting name to CS0
udf: Prevent buffer overrun with multi-byte characters
quota: constify qtree_fmt_operations structures
udf: avoid uninitialized variable use
udf: Fix lost indirect extent block
udf: Factor out code for creating indirect extent
udf: limit the maximum number of indirect extents in a row
udf: limit the maximum number of TD redirections
fs: make quota/dquot.c explicitly non-modular
fs: make quota/netlink.c explicitly non-modular
-rw-r--r-- | fs/ocfs2/quota.h | 2 | ||||
-rw-r--r-- | fs/ocfs2/quota_global.c | 2 | ||||
-rw-r--r-- | fs/quota/dquot.c | 2 | ||||
-rw-r--r-- | fs/quota/netlink.c | 5 | ||||
-rw-r--r-- | fs/quota/quota_v2.c | 4 | ||||
-rw-r--r-- | fs/udf/balloc.c | 98 | ||||
-rw-r--r-- | fs/udf/inode.c | 243 | ||||
-rw-r--r-- | fs/udf/super.c | 14 | ||||
-rw-r--r-- | fs/udf/udfdecl.h | 4 | ||||
-rw-r--r-- | fs/udf/unicode.c | 21 | ||||
-rw-r--r-- | include/linux/dqblk_qtree.h | 2 |
11 files changed, 196 insertions, 201 deletions
diff --git a/fs/ocfs2/quota.h b/fs/ocfs2/quota.h index b6d51333ad02..d153e6e31529 100644 --- a/fs/ocfs2/quota.h +++ b/fs/ocfs2/quota.h | |||
@@ -82,7 +82,7 @@ struct ocfs2_quota_chunk { | |||
82 | extern struct kmem_cache *ocfs2_dquot_cachep; | 82 | extern struct kmem_cache *ocfs2_dquot_cachep; |
83 | extern struct kmem_cache *ocfs2_qf_chunk_cachep; | 83 | extern struct kmem_cache *ocfs2_qf_chunk_cachep; |
84 | 84 | ||
85 | extern struct qtree_fmt_operations ocfs2_global_ops; | 85 | extern const struct qtree_fmt_operations ocfs2_global_ops; |
86 | 86 | ||
87 | struct ocfs2_quota_recovery *ocfs2_begin_quota_recovery( | 87 | struct ocfs2_quota_recovery *ocfs2_begin_quota_recovery( |
88 | struct ocfs2_super *osb, int slot_num); | 88 | struct ocfs2_super *osb, int slot_num); |
diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c index c93d67220887..fde9ef18cff3 100644 --- a/fs/ocfs2/quota_global.c +++ b/fs/ocfs2/quota_global.c | |||
@@ -123,7 +123,7 @@ static int ocfs2_global_is_id(void *dp, struct dquot *dquot) | |||
123 | dquot->dq_id); | 123 | dquot->dq_id); |
124 | } | 124 | } |
125 | 125 | ||
126 | struct qtree_fmt_operations ocfs2_global_ops = { | 126 | const struct qtree_fmt_operations ocfs2_global_ops = { |
127 | .mem2disk_dqblk = ocfs2_global_mem2diskdqb, | 127 | .mem2disk_dqblk = ocfs2_global_mem2diskdqb, |
128 | .disk2mem_dqblk = ocfs2_global_disk2memdqb, | 128 | .disk2mem_dqblk = ocfs2_global_disk2memdqb, |
129 | .is_id = ocfs2_global_is_id, | 129 | .is_id = ocfs2_global_is_id, |
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index ef0d64b2a6d9..fbd70af98820 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c | |||
@@ -2924,4 +2924,4 @@ static int __init dquot_init(void) | |||
2924 | 2924 | ||
2925 | return 0; | 2925 | return 0; |
2926 | } | 2926 | } |
2927 | module_init(dquot_init); | 2927 | fs_initcall(dquot_init); |
diff --git a/fs/quota/netlink.c b/fs/quota/netlink.c index bb2869f5dfd8..d07a2f91d858 100644 --- a/fs/quota/netlink.c +++ b/fs/quota/netlink.c | |||
@@ -1,7 +1,5 @@ | |||
1 | |||
2 | #include <linux/cred.h> | 1 | #include <linux/cred.h> |
3 | #include <linux/init.h> | 2 | #include <linux/init.h> |
4 | #include <linux/module.h> | ||
5 | #include <linux/kernel.h> | 3 | #include <linux/kernel.h> |
6 | #include <linux/quotaops.h> | 4 | #include <linux/quotaops.h> |
7 | #include <linux/sched.h> | 5 | #include <linux/sched.h> |
@@ -105,5 +103,4 @@ static int __init quota_init(void) | |||
105 | "VFS: Failed to create quota netlink interface.\n"); | 103 | "VFS: Failed to create quota netlink interface.\n"); |
106 | return 0; | 104 | return 0; |
107 | }; | 105 | }; |
108 | 106 | fs_initcall(quota_init); | |
109 | module_init(quota_init); | ||
diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c index 2aa012a68e90..ed85d4f35c04 100644 --- a/fs/quota/quota_v2.c +++ b/fs/quota/quota_v2.c | |||
@@ -30,13 +30,13 @@ static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot); | |||
30 | static void v2r1_disk2memdqb(struct dquot *dquot, void *dp); | 30 | static void v2r1_disk2memdqb(struct dquot *dquot, void *dp); |
31 | static int v2r1_is_id(void *dp, struct dquot *dquot); | 31 | static int v2r1_is_id(void *dp, struct dquot *dquot); |
32 | 32 | ||
33 | static struct qtree_fmt_operations v2r0_qtree_ops = { | 33 | static const struct qtree_fmt_operations v2r0_qtree_ops = { |
34 | .mem2disk_dqblk = v2r0_mem2diskdqb, | 34 | .mem2disk_dqblk = v2r0_mem2diskdqb, |
35 | .disk2mem_dqblk = v2r0_disk2memdqb, | 35 | .disk2mem_dqblk = v2r0_disk2memdqb, |
36 | .is_id = v2r0_is_id, | 36 | .is_id = v2r0_is_id, |
37 | }; | 37 | }; |
38 | 38 | ||
39 | static struct qtree_fmt_operations v2r1_qtree_ops = { | 39 | static const struct qtree_fmt_operations v2r1_qtree_ops = { |
40 | .mem2disk_dqblk = v2r1_mem2diskdqb, | 40 | .mem2disk_dqblk = v2r1_mem2diskdqb, |
41 | .disk2mem_dqblk = v2r1_disk2memdqb, | 41 | .disk2mem_dqblk = v2r1_disk2memdqb, |
42 | .is_id = v2r1_is_id, | 42 | .is_id = v2r1_is_id, |
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 055746350d16..87dc16d15572 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c | |||
@@ -539,9 +539,18 @@ static int udf_do_extend_file(struct inode *inode, | |||
539 | udf_add_aext(inode, last_pos, &last_ext->extLocation, | 539 | udf_add_aext(inode, last_pos, &last_ext->extLocation, |
540 | last_ext->extLength, 1); | 540 | last_ext->extLength, 1); |
541 | count++; | 541 | count++; |
542 | } else | 542 | } else { |
543 | struct kernel_lb_addr tmploc; | ||
544 | uint32_t tmplen; | ||
545 | |||
543 | udf_write_aext(inode, last_pos, &last_ext->extLocation, | 546 | udf_write_aext(inode, last_pos, &last_ext->extLocation, |
544 | last_ext->extLength, 1); | 547 | last_ext->extLength, 1); |
548 | /* | ||
549 | * We've rewritten the last extent but there may be empty | ||
550 | * indirect extent after it - enter it. | ||
551 | */ | ||
552 | udf_next_aext(inode, last_pos, &tmploc, &tmplen, 0); | ||
553 | } | ||
545 | 554 | ||
546 | /* Managed to do everything necessary? */ | 555 | /* Managed to do everything necessary? */ |
547 | if (!blocks) | 556 | if (!blocks) |
@@ -1867,22 +1876,90 @@ struct inode *__udf_iget(struct super_block *sb, struct kernel_lb_addr *ino, | |||
1867 | return inode; | 1876 | return inode; |
1868 | } | 1877 | } |
1869 | 1878 | ||
1870 | int udf_add_aext(struct inode *inode, struct extent_position *epos, | 1879 | int udf_setup_indirect_aext(struct inode *inode, int block, |
1871 | struct kernel_lb_addr *eloc, uint32_t elen, int inc) | 1880 | struct extent_position *epos) |
1872 | { | 1881 | { |
1873 | int adsize; | 1882 | struct super_block *sb = inode->i_sb; |
1874 | struct short_ad *sad = NULL; | 1883 | struct buffer_head *bh; |
1875 | struct long_ad *lad = NULL; | ||
1876 | struct allocExtDesc *aed; | 1884 | struct allocExtDesc *aed; |
1877 | uint8_t *ptr; | 1885 | struct extent_position nepos; |
1878 | struct udf_inode_info *iinfo = UDF_I(inode); | 1886 | struct kernel_lb_addr neloc; |
1887 | int ver, adsize; | ||
1879 | 1888 | ||
1880 | if (!epos->bh) | 1889 | if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_SHORT) |
1881 | ptr = iinfo->i_ext.i_data + epos->offset - | 1890 | adsize = sizeof(struct short_ad); |
1882 | udf_file_entry_alloc_offset(inode) + | 1891 | else if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_LONG) |
1883 | iinfo->i_lenEAttr; | 1892 | adsize = sizeof(struct long_ad); |
1884 | else | 1893 | else |
1885 | ptr = epos->bh->b_data + epos->offset; | 1894 | return -EIO; |
1895 | |||
1896 | neloc.logicalBlockNum = block; | ||
1897 | neloc.partitionReferenceNum = epos->block.partitionReferenceNum; | ||
1898 | |||
1899 | bh = udf_tgetblk(sb, udf_get_lb_pblock(sb, &neloc, 0)); | ||
1900 | if (!bh) | ||
1901 | return -EIO; | ||
1902 | lock_buffer(bh); | ||
1903 | memset(bh->b_data, 0x00, sb->s_blocksize); | ||
1904 | set_buffer_uptodate(bh); | ||
1905 | unlock_buffer(bh); | ||
1906 | mark_buffer_dirty_inode(bh, inode); | ||
1907 | |||
1908 | aed = (struct allocExtDesc *)(bh->b_data); | ||
1909 | if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT)) { | ||
1910 | aed->previousAllocExtLocation = | ||
1911 | cpu_to_le32(epos->block.logicalBlockNum); | ||
1912 | } | ||
1913 | aed->lengthAllocDescs = cpu_to_le32(0); | ||
1914 | if (UDF_SB(sb)->s_udfrev >= 0x0200) | ||
1915 | ver = 3; | ||
1916 | else | ||
1917 | ver = 2; | ||
1918 | udf_new_tag(bh->b_data, TAG_IDENT_AED, ver, 1, block, | ||
1919 | sizeof(struct tag)); | ||
1920 | |||
1921 | nepos.block = neloc; | ||
1922 | nepos.offset = sizeof(struct allocExtDesc); | ||
1923 | nepos.bh = bh; | ||
1924 | |||
1925 | /* | ||
1926 | * Do we have to copy current last extent to make space for indirect | ||
1927 | * one? | ||
1928 | */ | ||
1929 | if (epos->offset + adsize > sb->s_blocksize) { | ||
1930 | struct kernel_lb_addr cp_loc; | ||
1931 | uint32_t cp_len; | ||
1932 | int cp_type; | ||
1933 | |||
1934 | epos->offset -= adsize; | ||
1935 | cp_type = udf_current_aext(inode, epos, &cp_loc, &cp_len, 0); | ||
1936 | cp_len |= ((uint32_t)cp_type) << 30; | ||
1937 | |||
1938 | __udf_add_aext(inode, &nepos, &cp_loc, cp_len, 1); | ||
1939 | udf_write_aext(inode, epos, &nepos.block, | ||
1940 | sb->s_blocksize | EXT_NEXT_EXTENT_ALLOCDECS, 0); | ||
1941 | } else { | ||
1942 | __udf_add_aext(inode, epos, &nepos.block, | ||
1943 | sb->s_blocksize | EXT_NEXT_EXTENT_ALLOCDECS, 0); | ||
1944 | } | ||
1945 | |||
1946 | brelse(epos->bh); | ||
1947 | *epos = nepos; | ||
1948 | |||
1949 | return 0; | ||
1950 | } | ||
1951 | |||
1952 | /* | ||
1953 | * Append extent at the given position - should be the first free one in inode | ||
1954 | * / indirect extent. This function assumes there is enough space in the inode | ||
1955 | * or indirect extent. Use udf_add_aext() if you didn't check for this before. | ||
1956 | */ | ||
1957 | int __udf_add_aext(struct inode *inode, struct extent_position *epos, | ||
1958 | struct kernel_lb_addr *eloc, uint32_t elen, int inc) | ||
1959 | { | ||
1960 | struct udf_inode_info *iinfo = UDF_I(inode); | ||
1961 | struct allocExtDesc *aed; | ||
1962 | int adsize; | ||
1886 | 1963 | ||
1887 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) | 1964 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) |
1888 | adsize = sizeof(struct short_ad); | 1965 | adsize = sizeof(struct short_ad); |
@@ -1891,88 +1968,14 @@ int udf_add_aext(struct inode *inode, struct extent_position *epos, | |||
1891 | else | 1968 | else |
1892 | return -EIO; | 1969 | return -EIO; |
1893 | 1970 | ||
1894 | if (epos->offset + (2 * adsize) > inode->i_sb->s_blocksize) { | 1971 | if (!epos->bh) { |
1895 | unsigned char *sptr, *dptr; | 1972 | WARN_ON(iinfo->i_lenAlloc != |
1896 | struct buffer_head *nbh; | 1973 | epos->offset - udf_file_entry_alloc_offset(inode)); |
1897 | int err, loffset; | 1974 | } else { |
1898 | struct kernel_lb_addr obloc = epos->block; | 1975 | aed = (struct allocExtDesc *)epos->bh->b_data; |
1899 | 1976 | WARN_ON(le32_to_cpu(aed->lengthAllocDescs) != | |
1900 | epos->block.logicalBlockNum = udf_new_block(inode->i_sb, NULL, | 1977 | epos->offset - sizeof(struct allocExtDesc)); |
1901 | obloc.partitionReferenceNum, | 1978 | WARN_ON(epos->offset + adsize > inode->i_sb->s_blocksize); |
1902 | obloc.logicalBlockNum, &err); | ||
1903 | if (!epos->block.logicalBlockNum) | ||
1904 | return -ENOSPC; | ||
1905 | nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb, | ||
1906 | &epos->block, | ||
1907 | 0)); | ||
1908 | if (!nbh) | ||
1909 | return -EIO; | ||
1910 | lock_buffer(nbh); | ||
1911 | memset(nbh->b_data, 0x00, inode->i_sb->s_blocksize); | ||
1912 | set_buffer_uptodate(nbh); | ||
1913 | unlock_buffer(nbh); | ||
1914 | mark_buffer_dirty_inode(nbh, inode); | ||
1915 | |||
1916 | aed = (struct allocExtDesc *)(nbh->b_data); | ||
1917 | if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT)) | ||
1918 | aed->previousAllocExtLocation = | ||
1919 | cpu_to_le32(obloc.logicalBlockNum); | ||
1920 | if (epos->offset + adsize > inode->i_sb->s_blocksize) { | ||
1921 | loffset = epos->offset; | ||
1922 | aed->lengthAllocDescs = cpu_to_le32(adsize); | ||
1923 | sptr = ptr - adsize; | ||
1924 | dptr = nbh->b_data + sizeof(struct allocExtDesc); | ||
1925 | memcpy(dptr, sptr, adsize); | ||
1926 | epos->offset = sizeof(struct allocExtDesc) + adsize; | ||
1927 | } else { | ||
1928 | loffset = epos->offset + adsize; | ||
1929 | aed->lengthAllocDescs = cpu_to_le32(0); | ||
1930 | sptr = ptr; | ||
1931 | epos->offset = sizeof(struct allocExtDesc); | ||
1932 | |||
1933 | if (epos->bh) { | ||
1934 | aed = (struct allocExtDesc *)epos->bh->b_data; | ||
1935 | le32_add_cpu(&aed->lengthAllocDescs, adsize); | ||
1936 | } else { | ||
1937 | iinfo->i_lenAlloc += adsize; | ||
1938 | mark_inode_dirty(inode); | ||
1939 | } | ||
1940 | } | ||
1941 | if (UDF_SB(inode->i_sb)->s_udfrev >= 0x0200) | ||
1942 | udf_new_tag(nbh->b_data, TAG_IDENT_AED, 3, 1, | ||
1943 | epos->block.logicalBlockNum, sizeof(struct tag)); | ||
1944 | else | ||
1945 | udf_new_tag(nbh->b_data, TAG_IDENT_AED, 2, 1, | ||
1946 | epos->block.logicalBlockNum, sizeof(struct tag)); | ||
1947 | switch (iinfo->i_alloc_type) { | ||
1948 | case ICBTAG_FLAG_AD_SHORT: | ||
1949 | sad = (struct short_ad *)sptr; | ||
1950 | sad->extLength = cpu_to_le32(EXT_NEXT_EXTENT_ALLOCDECS | | ||
1951 | inode->i_sb->s_blocksize); | ||
1952 | sad->extPosition = | ||
1953 | cpu_to_le32(epos->block.logicalBlockNum); | ||
1954 | break; | ||
1955 | case ICBTAG_FLAG_AD_LONG: | ||
1956 | lad = (struct long_ad *)sptr; | ||
1957 | lad->extLength = cpu_to_le32(EXT_NEXT_EXTENT_ALLOCDECS | | ||
1958 | inode->i_sb->s_blocksize); | ||
1959 | lad->extLocation = cpu_to_lelb(epos->block); | ||
1960 | memset(lad->impUse, 0x00, sizeof(lad->impUse)); | ||
1961 | break; | ||
1962 | } | ||
1963 | if (epos->bh) { | ||
1964 | if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || | ||
1965 | UDF_SB(inode->i_sb)->s_udfrev >= 0x0201) | ||
1966 | udf_update_tag(epos->bh->b_data, loffset); | ||
1967 | else | ||
1968 | udf_update_tag(epos->bh->b_data, | ||
1969 | sizeof(struct allocExtDesc)); | ||
1970 | mark_buffer_dirty_inode(epos->bh, inode); | ||
1971 | brelse(epos->bh); | ||
1972 | } else { | ||
1973 | mark_inode_dirty(inode); | ||
1974 | } | ||
1975 | epos->bh = nbh; | ||
1976 | } | 1979 | } |
1977 | 1980 | ||
1978 | udf_write_aext(inode, epos, eloc, elen, inc); | 1981 | udf_write_aext(inode, epos, eloc, elen, inc); |
@@ -1996,6 +1999,41 @@ int udf_add_aext(struct inode *inode, struct extent_position *epos, | |||
1996 | return 0; | 1999 | return 0; |
1997 | } | 2000 | } |
1998 | 2001 | ||
2002 | /* | ||
2003 | * Append extent at given position - should be the first free one in inode | ||
2004 | * / indirect extent. Takes care of allocating and linking indirect blocks. | ||
2005 | */ | ||
2006 | int udf_add_aext(struct inode *inode, struct extent_position *epos, | ||
2007 | struct kernel_lb_addr *eloc, uint32_t elen, int inc) | ||
2008 | { | ||
2009 | int adsize; | ||
2010 | struct super_block *sb = inode->i_sb; | ||
2011 | |||
2012 | if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_SHORT) | ||
2013 | adsize = sizeof(struct short_ad); | ||
2014 | else if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_LONG) | ||
2015 | adsize = sizeof(struct long_ad); | ||
2016 | else | ||
2017 | return -EIO; | ||
2018 | |||
2019 | if (epos->offset + (2 * adsize) > sb->s_blocksize) { | ||
2020 | int err; | ||
2021 | int new_block; | ||
2022 | |||
2023 | new_block = udf_new_block(sb, NULL, | ||
2024 | epos->block.partitionReferenceNum, | ||
2025 | epos->block.logicalBlockNum, &err); | ||
2026 | if (!new_block) | ||
2027 | return -ENOSPC; | ||
2028 | |||
2029 | err = udf_setup_indirect_aext(inode, new_block, epos); | ||
2030 | if (err) | ||
2031 | return err; | ||
2032 | } | ||
2033 | |||
2034 | return __udf_add_aext(inode, epos, eloc, elen, inc); | ||
2035 | } | ||
2036 | |||
1999 | void udf_write_aext(struct inode *inode, struct extent_position *epos, | 2037 | void udf_write_aext(struct inode *inode, struct extent_position *epos, |
2000 | struct kernel_lb_addr *eloc, uint32_t elen, int inc) | 2038 | struct kernel_lb_addr *eloc, uint32_t elen, int inc) |
2001 | { | 2039 | { |
@@ -2048,14 +2086,29 @@ void udf_write_aext(struct inode *inode, struct extent_position *epos, | |||
2048 | epos->offset += adsize; | 2086 | epos->offset += adsize; |
2049 | } | 2087 | } |
2050 | 2088 | ||
2089 | /* | ||
2090 | * Only 1 indirect extent in a row really makes sense but allow upto 16 in case | ||
2091 | * someone does some weird stuff. | ||
2092 | */ | ||
2093 | #define UDF_MAX_INDIR_EXTS 16 | ||
2094 | |||
2051 | int8_t udf_next_aext(struct inode *inode, struct extent_position *epos, | 2095 | int8_t udf_next_aext(struct inode *inode, struct extent_position *epos, |
2052 | struct kernel_lb_addr *eloc, uint32_t *elen, int inc) | 2096 | struct kernel_lb_addr *eloc, uint32_t *elen, int inc) |
2053 | { | 2097 | { |
2054 | int8_t etype; | 2098 | int8_t etype; |
2099 | unsigned int indirections = 0; | ||
2055 | 2100 | ||
2056 | while ((etype = udf_current_aext(inode, epos, eloc, elen, inc)) == | 2101 | while ((etype = udf_current_aext(inode, epos, eloc, elen, inc)) == |
2057 | (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) { | 2102 | (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) { |
2058 | int block; | 2103 | int block; |
2104 | |||
2105 | if (++indirections > UDF_MAX_INDIR_EXTS) { | ||
2106 | udf_err(inode->i_sb, | ||
2107 | "too many indirect extents in inode %lu\n", | ||
2108 | inode->i_ino); | ||
2109 | return -1; | ||
2110 | } | ||
2111 | |||
2059 | epos->block = *eloc; | 2112 | epos->block = *eloc; |
2060 | epos->offset = sizeof(struct allocExtDesc); | 2113 | epos->offset = sizeof(struct allocExtDesc); |
2061 | brelse(epos->bh); | 2114 | brelse(epos->bh); |
diff --git a/fs/udf/super.c b/fs/udf/super.c index 9c64a3ca9837..0fbb4c7c72e8 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c | |||
@@ -1587,6 +1587,13 @@ static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_ | |||
1587 | } | 1587 | } |
1588 | 1588 | ||
1589 | /* | 1589 | /* |
1590 | * Maximum number of Terminating Descriptor redirections. The chosen number is | ||
1591 | * arbitrary - just that we hopefully don't limit any real use of rewritten | ||
1592 | * inode on write-once media but avoid looping for too long on corrupted media. | ||
1593 | */ | ||
1594 | #define UDF_MAX_TD_NESTING 64 | ||
1595 | |||
1596 | /* | ||
1590 | * Process a main/reserve volume descriptor sequence. | 1597 | * Process a main/reserve volume descriptor sequence. |
1591 | * @block First block of first extent of the sequence. | 1598 | * @block First block of first extent of the sequence. |
1592 | * @lastblock Lastblock of first extent of the sequence. | 1599 | * @lastblock Lastblock of first extent of the sequence. |
@@ -1610,6 +1617,7 @@ static noinline int udf_process_sequence( | |||
1610 | uint16_t ident; | 1617 | uint16_t ident; |
1611 | long next_s = 0, next_e = 0; | 1618 | long next_s = 0, next_e = 0; |
1612 | int ret; | 1619 | int ret; |
1620 | unsigned int indirections = 0; | ||
1613 | 1621 | ||
1614 | memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH); | 1622 | memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH); |
1615 | 1623 | ||
@@ -1680,6 +1688,12 @@ static noinline int udf_process_sequence( | |||
1680 | } | 1688 | } |
1681 | break; | 1689 | break; |
1682 | case TAG_IDENT_TD: /* ISO 13346 3/10.9 */ | 1690 | case TAG_IDENT_TD: /* ISO 13346 3/10.9 */ |
1691 | if (++indirections > UDF_MAX_TD_NESTING) { | ||
1692 | udf_err(sb, "too many TDs (max %u supported)\n", UDF_MAX_TD_NESTING); | ||
1693 | brelse(bh); | ||
1694 | return -EIO; | ||
1695 | } | ||
1696 | |||
1683 | vds[VDS_POS_TERMINATING_DESC].block = block; | 1697 | vds[VDS_POS_TERMINATING_DESC].block = block; |
1684 | if (next_e) { | 1698 | if (next_e) { |
1685 | block = next_s; | 1699 | block = next_s; |
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index ce169b49429d..fa0044b6b81d 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h | |||
@@ -158,6 +158,10 @@ extern int udf_write_inode(struct inode *, struct writeback_control *wbc); | |||
158 | extern long udf_block_map(struct inode *, sector_t); | 158 | extern long udf_block_map(struct inode *, sector_t); |
159 | extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *, | 159 | extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *, |
160 | struct kernel_lb_addr *, uint32_t *, sector_t *); | 160 | struct kernel_lb_addr *, uint32_t *, sector_t *); |
161 | extern int udf_setup_indirect_aext(struct inode *inode, int block, | ||
162 | struct extent_position *epos); | ||
163 | extern int __udf_add_aext(struct inode *inode, struct extent_position *epos, | ||
164 | struct kernel_lb_addr *eloc, uint32_t elen, int inc); | ||
161 | extern int udf_add_aext(struct inode *, struct extent_position *, | 165 | extern int udf_add_aext(struct inode *, struct extent_position *, |
162 | struct kernel_lb_addr *, uint32_t, int); | 166 | struct kernel_lb_addr *, uint32_t, int); |
163 | extern void udf_write_aext(struct inode *, struct extent_position *, | 167 | extern void udf_write_aext(struct inode *, struct extent_position *, |
diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c index ab478e62baae..e788a05aab83 100644 --- a/fs/udf/unicode.c +++ b/fs/udf/unicode.c | |||
@@ -128,11 +128,15 @@ int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i) | |||
128 | if (c < 0x80U) | 128 | if (c < 0x80U) |
129 | utf_o->u_name[utf_o->u_len++] = (uint8_t)c; | 129 | utf_o->u_name[utf_o->u_len++] = (uint8_t)c; |
130 | else if (c < 0x800U) { | 130 | else if (c < 0x800U) { |
131 | if (utf_o->u_len > (UDF_NAME_LEN - 4)) | ||
132 | break; | ||
131 | utf_o->u_name[utf_o->u_len++] = | 133 | utf_o->u_name[utf_o->u_len++] = |
132 | (uint8_t)(0xc0 | (c >> 6)); | 134 | (uint8_t)(0xc0 | (c >> 6)); |
133 | utf_o->u_name[utf_o->u_len++] = | 135 | utf_o->u_name[utf_o->u_len++] = |
134 | (uint8_t)(0x80 | (c & 0x3f)); | 136 | (uint8_t)(0x80 | (c & 0x3f)); |
135 | } else { | 137 | } else { |
138 | if (utf_o->u_len > (UDF_NAME_LEN - 5)) | ||
139 | break; | ||
136 | utf_o->u_name[utf_o->u_len++] = | 140 | utf_o->u_name[utf_o->u_len++] = |
137 | (uint8_t)(0xe0 | (c >> 12)); | 141 | (uint8_t)(0xe0 | (c >> 12)); |
138 | utf_o->u_name[utf_o->u_len++] = | 142 | utf_o->u_name[utf_o->u_len++] = |
@@ -173,17 +177,22 @@ int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i) | |||
173 | static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length) | 177 | static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length) |
174 | { | 178 | { |
175 | unsigned c, i, max_val, utf_char; | 179 | unsigned c, i, max_val, utf_char; |
176 | int utf_cnt, u_len; | 180 | int utf_cnt, u_len, u_ch; |
177 | 181 | ||
178 | memset(ocu, 0, sizeof(dstring) * length); | 182 | memset(ocu, 0, sizeof(dstring) * length); |
179 | ocu[0] = 8; | 183 | ocu[0] = 8; |
180 | max_val = 0xffU; | 184 | max_val = 0xffU; |
185 | u_ch = 1; | ||
181 | 186 | ||
182 | try_again: | 187 | try_again: |
183 | u_len = 0U; | 188 | u_len = 0U; |
184 | utf_char = 0U; | 189 | utf_char = 0U; |
185 | utf_cnt = 0U; | 190 | utf_cnt = 0U; |
186 | for (i = 0U; i < utf->u_len; i++) { | 191 | for (i = 0U; i < utf->u_len; i++) { |
192 | /* Name didn't fit? */ | ||
193 | if (u_len + 1 + u_ch >= length) | ||
194 | return 0; | ||
195 | |||
187 | c = (uint8_t)utf->u_name[i]; | 196 | c = (uint8_t)utf->u_name[i]; |
188 | 197 | ||
189 | /* Complete a multi-byte UTF-8 character */ | 198 | /* Complete a multi-byte UTF-8 character */ |
@@ -225,6 +234,7 @@ try_again: | |||
225 | if (max_val == 0xffU) { | 234 | if (max_val == 0xffU) { |
226 | max_val = 0xffffU; | 235 | max_val = 0xffffU; |
227 | ocu[0] = (uint8_t)0x10U; | 236 | ocu[0] = (uint8_t)0x10U; |
237 | u_ch = 2; | ||
228 | goto try_again; | 238 | goto try_again; |
229 | } | 239 | } |
230 | goto error_out; | 240 | goto error_out; |
@@ -277,7 +287,7 @@ static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o, | |||
277 | c = (c << 8) | ocu[i++]; | 287 | c = (c << 8) | ocu[i++]; |
278 | 288 | ||
279 | len = nls->uni2char(c, &utf_o->u_name[utf_o->u_len], | 289 | len = nls->uni2char(c, &utf_o->u_name[utf_o->u_len], |
280 | UDF_NAME_LEN - utf_o->u_len); | 290 | UDF_NAME_LEN - 2 - utf_o->u_len); |
281 | /* Valid character? */ | 291 | /* Valid character? */ |
282 | if (len >= 0) | 292 | if (len >= 0) |
283 | utf_o->u_len += len; | 293 | utf_o->u_len += len; |
@@ -295,15 +305,19 @@ static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni, | |||
295 | int len; | 305 | int len; |
296 | unsigned i, max_val; | 306 | unsigned i, max_val; |
297 | uint16_t uni_char; | 307 | uint16_t uni_char; |
298 | int u_len; | 308 | int u_len, u_ch; |
299 | 309 | ||
300 | memset(ocu, 0, sizeof(dstring) * length); | 310 | memset(ocu, 0, sizeof(dstring) * length); |
301 | ocu[0] = 8; | 311 | ocu[0] = 8; |
302 | max_val = 0xffU; | 312 | max_val = 0xffU; |
313 | u_ch = 1; | ||
303 | 314 | ||
304 | try_again: | 315 | try_again: |
305 | u_len = 0U; | 316 | u_len = 0U; |
306 | for (i = 0U; i < uni->u_len; i++) { | 317 | for (i = 0U; i < uni->u_len; i++) { |
318 | /* Name didn't fit? */ | ||
319 | if (u_len + 1 + u_ch >= length) | ||
320 | return 0; | ||
307 | len = nls->char2uni(&uni->u_name[i], uni->u_len - i, &uni_char); | 321 | len = nls->char2uni(&uni->u_name[i], uni->u_len - i, &uni_char); |
308 | if (!len) | 322 | if (!len) |
309 | continue; | 323 | continue; |
@@ -316,6 +330,7 @@ try_again: | |||
316 | if (uni_char > max_val) { | 330 | if (uni_char > max_val) { |
317 | max_val = 0xffffU; | 331 | max_val = 0xffffU; |
318 | ocu[0] = (uint8_t)0x10U; | 332 | ocu[0] = (uint8_t)0x10U; |
333 | u_ch = 2; | ||
319 | goto try_again; | 334 | goto try_again; |
320 | } | 335 | } |
321 | 336 | ||
diff --git a/include/linux/dqblk_qtree.h b/include/linux/dqblk_qtree.h index 82a16527b367..ff8b55359648 100644 --- a/include/linux/dqblk_qtree.h +++ b/include/linux/dqblk_qtree.h | |||
@@ -34,7 +34,7 @@ struct qtree_mem_dqinfo { | |||
34 | unsigned int dqi_entry_size; /* Size of quota entry in quota file */ | 34 | unsigned int dqi_entry_size; /* Size of quota entry in quota file */ |
35 | unsigned int dqi_usable_bs; /* Space usable in block for quota data */ | 35 | unsigned int dqi_usable_bs; /* Space usable in block for quota data */ |
36 | unsigned int dqi_qtree_depth; /* Precomputed depth of quota tree */ | 36 | unsigned int dqi_qtree_depth; /* Precomputed depth of quota tree */ |
37 | struct qtree_fmt_operations *dqi_ops; /* Operations for entry manipulation */ | 37 | const struct qtree_fmt_operations *dqi_ops; /* Operations for entry manipulation */ |
38 | }; | 38 | }; |
39 | 39 | ||
40 | int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot); | 40 | int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot); |