Merge branch 'sii-m15w' into upstream
[pandora-kernel.git] / fs / reiserfs / ioctl.c
index 94dc424..a986b5e 100644 (file)
@@ -2,6 +2,7 @@
  * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
  */
 
+#include <linux/capability.h>
 #include <linux/fs.h>
 #include <linux/reiserfs_fs.h>
 #include <linux/time.h>
@@ -9,7 +10,7 @@
 #include <linux/pagemap.h>
 #include <linux/smp_lock.h>
 
-static int reiserfs_unpack (struct inode * inode, struct file * filp);
+static int reiserfs_unpack(struct inode *inode, struct file *filp);
 
 /*
 ** reiserfs_ioctl - handler for ioctl for inode
@@ -19,63 +20,72 @@ static int reiserfs_unpack (struct inode * inode, struct file * filp);
 **  2) REISERFS_IOC_[GS]ETFLAGS, REISERFS_IOC_[GS]ETVERSION
 **  3) That's all for a while ...
 */
-int reiserfs_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
-               unsigned long arg)
+int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+                  unsigned long arg)
 {
        unsigned int flags;
 
        switch (cmd) {
-           case REISERFS_IOC_UNPACK:
-               if( S_ISREG( inode -> i_mode ) ) {
-               if (arg)
-                   return reiserfs_unpack (inode, filp);
+       case REISERFS_IOC_UNPACK:
+               if (S_ISREG(inode->i_mode)) {
+                       if (arg)
+                               return reiserfs_unpack(inode, filp);
                        else
                                return 0;
                } else
                        return -ENOTTY;
-       /* following two cases are taken from fs/ext2/ioctl.c by Remy
-          Card (card@masi.ibp.fr) */
+               /* following two cases are taken from fs/ext2/ioctl.c by Remy
+                  Card (card@masi.ibp.fr) */
        case REISERFS_IOC_GETFLAGS:
-               flags = REISERFS_I(inode) -> i_attrs;
-               i_attrs_to_sd_attrs( inode, ( __u16 * ) &flags );
-               return put_user(flags, (int __user *) arg);
-       case REISERFS_IOC_SETFLAGS: {
-               if (IS_RDONLY(inode))
-                       return -EROFS;
+               if (!reiserfs_attrs(inode->i_sb))
+                       return -ENOTTY;
 
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
-                       return -EPERM;
+               flags = REISERFS_I(inode)->i_attrs;
+               i_attrs_to_sd_attrs(inode, (__u16 *) & flags);
+               return put_user(flags, (int __user *)arg);
+       case REISERFS_IOC_SETFLAGS:{
+                       if (!reiserfs_attrs(inode->i_sb))
+                               return -ENOTTY;
 
-               if (get_user(flags, (int __user *) arg))
-                       return -EFAULT;
+                       if (IS_RDONLY(inode))
+                               return -EROFS;
 
-               if ( ( ( flags ^ REISERFS_I(inode) -> i_attrs) & ( REISERFS_IMMUTABLE_FL | REISERFS_APPEND_FL)) &&
-                    !capable( CAP_LINUX_IMMUTABLE ) )
-                       return -EPERM;
-                       
-               if( ( flags & REISERFS_NOTAIL_FL ) &&
-                   S_ISREG( inode -> i_mode ) ) {
+                       if ((current->fsuid != inode->i_uid)
+                           && !capable(CAP_FOWNER))
+                               return -EPERM;
+
+                       if (get_user(flags, (int __user *)arg))
+                               return -EFAULT;
+
+                       if (((flags ^ REISERFS_I(inode)->
+                             i_attrs) & (REISERFS_IMMUTABLE_FL |
+                                         REISERFS_APPEND_FL))
+                           && !capable(CAP_LINUX_IMMUTABLE))
+                               return -EPERM;
+
+                       if ((flags & REISERFS_NOTAIL_FL) &&
+                           S_ISREG(inode->i_mode)) {
                                int result;
 
-                               result = reiserfs_unpack( inode, filp );
-                               if( result )
+                               result = reiserfs_unpack(inode, filp);
+                               if (result)
                                        return result;
+                       }
+                       sd_attrs_to_i_attrs(flags, inode);
+                       REISERFS_I(inode)->i_attrs = flags;
+                       inode->i_ctime = CURRENT_TIME_SEC;
+                       mark_inode_dirty(inode);
+                       return 0;
                }
-               sd_attrs_to_i_attrs( flags, inode );
-               REISERFS_I(inode) -> i_attrs = flags;
-               inode->i_ctime = CURRENT_TIME_SEC;
-               mark_inode_dirty(inode);
-               return 0;
-       }
        case REISERFS_IOC_GETVERSION:
-               return put_user(inode->i_generation, (int __user *) arg);
+               return put_user(inode->i_generation, (int __user *)arg);
        case REISERFS_IOC_SETVERSION:
                if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
                        return -EPERM;
                if (IS_RDONLY(inode))
                        return -EROFS;
-               if (get_user(inode->i_generation, (int __user *) arg))
-                       return -EFAULT; 
+               if (get_user(inode->i_generation, (int __user *)arg))
+                       return -EFAULT;
                inode->i_ctime = CURRENT_TIME_SEC;
                mark_inode_dirty(inode);
                return 0;
@@ -89,63 +99,65 @@ int reiserfs_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
 ** Function try to convert tail from direct item into indirect.
 ** It set up nopack attribute in the REISERFS_I(inode)->nopack
 */
-static int reiserfs_unpack (struct inode * inode, struct file * filp)
+static int reiserfs_unpack(struct inode *inode, struct file *filp)
 {
-    int retval = 0;
-    int index ;
-    struct page *page ;
-    struct address_space *mapping ;
-    unsigned long write_from ;
-    unsigned long blocksize = inode->i_sb->s_blocksize ;
-       
-    if (inode->i_size == 0) {
-        REISERFS_I(inode)->i_flags |= i_nopack_mask;
-        return 0 ;
-    }
-    /* ioctl already done */
-    if (REISERFS_I(inode)->i_flags & i_nopack_mask) {
-        return 0 ;
-    }
-    reiserfs_write_lock(inode->i_sb);
-
-    /* we need to make sure nobody is changing the file size beneath
-    ** us
-    */
-    down(&inode->i_sem) ;
-
-    write_from = inode->i_size & (blocksize - 1) ;
-    /* if we are on a block boundary, we are already unpacked.  */
-    if ( write_from == 0) {
+       int retval = 0;
+       int index;
+       struct page *page;
+       struct address_space *mapping;
+       unsigned long write_from;
+       unsigned long blocksize = inode->i_sb->s_blocksize;
+
+       if (inode->i_size == 0) {
+               REISERFS_I(inode)->i_flags |= i_nopack_mask;
+               return 0;
+       }
+       /* ioctl already done */
+       if (REISERFS_I(inode)->i_flags & i_nopack_mask) {
+               return 0;
+       }
+
+       /* we need to make sure nobody is changing the file size beneath
+        ** us
+        */
+       mutex_lock(&inode->i_mutex);
+       reiserfs_write_lock(inode->i_sb);
+
+       write_from = inode->i_size & (blocksize - 1);
+       /* if we are on a block boundary, we are already unpacked.  */
+       if (write_from == 0) {
+               REISERFS_I(inode)->i_flags |= i_nopack_mask;
+               goto out;
+       }
+
+       /* we unpack by finding the page with the tail, and calling
+        ** reiserfs_prepare_write on that page.  This will force a 
+        ** reiserfs_get_block to unpack the tail for us.
+        */
+       index = inode->i_size >> PAGE_CACHE_SHIFT;
+       mapping = inode->i_mapping;
+       page = grab_cache_page(mapping, index);
+       retval = -ENOMEM;
+       if (!page) {
+               goto out;
+       }
+       retval =
+           mapping->a_ops->prepare_write(NULL, page, write_from, write_from);
+       if (retval)
+               goto out_unlock;
+
+       /* conversion can change page contents, must flush */
+       flush_dcache_page(page);
+       retval =
+           mapping->a_ops->commit_write(NULL, page, write_from, write_from);
        REISERFS_I(inode)->i_flags |= i_nopack_mask;
-       goto out ;
-    }
-
-    /* we unpack by finding the page with the tail, and calling
-    ** reiserfs_prepare_write on that page.  This will force a 
-    ** reiserfs_get_block to unpack the tail for us.
-    */
-    index = inode->i_size >> PAGE_CACHE_SHIFT ;
-    mapping = inode->i_mapping ;
-    page = grab_cache_page(mapping, index) ;
-    retval = -ENOMEM;
-    if (!page) {
-        goto out ;
-    }
-    retval = mapping->a_ops->prepare_write(NULL, page, write_from, write_from) ;
-    if (retval)
-        goto out_unlock ;
-
-    /* conversion can change page contents, must flush */
-    flush_dcache_page(page) ;
-    retval = mapping->a_ops->commit_write(NULL, page, write_from, write_from) ;
-    REISERFS_I(inode)->i_flags |= i_nopack_mask;
-
-out_unlock:
-    unlock_page(page) ;
-    page_cache_release(page) ;
-
-out:
-    up(&inode->i_sem) ;
-    reiserfs_write_unlock(inode->i_sb);
-    return retval;
+
+      out_unlock:
+       unlock_page(page);
+       page_cache_release(page);
+
+      out:
+       mutex_unlock(&inode->i_mutex);
+       reiserfs_write_unlock(inode->i_sb);
+       return retval;
 }