Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs fixes from Al Viro: "Overlayfs fixes from Miklos, assorted fixes from me. Stable fodder of varying severity, all sat in -next for a while" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: ovl: ignore permissions on underlying lookup vfs: add lookup_hash() helper vfs: rename: check backing inode being equal vfs: add vfs_select_inode() helper get_rock_ridge_filename(): handle malformed NM entries ecryptfs: fix handling of directory opening atomic_open(): fix the handling of create_error fix the copy vs. map logics in blk_rq_map_user_iov() do_splice_to(): cap the size before passing to ->splice_read()
This commit is contained in:
commit
6ba5b85fd4
|
@ -9,24 +9,6 @@
|
|||
|
||||
#include "blk.h"
|
||||
|
||||
static bool iovec_gap_to_prv(struct request_queue *q,
|
||||
struct iovec *prv, struct iovec *cur)
|
||||
{
|
||||
unsigned long prev_end;
|
||||
|
||||
if (!queue_virt_boundary(q))
|
||||
return false;
|
||||
|
||||
if (prv->iov_base == NULL && prv->iov_len == 0)
|
||||
/* prv is not set - don't check */
|
||||
return false;
|
||||
|
||||
prev_end = (unsigned long)(prv->iov_base + prv->iov_len);
|
||||
|
||||
return (((unsigned long)cur->iov_base & queue_virt_boundary(q)) ||
|
||||
prev_end & queue_virt_boundary(q));
|
||||
}
|
||||
|
||||
int blk_rq_append_bio(struct request_queue *q, struct request *rq,
|
||||
struct bio *bio)
|
||||
{
|
||||
|
@ -125,31 +107,18 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
|
|||
struct rq_map_data *map_data,
|
||||
const struct iov_iter *iter, gfp_t gfp_mask)
|
||||
{
|
||||
struct iovec iov, prv = {.iov_base = NULL, .iov_len = 0};
|
||||
bool copy = (q->dma_pad_mask & iter->count) || map_data;
|
||||
bool copy = false;
|
||||
unsigned long align = q->dma_pad_mask | queue_dma_alignment(q);
|
||||
struct bio *bio = NULL;
|
||||
struct iov_iter i;
|
||||
int ret;
|
||||
|
||||
if (!iter || !iter->count)
|
||||
return -EINVAL;
|
||||
|
||||
iov_for_each(iov, i, *iter) {
|
||||
unsigned long uaddr = (unsigned long) iov.iov_base;
|
||||
|
||||
if (!iov.iov_len)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Keep going so we check length of all segments
|
||||
*/
|
||||
if ((uaddr & queue_dma_alignment(q)) ||
|
||||
iovec_gap_to_prv(q, &prv, &iov))
|
||||
copy = true;
|
||||
|
||||
prv.iov_base = iov.iov_base;
|
||||
prv.iov_len = iov.iov_len;
|
||||
}
|
||||
if (map_data)
|
||||
copy = true;
|
||||
else if (iov_iter_alignment(iter) & align)
|
||||
copy = true;
|
||||
else if (queue_virt_boundary(q))
|
||||
copy = queue_virt_boundary(q) & iov_iter_gap_alignment(iter);
|
||||
|
||||
i = *iter;
|
||||
do {
|
||||
|
|
|
@ -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 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
|
|||
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,
|
||||
|
|
|
@ -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 @@ int get_rock_ridge_filename(struct iso_directory_record *de,
|
|||
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);
|
||||
|
|
59
fs/namei.c
59
fs/namei.c
|
@ -2266,6 +2266,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
|
||||
|
@ -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 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
|
|||
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);
|
||||
|
|
12
fs/open.c
12
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);
|
||||
|
||||
if (IS_ERR(inode))
|
||||
return PTR_ERR(inode);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return do_dentry_open(file, inode, NULL, cred);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -565,4 +565,16 @@ static inline struct dentry *d_real(struct dentry *dentry)
|
|||
return dentry;
|
||||
}
|
||||
|
||||
static inline struct inode *vfs_select_inode(struct dentry *dentry,
|
||||
unsigned open_flags)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
|
||||
if (inode && unlikely(dentry->d_flags & DCACHE_OP_SELECT_INODE))
|
||||
inode = dentry->d_op->d_select_inode(dentry, open_flags);
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
||||
|
||||
#endif /* __LINUX_DCACHE_H */
|
||||
|
|
|
@ -79,6 +79,8 @@ extern int kern_path_mountpoint(int, const char *, struct path *, unsigned int);
|
|||
|
||||
extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
|
||||
extern struct dentry *lookup_one_len_unlocked(const char *, struct dentry *, int);
|
||||
struct qstr;
|
||||
extern struct dentry *lookup_hash(const struct qstr *, struct dentry *);
|
||||
|
||||
extern int follow_down_one(struct path *);
|
||||
extern int follow_down(struct path *);
|
||||
|
|
|
@ -87,6 +87,7 @@ size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i);
|
|||
size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i);
|
||||
size_t iov_iter_zero(size_t bytes, struct iov_iter *);
|
||||
unsigned long iov_iter_alignment(const struct iov_iter *i);
|
||||
unsigned long iov_iter_gap_alignment(const struct iov_iter *i);
|
||||
void iov_iter_init(struct iov_iter *i, int direction, const struct iovec *iov,
|
||||
unsigned long nr_segs, size_t count);
|
||||
void iov_iter_kvec(struct iov_iter *i, int direction, const struct kvec *kvec,
|
||||
|
|
|
@ -569,6 +569,25 @@ unsigned long iov_iter_alignment(const struct iov_iter *i)
|
|||
}
|
||||
EXPORT_SYMBOL(iov_iter_alignment);
|
||||
|
||||
unsigned long iov_iter_gap_alignment(const struct iov_iter *i)
|
||||
{
|
||||
unsigned long res = 0;
|
||||
size_t size = i->count;
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
iterate_all_kinds(i, size, v,
|
||||
(res |= (!res ? 0 : (unsigned long)v.iov_base) |
|
||||
(size != v.iov_len ? size : 0), 0),
|
||||
(res |= (!res ? 0 : (unsigned long)v.bv_offset) |
|
||||
(size != v.bv_len ? size : 0)),
|
||||
(res |= (!res ? 0 : (unsigned long)v.iov_base) |
|
||||
(size != v.iov_len ? size : 0))
|
||||
);
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(iov_iter_gap_alignment);
|
||||
|
||||
ssize_t iov_iter_get_pages(struct iov_iter *i,
|
||||
struct page **pages, size_t maxsize, unsigned maxpages,
|
||||
size_t *start)
|
||||
|
|
Loading…
Reference in New Issue
Block a user