Merge branch 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull misc vfs updates from Al Viro: - bmap series from cmaiolino - getting rid of convolutions in copy_mount_options() (use a couple of copy_from_user() instead of the __get_user() crap) * 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: saner copy_mount_options() fibmap: Reject negative block numbers fibmap: Use bmap instead of ->bmap method in ioctl_fibmap ecryptfs: drop direct calls to ->bmap cachefiles: drop direct usage of ->bmap method. fs: Enable bmap() function to properly return errors
This commit is contained in:
commit
236f453294
|
@ -364,7 +364,7 @@ static int read_page(struct file *file, unsigned long index,
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
struct buffer_head *bh;
|
struct buffer_head *bh;
|
||||||
sector_t block;
|
sector_t block, blk_cur;
|
||||||
|
|
||||||
pr_debug("read bitmap file (%dB @ %llu)\n", (int)PAGE_SIZE,
|
pr_debug("read bitmap file (%dB @ %llu)\n", (int)PAGE_SIZE,
|
||||||
(unsigned long long)index << PAGE_SHIFT);
|
(unsigned long long)index << PAGE_SHIFT);
|
||||||
|
@ -375,17 +375,21 @@ static int read_page(struct file *file, unsigned long index,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
attach_page_buffers(page, bh);
|
attach_page_buffers(page, bh);
|
||||||
block = index << (PAGE_SHIFT - inode->i_blkbits);
|
blk_cur = index << (PAGE_SHIFT - inode->i_blkbits);
|
||||||
while (bh) {
|
while (bh) {
|
||||||
|
block = blk_cur;
|
||||||
|
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
bh->b_blocknr = 0;
|
bh->b_blocknr = 0;
|
||||||
else {
|
else {
|
||||||
bh->b_blocknr = bmap(inode, block);
|
ret = bmap(inode, &block);
|
||||||
if (bh->b_blocknr == 0) {
|
if (ret || !block) {
|
||||||
/* Cannot use this file! */
|
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
|
bh->b_blocknr = 0;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bh->b_blocknr = block;
|
||||||
bh->b_bdev = inode->i_sb->s_bdev;
|
bh->b_bdev = inode->i_sb->s_bdev;
|
||||||
if (count < (1<<inode->i_blkbits))
|
if (count < (1<<inode->i_blkbits))
|
||||||
count = 0;
|
count = 0;
|
||||||
|
@ -399,7 +403,7 @@ static int read_page(struct file *file, unsigned long index,
|
||||||
set_buffer_mapped(bh);
|
set_buffer_mapped(bh);
|
||||||
submit_bh(REQ_OP_READ, 0, bh);
|
submit_bh(REQ_OP_READ, 0, bh);
|
||||||
}
|
}
|
||||||
block++;
|
blk_cur++;
|
||||||
bh = bh->b_this_page;
|
bh = bh->b_this_page;
|
||||||
}
|
}
|
||||||
page->index = index;
|
page->index = index;
|
||||||
|
|
|
@ -396,7 +396,7 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op,
|
||||||
struct cachefiles_object *object;
|
struct cachefiles_object *object;
|
||||||
struct cachefiles_cache *cache;
|
struct cachefiles_cache *cache;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
sector_t block0, block;
|
sector_t block;
|
||||||
unsigned shift;
|
unsigned shift;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -412,7 +412,6 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op,
|
||||||
|
|
||||||
inode = d_backing_inode(object->backer);
|
inode = d_backing_inode(object->backer);
|
||||||
ASSERT(S_ISREG(inode->i_mode));
|
ASSERT(S_ISREG(inode->i_mode));
|
||||||
ASSERT(inode->i_mapping->a_ops->bmap);
|
|
||||||
ASSERT(inode->i_mapping->a_ops->readpages);
|
ASSERT(inode->i_mapping->a_ops->readpages);
|
||||||
|
|
||||||
/* calculate the shift required to use bmap */
|
/* calculate the shift required to use bmap */
|
||||||
|
@ -428,12 +427,14 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op,
|
||||||
* enough for this as it doesn't indicate errors, but it's all we've
|
* enough for this as it doesn't indicate errors, but it's all we've
|
||||||
* got for the moment
|
* got for the moment
|
||||||
*/
|
*/
|
||||||
block0 = page->index;
|
block = page->index;
|
||||||
block0 <<= shift;
|
block <<= shift;
|
||||||
|
|
||||||
|
ret = bmap(inode, &block);
|
||||||
|
ASSERT(ret < 0);
|
||||||
|
|
||||||
block = inode->i_mapping->a_ops->bmap(inode->i_mapping, block0);
|
|
||||||
_debug("%llx -> %llx",
|
_debug("%llx -> %llx",
|
||||||
(unsigned long long) block0,
|
(unsigned long long) (page->index << shift),
|
||||||
(unsigned long long) block);
|
(unsigned long long) block);
|
||||||
|
|
||||||
if (block) {
|
if (block) {
|
||||||
|
@ -711,7 +712,6 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,
|
||||||
|
|
||||||
inode = d_backing_inode(object->backer);
|
inode = d_backing_inode(object->backer);
|
||||||
ASSERT(S_ISREG(inode->i_mode));
|
ASSERT(S_ISREG(inode->i_mode));
|
||||||
ASSERT(inode->i_mapping->a_ops->bmap);
|
|
||||||
ASSERT(inode->i_mapping->a_ops->readpages);
|
ASSERT(inode->i_mapping->a_ops->readpages);
|
||||||
|
|
||||||
/* calculate the shift required to use bmap */
|
/* calculate the shift required to use bmap */
|
||||||
|
@ -728,7 +728,7 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,
|
||||||
|
|
||||||
ret = space ? -ENODATA : -ENOBUFS;
|
ret = space ? -ENODATA : -ENOBUFS;
|
||||||
list_for_each_entry_safe(page, _n, pages, lru) {
|
list_for_each_entry_safe(page, _n, pages, lru) {
|
||||||
sector_t block0, block;
|
sector_t block;
|
||||||
|
|
||||||
/* we assume the absence or presence of the first block is a
|
/* we assume the absence or presence of the first block is a
|
||||||
* good enough indication for the page as a whole
|
* good enough indication for the page as a whole
|
||||||
|
@ -736,13 +736,14 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,
|
||||||
* good enough for this as it doesn't indicate errors, but
|
* good enough for this as it doesn't indicate errors, but
|
||||||
* it's all we've got for the moment
|
* it's all we've got for the moment
|
||||||
*/
|
*/
|
||||||
block0 = page->index;
|
block = page->index;
|
||||||
block0 <<= shift;
|
block <<= shift;
|
||||||
|
|
||||||
|
ret = bmap(inode, &block);
|
||||||
|
ASSERT(!ret);
|
||||||
|
|
||||||
block = inode->i_mapping->a_ops->bmap(inode->i_mapping,
|
|
||||||
block0);
|
|
||||||
_debug("%llx -> %llx",
|
_debug("%llx -> %llx",
|
||||||
(unsigned long long) block0,
|
(unsigned long long) (page->index << shift),
|
||||||
(unsigned long long) block);
|
(unsigned long long) block);
|
||||||
|
|
||||||
if (block) {
|
if (block) {
|
||||||
|
|
|
@ -524,16 +524,12 @@ out:
|
||||||
|
|
||||||
static sector_t ecryptfs_bmap(struct address_space *mapping, sector_t block)
|
static sector_t ecryptfs_bmap(struct address_space *mapping, sector_t block)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
struct inode *lower_inode = ecryptfs_inode_to_lower(mapping->host);
|
||||||
struct inode *inode;
|
int ret = bmap(lower_inode, &block);
|
||||||
struct inode *lower_inode;
|
|
||||||
|
|
||||||
inode = (struct inode *)mapping->host;
|
if (ret)
|
||||||
lower_inode = ecryptfs_inode_to_lower(inode);
|
return 0;
|
||||||
if (lower_inode->i_mapping->a_ops->bmap)
|
return block;
|
||||||
rc = lower_inode->i_mapping->a_ops->bmap(lower_inode->i_mapping,
|
|
||||||
block);
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct address_space_operations ecryptfs_aops = {
|
const struct address_space_operations ecryptfs_aops = {
|
||||||
|
|
|
@ -3666,12 +3666,16 @@ static int check_swap_activate(struct swap_info_struct *sis,
|
||||||
page_no < sis->max) {
|
page_no < sis->max) {
|
||||||
unsigned block_in_page;
|
unsigned block_in_page;
|
||||||
sector_t first_block;
|
sector_t first_block;
|
||||||
|
sector_t block = 0;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
cond_resched();
|
cond_resched();
|
||||||
|
|
||||||
first_block = bmap(inode, probe_block);
|
block = probe_block;
|
||||||
if (first_block == 0)
|
err = bmap(inode, &block);
|
||||||
|
if (err || !block)
|
||||||
goto bad_bmap;
|
goto bad_bmap;
|
||||||
|
first_block = block;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It must be PAGE_SIZE aligned on-disk
|
* It must be PAGE_SIZE aligned on-disk
|
||||||
|
@ -3683,11 +3687,13 @@ static int check_swap_activate(struct swap_info_struct *sis,
|
||||||
|
|
||||||
for (block_in_page = 1; block_in_page < blocks_per_page;
|
for (block_in_page = 1; block_in_page < blocks_per_page;
|
||||||
block_in_page++) {
|
block_in_page++) {
|
||||||
sector_t block;
|
|
||||||
|
|
||||||
block = bmap(inode, probe_block + block_in_page);
|
block = probe_block + block_in_page;
|
||||||
if (block == 0)
|
err = bmap(inode, &block);
|
||||||
|
|
||||||
|
if (err || !block)
|
||||||
goto bad_bmap;
|
goto bad_bmap;
|
||||||
|
|
||||||
if (block != first_block + block_in_page) {
|
if (block != first_block + block_in_page) {
|
||||||
/* Discontiguity */
|
/* Discontiguity */
|
||||||
probe_block++;
|
probe_block++;
|
||||||
|
|
30
fs/inode.c
30
fs/inode.c
|
@ -1599,25 +1599,31 @@ retry:
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(iput);
|
EXPORT_SYMBOL(iput);
|
||||||
|
|
||||||
|
#ifdef CONFIG_BLOCK
|
||||||
/**
|
/**
|
||||||
* bmap - find a block number in a file
|
* bmap - find a block number in a file
|
||||||
* @inode: inode of file
|
* @inode: inode owning the block number being requested
|
||||||
* @block: block to find
|
* @block: pointer containing the block to find
|
||||||
*
|
*
|
||||||
* Returns the block number on the device holding the inode that
|
* Replaces the value in *block with the block number on the device holding
|
||||||
* is the disk block number for the block of the file requested.
|
* corresponding to the requested block number in the file.
|
||||||
* That is, asked for block 4 of inode 1 the function will return the
|
* That is, asked for block 4 of inode 1 the function will replace the
|
||||||
* disk block relative to the disk start that holds that block of the
|
* 4 in *block, with disk block relative to the disk start that holds that
|
||||||
* file.
|
* block of the file.
|
||||||
|
*
|
||||||
|
* Returns -EINVAL in case of error, 0 otherwise. If mapping falls into a
|
||||||
|
* hole, returns 0 and *block is also set to 0.
|
||||||
*/
|
*/
|
||||||
sector_t bmap(struct inode *inode, sector_t block)
|
int bmap(struct inode *inode, sector_t *block)
|
||||||
{
|
{
|
||||||
sector_t res = 0;
|
if (!inode->i_mapping->a_ops->bmap)
|
||||||
if (inode->i_mapping->a_ops->bmap)
|
return -EINVAL;
|
||||||
res = inode->i_mapping->a_ops->bmap(inode->i_mapping, block);
|
|
||||||
return res;
|
*block = inode->i_mapping->a_ops->bmap(inode->i_mapping, *block);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(bmap);
|
EXPORT_SYMBOL(bmap);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* With relative atime, only update atime if the previous atime is
|
* With relative atime, only update atime if the previous atime is
|
||||||
|
|
33
fs/ioctl.c
33
fs/ioctl.c
|
@ -54,19 +54,32 @@ EXPORT_SYMBOL(vfs_ioctl);
|
||||||
|
|
||||||
static int ioctl_fibmap(struct file *filp, int __user *p)
|
static int ioctl_fibmap(struct file *filp, int __user *p)
|
||||||
{
|
{
|
||||||
struct address_space *mapping = filp->f_mapping;
|
struct inode *inode = file_inode(filp);
|
||||||
int res, block;
|
int error, ur_block;
|
||||||
|
sector_t block;
|
||||||
|
|
||||||
/* do we support this mess? */
|
|
||||||
if (!mapping->a_ops->bmap)
|
|
||||||
return -EINVAL;
|
|
||||||
if (!capable(CAP_SYS_RAWIO))
|
if (!capable(CAP_SYS_RAWIO))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
res = get_user(block, p);
|
|
||||||
if (res)
|
error = get_user(ur_block, p);
|
||||||
return res;
|
if (error)
|
||||||
res = mapping->a_ops->bmap(mapping, block);
|
return error;
|
||||||
return put_user(res, p);
|
|
||||||
|
if (ur_block < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
block = ur_block;
|
||||||
|
error = bmap(inode, &block);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
ur_block = 0;
|
||||||
|
else
|
||||||
|
ur_block = block;
|
||||||
|
|
||||||
|
if (put_user(ur_block, p))
|
||||||
|
error = -EFAULT;
|
||||||
|
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -794,18 +794,22 @@ int jbd2_journal_bmap(journal_t *journal, unsigned long blocknr,
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
unsigned long long ret;
|
unsigned long long ret;
|
||||||
|
sector_t block = 0;
|
||||||
|
|
||||||
if (journal->j_inode) {
|
if (journal->j_inode) {
|
||||||
ret = bmap(journal->j_inode, blocknr);
|
block = blocknr;
|
||||||
if (ret)
|
ret = bmap(journal->j_inode, &block);
|
||||||
*retp = ret;
|
|
||||||
else {
|
if (ret || !block) {
|
||||||
printk(KERN_ALERT "%s: journal block not found "
|
printk(KERN_ALERT "%s: journal block not found "
|
||||||
"at offset %lu on %s\n",
|
"at offset %lu on %s\n",
|
||||||
__func__, blocknr, journal->j_devname);
|
__func__, blocknr, journal->j_devname);
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
jbd2_journal_abort(journal, err);
|
jbd2_journal_abort(journal, err);
|
||||||
|
} else {
|
||||||
|
*retp = block;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
*retp = blocknr; /* +journal->j_blk_offset */
|
*retp = blocknr; /* +journal->j_blk_offset */
|
||||||
}
|
}
|
||||||
|
@ -1243,11 +1247,14 @@ journal_t *jbd2_journal_init_dev(struct block_device *bdev,
|
||||||
journal_t *jbd2_journal_init_inode(struct inode *inode)
|
journal_t *jbd2_journal_init_inode(struct inode *inode)
|
||||||
{
|
{
|
||||||
journal_t *journal;
|
journal_t *journal;
|
||||||
|
sector_t blocknr;
|
||||||
char *p;
|
char *p;
|
||||||
unsigned long long blocknr;
|
int err = 0;
|
||||||
|
|
||||||
blocknr = bmap(inode, 0);
|
blocknr = 0;
|
||||||
if (!blocknr) {
|
err = bmap(inode, &blocknr);
|
||||||
|
|
||||||
|
if (err || !blocknr) {
|
||||||
pr_err("%s: Cannot locate journal superblock\n",
|
pr_err("%s: Cannot locate journal superblock\n",
|
||||||
__func__);
|
__func__);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -2979,39 +2979,10 @@ static void shrink_submounts(struct mount *mnt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Some copy_from_user() implementations do not return the exact number of
|
|
||||||
* bytes remaining to copy on a fault. But copy_mount_options() requires that.
|
|
||||||
* Note that this function differs from copy_from_user() in that it will oops
|
|
||||||
* on bad values of `to', rather than returning a short copy.
|
|
||||||
*/
|
|
||||||
static long exact_copy_from_user(void *to, const void __user * from,
|
|
||||||
unsigned long n)
|
|
||||||
{
|
|
||||||
char *t = to;
|
|
||||||
const char __user *f = from;
|
|
||||||
char c;
|
|
||||||
|
|
||||||
if (!access_ok(from, n))
|
|
||||||
return n;
|
|
||||||
|
|
||||||
while (n) {
|
|
||||||
if (__get_user(c, f)) {
|
|
||||||
memset(t, 0, n);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*t++ = c;
|
|
||||||
f++;
|
|
||||||
n--;
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *copy_mount_options(const void __user * data)
|
void *copy_mount_options(const void __user * data)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
unsigned long size;
|
|
||||||
char *copy;
|
char *copy;
|
||||||
|
unsigned size;
|
||||||
|
|
||||||
if (!data)
|
if (!data)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -3020,22 +2991,16 @@ void *copy_mount_options(const void __user * data)
|
||||||
if (!copy)
|
if (!copy)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
/* We only care that *some* data at the address the user
|
size = PAGE_SIZE - offset_in_page(data);
|
||||||
* gave us is valid. Just in case, we'll zero
|
|
||||||
* the remainder of the page.
|
|
||||||
*/
|
|
||||||
/* copy_from_user cannot cross TASK_SIZE ! */
|
|
||||||
size = TASK_SIZE - (unsigned long)untagged_addr(data);
|
|
||||||
if (size > PAGE_SIZE)
|
|
||||||
size = PAGE_SIZE;
|
|
||||||
|
|
||||||
i = size - exact_copy_from_user(copy, data, size);
|
if (copy_from_user(copy, data, size)) {
|
||||||
if (!i) {
|
|
||||||
kfree(copy);
|
kfree(copy);
|
||||||
return ERR_PTR(-EFAULT);
|
return ERR_PTR(-EFAULT);
|
||||||
}
|
}
|
||||||
if (i != PAGE_SIZE)
|
if (size != PAGE_SIZE) {
|
||||||
memset(copy + i, 0, PAGE_SIZE - i);
|
if (copy_from_user(copy + size, data + size, PAGE_SIZE - size))
|
||||||
|
memset(copy + size, 0, PAGE_SIZE - size);
|
||||||
|
}
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2876,9 +2876,16 @@ static inline ssize_t generic_write_sync(struct kiocb *iocb, ssize_t count)
|
||||||
|
|
||||||
extern void emergency_sync(void);
|
extern void emergency_sync(void);
|
||||||
extern void emergency_remount(void);
|
extern void emergency_remount(void);
|
||||||
|
|
||||||
#ifdef CONFIG_BLOCK
|
#ifdef CONFIG_BLOCK
|
||||||
extern sector_t bmap(struct inode *, sector_t);
|
extern int bmap(struct inode *inode, sector_t *block);
|
||||||
|
#else
|
||||||
|
static inline int bmap(struct inode *inode, sector_t *block)
|
||||||
|
{
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern int notify_change(struct dentry *, struct iattr *, struct inode **);
|
extern int notify_change(struct dentry *, struct iattr *, struct inode **);
|
||||||
extern int inode_permission(struct inode *, int);
|
extern int inode_permission(struct inode *, int);
|
||||||
extern int generic_permission(struct inode *, int);
|
extern int generic_permission(struct inode *, int);
|
||||||
|
|
11
mm/page_io.c
11
mm/page_io.c
|
@ -177,8 +177,9 @@ int generic_swapfile_activate(struct swap_info_struct *sis,
|
||||||
|
|
||||||
cond_resched();
|
cond_resched();
|
||||||
|
|
||||||
first_block = bmap(inode, probe_block);
|
first_block = probe_block;
|
||||||
if (first_block == 0)
|
ret = bmap(inode, &first_block);
|
||||||
|
if (ret || !first_block)
|
||||||
goto bad_bmap;
|
goto bad_bmap;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -193,9 +194,11 @@ int generic_swapfile_activate(struct swap_info_struct *sis,
|
||||||
block_in_page++) {
|
block_in_page++) {
|
||||||
sector_t block;
|
sector_t block;
|
||||||
|
|
||||||
block = bmap(inode, probe_block + block_in_page);
|
block = probe_block + block_in_page;
|
||||||
if (block == 0)
|
ret = bmap(inode, &block);
|
||||||
|
if (ret || !block)
|
||||||
goto bad_bmap;
|
goto bad_bmap;
|
||||||
|
|
||||||
if (block != first_block + block_in_page) {
|
if (block != first_block + block_in_page) {
|
||||||
/* Discontiguity */
|
/* Discontiguity */
|
||||||
probe_block++;
|
probe_block++;
|
||||||
|
|
Loading…
Reference in New Issue