drm/radeon: don't actually enable the IRQ regs until irq is enabled
[safe/jmp/linux-2.6] / fs / ioctl.c
index 045d960..43e8b2c 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/security.h>
 #include <linux/module.h>
 #include <linux/uaccess.h>
+#include <linux/writeback.h>
+#include <linux/buffer_head.h>
 
 #include <asm/ioctls.h>
 
@@ -224,6 +226,126 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg)
        return error;
 }
 
+#ifdef CONFIG_BLOCK
+
+#define blk_to_logical(inode, blk) (blk << (inode)->i_blkbits)
+#define logical_to_blk(inode, offset) (offset >> (inode)->i_blkbits);
+
+/*
+ * @inode - the inode to map
+ * @arg - the pointer to userspace where we copy everything to
+ * @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
+ * go past the end of the file and hit a hole.
+ *
+ * If it is possible to have data blocks beyond a hole past @inode->i_size, then
+ * please do not use this function, it will stop at the first unmapped block
+ * beyond i_size
+ */
+int generic_block_fiemap(struct inode *inode,
+                        struct fiemap_extent_info *fieinfo, u64 start,
+                        u64 len, get_block_t *get_block)
+{
+       struct buffer_head tmp;
+       unsigned int start_blk;
+       long long length = 0, map_len = 0;
+       u64 logical = 0, phys = 0, size = 0;
+       u32 flags = FIEMAP_EXTENT_MERGED;
+       int ret = 0;
+
+       if ((ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC)))
+               return ret;
+
+       start_blk = logical_to_blk(inode, start);
+
+       /* guard against change */
+       mutex_lock(&inode->i_mutex);
+
+       length = (long long)min_t(u64, len, i_size_read(inode));
+       map_len = length;
+
+       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;
+
+               ret = get_block(inode, start_blk, &tmp, 0);
+               if (ret)
+                       break;
+
+               /* HOLE */
+               if (!buffer_mapped(&tmp)) {
+                       /*
+                        * first hole after going past the EOF, this is our
+                        * last extent
+                        */
+                       if (length <= 0) {
+                               flags = FIEMAP_EXTENT_MERGED|FIEMAP_EXTENT_LAST;
+                               ret = fiemap_fill_next_extent(fieinfo, logical,
+                                                             phys, size,
+                                                             flags);
+                               break;
+                       }
+
+                       length -= blk_to_logical(inode, 1);
+
+                       /* if we have holes up to/past EOF then we're done */
+                       if (length <= 0)
+                               break;
+
+                       start_blk++;
+               } else {
+                       if (length <= 0 && size) {
+                               ret = fiemap_fill_next_extent(fieinfo, logical,
+                                                             phys, size,
+                                                             flags);
+                               if (ret)
+                                       break;
+                       }
+
+                       logical = blk_to_logical(inode, start_blk);
+                       phys = blk_to_logical(inode, tmp.b_blocknr);
+                       size = tmp.b_size;
+                       flags = FIEMAP_EXTENT_MERGED;
+
+                       length -= tmp.b_size;
+                       start_blk += logical_to_blk(inode, size);
+
+                       /*
+                        * if we are past the EOF we need to loop again to see
+                        * if there is a hole so we can mark this extent as the
+                        * last one, and if not keep mapping things until we
+                        * find a hole, or we run out of slots in the extent
+                        * array
+                        */
+                       if (length <= 0)
+                               continue;
+
+                       ret = fiemap_fill_next_extent(fieinfo, logical, phys,
+                                                     size, flags);
+                       if (ret)
+                               break;
+               }
+               cond_resched();
+       } while (1);
+
+       mutex_unlock(&inode->i_mutex);
+
+       /* if ret is 1 then we just hit the end of the extent array */
+       if (ret == 1)
+               ret = 0;
+
+       return ret;
+}
+EXPORT_SYMBOL(generic_block_fiemap);
+
+#endif  /*  CONFIG_BLOCK  */
+
 static int file_ioctl(struct file *filp, unsigned int cmd,
                unsigned long arg)
 {
@@ -278,11 +400,9 @@ static int ioctl_fioasync(unsigned int fd, struct file *filp,
 
        /* Did FASYNC state change ? */
        if ((flag ^ filp->f_flags) & FASYNC) {
-               if (filp->f_op && filp->f_op->fasync) {
-                       lock_kernel();
+               if (filp->f_op && filp->f_op->fasync)
                        error = filp->f_op->fasync(fd, filp, on);
-                       unlock_kernel();
-               } else
+               else
                        error = -ENOTTY;
        }
        if (error)
@@ -318,11 +438,17 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
                break;
 
        case FIONBIO:
+               /* BKL needed to avoid races tweaking f_flags */
+               lock_kernel();
                error = ioctl_fionbio(filp, argp);
+               unlock_kernel();
                break;
 
        case FIOASYNC:
+               /* BKL needed to avoid races tweaking f_flags */
+               lock_kernel();
                error = ioctl_fioasync(fd, filp, argp);
+               unlock_kernel();
                break;
 
        case FIOQSIZE: