mmc: s3c6410: enable ADMA feature in 6410 sdhci controller
[safe/jmp/linux-2.6] / fs / ioctl.c
index 001f8d3..2d140a7 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/uaccess.h>
 #include <linux/writeback.h>
 #include <linux/buffer_head.h>
+#include <linux/falloc.h>
 
 #include <asm/ioctls.h>
 
@@ -161,20 +162,21 @@ EXPORT_SYMBOL(fiemap_check_flags);
 static int fiemap_check_ranges(struct super_block *sb,
                               u64 start, u64 len, u64 *new_len)
 {
+       u64 maxbytes = (u64) sb->s_maxbytes;
+
        *new_len = len;
 
        if (len == 0)
                return -EINVAL;
 
-       if (start > sb->s_maxbytes)
+       if (start > maxbytes)
                return -EFBIG;
 
        /*
         * Shrink request scope to what the fs can actually handle.
         */
-       if ((len > sb->s_maxbytes) ||
-           (sb->s_maxbytes - len) < start)
-               *new_len = sb->s_maxbytes - start;
+       if (len > maxbytes || (maxbytes - len) < start)
+               *new_len = maxbytes - start;
 
        return 0;
 }
@@ -226,14 +228,23 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg)
 
 #ifdef CONFIG_BLOCK
 
-#define blk_to_logical(inode, blk) (blk << (inode)->i_blkbits)
-#define logical_to_blk(inode, offset) (offset >> (inode)->i_blkbits);
+static inline sector_t logical_to_blk(struct inode *inode, loff_t offset)
+{
+       return (offset >> inode->i_blkbits);
+}
+
+static inline loff_t blk_to_logical(struct inode *inode, sector_t blk)
+{
+       return (blk << inode->i_blkbits);
+}
 
 /**
  * __generic_block_fiemap - FIEMAP for block based inodes (no locking)
- * @inode - the inode to map
- * @arg - the pointer to userspace where we copy everything to
- * @get_block - the fs's get_block function
+ * @inode: the inode to map
+ * @fieinfo: the fiemap info struct that will be passed back to userspace
+ * @start: where to start mapping in the inode
+ * @len: how much space to map
+ * @get_block: the fs's get_block function
  *
  * This does FIEMAP for block based inodes.  Basically it will just loop
  * through get_block until we hit the number of extents we want to map, or we
@@ -248,58 +259,63 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg)
  */
 
 int __generic_block_fiemap(struct inode *inode,
-                          struct fiemap_extent_info *fieinfo, u64 start,
-                          u64 len, get_block_t *get_block)
+                          struct fiemap_extent_info *fieinfo, loff_t start,
+                          loff_t len, get_block_t *get_block)
 {
-       struct buffer_head tmp;
-       unsigned int start_blk;
-       long long length = 0, map_len = 0;
+       struct buffer_head map_bh;
+       sector_t start_blk, last_blk;
+       loff_t isize = i_size_read(inode);
        u64 logical = 0, phys = 0, size = 0;
        u32 flags = FIEMAP_EXTENT_MERGED;
-       int ret = 0, past_eof = 0, whole_file = 0;
+       bool past_eof = false, whole_file = false;
+       int ret = 0;
 
-       if ((ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC)))
+       ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC);
+       if (ret)
                return ret;
 
-       start_blk = logical_to_blk(inode, start);
-
-       length = (long long)min_t(u64, len, i_size_read(inode));
-       if (length < len)
-               whole_file = 1;
+       /*
+        * Either the i_mutex or other appropriate locking needs to be held
+        * since we expect isize to not change at all through the duration of
+        * this call.
+        */
+       if (len >= isize) {
+               whole_file = true;
+               len = isize;
+       }
 
-       map_len = length;
+       start_blk = logical_to_blk(inode, start);
+       last_blk = logical_to_blk(inode, start + len - 1);
 
        do {
                /*
                 * we set b_size to the total size we want so it will map as
                 * many contiguous blocks as possible at once
                 */
-               memset(&tmp, 0, sizeof(struct buffer_head));
-               tmp.b_size = map_len;
+               memset(&map_bh, 0, sizeof(struct buffer_head));
+               map_bh.b_size = len;
 
-               ret = get_block(inode, start_blk, &tmp, 0);
+               ret = get_block(inode, start_blk, &map_bh, 0);
                if (ret)
                        break;
 
                /* HOLE */
-               if (!buffer_mapped(&tmp)) {
-                       length -= blk_to_logical(inode, 1);
+               if (!buffer_mapped(&map_bh)) {
                        start_blk++;
 
                        /*
-                        * we want to handle the case where there is an
+                        * We want to handle the case where there is an
                         * allocated block at the front of the file, and then
                         * nothing but holes up to the end of the file properly,
                         * to make sure that extent at the front gets properly
                         * marked with FIEMAP_EXTENT_LAST
                         */
                        if (!past_eof &&
-                           blk_to_logical(inode, start_blk) >=
-                           blk_to_logical(inode, 0)+i_size_read(inode))
+                           blk_to_logical(inode, start_blk) >= isize)
                                past_eof = 1;
 
                        /*
-                        * first hole after going past the EOF, this is our
+                        * First hole after going past the EOF, this is our
                         * last extent
                         */
                        if (past_eof && size) {
@@ -307,15 +323,18 @@ int __generic_block_fiemap(struct inode *inode,
                                ret = fiemap_fill_next_extent(fieinfo, logical,
                                                              phys, size,
                                                              flags);
-                               break;
+                       } else if (size) {
+                               ret = fiemap_fill_next_extent(fieinfo, logical,
+                                                             phys, size, flags);
+                               size = 0;
                        }
 
                        /* if we have holes up to/past EOF then we're done */
-                       if (length <= 0 || past_eof)
+                       if (start_blk > last_blk || past_eof || ret)
                                break;
                } else {
                        /*
-                        * we have gone over the length of what we wanted to
+                        * We have gone over the length of what we wanted to
                         * map, and it wasn't the entire file, so add the extent
                         * we got last time and exit.
                         *
@@ -329,7 +348,7 @@ int __generic_block_fiemap(struct inode *inode,
                         * are good to go, just add the extent to the fieinfo
                         * and break
                         */
-                       if (length <= 0 && !whole_file) {
+                       if (start_blk > last_blk && !whole_file) {
                                ret = fiemap_fill_next_extent(fieinfo, logical,
                                                              phys, size,
                                                              flags);
@@ -349,11 +368,10 @@ int __generic_block_fiemap(struct inode *inode,
                        }
 
                        logical = blk_to_logical(inode, start_blk);
-                       phys = blk_to_logical(inode, tmp.b_blocknr);
-                       size = tmp.b_size;
+                       phys = blk_to_logical(inode, map_bh.b_blocknr);
+                       size = map_bh.b_size;
                        flags = FIEMAP_EXTENT_MERGED;
 
-                       length -= tmp.b_size;
                        start_blk += logical_to_blk(inode, size);
 
                        /*
@@ -361,15 +379,13 @@ int __generic_block_fiemap(struct inode *inode,
                         * soon as we find a hole that the last extent we found
                         * is marked with FIEMAP_EXTENT_LAST
                         */
-                       if (!past_eof &&
-                           logical+size >=
-                           blk_to_logical(inode, 0)+i_size_read(inode))
-                               past_eof = 1;
+                       if (!past_eof && logical + size >= isize)
+                               past_eof = true;
                }
                cond_resched();
        } while (1);
 
-       /* if ret is 1 then we just hit the end of the extent array */
+       /* If ret is 1 then we just hit the end of the extent array */
        if (ret == 1)
                ret = 0;
 
@@ -403,6 +419,37 @@ EXPORT_SYMBOL(generic_block_fiemap);
 
 #endif  /*  CONFIG_BLOCK  */
 
+/*
+ * This provides compatibility with legacy XFS pre-allocation ioctls
+ * which predate the fallocate syscall.
+ *
+ * Only the l_start, l_len and l_whence fields of the 'struct space_resv'
+ * are used here, rest are ignored.
+ */
+int ioctl_preallocate(struct file *filp, void __user *argp)
+{
+       struct inode *inode = filp->f_path.dentry->d_inode;
+       struct space_resv sr;
+
+       if (copy_from_user(&sr, argp, sizeof(sr)))
+               return -EFAULT;
+
+       switch (sr.l_whence) {
+       case SEEK_SET:
+               break;
+       case SEEK_CUR:
+               sr.l_start += filp->f_pos;
+               break;
+       case SEEK_END:
+               sr.l_start += i_size_read(inode);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return do_fallocate(filp, FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len);
+}
+
 static int file_ioctl(struct file *filp, unsigned int cmd,
                unsigned long arg)
 {
@@ -414,6 +461,9 @@ static int file_ioctl(struct file *filp, unsigned int cmd,
                return ioctl_fibmap(filp, p);
        case FIONREAD:
                return put_user(i_size_read(inode) - filp->f_pos, p);
+       case FS_IOC_RESVSP:
+       case FS_IOC_RESVSP64:
+               return ioctl_preallocate(filp, p);
        }
 
        return vfs_ioctl(filp, cmd, arg);
@@ -475,15 +525,8 @@ static int ioctl_fsfreeze(struct file *filp)
        if (sb->s_op->freeze_fs == NULL)
                return -EOPNOTSUPP;
 
-       /* If a blockdevice-backed filesystem isn't specified, return. */
-       if (sb->s_bdev == NULL)
-               return -EINVAL;
-
        /* Freeze */
-       sb = freeze_bdev(sb->s_bdev);
-       if (IS_ERR(sb))
-               return PTR_ERR(sb);
-       return 0;
+       return freeze_super(sb);
 }
 
 static int ioctl_fsthaw(struct file *filp)
@@ -493,12 +536,8 @@ static int ioctl_fsthaw(struct file *filp)
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       /* If a blockdevice-backed filesystem isn't specified, return EINVAL. */
-       if (sb->s_bdev == NULL)
-               return -EINVAL;
-
        /* Thaw */
-       return thaw_bdev(sb->s_bdev, sb);
+       return thaw_super(sb);
 }
 
 /*