diff options
Diffstat (limited to 'fs/isofs/inode.c')
| -rw-r--r-- | fs/isofs/inode.c | 203 | 
1 files changed, 109 insertions, 94 deletions
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index bfdeb82a53b..4556ce1af5b 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -20,22 +20,32 @@  #include <linux/statfs.h>  #include <linux/cdrom.h>  #include <linux/parser.h> +#include <linux/mpage.h> +#include <linux/user_namespace.h>  #include "isofs.h"  #include "zisofs.h"  #define BEQUIET -static int isofs_hashi(struct dentry *parent, struct qstr *qstr); -static int isofs_hash(struct dentry *parent, struct qstr *qstr); -static int isofs_dentry_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b); -static int isofs_dentry_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b); +static int isofs_hashi(const struct dentry *parent, struct qstr *qstr); +static int isofs_hash(const struct dentry *parent, struct qstr *qstr); +static int isofs_dentry_cmpi(const struct dentry *parent, +		const struct dentry *dentry, +		unsigned int len, const char *str, const struct qstr *name); +static int isofs_dentry_cmp(const struct dentry *parent, +		const struct dentry *dentry, +		unsigned int len, const char *str, const struct qstr *name);  #ifdef CONFIG_JOLIET -static int isofs_hashi_ms(struct dentry *parent, struct qstr *qstr); -static int isofs_hash_ms(struct dentry *parent, struct qstr *qstr); -static int isofs_dentry_cmpi_ms(struct dentry *dentry, struct qstr *a, struct qstr *b); -static int isofs_dentry_cmp_ms(struct dentry *dentry, struct qstr *a, struct qstr *b); +static int isofs_hashi_ms(const struct dentry *parent, struct qstr *qstr); +static int isofs_hash_ms(const struct dentry *parent, struct qstr *qstr); +static int isofs_dentry_cmpi_ms(const struct dentry *parent, +		const struct dentry *dentry, +		unsigned int len, const char *str, const struct qstr *name); +static int isofs_dentry_cmp_ms(const struct dentry *parent, +		const struct dentry *dentry, +		unsigned int len, const char *str, const struct qstr *name);  #endif  static void isofs_put_super(struct super_block *sb) @@ -65,11 +75,17 @@ static struct inode *isofs_alloc_inode(struct super_block *sb)  	return &ei->vfs_inode;  } -static void isofs_destroy_inode(struct inode *inode) +static void isofs_i_callback(struct rcu_head *head)  { +	struct inode *inode = container_of(head, struct inode, i_rcu);  	kmem_cache_free(isofs_inode_cachep, ISOFS_I(inode));  } +static void isofs_destroy_inode(struct inode *inode) +{ +	call_rcu(&inode->i_rcu, isofs_i_callback); +} +  static void init_once(void *foo)  {  	struct iso_inode_info *ei = foo; @@ -77,7 +93,7 @@ static void init_once(void *foo)  	inode_init_once(&ei->vfs_inode);  } -static int init_inodecache(void) +static int __init init_inodecache(void)  {  	isofs_inode_cachep = kmem_cache_create("isofs_inode_cache",  					sizeof(struct iso_inode_info), @@ -91,13 +107,19 @@ static int init_inodecache(void)  static void destroy_inodecache(void)  { +	/* +	 * Make sure all delayed rcu free inodes are flushed before we +	 * destroy cache. +	 */ +	rcu_barrier();  	kmem_cache_destroy(isofs_inode_cachep);  }  static int isofs_remount(struct super_block *sb, int *flags, char *data)  { -	/* we probably want a lot more here */ -	*flags |= MS_RDONLY; +	sync_filesystem(sb); +	if (!(*flags & MS_RDONLY)) +		return -EROFS;  	return 0;  } @@ -146,10 +168,10 @@ struct iso9660_options{  	unsigned char map;  	unsigned char check;  	unsigned int blocksize; -	mode_t fmode; -	mode_t dmode; -	gid_t gid; -	uid_t uid; +	umode_t fmode; +	umode_t dmode; +	kgid_t gid; +	kuid_t uid;  	char *iocharset;  	/* LVE */  	s32 session; @@ -160,7 +182,7 @@ struct iso9660_options{   * Compute the hash for the isofs name corresponding to the dentry.   */  static int -isofs_hash_common(struct dentry *dentry, struct qstr *qstr, int ms) +isofs_hash_common(struct qstr *qstr, int ms)  {  	const char *name;  	int len; @@ -181,7 +203,7 @@ isofs_hash_common(struct dentry *dentry, struct qstr *qstr, int ms)   * Compute the hash for the isofs name corresponding to the dentry.   */  static int -isofs_hashi_common(struct dentry *dentry, struct qstr *qstr, int ms) +isofs_hashi_common(struct qstr *qstr, int ms)  {  	const char *name;  	int len; @@ -206,100 +228,86 @@ isofs_hashi_common(struct dentry *dentry, struct qstr *qstr, int ms)  }  /* - * Case insensitive compare of two isofs names. + * Compare of two isofs names.   */ -static int isofs_dentry_cmpi_common(struct dentry *dentry, struct qstr *a, -				struct qstr *b, int ms) +static int isofs_dentry_cmp_common( +		unsigned int len, const char *str, +		const struct qstr *name, int ms, int ci)  {  	int alen, blen;  	/* A filename cannot end in '.' or we treat it like it has none */ -	alen = a->len; -	blen = b->len; +	alen = name->len; +	blen = len;  	if (ms) { -		while (alen && a->name[alen-1] == '.') +		while (alen && name->name[alen-1] == '.')  			alen--; -		while (blen && b->name[blen-1] == '.') +		while (blen && str[blen-1] == '.')  			blen--;  	}  	if (alen == blen) { -		if (strnicmp(a->name, b->name, alen) == 0) -			return 0; -	} -	return 1; -} - -/* - * Case sensitive compare of two isofs names. - */ -static int isofs_dentry_cmp_common(struct dentry *dentry, struct qstr *a, -					struct qstr *b, int ms) -{ -	int alen, blen; - -	/* A filename cannot end in '.' or we treat it like it has none */ -	alen = a->len; -	blen = b->len; -	if (ms) { -		while (alen && a->name[alen-1] == '.') -			alen--; -		while (blen && b->name[blen-1] == '.') -			blen--; -	} -	if (alen == blen) { -		if (strncmp(a->name, b->name, alen) == 0) -			return 0; +		if (ci) { +			if (strnicmp(name->name, str, alen) == 0) +				return 0; +		} else { +			if (strncmp(name->name, str, alen) == 0) +				return 0; +		}  	}  	return 1;  }  static int -isofs_hash(struct dentry *dentry, struct qstr *qstr) +isofs_hash(const struct dentry *dentry, struct qstr *qstr)  { -	return isofs_hash_common(dentry, qstr, 0); +	return isofs_hash_common(qstr, 0);  }  static int -isofs_hashi(struct dentry *dentry, struct qstr *qstr) +isofs_hashi(const struct dentry *dentry, struct qstr *qstr)  { -	return isofs_hashi_common(dentry, qstr, 0); +	return isofs_hashi_common(qstr, 0);  }  static int -isofs_dentry_cmp(struct dentry *dentry,struct qstr *a,struct qstr *b) +isofs_dentry_cmp(const struct dentry *parent, const struct dentry *dentry, +		unsigned int len, const char *str, const struct qstr *name)  { -	return isofs_dentry_cmp_common(dentry, a, b, 0); +	return isofs_dentry_cmp_common(len, str, name, 0, 0);  }  static int -isofs_dentry_cmpi(struct dentry *dentry,struct qstr *a,struct qstr *b) +isofs_dentry_cmpi(const struct dentry *parent, const struct dentry *dentry, +		unsigned int len, const char *str, const struct qstr *name)  { -	return isofs_dentry_cmpi_common(dentry, a, b, 0); +	return isofs_dentry_cmp_common(len, str, name, 0, 1);  }  #ifdef CONFIG_JOLIET  static int -isofs_hash_ms(struct dentry *dentry, struct qstr *qstr) +isofs_hash_ms(const struct dentry *dentry, struct qstr *qstr)  { -	return isofs_hash_common(dentry, qstr, 1); +	return isofs_hash_common(qstr, 1);  }  static int -isofs_hashi_ms(struct dentry *dentry, struct qstr *qstr) +isofs_hashi_ms(const struct dentry *dentry, struct qstr *qstr)  { -	return isofs_hashi_common(dentry, qstr, 1); +	return isofs_hashi_common(qstr, 1);  }  static int -isofs_dentry_cmp_ms(struct dentry *dentry,struct qstr *a,struct qstr *b) +isofs_dentry_cmp_ms(const struct dentry *parent, const struct dentry *dentry, +		unsigned int len, const char *str, const struct qstr *name)  { -	return isofs_dentry_cmp_common(dentry, a, b, 1); +	return isofs_dentry_cmp_common(len, str, name, 1, 0);  }  static int -isofs_dentry_cmpi_ms(struct dentry *dentry,struct qstr *a,struct qstr *b) +isofs_dentry_cmpi_ms(const struct dentry *parent, const struct dentry *dentry, +		unsigned int len, const char *str, const struct qstr *name)  { -	return isofs_dentry_cmpi_common(dentry, a, b, 1); +	return isofs_dentry_cmp_common(len, str, name, 1, 1);  }  #endif @@ -366,8 +374,8 @@ static int parse_options(char *options, struct iso9660_options *popt)  	popt->fmode = popt->dmode = ISOFS_INVALID_MODE;  	popt->uid_set = 0;  	popt->gid_set = 0; -	popt->gid = 0; -	popt->uid = 0; +	popt->gid = GLOBAL_ROOT_GID; +	popt->uid = GLOBAL_ROOT_UID;  	popt->iocharset = NULL;  	popt->utf8 = 0;  	popt->overriderockperm = 0; @@ -443,13 +451,17 @@ static int parse_options(char *options, struct iso9660_options *popt)  		case Opt_uid:  			if (match_int(&args[0], &option))  				return 0; -			popt->uid = option; +			popt->uid = make_kuid(current_user_ns(), option); +			if (!uid_valid(popt->uid)) +				return 0;  			popt->uid_set = 1;  			break;  		case Opt_gid:  			if (match_int(&args[0], &option))  				return 0; -			popt->gid = option; +			popt->gid = make_kgid(current_user_ns(), option); +			if (!gid_valid(popt->gid)) +				return 0;  			popt->gid_set = 1;  			break;  		case Opt_mode: @@ -752,15 +764,6 @@ root_found:  	 */  	s->s_maxbytes = 0x80000000000LL; -	/* -	 * The CDROM is read-only, has no nodes (devices) on it, and since -	 * all of the files appear to be owned by root, we really do not want -	 * to allow suid.  (suid or devices will not show up unless we have -	 * Rock Ridge extensions) -	 */ - -	s->s_flags |= MS_RDONLY /* | MS_NODEV | MS_NOSUID */; -  	/* Set this for reference. Its not currently used except on write  	   which we don't have .. */ @@ -846,7 +849,6 @@ root_found:  	sbi->s_utf8 = opt.utf8;  	sbi->s_nocompress = opt.nocompress;  	sbi->s_overriderockperm = opt.overriderockperm; -	mutex_init(&sbi->s_mutex);  	/*  	 * It would be incredibly stupid to allow people to mark every file  	 * on the disk as suid, so we merely allow them to set the default @@ -922,17 +924,20 @@ root_found:  		goto out_iput;  	} -	/* get the root dentry */ -	s->s_root = d_alloc_root(inode); -	if (!(s->s_root)) -		goto out_no_root; -  	table = 0;  	if (joliet_level)  		table += 2;  	if (opt.check == 'r')  		table++; -	s->s_root->d_op = &isofs_dentry_ops[table]; + +	s->s_d_op = &isofs_dentry_ops[table]; + +	/* get the root dentry */ +	s->s_root = d_make_root(inode); +	if (!(s->s_root)) { +		error = -ENOMEM; +		goto out_no_inode; +	}  	kfree(opt.iocharset); @@ -956,7 +961,7 @@ out_no_inode:  out_no_read:  	printk(KERN_WARNING "%s: bread failed, dev=%s, iso_blknum=%d, block=%d\n",  		__func__, s->s_id, iso_blknum, block); -	goto out_freesbi; +	goto out_freebh;  out_bad_zone_size:  	printk(KERN_WARNING "ISOFS: Bad logical zone size %ld\n",  		sbi->s_log_zone_size); @@ -971,6 +976,7 @@ out_unknown_format:  out_freebh:  	brelse(bh); +	brelse(pri_bh);  out_freesbi:  	kfree(opt.iocharset);  	kfree(sbi); @@ -1130,7 +1136,13 @@ struct buffer_head *isofs_bread(struct inode *inode, sector_t block)  static int isofs_readpage(struct file *file, struct page *page)  { -	return block_read_full_page(page,isofs_get_block); +	return mpage_readpage(page, isofs_get_block); +} + +static int isofs_readpages(struct file *file, struct address_space *mapping, +			struct list_head *pages, unsigned nr_pages) +{ +	return mpage_readpages(mapping, pages, nr_pages, isofs_get_block);  }  static sector_t _isofs_bmap(struct address_space *mapping, sector_t block) @@ -1140,7 +1152,7 @@ static sector_t _isofs_bmap(struct address_space *mapping, sector_t block)  static const struct address_space_operations isofs_aops = {  	.readpage = isofs_readpage, -	.sync_page = block_sync_page, +	.readpages = isofs_readpages,  	.bmap = _isofs_bmap  }; @@ -1302,7 +1314,7 @@ static int isofs_read_inode(struct inode *inode)  			inode->i_mode = S_IFDIR | sbi->s_dmode;  		else  			inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; -		inode->i_nlink = 1;	/* +		set_nlink(inode, 1);	/*  					 * Set to 1.  We know there are 2, but  					 * the find utility tries to optimize  					 * if it is 2, and it screws up.  It is @@ -1320,7 +1332,7 @@ static int isofs_read_inode(struct inode *inode)  			 */  			inode->i_mode = S_IFREG | S_IRUGO | S_IXUGO;  		} -		inode->i_nlink = 1; +		set_nlink(inode, 1);  	}  	inode->i_uid = sbi->s_uid;  	inode->i_gid = sbi->s_gid; @@ -1510,6 +1522,9 @@ struct inode *isofs_iget(struct super_block *sb,  static struct dentry *isofs_mount(struct file_system_type *fs_type,  	int flags, const char *dev_name, void *data)  { +	/* We don't support read-write mounts */ +	if (!(flags & MS_RDONLY)) +		return ERR_PTR(-EACCES);  	return mount_bdev(fs_type, flags, dev_name, data, isofs_fill_super);  } @@ -1520,6 +1535,8 @@ static struct file_system_type iso9660_fs_type = {  	.kill_sb	= kill_block_super,  	.fs_flags	= FS_REQUIRES_DEV,  }; +MODULE_ALIAS_FS("iso9660"); +MODULE_ALIAS("iso9660");  static int __init init_iso9660_fs(void)  { @@ -1557,5 +1574,3 @@ static void __exit exit_iso9660_fs(void)  module_init(init_iso9660_fs)  module_exit(exit_iso9660_fs)  MODULE_LICENSE("GPL"); -/* Actual filesystem name is iso9660, as requested in filesystems.c */ -MODULE_ALIAS("iso9660");  | 
