diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/ecryptfs/file.c | 71 | ||||
| -rw-r--r-- | fs/isofs/rock.c | 13 | ||||
| -rw-r--r-- | fs/namei.c | 59 | ||||
| -rw-r--r-- | fs/open.c | 12 | ||||
| -rw-r--r-- | fs/overlayfs/super.c | 4 | ||||
| -rw-r--r-- | fs/splice.c | 3 | 
6 files changed, 110 insertions, 52 deletions
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index feef8a9c4de7..f02404052b7b 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -112,7 +112,6 @@ static int ecryptfs_readdir(struct file *file, struct dir_context *ctx)  		.sb = inode->i_sb,  	};  	lower_file = ecryptfs_file_to_lower(file); -	lower_file->f_pos = ctx->pos;  	rc = iterate_dir(lower_file, &buf.ctx);  	ctx->pos = buf.ctx.pos;  	if (rc < 0) @@ -223,14 +222,6 @@ static int ecryptfs_open(struct inode *inode, struct file *file)  	}  	ecryptfs_set_file_lower(  		file, ecryptfs_inode_to_private(inode)->lower_file); -	if (d_is_dir(ecryptfs_dentry)) { -		ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); -		mutex_lock(&crypt_stat->cs_mutex); -		crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); -		mutex_unlock(&crypt_stat->cs_mutex); -		rc = 0; -		goto out; -	}  	rc = read_or_initialize_metadata(ecryptfs_dentry);  	if (rc)  		goto out_put; @@ -247,6 +238,45 @@ out:  	return rc;  } +/** + * ecryptfs_dir_open + * @inode: inode speciying file to open + * @file: Structure to return filled in + * + * Opens the file specified by inode. + * + * Returns zero on success; non-zero otherwise + */ +static int ecryptfs_dir_open(struct inode *inode, struct file *file) +{ +	struct dentry *ecryptfs_dentry = file->f_path.dentry; +	/* Private value of ecryptfs_dentry allocated in +	 * ecryptfs_lookup() */ +	struct ecryptfs_file_info *file_info; +	struct file *lower_file; + +	/* Released in ecryptfs_release or end of function if failure */ +	file_info = kmem_cache_zalloc(ecryptfs_file_info_cache, GFP_KERNEL); +	ecryptfs_set_file_private(file, file_info); +	if (unlikely(!file_info)) { +		ecryptfs_printk(KERN_ERR, +				"Error attempting to allocate memory\n"); +		return -ENOMEM; +	} +	lower_file = dentry_open(ecryptfs_dentry_to_lower_path(ecryptfs_dentry), +				 file->f_flags, current_cred()); +	if (IS_ERR(lower_file)) { +		printk(KERN_ERR "%s: Error attempting to initialize " +			"the lower file for the dentry with name " +			"[%pd]; rc = [%ld]\n", __func__, +			ecryptfs_dentry, PTR_ERR(lower_file)); +		kmem_cache_free(ecryptfs_file_info_cache, file_info); +		return PTR_ERR(lower_file); +	} +	ecryptfs_set_file_lower(file, lower_file); +	return 0; +} +  static int ecryptfs_flush(struct file *file, fl_owner_t td)  {  	struct file *lower_file = ecryptfs_file_to_lower(file); @@ -267,6 +297,19 @@ static int ecryptfs_release(struct inode *inode, struct file *file)  	return 0;  } +static int ecryptfs_dir_release(struct inode *inode, struct file *file) +{ +	fput(ecryptfs_file_to_lower(file)); +	kmem_cache_free(ecryptfs_file_info_cache, +			ecryptfs_file_to_private(file)); +	return 0; +} + +static loff_t ecryptfs_dir_llseek(struct file *file, loff_t offset, int whence) +{ +	return vfs_llseek(ecryptfs_file_to_lower(file), offset, whence); +} +  static int  ecryptfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)  { @@ -346,20 +389,16 @@ const struct file_operations ecryptfs_dir_fops = {  #ifdef CONFIG_COMPAT  	.compat_ioctl = ecryptfs_compat_ioctl,  #endif -	.open = ecryptfs_open, -	.flush = ecryptfs_flush, -	.release = ecryptfs_release, +	.open = ecryptfs_dir_open, +	.release = ecryptfs_dir_release,  	.fsync = ecryptfs_fsync, -	.fasync = ecryptfs_fasync, -	.splice_read = generic_file_splice_read, -	.llseek = default_llseek, +	.llseek = ecryptfs_dir_llseek,  };  const struct file_operations ecryptfs_main_fops = {  	.llseek = generic_file_llseek,  	.read_iter = ecryptfs_read_update_atime,  	.write_iter = generic_file_write_iter, -	.iterate = ecryptfs_readdir,  	.unlocked_ioctl = ecryptfs_unlocked_ioctl,  #ifdef CONFIG_COMPAT  	.compat_ioctl = ecryptfs_compat_ioctl, diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index 5384ceb35b1c..98b3eb7d8eaf 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -203,6 +203,8 @@ int get_rock_ridge_filename(struct iso_directory_record *de,  	int retnamlen = 0;  	int truncate = 0;  	int ret = 0; +	char *p; +	int len;  	if (!ISOFS_SB(inode->i_sb)->s_rock)  		return 0; @@ -267,12 +269,17 @@ repeat:  					rr->u.NM.flags);  				break;  			} -			if ((strlen(retname) + rr->len - 5) >= 254) { +			len = rr->len - 5; +			if (retnamlen + len >= 254) {  				truncate = 1;  				break;  			} -			strncat(retname, rr->u.NM.name, rr->len - 5); -			retnamlen += rr->len - 5; +			p = memchr(rr->u.NM.name, '\0', len); +			if (unlikely(p)) +				len = p - rr->u.NM.name; +			memcpy(retname + retnamlen, rr->u.NM.name, len); +			retnamlen += len; +			retname[retnamlen] = '\0';  			break;  		case SIG('R', 'E'):  			kfree(rs.buffer); diff --git a/fs/namei.c b/fs/namei.c index 1d9ca2d5dff6..30145f8f21ed 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2267,6 +2267,33 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,  EXPORT_SYMBOL(vfs_path_lookup);  /** + * lookup_hash - lookup single pathname component on already hashed name + * @name:	name and hash to lookup + * @base:	base directory to lookup from + * + * The name must have been verified and hashed (see lookup_one_len()).  Using + * this after just full_name_hash() is unsafe. + * + * This function also doesn't check for search permission on base directory. + * + * Use lookup_one_len_unlocked() instead, unless you really know what you are + * doing. + * + * Do not hold i_mutex; this helper takes i_mutex if necessary. + */ +struct dentry *lookup_hash(const struct qstr *name, struct dentry *base) +{ +	struct dentry *ret; + +	ret = lookup_dcache(name, base, 0); +	if (!ret) +		ret = lookup_slow(name, base, 0); + +	return ret; +} +EXPORT_SYMBOL(lookup_hash); + +/**   * lookup_one_len - filesystem helper to lookup single pathname component   * @name:	pathname component to lookup   * @base:	base directory to lookup from @@ -2337,7 +2364,6 @@ struct dentry *lookup_one_len_unlocked(const char *name,  	struct qstr this;  	unsigned int c;  	int err; -	struct dentry *ret;  	this.name = name;  	this.len = len; @@ -2369,10 +2395,7 @@ struct dentry *lookup_one_len_unlocked(const char *name,  	if (err)  		return ERR_PTR(err); -	ret = lookup_dcache(&this, base, 0); -	if (!ret) -		ret = lookup_slow(&this, base, 0); -	return ret; +	return lookup_hash(&this, base);  }  EXPORT_SYMBOL(lookup_one_len_unlocked); @@ -2942,22 +2965,10 @@ no_open:  		dentry = lookup_real(dir, dentry, nd->flags);  		if (IS_ERR(dentry))  			return PTR_ERR(dentry); - -		if (create_error) { -			int open_flag = op->open_flag; - -			error = create_error; -			if ((open_flag & O_EXCL)) { -				if (!dentry->d_inode) -					goto out; -			} else if (!dentry->d_inode) { -				goto out; -			} else if ((open_flag & O_TRUNC) && -				   d_is_reg(dentry)) { -				goto out; -			} -			/* will fail later, go on to get the right error */ -		} +	} +	if (create_error && !dentry->d_inode) { +		error = create_error; +		goto out;  	}  looked_up:  	path->dentry = dentry; @@ -4213,7 +4224,11 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,  	bool new_is_dir = false;  	unsigned max_links = new_dir->i_sb->s_max_links; -	if (source == target) +	/* +	 * Check source == target. +	 * On overlayfs need to look at underlying inodes. +	 */ +	if (vfs_select_inode(old_dentry, 0) == vfs_select_inode(new_dentry, 0))  		return 0;  	error = may_delete(old_dir, old_dentry, is_dir); diff --git a/fs/open.c b/fs/open.c index 17cb6b1dab75..081d3d6df74b 100644 --- a/fs/open.c +++ b/fs/open.c @@ -840,16 +840,12 @@ EXPORT_SYMBOL(file_path);  int vfs_open(const struct path *path, struct file *file,  	     const struct cred *cred)  { -	struct dentry *dentry = path->dentry; -	struct inode *inode = dentry->d_inode; +	struct inode *inode = vfs_select_inode(path->dentry, file->f_flags); -	file->f_path = *path; -	if (dentry->d_flags & DCACHE_OP_SELECT_INODE) { -		inode = dentry->d_op->d_select_inode(dentry, file->f_flags); -		if (IS_ERR(inode)) -			return PTR_ERR(inode); -	} +	if (IS_ERR(inode)) +		return PTR_ERR(inode); +	file->f_path = *path;  	return do_dentry_open(file, inode, NULL, cred);  } diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 5d972e6cd3fe..791235e03d17 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -411,9 +411,7 @@ static inline struct dentry *ovl_lookup_real(struct dentry *dir,  {  	struct dentry *dentry; -	inode_lock(dir->d_inode); -	dentry = lookup_one_len(name->name, dir, name->len); -	inode_unlock(dir->d_inode); +	dentry = lookup_hash(name, dir);  	if (IS_ERR(dentry)) {  		if (PTR_ERR(dentry) == -ENOENT) diff --git a/fs/splice.c b/fs/splice.c index b018eb485019..dd9bf7e410d2 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -1143,6 +1143,9 @@ static long do_splice_to(struct file *in, loff_t *ppos,  	if (unlikely(ret < 0))  		return ret; +	if (unlikely(len > MAX_RW_COUNT)) +		len = MAX_RW_COUNT; +  	if (in->f_op->splice_read)  		splice_read = in->f_op->splice_read;  	else  | 
