Merge branch 'fix/hda' into for-linus
[pandora-kernel.git] / fs / ext4 / ioctl.c
index 91e75f7..7050a9c 100644 (file)
@@ -12,8 +12,8 @@
 #include <linux/capability.h>
 #include <linux/time.h>
 #include <linux/compat.h>
-#include <linux/smp_lock.h>
 #include <linux/mount.h>
+#include <linux/file.h>
 #include <asm/uaccess.h>
 #include "ext4_jbd2.h"
 #include "ext4.h"
@@ -191,7 +191,7 @@ setversion_out:
        case EXT4_IOC_GROUP_EXTEND: {
                ext4_fsblk_t n_blocks_count;
                struct super_block *sb = inode->i_sb;
-               int err, err2;
+               int err, err2=0;
 
                if (!capable(CAP_SYS_RESOURCE))
                        return -EPERM;
@@ -204,19 +204,56 @@ setversion_out:
                        return err;
 
                err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count);
-               jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
-               err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
-               jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+               if (EXT4_SB(sb)->s_journal) {
+                       jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
+                       err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
+                       jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+               }
                if (err == 0)
                        err = err2;
                mnt_drop_write(filp->f_path.mnt);
 
                return err;
        }
+
+       case EXT4_IOC_MOVE_EXT: {
+               struct move_extent me;
+               struct file *donor_filp;
+               int err;
+
+               if (copy_from_user(&me,
+                       (struct move_extent __user *)arg, sizeof(me)))
+                       return -EFAULT;
+
+               donor_filp = fget(me.donor_fd);
+               if (!donor_filp)
+                       return -EBADF;
+
+               if (!capable(CAP_DAC_OVERRIDE)) {
+                       if ((current->real_cred->fsuid != inode->i_uid) ||
+                               !(inode->i_mode & S_IRUSR) ||
+                               !(donor_filp->f_dentry->d_inode->i_mode &
+                               S_IRUSR)) {
+                               fput(donor_filp);
+                               return -EACCES;
+                       }
+               }
+
+               err = ext4_move_extents(filp, donor_filp, me.orig_start,
+                                       me.donor_start, me.len, &me.moved_len);
+               fput(donor_filp);
+
+               if (!err)
+                       if (copy_to_user((struct move_extent *)arg,
+                               &me, sizeof(me)))
+                               return -EFAULT;
+               return err;
+       }
+
        case EXT4_IOC_GROUP_ADD: {
                struct ext4_new_group_data input;
                struct super_block *sb = inode->i_sb;
-               int err, err2;
+               int err, err2=0;
 
                if (!capable(CAP_SYS_RESOURCE))
                        return -EPERM;
@@ -230,9 +267,11 @@ setversion_out:
                        return err;
 
                err = ext4_group_add(sb, &input);
-               jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
-               err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
-               jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+               if (EXT4_SB(sb)->s_journal) {
+                       jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
+                       err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
+                       jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+               }
                if (err == 0)
                        err = err2;
                mnt_drop_write(filp->f_path.mnt);