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:
commit
1d3671df72
|
@ -82,7 +82,7 @@ struct ocfs2_quota_chunk {
|
||||||
extern struct kmem_cache *ocfs2_dquot_cachep;
|
extern struct kmem_cache *ocfs2_dquot_cachep;
|
||||||
extern struct kmem_cache *ocfs2_qf_chunk_cachep;
|
extern struct kmem_cache *ocfs2_qf_chunk_cachep;
|
||||||
|
|
||||||
extern struct qtree_fmt_operations ocfs2_global_ops;
|
extern const struct qtree_fmt_operations ocfs2_global_ops;
|
||||||
|
|
||||||
struct ocfs2_quota_recovery *ocfs2_begin_quota_recovery(
|
struct ocfs2_quota_recovery *ocfs2_begin_quota_recovery(
|
||||||
struct ocfs2_super *osb, int slot_num);
|
struct ocfs2_super *osb, int slot_num);
|
||||||
|
|
|
@ -123,7 +123,7 @@ static int ocfs2_global_is_id(void *dp, struct dquot *dquot)
|
||||||
dquot->dq_id);
|
dquot->dq_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct qtree_fmt_operations ocfs2_global_ops = {
|
const struct qtree_fmt_operations ocfs2_global_ops = {
|
||||||
.mem2disk_dqblk = ocfs2_global_mem2diskdqb,
|
.mem2disk_dqblk = ocfs2_global_mem2diskdqb,
|
||||||
.disk2mem_dqblk = ocfs2_global_disk2memdqb,
|
.disk2mem_dqblk = ocfs2_global_disk2memdqb,
|
||||||
.is_id = ocfs2_global_is_id,
|
.is_id = ocfs2_global_is_id,
|
||||||
|
|
|
@ -2924,4 +2924,4 @@ static int __init dquot_init(void)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
module_init(dquot_init);
|
fs_initcall(dquot_init);
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
|
|
||||||
#include <linux/cred.h>
|
#include <linux/cred.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/quotaops.h>
|
#include <linux/quotaops.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
|
@ -105,5 +103,4 @@ static int __init quota_init(void)
|
||||||
"VFS: Failed to create quota netlink interface.\n");
|
"VFS: Failed to create quota netlink interface.\n");
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
fs_initcall(quota_init);
|
||||||
module_init(quota_init);
|
|
||||||
|
|
|
@ -30,13 +30,13 @@ static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot);
|
||||||
static void v2r1_disk2memdqb(struct dquot *dquot, void *dp);
|
static void v2r1_disk2memdqb(struct dquot *dquot, void *dp);
|
||||||
static int v2r1_is_id(void *dp, struct dquot *dquot);
|
static int v2r1_is_id(void *dp, struct dquot *dquot);
|
||||||
|
|
||||||
static struct qtree_fmt_operations v2r0_qtree_ops = {
|
static const struct qtree_fmt_operations v2r0_qtree_ops = {
|
||||||
.mem2disk_dqblk = v2r0_mem2diskdqb,
|
.mem2disk_dqblk = v2r0_mem2diskdqb,
|
||||||
.disk2mem_dqblk = v2r0_disk2memdqb,
|
.disk2mem_dqblk = v2r0_disk2memdqb,
|
||||||
.is_id = v2r0_is_id,
|
.is_id = v2r0_is_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct qtree_fmt_operations v2r1_qtree_ops = {
|
static const struct qtree_fmt_operations v2r1_qtree_ops = {
|
||||||
.mem2disk_dqblk = v2r1_mem2diskdqb,
|
.mem2disk_dqblk = v2r1_mem2diskdqb,
|
||||||
.disk2mem_dqblk = v2r1_disk2memdqb,
|
.disk2mem_dqblk = v2r1_disk2memdqb,
|
||||||
.is_id = v2r1_is_id,
|
.is_id = v2r1_is_id,
|
||||||
|
|
|
@ -447,9 +447,6 @@ static void udf_table_free_blocks(struct super_block *sb,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int adsize;
|
int adsize;
|
||||||
struct short_ad *sad = NULL;
|
|
||||||
struct long_ad *lad = NULL;
|
|
||||||
struct allocExtDesc *aed;
|
|
||||||
|
|
||||||
eloc.logicalBlockNum = start;
|
eloc.logicalBlockNum = start;
|
||||||
elen = EXT_RECORDED_ALLOCATED |
|
elen = EXT_RECORDED_ALLOCATED |
|
||||||
|
@ -466,102 +463,17 @@ static void udf_table_free_blocks(struct super_block *sb,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (epos.offset + (2 * adsize) > sb->s_blocksize) {
|
if (epos.offset + (2 * adsize) > sb->s_blocksize) {
|
||||||
unsigned char *sptr, *dptr;
|
|
||||||
int loffset;
|
|
||||||
|
|
||||||
brelse(oepos.bh);
|
|
||||||
oepos = epos;
|
|
||||||
|
|
||||||
/* Steal a block from the extent being free'd */
|
/* Steal a block from the extent being free'd */
|
||||||
epos.block.logicalBlockNum = eloc.logicalBlockNum;
|
udf_setup_indirect_aext(table, eloc.logicalBlockNum,
|
||||||
|
&epos);
|
||||||
|
|
||||||
eloc.logicalBlockNum++;
|
eloc.logicalBlockNum++;
|
||||||
elen -= sb->s_blocksize;
|
elen -= sb->s_blocksize;
|
||||||
|
|
||||||
epos.bh = udf_tread(sb,
|
|
||||||
udf_get_lb_pblock(sb, &epos.block, 0));
|
|
||||||
if (!epos.bh) {
|
|
||||||
brelse(oepos.bh);
|
|
||||||
goto error_return;
|
|
||||||
}
|
|
||||||
aed = (struct allocExtDesc *)(epos.bh->b_data);
|
|
||||||
aed->previousAllocExtLocation =
|
|
||||||
cpu_to_le32(oepos.block.logicalBlockNum);
|
|
||||||
if (epos.offset + adsize > sb->s_blocksize) {
|
|
||||||
loffset = epos.offset;
|
|
||||||
aed->lengthAllocDescs = cpu_to_le32(adsize);
|
|
||||||
sptr = iinfo->i_ext.i_data + epos.offset
|
|
||||||
- adsize;
|
|
||||||
dptr = epos.bh->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);
|
|
||||||
if (oepos.bh) {
|
|
||||||
sptr = oepos.bh->b_data + epos.offset;
|
|
||||||
aed = (struct allocExtDesc *)
|
|
||||||
oepos.bh->b_data;
|
|
||||||
le32_add_cpu(&aed->lengthAllocDescs,
|
|
||||||
adsize);
|
|
||||||
} else {
|
|
||||||
sptr = iinfo->i_ext.i_data +
|
|
||||||
epos.offset;
|
|
||||||
iinfo->i_lenAlloc += adsize;
|
|
||||||
mark_inode_dirty(table);
|
|
||||||
}
|
|
||||||
epos.offset = sizeof(struct allocExtDesc);
|
|
||||||
}
|
|
||||||
if (sbi->s_udfrev >= 0x0200)
|
|
||||||
udf_new_tag(epos.bh->b_data, TAG_IDENT_AED,
|
|
||||||
3, 1, epos.block.logicalBlockNum,
|
|
||||||
sizeof(struct tag));
|
|
||||||
else
|
|
||||||
udf_new_tag(epos.bh->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 |
|
|
||||||
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 |
|
|
||||||
sb->s_blocksize);
|
|
||||||
lad->extLocation =
|
|
||||||
cpu_to_lelb(epos.block);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (oepos.bh) {
|
|
||||||
udf_update_tag(oepos.bh->b_data, loffset);
|
|
||||||
mark_buffer_dirty(oepos.bh);
|
|
||||||
} else {
|
|
||||||
mark_inode_dirty(table);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* It's possible that stealing the block emptied the extent */
|
/* It's possible that stealing the block emptied the extent */
|
||||||
if (elen) {
|
if (elen)
|
||||||
udf_write_aext(table, &epos, &eloc, elen, 1);
|
__udf_add_aext(table, &epos, &eloc, elen, 1);
|
||||||
|
|
||||||
if (!epos.bh) {
|
|
||||||
iinfo->i_lenAlloc += adsize;
|
|
||||||
mark_inode_dirty(table);
|
|
||||||
} else {
|
|
||||||
aed = (struct allocExtDesc *)epos.bh->b_data;
|
|
||||||
le32_add_cpu(&aed->lengthAllocDescs, adsize);
|
|
||||||
udf_update_tag(epos.bh->b_data, epos.offset);
|
|
||||||
mark_buffer_dirty(epos.bh);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
brelse(epos.bh);
|
brelse(epos.bh);
|
||||||
|
|
243
fs/udf/inode.c
243
fs/udf/inode.c
|
@ -539,9 +539,18 @@ static int udf_do_extend_file(struct inode *inode,
|
||||||
udf_add_aext(inode, last_pos, &last_ext->extLocation,
|
udf_add_aext(inode, last_pos, &last_ext->extLocation,
|
||||||
last_ext->extLength, 1);
|
last_ext->extLength, 1);
|
||||||
count++;
|
count++;
|
||||||
} else
|
} else {
|
||||||
|
struct kernel_lb_addr tmploc;
|
||||||
|
uint32_t tmplen;
|
||||||
|
|
||||||
udf_write_aext(inode, last_pos, &last_ext->extLocation,
|
udf_write_aext(inode, last_pos, &last_ext->extLocation,
|
||||||
last_ext->extLength, 1);
|
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? */
|
/* Managed to do everything necessary? */
|
||||||
if (!blocks)
|
if (!blocks)
|
||||||
|
@ -1867,22 +1876,90 @@ struct inode *__udf_iget(struct super_block *sb, struct kernel_lb_addr *ino,
|
||||||
return inode;
|
return inode;
|
||||||
}
|
}
|
||||||
|
|
||||||
int udf_add_aext(struct inode *inode, struct extent_position *epos,
|
int udf_setup_indirect_aext(struct inode *inode, int block,
|
||||||
struct kernel_lb_addr *eloc, uint32_t elen, int inc)
|
struct extent_position *epos)
|
||||||
{
|
{
|
||||||
int adsize;
|
struct super_block *sb = inode->i_sb;
|
||||||
struct short_ad *sad = NULL;
|
struct buffer_head *bh;
|
||||||
struct long_ad *lad = NULL;
|
|
||||||
struct allocExtDesc *aed;
|
struct allocExtDesc *aed;
|
||||||
uint8_t *ptr;
|
struct extent_position nepos;
|
||||||
struct udf_inode_info *iinfo = UDF_I(inode);
|
struct kernel_lb_addr neloc;
|
||||||
|
int ver, adsize;
|
||||||
|
|
||||||
if (!epos->bh)
|
if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
|
||||||
ptr = iinfo->i_ext.i_data + epos->offset -
|
adsize = sizeof(struct short_ad);
|
||||||
udf_file_entry_alloc_offset(inode) +
|
else if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_LONG)
|
||||||
iinfo->i_lenEAttr;
|
adsize = sizeof(struct long_ad);
|
||||||
else
|
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)
|
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
|
||||||
adsize = sizeof(struct short_ad);
|
adsize = sizeof(struct short_ad);
|
||||||
|
@ -1891,88 +1968,14 @@ int udf_add_aext(struct inode *inode, struct extent_position *epos,
|
||||||
else
|
else
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (epos->offset + (2 * adsize) > inode->i_sb->s_blocksize) {
|
if (!epos->bh) {
|
||||||
unsigned char *sptr, *dptr;
|
WARN_ON(iinfo->i_lenAlloc !=
|
||||||
struct buffer_head *nbh;
|
epos->offset - udf_file_entry_alloc_offset(inode));
|
||||||
int err, loffset;
|
} else {
|
||||||
struct kernel_lb_addr obloc = epos->block;
|
aed = (struct allocExtDesc *)epos->bh->b_data;
|
||||||
|
WARN_ON(le32_to_cpu(aed->lengthAllocDescs) !=
|
||||||
epos->block.logicalBlockNum = udf_new_block(inode->i_sb, NULL,
|
epos->offset - sizeof(struct allocExtDesc));
|
||||||
obloc.partitionReferenceNum,
|
WARN_ON(epos->offset + adsize > inode->i_sb->s_blocksize);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
udf_write_aext(inode, epos, eloc, elen, inc);
|
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;
|
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,
|
void udf_write_aext(struct inode *inode, struct extent_position *epos,
|
||||||
struct kernel_lb_addr *eloc, uint32_t elen, int inc)
|
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;
|
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,
|
int8_t udf_next_aext(struct inode *inode, struct extent_position *epos,
|
||||||
struct kernel_lb_addr *eloc, uint32_t *elen, int inc)
|
struct kernel_lb_addr *eloc, uint32_t *elen, int inc)
|
||||||
{
|
{
|
||||||
int8_t etype;
|
int8_t etype;
|
||||||
|
unsigned int indirections = 0;
|
||||||
|
|
||||||
while ((etype = udf_current_aext(inode, epos, eloc, elen, inc)) ==
|
while ((etype = udf_current_aext(inode, epos, eloc, elen, inc)) ==
|
||||||
(EXT_NEXT_EXTENT_ALLOCDECS >> 30)) {
|
(EXT_NEXT_EXTENT_ALLOCDECS >> 30)) {
|
||||||
int block;
|
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->block = *eloc;
|
||||||
epos->offset = sizeof(struct allocExtDesc);
|
epos->offset = sizeof(struct allocExtDesc);
|
||||||
brelse(epos->bh);
|
brelse(epos->bh);
|
||||||
|
|
|
@ -1586,6 +1586,13 @@ static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_
|
||||||
brelse(bh);
|
brelse(bh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maximum number of Terminating Descriptor redirections. The chosen number is
|
||||||
|
* arbitrary - just that we hopefully don't limit any real use of rewritten
|
||||||
|
* inode on write-once media but avoid looping for too long on corrupted media.
|
||||||
|
*/
|
||||||
|
#define UDF_MAX_TD_NESTING 64
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Process a main/reserve volume descriptor sequence.
|
* Process a main/reserve volume descriptor sequence.
|
||||||
* @block First block of first extent of the sequence.
|
* @block First block of first extent of the sequence.
|
||||||
|
@ -1610,6 +1617,7 @@ static noinline int udf_process_sequence(
|
||||||
uint16_t ident;
|
uint16_t ident;
|
||||||
long next_s = 0, next_e = 0;
|
long next_s = 0, next_e = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
unsigned int indirections = 0;
|
||||||
|
|
||||||
memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH);
|
memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH);
|
||||||
|
|
||||||
|
@ -1680,6 +1688,12 @@ static noinline int udf_process_sequence(
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TAG_IDENT_TD: /* ISO 13346 3/10.9 */
|
case TAG_IDENT_TD: /* ISO 13346 3/10.9 */
|
||||||
|
if (++indirections > UDF_MAX_TD_NESTING) {
|
||||||
|
udf_err(sb, "too many TDs (max %u supported)\n", UDF_MAX_TD_NESTING);
|
||||||
|
brelse(bh);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
vds[VDS_POS_TERMINATING_DESC].block = block;
|
vds[VDS_POS_TERMINATING_DESC].block = block;
|
||||||
if (next_e) {
|
if (next_e) {
|
||||||
block = next_s;
|
block = next_s;
|
||||||
|
|
|
@ -158,6 +158,10 @@ extern int udf_write_inode(struct inode *, struct writeback_control *wbc);
|
||||||
extern long udf_block_map(struct inode *, sector_t);
|
extern long udf_block_map(struct inode *, sector_t);
|
||||||
extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *,
|
extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *,
|
||||||
struct kernel_lb_addr *, uint32_t *, sector_t *);
|
struct kernel_lb_addr *, uint32_t *, sector_t *);
|
||||||
|
extern int udf_setup_indirect_aext(struct inode *inode, int block,
|
||||||
|
struct extent_position *epos);
|
||||||
|
extern int __udf_add_aext(struct inode *inode, struct extent_position *epos,
|
||||||
|
struct kernel_lb_addr *eloc, uint32_t elen, int inc);
|
||||||
extern int udf_add_aext(struct inode *, struct extent_position *,
|
extern int udf_add_aext(struct inode *, struct extent_position *,
|
||||||
struct kernel_lb_addr *, uint32_t, int);
|
struct kernel_lb_addr *, uint32_t, int);
|
||||||
extern void udf_write_aext(struct inode *, struct extent_position *,
|
extern void udf_write_aext(struct inode *, struct extent_position *,
|
||||||
|
|
|
@ -128,11 +128,15 @@ int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i)
|
||||||
if (c < 0x80U)
|
if (c < 0x80U)
|
||||||
utf_o->u_name[utf_o->u_len++] = (uint8_t)c;
|
utf_o->u_name[utf_o->u_len++] = (uint8_t)c;
|
||||||
else if (c < 0x800U) {
|
else if (c < 0x800U) {
|
||||||
|
if (utf_o->u_len > (UDF_NAME_LEN - 4))
|
||||||
|
break;
|
||||||
utf_o->u_name[utf_o->u_len++] =
|
utf_o->u_name[utf_o->u_len++] =
|
||||||
(uint8_t)(0xc0 | (c >> 6));
|
(uint8_t)(0xc0 | (c >> 6));
|
||||||
utf_o->u_name[utf_o->u_len++] =
|
utf_o->u_name[utf_o->u_len++] =
|
||||||
(uint8_t)(0x80 | (c & 0x3f));
|
(uint8_t)(0x80 | (c & 0x3f));
|
||||||
} else {
|
} else {
|
||||||
|
if (utf_o->u_len > (UDF_NAME_LEN - 5))
|
||||||
|
break;
|
||||||
utf_o->u_name[utf_o->u_len++] =
|
utf_o->u_name[utf_o->u_len++] =
|
||||||
(uint8_t)(0xe0 | (c >> 12));
|
(uint8_t)(0xe0 | (c >> 12));
|
||||||
utf_o->u_name[utf_o->u_len++] =
|
utf_o->u_name[utf_o->u_len++] =
|
||||||
|
@ -173,17 +177,22 @@ int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i)
|
||||||
static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length)
|
static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length)
|
||||||
{
|
{
|
||||||
unsigned c, i, max_val, utf_char;
|
unsigned c, i, max_val, utf_char;
|
||||||
int utf_cnt, u_len;
|
int utf_cnt, u_len, u_ch;
|
||||||
|
|
||||||
memset(ocu, 0, sizeof(dstring) * length);
|
memset(ocu, 0, sizeof(dstring) * length);
|
||||||
ocu[0] = 8;
|
ocu[0] = 8;
|
||||||
max_val = 0xffU;
|
max_val = 0xffU;
|
||||||
|
u_ch = 1;
|
||||||
|
|
||||||
try_again:
|
try_again:
|
||||||
u_len = 0U;
|
u_len = 0U;
|
||||||
utf_char = 0U;
|
utf_char = 0U;
|
||||||
utf_cnt = 0U;
|
utf_cnt = 0U;
|
||||||
for (i = 0U; i < utf->u_len; i++) {
|
for (i = 0U; i < utf->u_len; i++) {
|
||||||
|
/* Name didn't fit? */
|
||||||
|
if (u_len + 1 + u_ch >= length)
|
||||||
|
return 0;
|
||||||
|
|
||||||
c = (uint8_t)utf->u_name[i];
|
c = (uint8_t)utf->u_name[i];
|
||||||
|
|
||||||
/* Complete a multi-byte UTF-8 character */
|
/* Complete a multi-byte UTF-8 character */
|
||||||
|
@ -225,6 +234,7 @@ static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length)
|
||||||
if (max_val == 0xffU) {
|
if (max_val == 0xffU) {
|
||||||
max_val = 0xffffU;
|
max_val = 0xffffU;
|
||||||
ocu[0] = (uint8_t)0x10U;
|
ocu[0] = (uint8_t)0x10U;
|
||||||
|
u_ch = 2;
|
||||||
goto try_again;
|
goto try_again;
|
||||||
}
|
}
|
||||||
goto error_out;
|
goto error_out;
|
||||||
|
@ -277,7 +287,7 @@ static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o,
|
||||||
c = (c << 8) | ocu[i++];
|
c = (c << 8) | ocu[i++];
|
||||||
|
|
||||||
len = nls->uni2char(c, &utf_o->u_name[utf_o->u_len],
|
len = nls->uni2char(c, &utf_o->u_name[utf_o->u_len],
|
||||||
UDF_NAME_LEN - utf_o->u_len);
|
UDF_NAME_LEN - 2 - utf_o->u_len);
|
||||||
/* Valid character? */
|
/* Valid character? */
|
||||||
if (len >= 0)
|
if (len >= 0)
|
||||||
utf_o->u_len += len;
|
utf_o->u_len += len;
|
||||||
|
@ -295,15 +305,19 @@ static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni,
|
||||||
int len;
|
int len;
|
||||||
unsigned i, max_val;
|
unsigned i, max_val;
|
||||||
uint16_t uni_char;
|
uint16_t uni_char;
|
||||||
int u_len;
|
int u_len, u_ch;
|
||||||
|
|
||||||
memset(ocu, 0, sizeof(dstring) * length);
|
memset(ocu, 0, sizeof(dstring) * length);
|
||||||
ocu[0] = 8;
|
ocu[0] = 8;
|
||||||
max_val = 0xffU;
|
max_val = 0xffU;
|
||||||
|
u_ch = 1;
|
||||||
|
|
||||||
try_again:
|
try_again:
|
||||||
u_len = 0U;
|
u_len = 0U;
|
||||||
for (i = 0U; i < uni->u_len; i++) {
|
for (i = 0U; i < uni->u_len; i++) {
|
||||||
|
/* Name didn't fit? */
|
||||||
|
if (u_len + 1 + u_ch >= length)
|
||||||
|
return 0;
|
||||||
len = nls->char2uni(&uni->u_name[i], uni->u_len - i, &uni_char);
|
len = nls->char2uni(&uni->u_name[i], uni->u_len - i, &uni_char);
|
||||||
if (!len)
|
if (!len)
|
||||||
continue;
|
continue;
|
||||||
|
@ -316,6 +330,7 @@ static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni,
|
||||||
if (uni_char > max_val) {
|
if (uni_char > max_val) {
|
||||||
max_val = 0xffffU;
|
max_val = 0xffffU;
|
||||||
ocu[0] = (uint8_t)0x10U;
|
ocu[0] = (uint8_t)0x10U;
|
||||||
|
u_ch = 2;
|
||||||
goto try_again;
|
goto try_again;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ struct qtree_mem_dqinfo {
|
||||||
unsigned int dqi_entry_size; /* Size of quota entry in quota file */
|
unsigned int dqi_entry_size; /* Size of quota entry in quota file */
|
||||||
unsigned int dqi_usable_bs; /* Space usable in block for quota data */
|
unsigned int dqi_usable_bs; /* Space usable in block for quota data */
|
||||||
unsigned int dqi_qtree_depth; /* Precomputed depth of quota tree */
|
unsigned int dqi_qtree_depth; /* Precomputed depth of quota tree */
|
||||||
struct qtree_fmt_operations *dqi_ops; /* Operations for entry manipulation */
|
const struct qtree_fmt_operations *dqi_ops; /* Operations for entry manipulation */
|
||||||
};
|
};
|
||||||
|
|
||||||
int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot);
|
int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot);
|
||||||
|
|
Loading…
Reference in New Issue