mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-03 18:20:25 +02:00 
			
		
		
		
	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
					
				
					 11 changed files with 196 additions and 201 deletions
				
			
		| 
						 | 
				
			
			@ -82,7 +82,7 @@ struct ocfs2_quota_chunk {
 | 
			
		|||
extern struct kmem_cache *ocfs2_dquot_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_super *osb, int slot_num);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -123,7 +123,7 @@ static int ocfs2_global_is_id(void *dp, struct dquot *dquot)
 | 
			
		|||
		      dquot->dq_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct qtree_fmt_operations ocfs2_global_ops = {
 | 
			
		||||
const struct qtree_fmt_operations ocfs2_global_ops = {
 | 
			
		||||
	.mem2disk_dqblk = ocfs2_global_mem2diskdqb,
 | 
			
		||||
	.disk2mem_dqblk = ocfs2_global_disk2memdqb,
 | 
			
		||||
	.is_id = ocfs2_global_is_id,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2924,4 +2924,4 @@ static int __init dquot_init(void)
 | 
			
		|||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
module_init(dquot_init);
 | 
			
		||||
fs_initcall(dquot_init);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,5 @@
 | 
			
		|||
 | 
			
		||||
#include <linux/cred.h>
 | 
			
		||||
#include <linux/init.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/kernel.h>
 | 
			
		||||
#include <linux/quotaops.h>
 | 
			
		||||
#include <linux/sched.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -105,5 +103,4 @@ static int __init quota_init(void)
 | 
			
		|||
		       "VFS: Failed to create quota netlink interface.\n");
 | 
			
		||||
	return 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module_init(quota_init);
 | 
			
		||||
fs_initcall(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 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,
 | 
			
		||||
	.disk2mem_dqblk = v2r0_disk2memdqb,
 | 
			
		||||
	.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,
 | 
			
		||||
	.disk2mem_dqblk = v2r1_disk2memdqb,
 | 
			
		||||
	.is_id = v2r1_is_id,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -447,9 +447,6 @@ static void udf_table_free_blocks(struct super_block *sb,
 | 
			
		|||
		 */
 | 
			
		||||
 | 
			
		||||
		int adsize;
 | 
			
		||||
		struct short_ad *sad = NULL;
 | 
			
		||||
		struct long_ad *lad = NULL;
 | 
			
		||||
		struct allocExtDesc *aed;
 | 
			
		||||
 | 
			
		||||
		eloc.logicalBlockNum = start;
 | 
			
		||||
		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) {
 | 
			
		||||
			unsigned char *sptr, *dptr;
 | 
			
		||||
			int loffset;
 | 
			
		||||
 | 
			
		||||
			brelse(oepos.bh);
 | 
			
		||||
			oepos = epos;
 | 
			
		||||
 | 
			
		||||
			/* Steal a block from the extent being free'd */
 | 
			
		||||
			epos.block.logicalBlockNum = eloc.logicalBlockNum;
 | 
			
		||||
			udf_setup_indirect_aext(table, eloc.logicalBlockNum,
 | 
			
		||||
						&epos);
 | 
			
		||||
 | 
			
		||||
			eloc.logicalBlockNum++;
 | 
			
		||||
			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 */
 | 
			
		||||
		if (elen) {
 | 
			
		||||
			udf_write_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);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (elen)
 | 
			
		||||
			__udf_add_aext(table, &epos, &eloc, elen, 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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,
 | 
			
		||||
			     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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1586,6 +1586,13 @@ static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_
 | 
			
		|||
		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.
 | 
			
		||||
 *   @block		First block of first extent of the sequence.
 | 
			
		||||
| 
						 | 
				
			
			@ -1610,6 +1617,7 @@ static noinline int udf_process_sequence(
 | 
			
		|||
	uint16_t ident;
 | 
			
		||||
	long next_s = 0, next_e = 0;
 | 
			
		||||
	int ret;
 | 
			
		||||
	unsigned int indirections = 0;
 | 
			
		||||
 | 
			
		||||
	memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1680,6 +1688,12 @@ static noinline int udf_process_sequence(
 | 
			
		|||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		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;
 | 
			
		||||
			if (next_e) {
 | 
			
		||||
				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 int8_t inode_bmap(struct inode *, sector_t, struct extent_position *,
 | 
			
		||||
			 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 *,
 | 
			
		||||
			struct kernel_lb_addr *, uint32_t, int);
 | 
			
		||||
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)
 | 
			
		||||
			utf_o->u_name[utf_o->u_len++] = (uint8_t)c;
 | 
			
		||||
		else if (c < 0x800U) {
 | 
			
		||||
			if (utf_o->u_len > (UDF_NAME_LEN - 4))
 | 
			
		||||
				break;
 | 
			
		||||
			utf_o->u_name[utf_o->u_len++] =
 | 
			
		||||
						(uint8_t)(0xc0 | (c >> 6));
 | 
			
		||||
			utf_o->u_name[utf_o->u_len++] =
 | 
			
		||||
						(uint8_t)(0x80 | (c & 0x3f));
 | 
			
		||||
		} else {
 | 
			
		||||
			if (utf_o->u_len > (UDF_NAME_LEN - 5))
 | 
			
		||||
				break;
 | 
			
		||||
			utf_o->u_name[utf_o->u_len++] =
 | 
			
		||||
						(uint8_t)(0xe0 | (c >> 12));
 | 
			
		||||
			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)
 | 
			
		||||
{
 | 
			
		||||
	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);
 | 
			
		||||
	ocu[0] = 8;
 | 
			
		||||
	max_val = 0xffU;
 | 
			
		||||
	u_ch = 1;
 | 
			
		||||
 | 
			
		||||
try_again:
 | 
			
		||||
	u_len = 0U;
 | 
			
		||||
	utf_char = 0U;
 | 
			
		||||
	utf_cnt = 0U;
 | 
			
		||||
	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];
 | 
			
		||||
 | 
			
		||||
		/* 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) {
 | 
			
		||||
				max_val = 0xffffU;
 | 
			
		||||
				ocu[0] = (uint8_t)0x10U;
 | 
			
		||||
				u_ch = 2;
 | 
			
		||||
				goto try_again;
 | 
			
		||||
			}
 | 
			
		||||
			goto error_out;
 | 
			
		||||
| 
						 | 
				
			
			@ -277,7 +287,7 @@ static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o,
 | 
			
		|||
			c = (c << 8) | ocu[i++];
 | 
			
		||||
 | 
			
		||||
		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? */
 | 
			
		||||
		if (len >= 0)
 | 
			
		||||
			utf_o->u_len += len;
 | 
			
		||||
| 
						 | 
				
			
			@ -295,15 +305,19 @@ static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni,
 | 
			
		|||
	int len;
 | 
			
		||||
	unsigned i, max_val;
 | 
			
		||||
	uint16_t uni_char;
 | 
			
		||||
	int u_len;
 | 
			
		||||
	int u_len, u_ch;
 | 
			
		||||
 | 
			
		||||
	memset(ocu, 0, sizeof(dstring) * length);
 | 
			
		||||
	ocu[0] = 8;
 | 
			
		||||
	max_val = 0xffU;
 | 
			
		||||
	u_ch = 1;
 | 
			
		||||
 | 
			
		||||
try_again:
 | 
			
		||||
	u_len = 0U;
 | 
			
		||||
	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);
 | 
			
		||||
		if (!len)
 | 
			
		||||
			continue;
 | 
			
		||||
| 
						 | 
				
			
			@ -316,6 +330,7 @@ static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni,
 | 
			
		|||
		if (uni_char > max_val) {
 | 
			
		||||
			max_val = 0xffffU;
 | 
			
		||||
			ocu[0] = (uint8_t)0x10U;
 | 
			
		||||
			u_ch = 2;
 | 
			
		||||
			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_usable_bs;	/* Space usable in block for quota data */
 | 
			
		||||
	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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue