diff options
Diffstat (limited to 'fs/udf/namei.c')
| -rw-r--r-- | fs/udf/namei.c | 199 | 
1 files changed, 79 insertions, 120 deletions
diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 6d8dc02baeb..9737cba1357 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -27,7 +27,6 @@  #include <linux/errno.h>  #include <linux/mm.h>  #include <linux/slab.h> -#include <linux/smp_lock.h>  #include <linux/buffer_head.h>  #include <linux/sched.h>  #include <linux/crc-itu-t.h> @@ -228,10 +227,8 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,  		}  		if ((cfi->fileCharacteristics & FID_FILE_CHAR_PARENT) && -		    isdotdot) { -			brelse(epos.bh); -			return fi; -		} +		    isdotdot) +			goto out_ok;  		if (!lfi)  			continue; @@ -254,7 +251,7 @@ out_ok:  }  static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry, -				 struct nameidata *nd) +				 unsigned int flags)  {  	struct inode *inode = NULL;  	struct fileIdentDesc cfi; @@ -263,7 +260,6 @@ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,  	if (dentry->d_name.len > UDF_NAME_LEN - 2)  		return ERR_PTR(-ENAMETOOLONG); -	lock_kernel();  #ifdef UDF_RECOVERY  	/* temporary shorthand for specifying files by inode number */  	if (!strncmp(dentry->d_name.name, ".B=", 3)) { @@ -275,7 +271,6 @@ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,  		};  		inode = udf_iget(dir->i_sb, lb);  		if (!inode) { -			unlock_kernel();  			return ERR_PTR(-EACCES);  		}  	} else @@ -291,11 +286,9 @@ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,  		loc = lelb_to_cpu(cfi.icb.extLocation);  		inode = udf_iget(dir->i_sb, &loc);  		if (!inode) { -			unlock_kernel();  			return ERR_PTR(-EACCES);  		}  	} -	unlock_kernel();  	return d_splice_alias(inode, dentry);  } @@ -476,15 +469,19 @@ add:  				f_pos >> dir->i_sb->s_blocksize_bits, 1, err);  		if (!fibh->ebh)  			goto out_err; +		/* Extents could have been merged, invalidate our position */ +		brelse(epos.bh); +		epos.bh = NULL; +		epos.block = dinfo->i_location; +		epos.offset = udf_file_entry_alloc_offset(dir);  		if (!fibh->soffset) { -			if (udf_next_aext(dir, &epos, &eloc, &elen, 1) == -			    (EXT_RECORDED_ALLOCATED >> 30)) { -				block = eloc.logicalBlockNum + ((elen - 1) >> +			/* Find the freshly allocated block */ +			while (udf_next_aext(dir, &epos, &eloc, &elen, 1) == +				(EXT_RECORDED_ALLOCATED >> 30)) +				; +			block = eloc.logicalBlockNum + ((elen - 1) >>  					dir->i_sb->s_blocksize_bits); -			} else -				block++; -  			brelse(fibh->sbh);  			fibh->sbh = fibh->ebh;  			fi = (struct fileIdentDesc *)(fibh->sbh->b_data); @@ -553,8 +550,8 @@ static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi,  	return udf_write_fi(inode, cfi, fi, fibh, NULL, NULL);  } -static int udf_create(struct inode *dir, struct dentry *dentry, int mode, -		      struct nameidata *nd) +static int udf_create(struct inode *dir, struct dentry *dentry, umode_t mode, +		      bool excl)  {  	struct udf_fileident_bh fibh;  	struct inode *inode; @@ -562,10 +559,8 @@ static int udf_create(struct inode *dir, struct dentry *dentry, int mode,  	int err;  	struct udf_inode_info *iinfo; -	lock_kernel();  	inode = udf_new_inode(dir, mode, &err);  	if (!inode) { -		unlock_kernel();  		return err;  	} @@ -580,10 +575,8 @@ static int udf_create(struct inode *dir, struct dentry *dentry, int mode,  	fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);  	if (!fi) { -		inode->i_nlink--; -		mark_inode_dirty(inode); +		inode_dec_link_count(inode);  		iput(inode); -		unlock_kernel();  		return err;  	}  	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); @@ -596,13 +589,35 @@ static int udf_create(struct inode *dir, struct dentry *dentry, int mode,  	if (fibh.sbh != fibh.ebh)  		brelse(fibh.ebh);  	brelse(fibh.sbh); -	unlock_kernel();  	d_instantiate(dentry, inode);  	return 0;  } -static int udf_mknod(struct inode *dir, struct dentry *dentry, int mode, +static int udf_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) +{ +	struct inode *inode; +	struct udf_inode_info *iinfo; +	int err; + +	inode = udf_new_inode(dir, mode, &err); +	if (!inode) +		return err; + +	iinfo = UDF_I(inode); +	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) +		inode->i_data.a_ops = &udf_adinicb_aops; +	else +		inode->i_data.a_ops = &udf_aops; +	inode->i_op = &udf_file_inode_operations; +	inode->i_fop = &udf_file_operations; +	mark_inode_dirty(inode); + +	d_tmpfile(dentry, inode); +	return 0; +} + +static int udf_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,  		     dev_t rdev)  {  	struct inode *inode; @@ -614,7 +629,6 @@ static int udf_mknod(struct inode *dir, struct dentry *dentry, int mode,  	if (!old_valid_dev(rdev))  		return -EINVAL; -	lock_kernel();  	err = -EIO;  	inode = udf_new_inode(dir, mode, &err);  	if (!inode) @@ -624,10 +638,8 @@ static int udf_mknod(struct inode *dir, struct dentry *dentry, int mode,  	init_special_inode(inode, mode, rdev);  	fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);  	if (!fi) { -		inode->i_nlink--; -		mark_inode_dirty(inode); +		inode_dec_link_count(inode);  		iput(inode); -		unlock_kernel();  		return err;  	}  	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); @@ -646,11 +658,10 @@ static int udf_mknod(struct inode *dir, struct dentry *dentry, int mode,  	err = 0;  out: -	unlock_kernel();  	return err;  } -static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int udf_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)  {  	struct inode *inode;  	struct udf_fileident_bh fibh; @@ -659,11 +670,6 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode)  	struct udf_inode_info *dinfo = UDF_I(dir);  	struct udf_inode_info *iinfo; -	lock_kernel(); -	err = -EMLINK; -	if (dir->i_nlink >= (256 << sizeof(dir->i_nlink)) - 1) -		goto out; -  	err = -EIO;  	inode = udf_new_inode(dir, S_IFDIR | mode, &err);  	if (!inode) @@ -674,12 +680,11 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode)  	inode->i_fop = &udf_dir_operations;  	fi = udf_add_entry(inode, NULL, &fibh, &cfi, &err);  	if (!fi) { -		inode->i_nlink--; -		mark_inode_dirty(inode); +		inode_dec_link_count(inode);  		iput(inode);  		goto out;  	} -	inode->i_nlink = 2; +	set_nlink(inode, 2);  	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);  	cfi.icb.extLocation = cpu_to_lelb(dinfo->i_location);  	*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse = @@ -692,7 +697,7 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode)  	fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);  	if (!fi) { -		inode->i_nlink = 0; +		clear_nlink(inode);  		mark_inode_dirty(inode);  		iput(inode);  		goto out; @@ -712,7 +717,6 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode)  	err = 0;  out: -	unlock_kernel();  	return err;  } @@ -794,7 +798,6 @@ static int udf_rmdir(struct inode *dir, struct dentry *dentry)  	struct kernel_lb_addr tloc;  	retval = -ENOENT; -	lock_kernel();  	fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi);  	if (!fi)  		goto out; @@ -810,9 +813,8 @@ static int udf_rmdir(struct inode *dir, struct dentry *dentry)  	if (retval)  		goto end_rmdir;  	if (inode->i_nlink != 2) -		udf_warning(inode->i_sb, "udf_rmdir", -			    "empty directory has nlink != 2 (%d)", -			    inode->i_nlink); +		udf_warn(inode->i_sb, "empty directory has nlink != 2 (%d)\n", +			 inode->i_nlink);  	clear_nlink(inode);  	inode->i_size = 0;  	inode_dec_link_count(dir); @@ -826,7 +828,6 @@ end_rmdir:  	brelse(fibh.sbh);  out: -	unlock_kernel();  	return retval;  } @@ -840,7 +841,6 @@ static int udf_unlink(struct inode *dir, struct dentry *dentry)  	struct kernel_lb_addr tloc;  	retval = -ENOENT; -	lock_kernel();  	fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi);  	if (!fi)  		goto out; @@ -853,7 +853,7 @@ static int udf_unlink(struct inode *dir, struct dentry *dentry)  	if (!inode->i_nlink) {  		udf_debug("Deleting nonexistent file (%lu), %d\n",  			  inode->i_ino, inode->i_nlink); -		inode->i_nlink = 1; +		set_nlink(inode, 1);  	}  	retval = udf_delete_entry(dir, fi, &fibh, &cfi);  	if (retval) @@ -870,7 +870,6 @@ end_unlink:  	brelse(fibh.sbh);  out: -	unlock_kernel();  	return retval;  } @@ -890,21 +889,21 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,  	int block;  	unsigned char *name = NULL;  	int namelen; -	struct buffer_head *bh;  	struct udf_inode_info *iinfo; +	struct super_block *sb = dir->i_sb; -	lock_kernel();  	inode = udf_new_inode(dir, S_IFLNK | S_IRWXUGO, &err);  	if (!inode)  		goto out; +	iinfo = UDF_I(inode); +	down_write(&iinfo->i_data_sem);  	name = kmalloc(UDF_NAME_LEN, GFP_NOFS);  	if (!name) {  		err = -ENOMEM;  		goto out_no_entry;  	} -	iinfo = UDF_I(inode);  	inode->i_data.a_ops = &udf_symlink_aops;  	inode->i_op = &udf_symlink_inode_operations; @@ -912,7 +911,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,  		struct kernel_lb_addr eloc;  		uint32_t bsize; -		block = udf_new_block(inode->i_sb, inode, +		block = udf_new_block(sb, inode,  				iinfo->i_location.partitionReferenceNum,  				iinfo->i_location.logicalBlockNum, &err);  		if (!block) @@ -923,17 +922,17 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,  		eloc.logicalBlockNum = block;  		eloc.partitionReferenceNum =  				iinfo->i_location.partitionReferenceNum; -		bsize = inode->i_sb->s_blocksize; +		bsize = sb->s_blocksize;  		iinfo->i_lenExtents = bsize;  		udf_add_aext(inode, &epos, &eloc, bsize, 0);  		brelse(epos.bh); -		block = udf_get_pblock(inode->i_sb, block, +		block = udf_get_pblock(sb, block,  				iinfo->i_location.partitionReferenceNum,  				0); -		epos.bh = udf_tgetblk(inode->i_sb, block); +		epos.bh = udf_tgetblk(sb, block);  		lock_buffer(epos.bh); -		memset(epos.bh->b_data, 0x00, inode->i_sb->s_blocksize); +		memset(epos.bh->b_data, 0x00, bsize);  		set_buffer_uptodate(epos.bh);  		unlock_buffer(epos.bh);  		mark_buffer_dirty_inode(epos.bh, inode); @@ -941,7 +940,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,  	} else  		ea = iinfo->i_ext.i_data + iinfo->i_lenEAttr; -	eoffset = inode->i_sb->s_blocksize - udf_ext0_offset(inode); +	eoffset = sb->s_blocksize - udf_ext0_offset(inode);  	pc = (struct pathComponent *)ea;  	if (*symname == '/') { @@ -981,7 +980,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,  		}  		if (pc->componentType == 5) { -			namelen = udf_put_filename(inode->i_sb, compstart, name, +			namelen = udf_put_filename(sb, compstart, name,  						   symname - compstart);  			if (!namelen)  				goto out_no_entry; @@ -1011,27 +1010,16 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,  	else  		udf_truncate_tail_extent(inode);  	mark_inode_dirty(inode); +	up_write(&iinfo->i_data_sem);  	fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);  	if (!fi)  		goto out_no_entry; -	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); +	cfi.icb.extLength = cpu_to_le32(sb->s_blocksize);  	cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location); -	bh = UDF_SB(inode->i_sb)->s_lvid_bh; -	if (bh) { -		struct logicalVolIntegrityDesc *lvid = -				(struct logicalVolIntegrityDesc *)bh->b_data; -		struct logicalVolHeaderDesc *lvhd; -		uint64_t uniqueID; -		lvhd = (struct logicalVolHeaderDesc *) -				lvid->logicalVolContentsUse; -		uniqueID = le64_to_cpu(lvhd->uniqueID); +	if (UDF_SB(inode->i_sb)->s_lvid_bh) {  		*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse = -			cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL); -		if (!(++uniqueID & 0x00000000FFFFFFFFUL)) -			uniqueID += 16; -		lvhd->uniqueID = cpu_to_le64(uniqueID); -		mark_buffer_dirty(bh); +			cpu_to_le32(lvid_get_unique_id(sb));  	}  	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);  	if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) @@ -1044,10 +1032,10 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,  out:  	kfree(name); -	unlock_kernel();  	return err;  out_no_entry: +	up_write(&iinfo->i_data_sem);  	inode_dec_link_count(inode);  	iput(inode);  	goto out; @@ -1060,36 +1048,16 @@ static int udf_link(struct dentry *old_dentry, struct inode *dir,  	struct udf_fileident_bh fibh;  	struct fileIdentDesc cfi, *fi;  	int err; -	struct buffer_head *bh; - -	lock_kernel(); -	if (inode->i_nlink >= (256 << sizeof(inode->i_nlink)) - 1) { -		unlock_kernel(); -		return -EMLINK; -	}  	fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);  	if (!fi) { -		unlock_kernel();  		return err;  	}  	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);  	cfi.icb.extLocation = cpu_to_lelb(UDF_I(inode)->i_location); -	bh = UDF_SB(inode->i_sb)->s_lvid_bh; -	if (bh) { -		struct logicalVolIntegrityDesc *lvid = -				(struct logicalVolIntegrityDesc *)bh->b_data; -		struct logicalVolHeaderDesc *lvhd; -		uint64_t uniqueID; -		lvhd = (struct logicalVolHeaderDesc *) -				(lvid->logicalVolContentsUse); -		uniqueID = le64_to_cpu(lvhd->uniqueID); +	if (UDF_SB(inode->i_sb)->s_lvid_bh) {  		*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse = -			cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL); -		if (!(++uniqueID & 0x00000000FFFFFFFFUL)) -			uniqueID += 16; -		lvhd->uniqueID = cpu_to_le64(uniqueID); -		mark_buffer_dirty(bh); +			cpu_to_le32(lvid_get_unique_id(inode->i_sb));  	}  	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);  	if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) @@ -1103,7 +1071,6 @@ static int udf_link(struct dentry *old_dentry, struct inode *dir,  	mark_inode_dirty(inode);  	ihold(inode);  	d_instantiate(dentry, inode); -	unlock_kernel();  	return 0;  } @@ -1124,7 +1091,6 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,  	struct kernel_lb_addr tloc;  	struct udf_inode_info *old_iinfo = UDF_I(old_inode); -	lock_kernel();  	ofi = udf_find_entry(old_dir, &old_dentry->d_name, &ofibh, &ocfi);  	if (ofi) {  		if (ofibh.sbh != ofibh.ebh) @@ -1174,12 +1140,6 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,  		if (udf_get_lb_pblock(old_inode->i_sb, &tloc, 0) !=  				old_dir->i_ino)  			goto end_rename; - -		retval = -EMLINK; -		if (!new_inode && -			new_dir->i_nlink >= -				(256 << sizeof(new_dir->i_nlink)) - 1) -			goto end_rename;  	}  	if (!nfi) {  		nfi = udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi, @@ -1248,7 +1208,6 @@ end_rename:  			brelse(nfibh.ebh);  		brelse(nfibh.sbh);  	} -	unlock_kernel();  	return retval;  } @@ -1257,11 +1216,10 @@ static struct dentry *udf_get_parent(struct dentry *child)  {  	struct kernel_lb_addr tloc;  	struct inode *inode = NULL; -	struct qstr dotdot = {.name = "..", .len = 2}; +	struct qstr dotdot = QSTR_INIT("..", 2);  	struct fileIdentDesc cfi;  	struct udf_fileident_bh fibh; -	lock_kernel();  	if (!udf_find_entry(child->d_inode, &dotdot, &fibh, &cfi))  		goto out_unlock; @@ -1273,11 +1231,9 @@ static struct dentry *udf_get_parent(struct dentry *child)  	inode = udf_iget(child->d_inode->i_sb, &tloc);  	if (!inode)  		goto out_unlock; -	unlock_kernel();  	return d_obtain_alias(inode);  out_unlock: -	unlock_kernel();  	return ERR_PTR(-EACCES);  } @@ -1327,31 +1283,33 @@ static struct dentry *udf_fh_to_parent(struct super_block *sb,  				 fid->udf.parent_partref,  				 fid->udf.parent_generation);  } -static int udf_encode_fh(struct dentry *de, __u32 *fh, int *lenp, -			 int connectable) +static int udf_encode_fh(struct inode *inode, __u32 *fh, int *lenp, +			 struct inode *parent)  {  	int len = *lenp; -	struct inode *inode =  de->d_inode;  	struct kernel_lb_addr location = UDF_I(inode)->i_location;  	struct fid *fid = (struct fid *)fh;  	int type = FILEID_UDF_WITHOUT_PARENT; -	if (len < 3 || (connectable && len < 5)) -		return 255; +	if (parent && (len < 5)) { +		*lenp = 5; +		return FILEID_INVALID; +	} else if (len < 3) { +		*lenp = 3; +		return FILEID_INVALID; +	}  	*lenp = 3;  	fid->udf.block = location.logicalBlockNum;  	fid->udf.partref = location.partitionReferenceNum; +	fid->udf.parent_partref = 0;  	fid->udf.generation = inode->i_generation; -	if (connectable && !S_ISDIR(inode->i_mode)) { -		spin_lock(&de->d_lock); -		inode = de->d_parent->d_inode; -		location = UDF_I(inode)->i_location; +	if (parent) { +		location = UDF_I(parent)->i_location;  		fid->udf.parent_block = location.logicalBlockNum;  		fid->udf.parent_partref = location.partitionReferenceNum;  		fid->udf.parent_generation = inode->i_generation; -		spin_unlock(&de->d_lock);  		*lenp = 5;  		type = FILEID_UDF_WITH_PARENT;  	} @@ -1376,6 +1334,7 @@ const struct inode_operations udf_dir_inode_operations = {  	.rmdir				= udf_rmdir,  	.mknod				= udf_mknod,  	.rename				= udf_rename, +	.tmpfile			= udf_tmpfile,  };  const struct inode_operations udf_symlink_inode_operations = {  	.readlink	= generic_readlink,  | 
