Commit 236f4532 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 99593330 12efec56
...@@ -364,7 +364,7 @@ static int read_page(struct file *file, unsigned long index, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 @@ static int ecryptfs_write_end(struct file *file, ...@@ -524,16 +524,12 @@ static int ecryptfs_write_end(struct file *file,
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;
if (ret)
inode = (struct inode *)mapping->host; return 0;
lower_inode = ecryptfs_inode_to_lower(inode); return block;
if (lower_inode->i_mapping->a_ops->bmap)
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, ...@@ -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, ...@@ -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++;
......
...@@ -1599,25 +1599,31 @@ void iput(struct inode *inode) ...@@ -1599,25 +1599,31 @@ void iput(struct inode *inode)
} }
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
......
...@@ -54,19 +54,32 @@ EXPORT_SYMBOL(vfs_ioctl); ...@@ -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, ...@@ -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, ...@@ -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 = 0;
err = bmap(inode, &blocknr);
blocknr = bmap(inode, 0); if (err || !blocknr) {
if (!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) ...@@ -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) ...@@ -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) ...@@ -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);
......
...@@ -177,8 +177,9 @@ int generic_swapfile_activate(struct swap_info_struct *sis, ...@@ -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, ...@@ -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++;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment