aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/afs/internal.h2
-rw-r--r--fs/binfmt_flat.c2
-rw-r--r--fs/compat.c17
-rw-r--r--fs/compat_ioctl.c33
-rw-r--r--fs/ecryptfs/file.c59
-rw-r--r--fs/ecryptfs/mmap.c38
-rw-r--r--fs/exec.c3
-rw-r--r--fs/ext4/balloc.c6
-rw-r--r--fs/ext4/extents.c148
-rw-r--r--fs/ext4/inode.c4
-rw-r--r--fs/ext4/namei.c4
-rw-r--r--fs/ext4/super.c2
-rw-r--r--fs/fuse/dir.c2
-rw-r--r--fs/fuse/file.c4
-rw-r--r--fs/fuse/inode.c1
-rw-r--r--fs/ioctl.c14
-rw-r--r--fs/jffs2/readinode.c22
-rw-r--r--fs/jffs2/super.c194
-rw-r--r--fs/jffs2/xattr.c6
-rw-r--r--fs/nfs/direct.c65
-rw-r--r--fs/nfs/pagelist.c20
-rw-r--r--fs/nfs/write.c6
-rw-r--r--fs/ntfs/inode.c2
-rw-r--r--fs/ocfs2/aops.c31
-rw-r--r--fs/ocfs2/cluster/masklog.c3
-rw-r--r--fs/ocfs2/file.c33
-rw-r--r--fs/ocfs2/localalloc.c7
-rw-r--r--fs/ramfs/file-nommu.c7
-rw-r--r--fs/reiserfs/dir.c2
-rw-r--r--fs/signalfd.c120
-rw-r--r--fs/splice.c70
-rw-r--r--fs/udf/inode.c12
-rw-r--r--fs/udf/super.c2
-rw-r--r--fs/xfs/linux-2.6/xfs_aops.c26
34 files changed, 475 insertions, 492 deletions
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 2dac3ad..2c55dd9 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -17,6 +17,8 @@
#include <linux/rxrpc.h>
#include <linux/key.h>
#include <linux/workqueue.h>
+#include <linux/sched.h>
+
#include "afs.h"
#include "afs_vl.h"
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c
index 7b0265d..861141b 100644
--- a/fs/binfmt_flat.c
+++ b/fs/binfmt_flat.c
@@ -558,7 +558,7 @@ static int load_flat_file(struct linux_binprm * bprm,
if (!realdatastart)
realdatastart = (unsigned long) -ENOMEM;
printk("Unable to allocate RAM for process data, errno %d\n",
- (int)-datapos);
+ (int)-realdatastart);
do_munmap(current->mm, textpos, text_len);
ret = realdatastart;
goto err;
diff --git a/fs/compat.c b/fs/compat.c
index 1de2331..4db6216 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1544,9 +1544,10 @@ int compat_core_sys_select(int n, compat_ulong_t __user *inp,
compat_ulong_t __user *outp, compat_ulong_t __user *exp, s64 *timeout)
{
fd_set_bits fds;
- char *bits;
+ void *bits;
int size, max_fds, ret = -EINVAL;
struct fdtable *fdt;
+ long stack_fds[SELECT_STACK_ALLOC/sizeof(long)];
if (n < 0)
goto out_nofds;
@@ -1564,11 +1565,14 @@ int compat_core_sys_select(int n, compat_ulong_t __user *inp,
* since we used fdset we need to allocate memory in units of
* long-words.
*/
- ret = -ENOMEM;
size = FDS_BYTES(n);
- bits = kmalloc(6 * size, GFP_KERNEL);
- if (!bits)
- goto out_nofds;
+ bits = stack_fds;
+ if (size > sizeof(stack_fds) / 6) {
+ bits = kmalloc(6 * size, GFP_KERNEL);
+ ret = -ENOMEM;
+ if (!bits)
+ goto out_nofds;
+ }
fds.in = (unsigned long *) bits;
fds.out = (unsigned long *) (bits + size);
fds.ex = (unsigned long *) (bits + 2*size);
@@ -1600,7 +1604,8 @@ int compat_core_sys_select(int n, compat_ulong_t __user *inp,
compat_set_fd_set(n, exp, fds.res_ex))
ret = -EFAULT;
out:
- kfree(bits);
+ if (bits != stack_fds)
+ kfree(bits);
out_nofds:
return ret;
}
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 65643de..6b44cdc 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -1194,6 +1194,7 @@ static int vt_check(struct file *file)
{
struct tty_struct *tty;
struct inode *inode = file->f_path.dentry->d_inode;
+ struct vc_data *vc;
if (file->f_op->ioctl != tty_ioctl)
return -EINVAL;
@@ -1204,12 +1205,16 @@ static int vt_check(struct file *file)
if (tty->driver->ioctl != vt_ioctl)
return -EINVAL;
-
+
+ vc = (struct vc_data *)tty->driver_data;
+ if (!vc_cons_allocated(vc->vc_num)) /* impossible? */
+ return -ENOIOCTLCMD;
+
/*
* To have permissions to do most of the vt ioctls, we either have
- * to be the owner of the tty, or super-user.
+ * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
*/
- if (current->signal->tty == tty || capable(CAP_SYS_ADMIN))
+ if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
return 1;
return 0;
}
@@ -1310,16 +1315,28 @@ static int do_unimap_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg,
struct unimapdesc32 tmp;
struct unimapdesc32 __user *user_ud = compat_ptr(arg);
int perm = vt_check(file);
-
- if (perm < 0) return perm;
+ struct vc_data *vc;
+
+ if (perm < 0)
+ return perm;
if (copy_from_user(&tmp, user_ud, sizeof tmp))
return -EFAULT;
+ if (tmp.entries)
+ if (!access_ok(VERIFY_WRITE, compat_ptr(tmp.entries),
+ tmp.entry_ct*sizeof(struct unipair)))
+ return -EFAULT;
+ vc = ((struct tty_struct *)file->private_data)->driver_data;
switch (cmd) {
case PIO_UNIMAP:
- if (!perm) return -EPERM;
- return con_set_unimap(vc_cons[fg_console].d, tmp.entry_ct, compat_ptr(tmp.entries));
+ if (!perm)
+ return -EPERM;
+ return con_set_unimap(vc, tmp.entry_ct,
+ compat_ptr(tmp.entries));
case GIO_UNIMAP:
- return con_get_unimap(vc_cons[fg_console].d, tmp.entry_ct, &(user_ud->entry_ct), compat_ptr(tmp.entries));
+ if (!perm && fg_console != vc->vc_num)
+ return -EPERM;
+ return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct),
+ compat_ptr(tmp.entries));
}
return 0;
}
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index 9881b5c..59288d8 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -33,63 +33,6 @@
#include "ecryptfs_kernel.h"
/**
- * ecryptfs_llseek
- * @file: File we are seeking in
- * @offset: The offset to seek to
- * @origin: 2 - offset from i_size; 1 - offset from f_pos
- *
- * Returns the position we have seeked to, or negative on error
- */
-static loff_t ecryptfs_llseek(struct file *file, loff_t offset, int origin)
-{
- loff_t rv;
- loff_t new_end_pos;
- int rc;
- int expanding_file = 0;
- struct inode *inode = file->f_mapping->host;
-
- /* If our offset is past the end of our file, we're going to
- * need to grow it so we have a valid length of 0's */
- new_end_pos = offset;
- switch (origin) {
- case 2:
- new_end_pos += i_size_read(inode);
- expanding_file = 1;
- break;
- case 1:
- new_end_pos += file->f_pos;
- if (new_end_pos > i_size_read(inode)) {
- ecryptfs_printk(KERN_DEBUG, "new_end_pos(=[0x%.16x]) "
- "> i_size_read(inode)(=[0x%.16x])\n",
- new_end_pos, i_size_read(inode));
- expanding_file = 1;
- }
- break;
- default:
- if (new_end_pos > i_size_read(inode)) {
- ecryptfs_printk(KERN_DEBUG, "new_end_pos(=[0x%.16x]) "
- "> i_size_read(inode)(=[0x%.16x])\n",
- new_end_pos, i_size_read(inode));
- expanding_file = 1;
- }
- }
- ecryptfs_printk(KERN_DEBUG, "new_end_pos = [0x%.16x]\n", new_end_pos);
- if (expanding_file) {
- rc = ecryptfs_truncate(file->f_path.dentry, new_end_pos);
- if (rc) {
- rv = rc;
- ecryptfs_printk(KERN_ERR, "Error on attempt to "
- "truncate to (higher) offset [0x%.16x];"
- " rc = [%d]\n", new_end_pos, rc);
- goto out;
- }
- }
- rv = generic_file_llseek(file, offset, origin);
-out:
- return rv;
-}
-
-/**
* ecryptfs_read_update_atime
*
* generic_file_read updates the atime of upper layer inode. But, it
@@ -425,7 +368,7 @@ const struct file_operations ecryptfs_dir_fops = {
};
const struct file_operations ecryptfs_main_fops = {
- .llseek = ecryptfs_llseek,
+ .llseek = generic_file_llseek,
.read = do_sync_read,
.aio_read = ecryptfs_read_update_atime,
.write = do_sync_write,
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 88ea669..55cec98 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -376,9 +376,31 @@ out:
return 0;
}
+/**
+ * eCryptfs does not currently support holes. When writing after a
+ * seek past the end of the file, eCryptfs fills in 0's through to the
+ * current location. The code to fill in the 0's to all the
+ * intermediate pages calls ecryptfs_prepare_write_no_truncate().
+ */
+static int
+ecryptfs_prepare_write_no_truncate(struct file *file, struct page *page,
+ unsigned from, unsigned to)
+{
+ int rc = 0;
+
+ if (from == 0 && to == PAGE_CACHE_SIZE)
+ goto out; /* If we are writing a full page, it will be
+ up to date. */
+ if (!PageUptodate(page))
+ rc = ecryptfs_do_readpage(file, page, page->index);
+out:
+ return rc;
+}
+
static int ecryptfs_prepare_write(struct file *file, struct page *page,
unsigned from, unsigned to)
{
+ loff_t pos;
int rc = 0;
if (from == 0 && to == PAGE_CACHE_SIZE)
@@ -386,6 +408,16 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page,
up to date. */
if (!PageUptodate(page))
rc = ecryptfs_do_readpage(file, page, page->index);
+ pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
+ if (pos > i_size_read(page->mapping->host)) {
+ rc = ecryptfs_truncate(file->f_path.dentry, pos);
+ if (rc) {
+ printk(KERN_ERR "Error on attempt to "
+ "truncate to (higher) offset [%lld];"
+ " rc = [%d]\n", pos, rc);
+ goto out;
+ }
+ }
out:
return rc;
}
@@ -744,10 +776,10 @@ int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros)
rc = PTR_ERR(tmp_page);
goto out;
}
- rc = ecryptfs_prepare_write(file, tmp_page, start, start + num_zeros);
- if (rc) {
+ if ((rc = ecryptfs_prepare_write_no_truncate(file, tmp_page, start,
+ (start + num_zeros)))) {
ecryptfs_printk(KERN_ERR, "Error preparing to write zero's "
- "to remainder of page at index [0x%.16x]\n",
+ "to page at index [0x%.16x]\n",
index);
page_cache_release(tmp_page);
goto out;
diff --git a/fs/exec.c b/fs/exec.c
index 0b68588..f20561f 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -134,6 +134,9 @@ asmlinkage long sys_uselib(const char __user * library)
if (error)
goto out;
+ error = -EACCES;
+ if (nd.mnt->mnt_flags & MNT_NOEXEC)
+ goto exit;
error = -EINVAL;
if (!S_ISREG(nd.dentry->d_inode->i_mode))
goto exit;
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index 8a23483..3b64bb1 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -30,15 +30,15 @@
void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
unsigned long *blockgrpp, ext4_grpblk_t *offsetp)
{
- struct ext4_super_block *es = EXT4_SB(sb)->s_es;
+ struct ext4_super_block *es = EXT4_SB(sb)->s_es;
ext4_grpblk_t offset;
- blocknr = blocknr - le32_to_cpu(es->s_first_data_block);
+ blocknr = blocknr - le32_to_cpu(es->s_first_data_block);
offset = do_div(blocknr, EXT4_BLOCKS_PER_GROUP(sb));
if (offsetp)
*offsetp = offset;
if (blockgrpp)
- *blockgrpp = blocknr;
+ *blockgrpp = blocknr;
}
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index a0f0c04..b9ce241 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -374,7 +374,7 @@ ext4_ext_binsearch_idx(struct inode *inode, struct ext4_ext_path *path, int bloc
le32_to_cpu(ix[-1].ei_block));
}
BUG_ON(k && le32_to_cpu(ix->ei_block)
- <= le32_to_cpu(ix[-1].ei_block));
+ <= le32_to_cpu(ix[-1].ei_block));
if (block < le32_to_cpu(ix->ei_block))
break;
chix = ix;
@@ -423,8 +423,8 @@ ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block)
path->p_ext = l - 1;
ext_debug(" -> %d:%llu:%d ",
- le32_to_cpu(path->p_ext->ee_block),
- ext_pblock(path->p_ext),
+ le32_to_cpu(path->p_ext->ee_block),
+ ext_pblock(path->p_ext),
le16_to_cpu(path->p_ext->ee_len));
#ifdef CHECK_BINSEARCH
@@ -435,7 +435,7 @@ ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block)
chex = ex = EXT_FIRST_EXTENT(eh);
for (k = 0; k < le16_to_cpu(eh->eh_entries); k++, ex++) {
BUG_ON(k && le32_to_cpu(ex->ee_block)
- <= le32_to_cpu(ex[-1].ee_block));
+ <= le32_to_cpu(ex[-1].ee_block));
if (block < le32_to_cpu(ex->ee_block))
break;
chex = ex;
@@ -577,7 +577,7 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
curp->p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(curp->p_hdr->eh_entries)+1);
BUG_ON(le16_to_cpu(curp->p_hdr->eh_entries)
- > le16_to_cpu(curp->p_hdr->eh_max));
+ > le16_to_cpu(curp->p_hdr->eh_max));
BUG_ON(ix > EXT_LAST_INDEX(curp->p_hdr));
err = ext4_ext_dirty(handle, inode, curp);
@@ -621,12 +621,12 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
border = path[depth].p_ext[1].ee_block;
ext_debug("leaf will be split."
" next leaf starts at %d\n",
- le32_to_cpu(border));
+ le32_to_cpu(border));
} else {
border = newext->ee_block;
ext_debug("leaf will be added."
" next leaf starts at %d\n",
- le32_to_cpu(border));
+ le32_to_cpu(border));
}
/*
@@ -684,9 +684,9 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
while (path[depth].p_ext <=
EXT_MAX_EXTENT(path[depth].p_hdr)) {
ext_debug("move %d:%llu:%d in new leaf %llu\n",
- le32_to_cpu(path[depth].p_ext->ee_block),
- ext_pblock(path[depth].p_ext),
- le16_to_cpu(path[depth].p_ext->ee_len),
+ le32_to_cpu(path[depth].p_ext->ee_block),
+ ext_pblock(path[depth].p_ext),
+ le16_to_cpu(path[depth].p_ext->ee_len),
newblock);
/*memmove(ex++, path[depth].p_ext++,
sizeof(struct ext4_extent));
@@ -765,9 +765,9 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
EXT_LAST_INDEX(path[i].p_hdr));
while (path[i].p_idx <= EXT_MAX_INDEX(path[i].p_hdr)) {
ext_debug("%d: move %d:%d in new index %llu\n", i,
- le32_to_cpu(path[i].p_idx->ei_block),
- idx_pblock(path[i].p_idx),
- newblock);
+ le32_to_cpu(path[i].p_idx->ei_block),
+ idx_pblock(path[i].p_idx),
+ newblock);
/*memmove(++fidx, path[i].p_idx++,
sizeof(struct ext4_extent_idx));
neh->eh_entries++;
@@ -1128,6 +1128,55 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,
}
/*
+ * check if a portion of the "newext" extent overlaps with an
+ * existing extent.
+ *
+ * If there is an overlap discovered, it updates the length of the newext
+ * such that there will be no overlap, and then returns 1.
+ * If there is no overlap found, it returns 0.
+ */
+unsigned int ext4_ext_check_overlap(struct inode *inode,
+ struct ext4_extent *newext,
+ struct ext4_ext_path *path)
+{
+ unsigned long b1, b2;
+ unsigned int depth, len1;
+ unsigned int ret = 0;
+
+ b1 = le32_to_cpu(newext->ee_block);
+ len1 = le16_to_cpu(newext->ee_len);
+ depth = ext_depth(inode);
+ if (!path[depth].p_ext)
+ goto out;
+ b2 = le32_to_cpu(path[depth].p_ext->ee_block);
+
+ /*
+ * get the next allocated block if the extent in the path
+ * is before the requested block(s)
+ */
+ if (b2 < b1) {
+ b2 = ext4_ext_next_allocated_block(path);
+ if (b2 == EXT_MAX_BLOCK)
+ goto out;
+ }
+
+ /* check for wrap through zero */
+ if (b1 + len1 < b1) {
+ len1 = EXT_MAX_BLOCK - b1;
+ newext->ee_len = cpu_to_le16(len1);
+ ret = 1;
+ }
+
+ /* check for overlap */
+ if (b1 + len1 > b2) {
+ newext->ee_len = cpu_to_le16(b2 - b1);
+ ret = 1;
+ }
+out:
+ return ret;
+}
+
+/*
* ext4_ext_insert_extent:
* tries to merge requsted extent into the existing extent or
* inserts requested extent as new one into the tree,
@@ -1212,12 +1261,12 @@ has_space:
if (!nearex) {
/* there is no extent in this leaf, create first one */
ext_debug("first extent in the leaf: %d:%llu:%d\n",
- le32_to_cpu(newext->ee_block),
- ext_pblock(newext),
- le16_to_cpu(newext->ee_len));
+ le32_to_cpu(newext->ee_block),
+ ext_pblock(newext),
+ le16_to_cpu(newext->ee_len));
path[depth].p_ext = EXT_FIRST_EXTENT(eh);
} else if (le32_to_cpu(newext->ee_block)
- > le32_to_cpu(nearex->ee_block)) {
+ > le32_to_cpu(nearex->ee_block)) {
/* BUG_ON(newext->ee_block == nearex->ee_block); */
if (nearex != EXT_LAST_EXTENT(eh)) {
len = EXT_MAX_EXTENT(eh) - nearex;
@@ -1225,9 +1274,9 @@ has_space:
len = len < 0 ? 0 : len;
ext_debug("insert %d:%llu:%d after: nearest 0x%p, "
"move %d from 0x%p to 0x%p\n",
- le32_to_cpu(newext->ee_block),
- ext_pblock(newext),
- le16_to_cpu(newext->ee_len),
+ le32_to_cpu(newext->ee_block),
+ ext_pblock(newext),
+ le16_to_cpu(newext->ee_len),
nearex, len, nearex + 1, nearex + 2);
memmove(nearex + 2, nearex + 1, len);
}
@@ -1358,9 +1407,9 @@ int ext4_ext_walk_space(struct inode *inode, unsigned long block,
cbex.ec_start = 0;
cbex.ec_type = EXT4_EXT_CACHE_GAP;
} else {
- cbex.ec_block = le32_to_cpu(ex->ee_block);
- cbex.ec_len = le16_to_cpu(ex->ee_len);
- cbex.ec_start = ext_pblock(ex);
+ cbex.ec_block = le32_to_cpu(ex->ee_block);
+ cbex.ec_len = le16_to_cpu(ex->ee_len);
+ cbex.ec_start = ext_pblock(ex);
cbex.ec_type = EXT4_EXT_CACHE_EXTENT;
}
@@ -1431,16 +1480,16 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
len = le32_to_cpu(ex->ee_block) - block;
ext_debug("cache gap(before): %lu [%lu:%lu]",
(unsigned long) block,
- (unsigned long) le32_to_cpu(ex->ee_block),
- (unsigned long) le16_to_cpu(ex->ee_len));
+ (unsigned long) le32_to_cpu(ex->ee_block),
+ (unsigned long) le16_to_cpu(ex->ee_len));
} else if (block >= le32_to_cpu(ex->ee_block)
- + le16_to_cpu(ex->ee_len)) {
- lblock = le32_to_cpu(ex->ee_block)
- + le16_to_cpu(ex->ee_len);
+ + le16_to_cpu(ex->ee_len)) {
+ lblock = le32_to_cpu(ex->ee_block)
+ + le16_to_cpu(ex->ee_len);
len = ext4_ext_next_allocated_block(path);
ext_debug("cache gap(after): [%lu:%lu] %lu",
- (unsigned long) le32_to_cpu(ex->ee_block),
- (unsigned long) le16_to_cpu(ex->ee_len),
+ (unsigned long) le32_to_cpu(ex->ee_block),
+ (unsigned long) le16_to_cpu(ex->ee_len),
(unsigned long) block);
BUG_ON(len == lblock);
len = len - lblock;
@@ -1468,9 +1517,9 @@ ext4_ext_in_cache(struct inode *inode, unsigned long block,
BUG_ON(cex->ec_type != EXT4_EXT_CACHE_GAP &&
cex->ec_type != EXT4_EXT_CACHE_EXTENT);
if (block >= cex->ec_block && block < cex->ec_block + cex->ec_len) {
- ex->ee_block = cpu_to_le32(cex->ec_block);
+ ex->ee_block = cpu_to_le32(cex->ec_block);
ext4_ext_store_pblock(ex, cex->ec_start);
- ex->ee_len = cpu_to_le16(cex->ec_len);
+ ex->ee_len = cpu_to_le16(cex->ec_len);
ext_debug("%lu cached by %lu:%lu:%llu\n",
(unsigned long) block,
(unsigned long) cex->ec_block,
@@ -1956,9 +2005,9 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
/* we should allocate requested block */
} else if (goal == EXT4_EXT_CACHE_EXTENT) {
/* block is already allocated */
- newblock = iblock
- - le32_to_cpu(newex.ee_block)
- + ext_pblock(&newex);
+ newblock = iblock
+ - le32_to_cpu(newex.ee_block)
+ + ext_pblock(&newex);
/* number of remaining blocks in the extent */
allocated = le16_to_cpu(newex.ee_len) -
(iblock - le32_to_cpu(newex.ee_block));
@@ -1987,7 +2036,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
ex = path[depth].p_ext;
if (ex) {
- unsigned long ee_block = le32_to_cpu(ex->ee_block);
+ unsigned long ee_block = le32_to_cpu(ex->ee_block);
ext4_fsblk_t ee_start = ext_pblock(ex);
unsigned short ee_len = le16_to_cpu(ex->ee_len);
@@ -2000,7 +2049,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
if (ee_len > EXT_MAX_LEN)
goto out2;
/* if found extent covers block, simply return it */
- if (iblock >= ee_block && iblock < ee_block + ee_len) {
+ if (iblock >= ee_block && iblock < ee_block + ee_len) {
newblock = iblock - ee_block + ee_start;
/* number of remaining blocks in the extent */
allocated = ee_len - (iblock - ee_block);
@@ -2031,7 +2080,15 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
/* allocate new block */
goal = ext4_ext_find_goal(inode, path, iblock);
- allocated = max_blocks;
+
+ /* Check if we can really insert (iblock)::(iblock+max_blocks) extent */
+ newex.ee_block = cpu_to_le32(iblock);
+ newex.ee_len = cpu_to_le16(max_blocks);
+ err = ext4_ext_check_overlap(inode, &newex, path);
+ if (err)
+ allocated = le16_to_cpu(newex.ee_len);
+ else
+ allocated = max_blocks;
newblock = ext4_new_blocks(handle, inode, goal, &allocated, &err);
if (!newblock)
goto out2;
@@ -2039,12 +2096,15 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
goal, newblock, allocated);
/* try to insert new extent into found leaf and return */
- newex.ee_block = cpu_to_le32(iblock);
ext4_ext_store_pblock(&newex, newblock);
newex.ee_len = cpu_to_le16(allocated);
err = ext4_ext_insert_extent(handle, inode, path, &newex);
- if (err)
+ if (err) {
+ /* free data blocks we just allocated */
+ ext4_free_blocks(handle, inode, ext_pblock(&newex),
+ le16_to_cpu(newex.ee_len));
goto out2;
+ }
if (extend_disksize && inode->i_size > EXT4_I(inode)->i_disksize)
EXT4_I(inode)->i_disksize = inode->i_size;
@@ -2157,11 +2217,3 @@ int ext4_ext_writepage_trans_blocks(struct inode *inode, int num)
return needed;
}
-
-EXPORT_SYMBOL(ext4_mark_inode_dirty);
-EXPORT_SYMBOL(ext4_ext_invalidate_cache);
-EXPORT_SYMBOL(ext4_ext_insert_extent);
-EXPORT_SYMBOL(ext4_ext_walk_space);
-EXPORT_SYMBOL(ext4_ext_find_goal);
-EXPORT_SYMBOL(ext4_ext_calc_credits_for_insert);
-
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index b34182b..0bcf62a 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -255,8 +255,8 @@ static int verify_chain(Indirect *from, Indirect *to)
* @inode: inode in question (we are only interested in its superblock)
* @i_block: block number to be parsed
* @offsets: array to store the offsets in
- * @boundary: set this non-zero if the referred-to block is likely to be
- * followed (on disk) by an indirect block.
+ * @boundary: set this non-zero if the referred-to block is likely to be
+ * followed (on disk) by an indirect block.
*
* To store the locations of file's data ext4 uses a data structure common
* for UNIX filesystems - tree of pointers anchored in the inode, with
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 4ec57be..2811e57 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -46,7 +46,7 @@
*/
#define NAMEI_RA_CHUNKS 2
#define NAMEI_RA_BLOCKS 4
-#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
+#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b))
static struct buffer_head *ext4_append(handle_t *handle,
@@ -241,7 +241,7 @@ static inline unsigned dx_node_limit (struct inode *dir)
static void dx_show_index (char * label, struct dx_entry *entries)
{
int i, n = dx_get_count (entries);
- printk("%s index ", label);
+ printk("%s index ", label);
for (i = 0; i < n; i++) {
printk("%x->%u ", i? dx_get_hash(entries + i) :
0, dx_get_block(entries + i));
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index cb9afdd..175b68c 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1985,7 +1985,7 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb,
if (bd_claim(bdev, sb)) {
printk(KERN_ERR
- "EXT4: failed to claim external journal device.\n");
+ "EXT4: failed to claim external journal device.\n");
blkdev_put(bdev);
return NULL;
}
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 8890eba..bd5a772 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -485,7 +485,7 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
struct nameidata *nd)
{
- if (nd && (nd->flags & LOOKUP_CREATE)) {
+ if (nd && (nd->flags & LOOKUP_OPEN)) {
int err = fuse_create_open(dir, entry, mode, nd);
if (err != -ENOSYS)
return err;
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index d0ed60b..adf7995 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -610,7 +610,9 @@ static ssize_t fuse_direct_write(struct file *file, const char __user *buf,
ssize_t res;
/* Don't allow parallel writes to the same file */
mutex_lock(&inode->i_mutex);
- res = fuse_direct_io(file, buf, count, ppos, 1);
+ res = generic_write_checks(file, ppos, &count, 0);
+ if (!res)
+ res = fuse_direct_io(file, buf, count, ppos, 1);
mutex_unlock(&inode->i_mutex);
return res;
}
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 78f7a1d..9804c0c 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -454,6 +454,7 @@ static const struct super_operations fuse_super_operations = {
.destroy_inode = fuse_destroy_inode,
.read_inode = fuse_read_inode,
.clear_inode = fuse_clear_inode,
+ .drop_inode = generic_delete_inode,
.remount_fs = fuse_remount_fs,
.put_super = fuse_put_super,
.umount_begin = fuse_umount_begin,
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 479c103..8c90cbc 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -12,6 +12,7 @@
#include <linux/fs.h>
#include <linux/security.h>
#include <linux/module.h>
+#include <linux/kallsyms.h>
#include <asm/uaccess.h>
#include <asm/ioctls.h>
@@ -20,6 +21,7 @@ static long do_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
int error = -ENOTTY;
+ void *f;
if (!filp->f_op)
goto out;
@@ -29,10 +31,16 @@ static long do_ioctl(struct file *filp, unsigned int cmd,
if (error == -ENOIOCTLCMD)
error = -EINVAL;
goto out;
- } else if (filp->f_op->ioctl) {
+ } else if ((f = filp->f_op->ioctl)) {
lock_kernel();
- error = filp->f_op->ioctl(filp->f_path.dentry->d_inode,
- filp, cmd, arg);
+ if (!filp->f_op->ioctl) {
+ printk("%s: ioctl %p disappeared\n", __FUNCTION__, f);
+ print_symbol("symbol: %s\n", (unsigned long)f);
+ dump_stack();
+ } else {
+ error = filp->f_op->ioctl(filp->f_path.dentry->d_inode,
+ filp, cmd, arg);
+ }
unlock_kernel();
}
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index 4884d5e..12e83f6 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -229,9 +229,16 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
check anyway. */
if (!tn->fn->size) {
if (rii->mdata_tn) {
- /* We had a candidate mdata node already */
- dbg_readinode("kill old mdata with ver %d\n", rii->mdata_tn->version);
- jffs2_kill_tn(c, rii->mdata_tn);
+ if (rii->mdata_tn->version < tn->version) {
+ /* We had a candidate mdata node already */
+ dbg_readinode("kill old mdata with ver %d\n", rii->mdata_tn->version);
+ jffs2_kill_tn(c, rii->mdata_tn);
+ } else {
+ dbg_readinode("kill new mdata with ver %d (older than existing %d\n",
+ tn->version, rii->mdata_tn->version);
+ jffs2_kill_tn(c, tn);
+ return 0;
+ }
}
rii->mdata_tn = tn;
dbg_readinode("keep new mdata with ver %d\n", tn->version);
@@ -1044,7 +1051,8 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf
case JFFS2_NODETYPE_DIRENT:
- if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_dirent)) {
+ if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_dirent) &&
+ len < sizeof(struct jffs2_raw_dirent)) {
err = read_more(c, ref, sizeof(struct jffs2_raw_dirent), &len, buf);
if (unlikely(err))
goto free_out;
@@ -1058,7 +1066,8 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf
case JFFS2_NODETYPE_INODE:
- if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_inode)) {
+ if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_inode) &&
+ len < sizeof(struct jffs2_raw_inode)) {
err = read_more(c, ref, sizeof(struct jffs2_raw_inode), &len, buf);
if (unlikely(err))
goto free_out;
@@ -1071,7 +1080,8 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf
break;
default:
- if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_unknown_node)) {
+ if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_unknown_node) &&
+ len < sizeof(struct jffs2_unknown_node)) {
err = read_more(c, ref, sizeof(struct jffs2_unknown_node), &len, buf);
if (unlikely(err))
goto free_out;
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index 6488af4..e220d3b 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -19,7 +19,7 @@
#include <linux/mount.h>
#include <linux/jffs2.h>
#include <linux/pagemap.h>
-#include <linux/mtd/mtd.h>
+#include <linux/mtd/super.h>
#include <linux/ctype.h>
#include <linux/namei.h>
#include "compr.h"
@@ -75,69 +75,27 @@ static const struct super_operations jffs2_super_operations =
.sync_fs = jffs2_sync_fs,
};
-static int jffs2_sb_compare(struct super_block *sb, void *data)
-{
- struct jffs2_sb_info *p = data;
- struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-
- /* The superblocks are considered to be equivalent if the underlying MTD
- device is the same one */
- if (c->mtd == p->mtd) {
- D1(printk(KERN_DEBUG "jffs2_sb_compare: match on device %d (\"%s\")\n", p->mtd->index, p->mtd->name));
- return 1;
- } else {
- D1(printk(KERN_DEBUG "jffs2_sb_compare: No match, device %d (\"%s\"), device %d (\"%s\")\n",
- c->mtd->index, c->mtd->name, p->mtd->index, p->mtd->name));
- return 0;
- }
-}
-
-static int jffs2_sb_set(struct super_block *sb, void *data)
-{
- struct jffs2_sb_info *p = data;
-
- /* For persistence of NFS exports etc. we use the same s_dev
- each time we mount the device, don't just use an anonymous
- device */
- sb->s_fs_info = p;
- p->os_priv = sb;
- sb->s_dev = MKDEV(MTD_BLOCK_MAJOR, p->mtd->index);
-
- return 0;
-}
-
-static int jffs2_get_sb_mtd(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data, struct mtd_info *mtd,
- struct vfsmount *mnt)
+/*
+ * fill in the superblock
+ */
+static int jffs2_fill_super(struct super_block *sb, void *data, int silent)
{
- struct super_block *sb;
struct jffs2_sb_info *c;
- int ret;
+
+ D1(printk(KERN_DEBUG "jffs2_get_sb_mtd():"
+ " New superblock for device %d (\"%s\")\n",
+ sb->s_mtd->index, sb->s_mtd->name));
c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c)
return -ENOMEM;
- c->mtd = mtd;
-
- sb = sget(fs_type, jffs2_sb_compare, jffs2_sb_set, c);
-
- if (IS_ERR(sb))
- goto out_error;
-
- if (sb->s_root) {
- /* New mountpoint for JFFS2 which is already mounted */
- D1(printk(KERN_DEBUG "jffs2_get_sb_mtd(): Device %d (\"%s\") is already mounted\n",
- mtd->index, mtd->name));
- ret = simple_set_mnt(mnt, sb);
- goto out_put;
- }
- D1(printk(KERN_DEBUG "jffs2_get_sb_mtd(): New superblock for device %d (\"%s\")\n",
- mtd->index, mtd->name));
+ c->mtd = sb->s_mtd;
+ c->os_priv = sb;
+ sb->s_fs_info = c;
- /* Initialize JFFS2 superblock locks, the further initialization will be
- * done later */
+ /* Initialize JFFS2 superblock locks, the further initialization will
+ * be done later */
init_MUTEX(&c->alloc_sem);
init_MUTEX(&c->erase_free_sem);
init_waitqueue_head(&c->erase_wait);
@@ -146,133 +104,20 @@ static int jffs2_get_sb_mtd(struct file_system_type *fs_type,
spin_lock_init(&c->inocache_lock);
sb->s_op = &jffs2_super_operations;
- sb->s_flags = flags | MS_NOATIME;
+ sb->s_flags = sb->s_flags | MS_NOATIME;
sb->s_xattr = jffs2_xattr_handlers;
#ifdef CONFIG_JFFS2_FS_POSIX_ACL
sb->s_flags |= MS_POSIXACL;
#endif
- ret = jffs2_do_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
-
- if (ret) {
- /* Failure case... */
- up_write(&sb->s_umount);
- deactivate_super(sb);
- return ret;
- }
-
- sb->s_flags |= MS_ACTIVE;
- return simple_set_mnt(mnt, sb);
-
-out_error:
- ret = PTR_ERR(sb);
- out_put:
- kfree(c);
- put_mtd_device(mtd);
-
- return ret;
-}
-
-static int jffs2_get_sb_mtdnr(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data, int mtdnr,
- struct vfsmount *mnt)
-{
- struct mtd_info *mtd;
-
- mtd = get_mtd_device(NULL, mtdnr);
- if (IS_ERR(mtd)) {
- D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", mtdnr));
- return PTR_ERR(mtd);
- }
-
- return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd, mnt);
+ return jffs2_do_fill_super(sb, data, silent);
}
static int jffs2_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name,
void *data, struct vfsmount *mnt)
{
- int err;
- struct nameidata nd;
- int mtdnr;
-
- if (!dev_name)
- return -EINVAL;
-
- D1(printk(KERN_DEBUG "jffs2_get_sb(): dev_name \"%s\"\n", dev_name));
-
- /* The preferred way of mounting in future; especially when
- CONFIG_BLK_DEV is implemented - we specify the underlying
- MTD device by number or by name, so that we don't require
- block device support to be present in the kernel. */
-
- /* FIXME: How to do the root fs this way? */
-
- if (dev_name[0] == 'm' && dev_name[1] == 't' && dev_name[2] == 'd') {
- /* Probably mounting without the blkdev crap */
- if (dev_name[3] == ':') {
- struct mtd_info *mtd;
-
- /* Mount by MTD device name */
- D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd:%%s, name \"%s\"\n", dev_name+4));
- for (mtdnr = 0; mtdnr < MAX_MTD_DEVICES; mtdnr++) {
- mtd = get_mtd_device(NULL, mtdnr);
- if (!IS_ERR(mtd)) {
- if (!strcmp(mtd->name, dev_name+4))
- return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd, mnt);
- put_mtd_device(mtd);
- }
- }
- printk(KERN_NOTICE "jffs2_get_sb(): MTD device with name \"%s\" not found.\n", dev_name+4);
- } else if (isdigit(dev_name[3])) {
- /* Mount by MTD device number name */
- char *endptr;
-
- mtdnr = simple_strtoul(dev_name+3, &endptr, 0);
- if (!*endptr) {
- /* It was a valid number */
- D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd%%d, mtdnr %d\n", mtdnr));
- return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr, mnt);
- }
- }
- }
-
- /* Try the old way - the hack where we allowed users to mount
- /dev/mtdblock$(n) but didn't actually _use_ the blkdev */
-
- err = path_lookup(dev_name, LOOKUP_FOLLOW, &nd);
-
- D1(printk(KERN_DEBUG "jffs2_get_sb(): path_lookup() returned %d, inode %p\n",
- err, nd.dentry->d_inode));
-
- if (err)
- return err;
-
- err = -EINVAL;
-
- if (!S_ISBLK(nd.dentry->d_inode->i_mode))
- goto out;
-
- if (nd.mnt->mnt_flags & MNT_NODEV) {
- err = -EACCES;
- goto out;
- }
-
- if (imajor(nd.dentry->d_inode) != MTD_BLOCK_MAJOR) {
- if (!(flags & MS_SILENT))
- printk(KERN_NOTICE "Attempt to mount non-MTD device \"%s\" as JFFS2\n",
- dev_name);
- goto out;
- }
-
- mtdnr = iminor(nd.dentry->d_inode);
- path_release(&nd);
-
- return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr, mnt);
-
-out:
- path_release(&nd);
- return err;
+ return get_sb_mtd(fs_type, flags, dev_name, data, jffs2_fill_super,
+ mnt);
}
static void jffs2_put_super (struct super_block *sb)
@@ -307,8 +152,7 @@ static void jffs2_kill_sb(struct super_block *sb)
struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
if (!(sb->s_flags & MS_RDONLY))
jffs2_stop_garbage_collect_thread(c);
- generic_shutdown_super(sb);
- put_mtd_device(c->mtd);
+ kill_mtd_super(sb);
kfree(c);
}
diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c
index 78fc088..e486659 100644
--- a/fs/jffs2/xattr.c
+++ b/fs/jffs2/xattr.c
@@ -754,6 +754,10 @@ void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c)
list_del(&xd->xindex);
jffs2_free_xattr_datum(xd);
}
+ list_for_each_entry_safe(xd, _xd, &c->xattr_unchecked, xindex) {
+ list_del(&xd->xindex);
+ jffs2_free_xattr_datum(xd);
+ }
}
#define XREF_TMPHASH_SIZE (128)
@@ -825,7 +829,7 @@ void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c)
ref->xd and ref->ic are not valid yet. */
xd = jffs2_find_xattr_datum(c, ref->xid);
ic = jffs2_get_ino_cache(c, ref->ino);
- if (!xd || !ic) {
+ if (!xd || !ic || !ic->nlink) {
dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) is orphan.\n",
ref->ino, ref->xid, ref->xseqno);
ref->xseqno |= XREF_DELETE_MARKER;
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 345aa5c..00eee87 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -122,19 +122,25 @@ ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_
return -EINVAL;
}
-static void nfs_direct_dirty_pages(struct page **pages, int npages)
+static void nfs_direct_dirty_pages(struct page **pages, unsigned int pgbase, size_t count)
{
- int i;
+ unsigned int npages;
+ unsigned int i;
+
+ if (count == 0)
+ return;
+ pages += (pgbase >> PAGE_SHIFT);
+ npages = (count + (pgbase & ~PAGE_MASK) + PAGE_SIZE - 1) >> PAGE_SHIFT;
for (i = 0; i < npages; i++) {
struct page *page = pages[i];
if (!PageCompound(page))
- set_page_dirty_lock(page);
+ set_page_dirty(page);
}
}
-static void nfs_direct_release_pages(struct page **pages, int npages)
+static void nfs_direct_release_pages(struct page **pages, unsigned int npages)
{
- int i;
+ unsigned int i;
for (i = 0; i < npages; i++)
page_cache_release(pages[i]);
}
@@ -162,7 +168,7 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void)
return dreq;
}
-static void nfs_direct_req_release(struct kref *kref)
+static void nfs_direct_req_free(struct kref *kref)
{
struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref);
@@ -171,6 +177,11 @@ static void nfs_direct_req_release(struct kref *kref)
kmem_cache_free(nfs_direct_cachep, dreq);
}
+static void nfs_direct_req_release(struct nfs_direct_req *dreq)
+{
+ kref_put(&dreq->kref, nfs_direct_req_free);
+}
+
/*
* Collects and returns the final error value/byte-count.
*/
@@ -190,7 +201,6 @@ static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq)
result = dreq->count;
out:
- kref_put(&dreq->kref, nfs_direct_req_release);
return (ssize_t) result;
}
@@ -208,7 +218,7 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq)
}
complete_all(&dreq->completion);
- kref_put(&dreq->kref, nfs_direct_req_release);
+ nfs_direct_req_release(dreq);
}
/*
@@ -224,17 +234,18 @@ static void nfs_direct_read_result(struct rpc_task *task, void *calldata)
if (nfs_readpage_result(task, data) != 0)
return;
- nfs_direct_dirty_pages(data->pagevec, data->npages);
- nfs_direct_release_pages(data->pagevec, data->npages);
-
spin_lock(&dreq->lock);
-
- if (likely(task->tk_status >= 0))
- dreq->count += data->res.count;
- else
+ if (unlikely(task->tk_status < 0)) {
dreq->error = task->tk_status;
-
- spin_unlock(&dreq->lock);
+ spin_unlock(&dreq->lock);
+ } else {
+ dreq->count += data->res.count;
+ spin_unlock(&dreq->lock);
+ nfs_direct_dirty_pages(data->pagevec,
+ data->args.pgbase,
+ data->res.count);
+ }
+ nfs_direct_release_pages(data->pagevec, data->npages);
if (put_dreq(dreq))
nfs_direct_complete(dreq);
@@ -279,9 +290,12 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo
result = get_user_pages(current, current->mm, user_addr,
data->npages, 1, 0, data->pagevec, NULL);
up_read(&current->mm->mmap_sem);
- if (unlikely(result < data->npages)) {
- if (result > 0)
- nfs_direct_release_pages(data->pagevec, result);
+ if (result < 0) {
+ nfs_readdata_release(data);
+ break;
+ }
+ if ((unsigned)result < data->npages) {
+ nfs_direct_release_pages(data->pagevec, result);
nfs_readdata_release(data);
break;
}
@@ -359,6 +373,7 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size
if (!result)
result = nfs_direct_wait(dreq);
rpc_clnt_sigunmask(clnt, &oldset);
+ nfs_direct_req_release(dreq);
return result;
}
@@ -610,9 +625,12 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l
result = get_user_pages(current, current->mm, user_addr,
data->npages, 0, 0, data->pagevec, NULL);
up_read(&current->mm->mmap_sem);
- if (unlikely(result < data->npages)) {
- if (result > 0)
- nfs_direct_release_pages(data->pagevec, result);
+ if (result < 0) {
+ nfs_writedata_release(data);
+ break;
+ }
+ if ((unsigned)result < data->npages) {
+ nfs_direct_release_pages(data->pagevec, result);
nfs_writedata_release(data);
break;
}
@@ -703,6 +721,7 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
if (!result)
result = nfs_direct_wait(dreq);
rpc_clnt_sigunmask(clnt, &oldset);
+ nfs_direct_req_release(dreq);
return result;
}
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index cbdd1c6..c5bb51a 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -355,6 +355,26 @@ void nfs_pageio_complete(struct nfs_pageio_descriptor *desc)
nfs_pageio_doio(desc);
}
+/**
+ * nfs_pageio_cond_complete - Conditional I/O completion
+ * @desc: pointer to io descriptor
+ * @index: page index
+ *
+ * It is important to ensure that processes don't try to take locks
+ * on non-contiguous ranges of pages as that might deadlock. This
+ * function should be called before attempting to wait on a locked
+ * nfs_page. It will complete the I/O if the page index 'index'
+ * is not contiguous with the existing list of pages in 'desc'.
+ */
+void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index)
+{
+ if (!list_empty(&desc->pg_list)) {
+ struct nfs_page *prev = nfs_list_entry(desc->pg_list.prev);
+ if (index != prev->wb_index + 1)
+ nfs_pageio_doio(desc);
+ }
+}
+
#define NFS_SCAN_MAXENTRIES 16
/**
* nfs_scan_list - Scan a list for matching requests
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index b084c03..af344a1 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -273,8 +273,6 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
* request as dirty (in which case we don't care).
*/
spin_unlock(req_lock);
- /* Prevent deadlock! */
- nfs_pageio_complete(pgio);
ret = nfs_wait_on_request(req);
nfs_release_request(req);
if (ret != 0)
@@ -321,6 +319,8 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc
pgio = &mypgio;
}
+ nfs_pageio_cond_complete(pgio, page->index);
+
err = nfs_page_async_flush(pgio, page);
if (err <= 0)
goto out;
@@ -329,6 +329,8 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc
if (!offset)
goto out;
+ nfs_pageio_cond_complete(pgio, page->index);
+
ctx = nfs_find_open_context(inode, NULL, FMODE_WRITE);
if (ctx == NULL) {
err = -EBADF;
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index 074791c..b532a73 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -140,7 +140,7 @@ static int ntfs_init_locked_inode(struct inode *vi, ntfs_attr *na)
if (!ni->name)
return -ENOMEM;
memcpy(ni->name, na->name, i);
- ni->name[i] = 0;
+ ni->name[na->name_len] = 0;
}
return 0;
}
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index 8e7cafb..a480b09 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -222,7 +222,10 @@ static int ocfs2_readpage(struct file *file, struct page *page)
goto out;
}
- down_read(&OCFS2_I(inode)->ip_alloc_sem);
+ if (down_read_trylock(&OCFS2_I(inode)->ip_alloc_sem) == 0) {
+ ret = AOP_TRUNCATED_PAGE;
+ goto out_meta_unlock;
+ }
/*
* i_size might have just been updated as we grabed the meta lock. We
@@ -235,10 +238,7 @@ static int ocfs2_readpage(struct file *file, struct page *page)
* XXX sys_readahead() seems to get that wrong?
*/
if (start >= i_size_read(inode)) {
- char *addr = kmap(page);
- memset(addr, 0, PAGE_SIZE);
- flush_dcache_page(page);
- kunmap(page);
+ zero_user_page(page, 0, PAGE_SIZE, KM_USER0);
SetPageUptodate(page);
ret = 0;
goto out_alloc;
@@ -258,6 +258,7 @@ static int ocfs2_readpage(struct file *file, struct page *page)
ocfs2_data_unlock(inode, 0);
out_alloc:
up_read(&OCFS2_I(inode)->ip_alloc_sem);
+out_meta_unlock:
ocfs2_meta_unlock(inode, 0);
out:
if (unlock)
@@ -797,6 +798,11 @@ int ocfs2_map_and_write_splice_data(struct inode *inode,
}
to = from + bytes;
+ BUG_ON(from > PAGE_CACHE_SIZE);
+ BUG_ON(to > PAGE_CACHE_SIZE);
+ BUG_ON(from < cluster_start);
+ BUG_ON(to > cluster_end);
+
if (wc->w_this_page_new)
ret = ocfs2_map_page_blocks(wc->w_this_page, p_blkno, inode,
cluster_start, cluster_end, 1);
@@ -808,11 +814,6 @@ int ocfs2_map_and_write_splice_data(struct inode *inode,
goto out;
}
- BUG_ON(from > PAGE_CACHE_SIZE);
- BUG_ON(to > PAGE_CACHE_SIZE);
- BUG_ON(from > osb->s_clustersize);
- BUG_ON(to > osb->s_clustersize);
-
src = buf->ops->map(sp->s_pipe, buf, 1);
dst = kmap_atomic(wc->w_this_page, KM_USER1);
memcpy(dst + from, src + src_from, bytes);
@@ -889,6 +890,11 @@ int ocfs2_map_and_write_user_data(struct inode *inode,
to = from + bytes;
+ BUG_ON(from > PAGE_CACHE_SIZE);
+ BUG_ON(to > PAGE_CACHE_SIZE);
+ BUG_ON(from < cluster_start);
+ BUG_ON(to > cluster_end);
+
if (wc->w_this_page_new)
ret = ocfs2_map_page_blocks(wc->w_this_page, p_blkno, inode,
cluster_start, cluster_end, 1);
@@ -900,11 +906,6 @@ int ocfs2_map_and_write_user_data(struct inode *inode,
goto out;
}
- BUG_ON(from > PAGE_CACHE_SIZE);
- BUG_ON(to > PAGE_CACHE_SIZE);
- BUG_ON(from > osb->s_clustersize);
- BUG_ON(to > osb->s_clustersize);
-
dst = kmap(wc->w_this_page);
memcpy(dst + from, bp->b_src_buf + src_from, bytes);
kunmap(wc->w_this_page);
diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c
index a93620c..2b205f5 100644
--- a/fs/ocfs2/cluster/masklog.c
+++ b/fs/ocfs2/cluster/masklog.c
@@ -144,8 +144,7 @@ static struct kobj_type mlog_ktype = {
};
static struct kset mlog_kset = {
- .kobj = {.name = "logmask"},
- .ktype = &mlog_ktype
+ .kobj = {.name = "logmask", .ktype = &mlog_ktype},
};
int mlog_sys_init(struct kset *o2cb_subsys)
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 9395b4f..ac6c964 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -326,6 +326,7 @@ static int ocfs2_truncate_file(struct inode *inode,
(unsigned long long)OCFS2_I(inode)->ip_blkno,
(unsigned long long)new_i_size);
+ unmap_mapping_range(inode->i_mapping, new_i_size + PAGE_SIZE - 1, 0, 1);
truncate_inode_pages(inode->i_mapping, new_i_size);
fe = (struct ocfs2_dinode *) di_bh->b_data;
@@ -1418,36 +1419,6 @@ out:
return total ? total : ret;
}
-static int ocfs2_check_iovec(const struct iovec *iov, size_t *counted,
- unsigned long *nr_segs)
-{
- size_t ocount; /* original count */
- unsigned long seg;
-
- ocount = 0;
- for (seg = 0; seg < *nr_segs; seg++) {
- const struct iovec *iv = &iov[seg];
-
- /*
- * If any segment has a negative length, or the cumulative
- * length ever wraps negative then return -EINVAL.
- */
- ocount += iv->iov_len;
- if (unlikely((ssize_t)(ocount|iv->iov_len) < 0))
- return -EINVAL;
- if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len))
- continue;
- if (seg == 0)
- return -EFAULT;
- *nr_segs = seg;
- ocount -= iv->iov_len; /* This segment is no good */
- break;
- }
-
- *counted = ocount;
- return 0;
-}
-
static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
const struct iovec *iov,
unsigned long nr_segs,
@@ -1470,7 +1441,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
if (iocb->ki_left == 0)
return 0;
- ret = ocfs2_check_iovec(iov, &ocount, &nr_segs);
+ ret = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ);
if (ret)
return ret;
diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c
index 4dedd97..545f789 100644
--- a/fs/ocfs2/localalloc.c
+++ b/fs/ocfs2/localalloc.c
@@ -471,9 +471,6 @@ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb,
mutex_lock(&local_alloc_inode->i_mutex);
- ac->ac_inode = local_alloc_inode;
- ac->ac_which = OCFS2_AC_USE_LOCAL;
-
if (osb->local_alloc_state != OCFS2_LA_ENABLED) {
status = -ENOSPC;
goto bail;
@@ -511,10 +508,14 @@ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb,
}
}
+ ac->ac_inode = local_alloc_inode;
+ ac->ac_which = OCFS2_AC_USE_LOCAL;
get_bh(osb->local_alloc_bh);
ac->ac_bh = osb->local_alloc_bh;
status = 0;
bail:
+ if (status < 0 && local_alloc_inode)
+ iput(local_alloc_inode);
mlog_exit(status);
return status;
diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
index 3b481d5..5d258c4 100644
--- a/fs/ramfs/file-nommu.c
+++ b/fs/ramfs/file-nommu.c
@@ -179,7 +179,7 @@ static int ramfs_nommu_resize(struct inode *inode, loff_t newsize, loff_t size)
return ret;
}
- ret = vmtruncate(inode, size);
+ ret = vmtruncate(inode, newsize);
return ret;
}
@@ -195,6 +195,11 @@ static int ramfs_nommu_setattr(struct dentry *dentry, struct iattr *ia)
unsigned int old_ia_valid = ia->ia_valid;
int ret = 0;
+ /* POSIX UID/GID verification for setting inode attributes */
+ ret = inode_change_ok(inode, ia);
+ if (ret)
+ return ret;
+
/* by providing our own setattr() method, we skip this quotaism */
if ((old_ia_valid & ATTR_UID && ia->ia_uid != inode->i_uid) ||
(old_ia_valid & ATTR_GID && ia->ia_gid != inode->i_gid))
diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c
index 9c23fee..ffbfc2c 100644
--- a/fs/reiserfs/dir.c
+++ b/fs/reiserfs/dir.c
@@ -10,7 +10,7 @@
#include <linux/buffer_head.h>
#include <asm/uaccess.h>
-extern struct reiserfs_key MIN_KEY;
+extern const struct reiserfs_key MIN_KEY;
static int reiserfs_readdir(struct file *, void *, filldir_t);
static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry,
diff --git a/fs/signalfd.c b/fs/signalfd.c
index 7cfeab4..f1da892 100644
--- a/fs/signalfd.c
+++ b/fs/signalfd.c
@@ -11,6 +11,8 @@
* Now using anonymous inode source.
* Thanks to Oleg Nesterov for useful code review and suggestions.
* More comments and suggestions from Arnd Bergmann.
+ * Sat May 19, 2007: Davi E. M. Arnaut <davi@haxent.com.br>
+ * Retrieve multiple signals with one read() call
*/
#include <linux/file.h>
@@ -206,6 +208,59 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
return err ? -EFAULT: sizeof(*uinfo);
}
+static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, siginfo_t *info,
+ int nonblock)
+{
+ ssize_t ret;
+ struct signalfd_lockctx lk;
+ DECLARE_WAITQUEUE(wait, current);
+
+ if (!signalfd_lock(ctx, &lk))
+ return 0;
+
+ ret = dequeue_signal(lk.tsk, &ctx->sigmask, info);
+ switch (ret) {
+ case 0:
+ if (!nonblock)
+ break;
+ ret = -EAGAIN;
+ default:
+ signalfd_unlock(&lk);
+ return ret;
+ }
+
+ add_wait_queue(&ctx->wqh, &wait);
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ ret = dequeue_signal(lk.tsk, &ctx->sigmask, info);
+ signalfd_unlock(&lk);
+ if (ret != 0)
+ break;
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ ret = signalfd_lock(ctx, &lk);
+ if (unlikely(!ret)) {
+ /*
+ * Let the caller read zero byte, ala socket
+ * recv() when the peer disconnect. This test
+ * must be done before doing a dequeue_signal(),
+ * because if the sighand has been orphaned,
+ * the dequeue_signal() call is going to crash
+ * because ->sighand will be long gone.
+ */
+ break;
+ }
+ }
+
+ remove_wait_queue(&ctx->wqh, &wait);
+ __set_current_state(TASK_RUNNING);
+
+ return ret;
+}
+
/*
* Returns either the size of a "struct signalfd_siginfo", or zero if the
* sighand we are attached to, has been orphaned. The "count" parameter
@@ -215,55 +270,30 @@ static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
struct signalfd_ctx *ctx = file->private_data;
- ssize_t res = 0;
- int locked, signo;
+ struct signalfd_siginfo __user *siginfo;
+ int nonblock = file->f_flags & O_NONBLOCK;
+ ssize_t ret, total = 0;
siginfo_t info;
- struct signalfd_lockctx lk;
- DECLARE_WAITQUEUE(wait, current);
- if (count < sizeof(struct signalfd_siginfo))
+ count /= sizeof(struct signalfd_siginfo);
+ if (!count)
return -EINVAL;
- locked = signalfd_lock(ctx, &lk);
- if (!locked)
- return 0;
- res = -EAGAIN;
- signo = dequeue_signal(lk.tsk, &ctx->sigmask, &info);
- if (signo == 0 && !(file->f_flags & O_NONBLOCK)) {
- add_wait_queue(&ctx->wqh, &wait);
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
- signo = dequeue_signal(lk.tsk, &ctx->sigmask, &info);
- if (signo != 0)
- break;
- if (signal_pending(current)) {
- res = -ERESTARTSYS;
- break;
- }
- signalfd_unlock(&lk);
- schedule();
- locked = signalfd_lock(ctx, &lk);
- if (unlikely(!locked)) {
- /*
- * Let the caller read zero byte, ala socket
- * recv() when the peer disconnect. This test
- * must be done before doing a dequeue_signal(),
- * because if the sighand has been orphaned,
- * the dequeue_signal() call is going to crash.
- */
- res = 0;
- break;
- }
- }
- remove_wait_queue(&ctx->wqh, &wait);
- __set_current_state(TASK_RUNNING);
- }
- if (likely(locked))
- signalfd_unlock(&lk);
- if (likely(signo))
- res = signalfd_copyinfo((struct signalfd_siginfo __user *) buf,
- &info);
- return res;
+ siginfo = (struct signalfd_siginfo __user *) buf;
+
+ do {
+ ret = signalfd_dequeue(ctx, &info, nonblock);
+ if (unlikely(ret <= 0))
+ break;
+ ret = signalfd_copyinfo(siginfo, &info);
+ if (ret < 0)
+ break;
+ siginfo++;
+ total += ret;
+ nonblock = 1;
+ } while (--count);
+
+ return total ? total : ret;
}
static const struct file_operations signalfd_fops = {
diff --git a/fs/splice.c b/fs/splice.c
index 12f2828..cb21136 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -272,7 +272,6 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
struct page *page;
pgoff_t index, end_index;
loff_t isize;
- size_t total_len;
int error, page_nr;
struct splice_pipe_desc spd = {
.pages = pages,
@@ -298,7 +297,6 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
* Now fill in the holes:
*/
error = 0;
- total_len = 0;
/*
* Lookup the (hopefully) full range of pages we need.
@@ -415,43 +413,47 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
break;
}
+ }
+fill_it:
+ /*
+ * i_size must be checked after PageUptodate.
+ */
+ isize = i_size_read(mapping->host);
+ end_index = (isize - 1) >> PAGE_CACHE_SHIFT;
+ if (unlikely(!isize || index > end_index))
+ break;
+
+ /*
+ * if this is the last page, see if we need to shrink
+ * the length and stop
+ */
+ if (end_index == index) {
+ unsigned int plen;
/*
- * i_size must be checked after ->readpage().
+ * max good bytes in this page
*/
- isize = i_size_read(mapping->host);
- end_index = (isize - 1) >> PAGE_CACHE_SHIFT;
- if (unlikely(!isize || index > end_index))
+ plen = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;
+ if (plen <= loff)
break;
/*
- * if this is the last page, see if we need to shrink
- * the length and stop
+ * force quit after adding this page
*/
- if (end_index == index) {
- loff = PAGE_CACHE_SIZE - (isize & ~PAGE_CACHE_MASK);
- if (total_len + loff > isize)
- break;
- /*
- * force quit after adding this page
- */
- len = this_len;
- this_len = min(this_len, loff);
- loff = 0;
- }
+ this_len = min(this_len, plen - loff);
+ len = this_len;
}
-fill_it:
+
partial[page_nr].offset = loff;
partial[page_nr].len = this_len;
len -= this_len;
- total_len += this_len;
loff = 0;
spd.nr_pages++;
index++;
}
/*
- * Release any pages at the end, if we quit early. 'i' is how far
+ * Release any pages at the end, if we quit early. 'page_nr' is how far
* we got, 'nr_pages' is how many pages are in the map.
*/
while (page_nr < nr_pages)
@@ -478,10 +480,18 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
{
ssize_t spliced;
int ret;
+ loff_t isize, left;
+
+ isize = i_size_read(in->f_mapping->host);
+ if (unlikely(*ppos >= isize))
+ return 0;
+
+ left = isize - *ppos;
+ if (unlikely(left < len))
+ len = left;
ret = 0;
spliced = 0;
-
while (len) {
ret = __generic_file_splice_read(in, ppos, pipe, len, flags);
@@ -644,7 +654,6 @@ find_page:
* accessed, we are now done!
*/
mark_page_accessed(page);
- balance_dirty_pages_ratelimited(mapping);
out:
page_cache_release(page);
unlock_page(page);
@@ -815,6 +824,7 @@ generic_file_splice_write_nolock(struct pipe_inode_info *pipe, struct file *out,
if (err)
ret = err;
}
+ balance_dirty_pages_ratelimited(mapping);
}
return ret;
@@ -868,6 +878,7 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
if (err)
ret = err;
}
+ balance_dirty_pages_ratelimited(mapping);
}
return ret;
@@ -922,7 +933,6 @@ static long do_splice_to(struct file *in, loff_t *ppos,
struct pipe_inode_info *pipe, size_t len,
unsigned int flags)
{
- loff_t isize, left;
int ret;
if (unlikely(!in->f_op || !in->f_op->splice_read))
@@ -935,14 +945,6 @@ static long do_splice_to(struct file *in, loff_t *ppos,
if (unlikely(ret < 0))
return ret;
- isize = i_size_read(in->f_mapping->host);
- if (unlikely(*ppos >= isize))
- return 0;
-
- left = isize - *ppos;
- if (unlikely(left < len))
- len = left;
-
return in->f_op->splice_read(in, ppos, pipe, len, flags);
}
@@ -1058,8 +1060,6 @@ out_release:
return ret;
}
-EXPORT_SYMBOL(do_splice_direct);
-
/*
* After the inode slimming patch, i_pipe/i_bdev/i_cdev share the same
* location, so checking ->i_pipe is not enough to verify that this is a
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index c846155..1f01294 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -460,8 +460,8 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
kernel_long_ad laarr[EXTENT_MERGE_SIZE];
struct extent_position prev_epos, cur_epos, next_epos;
int count = 0, startnum = 0, endnum = 0;
- uint32_t elen = 0;
- kernel_lb_addr eloc;
+ uint32_t elen = 0, tmpelen;
+ kernel_lb_addr eloc, tmpeloc;
int c = 1;
loff_t lbcount = 0, b_off = 0;
uint32_t newblocknum, newblock;
@@ -520,8 +520,12 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
b_off -= lbcount;
offset = b_off >> inode->i_sb->s_blocksize_bits;
- /* Move into indirect extent if we are at a pointer to it */
- udf_next_aext(inode, &prev_epos, &eloc, &elen, 0);
+ /*
+ * Move prev_epos and cur_epos into indirect extent if we are at
+ * the pointer to it
+ */
+ udf_next_aext(inode, &prev_epos, &tmpeloc, &tmpelen, 0);
+ udf_next_aext(inode, &cur_epos, &tmpeloc, &tmpelen, 0);
/* if the extent is allocated and recorded, return the block
if the extent is not a multiple of the blocksize, round up */
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 3a743d8..6658afb 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -1351,7 +1351,7 @@ udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
for (i=0; i<UDF_SB_NUMPARTS(sb); i++)
{
- switch UDF_SB_PARTTYPE(sb, i)
+ switch (UDF_SB_PARTTYPE(sb, i))
{
case UDF_VIRTUAL_MAP15:
case UDF_VIRTUAL_MAP20:
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index 4475588..7361861 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -701,7 +701,7 @@ xfs_is_delayed_page(
else if (buffer_delay(bh))
acceptable = (type == IOMAP_DELAY);
else if (buffer_dirty(bh) && buffer_mapped(bh))
- acceptable = (type == 0);
+ acceptable = (type == IOMAP_NEW);
else
break;
} while ((bh = bh->b_this_page) != head);
@@ -810,7 +810,7 @@ xfs_convert_page(
page_dirty--;
count++;
} else {
- type = 0;
+ type = IOMAP_NEW;
if (buffer_mapped(bh) && all_bh && startio) {
lock_buffer(bh);
xfs_add_to_ioend(inode, bh, offset,
@@ -968,8 +968,8 @@ xfs_page_state_convert(
bh = head = page_buffers(page);
offset = page_offset(page);
- flags = -1;
- type = IOMAP_READ;
+ flags = BMAPI_READ;
+ type = IOMAP_NEW;
/* TODO: cleanup count and page_dirty */
@@ -999,14 +999,14 @@ xfs_page_state_convert(
*
* Third case, an unmapped buffer was found, and we are
* in a path where we need to write the whole page out.
- */
+ */
if (buffer_unwritten(bh) || buffer_delay(bh) ||
((buffer_uptodate(bh) || PageUptodate(page)) &&
!buffer_mapped(bh) && (unmapped || startio))) {
- /*
+ /*
* Make sure we don't use a read-only iomap
*/
- if (flags == BMAPI_READ)
+ if (flags == BMAPI_READ)
iomap_valid = 0;
if (buffer_unwritten(bh)) {
@@ -1055,7 +1055,7 @@ xfs_page_state_convert(
* That means it must already have extents allocated
* underneath it. Map the extent by reading it.
*/
- if (!iomap_valid || type != IOMAP_READ) {
+ if (!iomap_valid || flags != BMAPI_READ) {
flags = BMAPI_READ;
size = xfs_probe_cluster(inode, page, bh,
head, 1);
@@ -1066,7 +1066,15 @@ xfs_page_state_convert(
iomap_valid = xfs_iomap_valid(&iomap, offset);
}
- type = IOMAP_READ;
+ /*
+ * We set the type to IOMAP_NEW in case we are doing a
+ * small write at EOF that is extending the file but
+ * without needing an allocation. We need to update the
+ * file size on I/O completion in this case so it is
+ * the same case as having just allocated a new extent
+ * that we are writing into for the first time.
+ */
+ type = IOMAP_NEW;
if (!test_and_set_bit(BH_Lock, &bh->b_state)) {
ASSERT(buffer_mapped(bh));
if (iomap_valid)