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
This commit is contained in:
Linus Torvalds
2016-01-15 11:51:51 -08:00
11 changed files with 196 additions and 201 deletions

View File

@ -539,9 +539,18 @@ static int udf_do_extend_file(struct inode *inode,
udf_add_aext(inode, last_pos, &last_ext->extLocation,
last_ext->extLength, 1);
count++;
} else
} else {
struct kernel_lb_addr tmploc;
uint32_t tmplen;
udf_write_aext(inode, last_pos, &last_ext->extLocation,
last_ext->extLength, 1);
/*
* We've rewritten the last extent but there may be empty
* indirect extent after it - enter it.
*/
udf_next_aext(inode, last_pos, &tmploc, &tmplen, 0);
}
/* Managed to do everything necessary? */
if (!blocks)
@ -1867,22 +1876,90 @@ struct inode *__udf_iget(struct super_block *sb, struct kernel_lb_addr *ino,
return inode;
}
int udf_add_aext(struct inode *inode, struct extent_position *epos,
struct kernel_lb_addr *eloc, uint32_t elen, int inc)
int udf_setup_indirect_aext(struct inode *inode, int block,
struct extent_position *epos)
{
int adsize;
struct short_ad *sad = NULL;
struct long_ad *lad = NULL;
struct super_block *sb = inode->i_sb;
struct buffer_head *bh;
struct allocExtDesc *aed;
uint8_t *ptr;
struct udf_inode_info *iinfo = UDF_I(inode);
struct extent_position nepos;
struct kernel_lb_addr neloc;
int ver, adsize;
if (!epos->bh)
ptr = iinfo->i_ext.i_data + epos->offset -
udf_file_entry_alloc_offset(inode) +
iinfo->i_lenEAttr;
if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
adsize = sizeof(struct short_ad);
else if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_LONG)
adsize = sizeof(struct long_ad);
else
ptr = epos->bh->b_data + epos->offset;
return -EIO;
neloc.logicalBlockNum = block;
neloc.partitionReferenceNum = epos->block.partitionReferenceNum;
bh = udf_tgetblk(sb, udf_get_lb_pblock(sb, &neloc, 0));
if (!bh)
return -EIO;
lock_buffer(bh);
memset(bh->b_data, 0x00, sb->s_blocksize);
set_buffer_uptodate(bh);
unlock_buffer(bh);
mark_buffer_dirty_inode(bh, inode);
aed = (struct allocExtDesc *)(bh->b_data);
if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT)) {
aed->previousAllocExtLocation =
cpu_to_le32(epos->block.logicalBlockNum);
}
aed->lengthAllocDescs = cpu_to_le32(0);
if (UDF_SB(sb)->s_udfrev >= 0x0200)
ver = 3;
else
ver = 2;
udf_new_tag(bh->b_data, TAG_IDENT_AED, ver, 1, block,
sizeof(struct tag));
nepos.block = neloc;
nepos.offset = sizeof(struct allocExtDesc);
nepos.bh = bh;
/*
* Do we have to copy current last extent to make space for indirect
* one?
*/
if (epos->offset + adsize > sb->s_blocksize) {
struct kernel_lb_addr cp_loc;
uint32_t cp_len;
int cp_type;
epos->offset -= adsize;
cp_type = udf_current_aext(inode, epos, &cp_loc, &cp_len, 0);
cp_len |= ((uint32_t)cp_type) << 30;
__udf_add_aext(inode, &nepos, &cp_loc, cp_len, 1);
udf_write_aext(inode, epos, &nepos.block,
sb->s_blocksize | EXT_NEXT_EXTENT_ALLOCDECS, 0);
} else {
__udf_add_aext(inode, epos, &nepos.block,
sb->s_blocksize | EXT_NEXT_EXTENT_ALLOCDECS, 0);
}
brelse(epos->bh);
*epos = nepos;
return 0;
}
/*
* Append extent at the given position - should be the first free one in inode
* / indirect extent. This function assumes there is enough space in the inode
* or indirect extent. Use udf_add_aext() if you didn't check for this before.
*/
int __udf_add_aext(struct inode *inode, struct extent_position *epos,
struct kernel_lb_addr *eloc, uint32_t elen, int inc)
{
struct udf_inode_info *iinfo = UDF_I(inode);
struct allocExtDesc *aed;
int adsize;
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
adsize = sizeof(struct short_ad);
@ -1891,88 +1968,14 @@ int udf_add_aext(struct inode *inode, struct extent_position *epos,
else
return -EIO;
if (epos->offset + (2 * adsize) > inode->i_sb->s_blocksize) {
unsigned char *sptr, *dptr;
struct buffer_head *nbh;
int err, loffset;
struct kernel_lb_addr obloc = epos->block;
epos->block.logicalBlockNum = udf_new_block(inode->i_sb, NULL,
obloc.partitionReferenceNum,
obloc.logicalBlockNum, &err);
if (!epos->block.logicalBlockNum)
return -ENOSPC;
nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb,
&epos->block,
0));
if (!nbh)
return -EIO;
lock_buffer(nbh);
memset(nbh->b_data, 0x00, inode->i_sb->s_blocksize);
set_buffer_uptodate(nbh);
unlock_buffer(nbh);
mark_buffer_dirty_inode(nbh, inode);
aed = (struct allocExtDesc *)(nbh->b_data);
if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT))
aed->previousAllocExtLocation =
cpu_to_le32(obloc.logicalBlockNum);
if (epos->offset + adsize > inode->i_sb->s_blocksize) {
loffset = epos->offset;
aed->lengthAllocDescs = cpu_to_le32(adsize);
sptr = ptr - adsize;
dptr = nbh->b_data + sizeof(struct allocExtDesc);
memcpy(dptr, sptr, adsize);
epos->offset = sizeof(struct allocExtDesc) + adsize;
} else {
loffset = epos->offset + adsize;
aed->lengthAllocDescs = cpu_to_le32(0);
sptr = ptr;
epos->offset = sizeof(struct allocExtDesc);
if (epos->bh) {
aed = (struct allocExtDesc *)epos->bh->b_data;
le32_add_cpu(&aed->lengthAllocDescs, adsize);
} else {
iinfo->i_lenAlloc += adsize;
mark_inode_dirty(inode);
}
}
if (UDF_SB(inode->i_sb)->s_udfrev >= 0x0200)
udf_new_tag(nbh->b_data, TAG_IDENT_AED, 3, 1,
epos->block.logicalBlockNum, sizeof(struct tag));
else
udf_new_tag(nbh->b_data, TAG_IDENT_AED, 2, 1,
epos->block.logicalBlockNum, sizeof(struct tag));
switch (iinfo->i_alloc_type) {
case ICBTAG_FLAG_AD_SHORT:
sad = (struct short_ad *)sptr;
sad->extLength = cpu_to_le32(EXT_NEXT_EXTENT_ALLOCDECS |
inode->i_sb->s_blocksize);
sad->extPosition =
cpu_to_le32(epos->block.logicalBlockNum);
break;
case ICBTAG_FLAG_AD_LONG:
lad = (struct long_ad *)sptr;
lad->extLength = cpu_to_le32(EXT_NEXT_EXTENT_ALLOCDECS |
inode->i_sb->s_blocksize);
lad->extLocation = cpu_to_lelb(epos->block);
memset(lad->impUse, 0x00, sizeof(lad->impUse));
break;
}
if (epos->bh) {
if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
UDF_SB(inode->i_sb)->s_udfrev >= 0x0201)
udf_update_tag(epos->bh->b_data, loffset);
else
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);
}
epos->bh = nbh;
if (!epos->bh) {
WARN_ON(iinfo->i_lenAlloc !=
epos->offset - udf_file_entry_alloc_offset(inode));
} else {
aed = (struct allocExtDesc *)epos->bh->b_data;
WARN_ON(le32_to_cpu(aed->lengthAllocDescs) !=
epos->offset - sizeof(struct allocExtDesc));
WARN_ON(epos->offset + adsize > inode->i_sb->s_blocksize);
}
udf_write_aext(inode, epos, eloc, elen, inc);
@ -1996,6 +1999,41 @@ int udf_add_aext(struct inode *inode, struct extent_position *epos,
return 0;
}
/*
* Append extent at given position - should be the first free one in inode
* / indirect extent. Takes care of allocating and linking indirect blocks.
*/
int udf_add_aext(struct inode *inode, struct extent_position *epos,
struct kernel_lb_addr *eloc, uint32_t elen, int inc)
{
int adsize;
struct super_block *sb = inode->i_sb;
if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
adsize = sizeof(struct short_ad);
else if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_LONG)
adsize = sizeof(struct long_ad);
else
return -EIO;
if (epos->offset + (2 * adsize) > sb->s_blocksize) {
int err;
int new_block;
new_block = udf_new_block(sb, NULL,
epos->block.partitionReferenceNum,
epos->block.logicalBlockNum, &err);
if (!new_block)
return -ENOSPC;
err = udf_setup_indirect_aext(inode, new_block, epos);
if (err)
return err;
}
return __udf_add_aext(inode, epos, eloc, elen, inc);
}
void udf_write_aext(struct inode *inode, struct extent_position *epos,
struct kernel_lb_addr *eloc, uint32_t elen, int inc)
{
@ -2048,14 +2086,29 @@ void udf_write_aext(struct inode *inode, struct extent_position *epos,
epos->offset += adsize;
}
/*
* Only 1 indirect extent in a row really makes sense but allow upto 16 in case
* someone does some weird stuff.
*/
#define UDF_MAX_INDIR_EXTS 16
int8_t udf_next_aext(struct inode *inode, struct extent_position *epos,
struct kernel_lb_addr *eloc, uint32_t *elen, int inc)
{
int8_t etype;
unsigned int indirections = 0;
while ((etype = udf_current_aext(inode, epos, eloc, elen, inc)) ==
(EXT_NEXT_EXTENT_ALLOCDECS >> 30)) {
int block;
if (++indirections > UDF_MAX_INDIR_EXTS) {
udf_err(inode->i_sb,
"too many indirect extents in inode %lu\n",
inode->i_ino);
return -1;
}
epos->block = *eloc;
epos->offset = sizeof(struct allocExtDesc);
brelse(epos->bh);