linux/fs/reiserfs/ioctl.c
<<
>>
Prefs
   1/*
   2 * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
   3 */
   4
   5#include <linux/capability.h>
   6#include <linux/fs.h>
   7#include <linux/mount.h>
   8#include <linux/reiserfs_fs.h>
   9#include <linux/time.h>
  10#include <asm/uaccess.h>
  11#include <linux/pagemap.h>
  12#include <linux/smp_lock.h>
  13#include <linux/compat.h>
  14
  15/*
  16** reiserfs_ioctl - handler for ioctl for inode
  17** supported commands:
  18**  1) REISERFS_IOC_UNPACK - try to unpack tail from direct item into indirect
  19**                           and prevent packing file (argument arg has to be non-zero)
  20**  2) REISERFS_IOC_[GS]ETFLAGS, REISERFS_IOC_[GS]ETVERSION
  21**  3) That's all for a while ...
  22*/
  23int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
  24                   unsigned long arg)
  25{
  26        unsigned int flags;
  27        int err = 0;
  28
  29        switch (cmd) {
  30        case REISERFS_IOC_UNPACK:
  31                if (S_ISREG(inode->i_mode)) {
  32                        if (arg)
  33                                return reiserfs_unpack(inode, filp);
  34                        else
  35                                return 0;
  36                } else
  37                        return -ENOTTY;
  38                /* following two cases are taken from fs/ext2/ioctl.c by Remy
  39                   Card (card@masi.ibp.fr) */
  40        case REISERFS_IOC_GETFLAGS:
  41                if (!reiserfs_attrs(inode->i_sb))
  42                        return -ENOTTY;
  43
  44                flags = REISERFS_I(inode)->i_attrs;
  45                i_attrs_to_sd_attrs(inode, (__u16 *) & flags);
  46                return put_user(flags, (int __user *)arg);
  47        case REISERFS_IOC_SETFLAGS:{
  48                        if (!reiserfs_attrs(inode->i_sb))
  49                                return -ENOTTY;
  50
  51                        err = mnt_want_write(filp->f_path.mnt);
  52                        if (err)
  53                                return err;
  54
  55                        if (!is_owner_or_cap(inode)) {
  56                                err = -EPERM;
  57                                goto setflags_out;
  58                        }
  59                        if (get_user(flags, (int __user *)arg)) {
  60                                err = -EFAULT;
  61                                goto setflags_out;
  62                        }
  63                        /*
  64                         * Is it quota file? Do not allow user to mess with it
  65                         */
  66                        if (IS_NOQUOTA(inode)) {
  67                                err = -EPERM;
  68                                goto setflags_out;
  69                        }
  70                        if (((flags ^ REISERFS_I(inode)->
  71                              i_attrs) & (REISERFS_IMMUTABLE_FL |
  72                                          REISERFS_APPEND_FL))
  73                            && !capable(CAP_LINUX_IMMUTABLE)) {
  74                                err = -EPERM;
  75                                goto setflags_out;
  76                        }
  77                        if ((flags & REISERFS_NOTAIL_FL) &&
  78                            S_ISREG(inode->i_mode)) {
  79                                int result;
  80
  81                                result = reiserfs_unpack(inode, filp);
  82                                if (result) {
  83                                        err = result;
  84                                        goto setflags_out;
  85                                }
  86                        }
  87                        sd_attrs_to_i_attrs(flags, inode);
  88                        REISERFS_I(inode)->i_attrs = flags;
  89                        inode->i_ctime = CURRENT_TIME_SEC;
  90                        mark_inode_dirty(inode);
  91setflags_out:
  92                        mnt_drop_write(filp->f_path.mnt);
  93                        return err;
  94                }
  95        case REISERFS_IOC_GETVERSION:
  96                return put_user(inode->i_generation, (int __user *)arg);
  97        case REISERFS_IOC_SETVERSION:
  98                if (!is_owner_or_cap(inode))
  99                        return -EPERM;
 100                err = mnt_want_write(filp->f_path.mnt);
 101                if (err)
 102                        return err;
 103                if (get_user(inode->i_generation, (int __user *)arg)) {
 104                        err = -EFAULT;
 105                        goto setversion_out;
 106                }
 107                inode->i_ctime = CURRENT_TIME_SEC;
 108                mark_inode_dirty(inode);
 109setversion_out:
 110                mnt_drop_write(filp->f_path.mnt);
 111                return err;
 112        default:
 113                return -ENOTTY;
 114        }
 115}
 116
 117#ifdef CONFIG_COMPAT
 118long reiserfs_compat_ioctl(struct file *file, unsigned int cmd,
 119                                unsigned long arg)
 120{
 121        struct inode *inode = file->f_path.dentry->d_inode;
 122        int ret;
 123
 124        /* These are just misnamed, they actually get/put from/to user an int */
 125        switch (cmd) {
 126        case REISERFS_IOC32_UNPACK:
 127                cmd = REISERFS_IOC_UNPACK;
 128                break;
 129        case REISERFS_IOC32_GETFLAGS:
 130                cmd = REISERFS_IOC_GETFLAGS;
 131                break;
 132        case REISERFS_IOC32_SETFLAGS:
 133                cmd = REISERFS_IOC_SETFLAGS;
 134                break;
 135        case REISERFS_IOC32_GETVERSION:
 136                cmd = REISERFS_IOC_GETVERSION;
 137                break;
 138        case REISERFS_IOC32_SETVERSION:
 139                cmd = REISERFS_IOC_SETVERSION;
 140                break;
 141        default:
 142                return -ENOIOCTLCMD;
 143        }
 144        lock_kernel();
 145        ret = reiserfs_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg));
 146        unlock_kernel();
 147        return ret;
 148}
 149#endif
 150
 151int reiserfs_commit_write(struct file *f, struct page *page,
 152                          unsigned from, unsigned to);
 153int reiserfs_prepare_write(struct file *f, struct page *page,
 154                           unsigned from, unsigned to);
 155/*
 156** reiserfs_unpack
 157** Function try to convert tail from direct item into indirect.
 158** It set up nopack attribute in the REISERFS_I(inode)->nopack
 159*/
 160int reiserfs_unpack(struct inode *inode, struct file *filp)
 161{
 162        int retval = 0;
 163        int index;
 164        struct page *page;
 165        struct address_space *mapping;
 166        unsigned long write_from;
 167        unsigned long blocksize = inode->i_sb->s_blocksize;
 168
 169        if (inode->i_size == 0) {
 170                REISERFS_I(inode)->i_flags |= i_nopack_mask;
 171                return 0;
 172        }
 173        /* ioctl already done */
 174        if (REISERFS_I(inode)->i_flags & i_nopack_mask) {
 175                return 0;
 176        }
 177
 178        /* we need to make sure nobody is changing the file size beneath
 179         ** us
 180         */
 181        mutex_lock(&inode->i_mutex);
 182        reiserfs_write_lock(inode->i_sb);
 183
 184        write_from = inode->i_size & (blocksize - 1);
 185        /* if we are on a block boundary, we are already unpacked.  */
 186        if (write_from == 0) {
 187                REISERFS_I(inode)->i_flags |= i_nopack_mask;
 188                goto out;
 189        }
 190
 191        /* we unpack by finding the page with the tail, and calling
 192         ** reiserfs_prepare_write on that page.  This will force a 
 193         ** reiserfs_get_block to unpack the tail for us.
 194         */
 195        index = inode->i_size >> PAGE_CACHE_SHIFT;
 196        mapping = inode->i_mapping;
 197        page = grab_cache_page(mapping, index);
 198        retval = -ENOMEM;
 199        if (!page) {
 200                goto out;
 201        }
 202        retval = reiserfs_prepare_write(NULL, page, write_from, write_from);
 203        if (retval)
 204                goto out_unlock;
 205
 206        /* conversion can change page contents, must flush */
 207        flush_dcache_page(page);
 208        retval = reiserfs_commit_write(NULL, page, write_from, write_from);
 209        REISERFS_I(inode)->i_flags |= i_nopack_mask;
 210
 211      out_unlock:
 212        unlock_page(page);
 213        page_cache_release(page);
 214
 215      out:
 216        mutex_unlock(&inode->i_mutex);
 217        reiserfs_write_unlock(inode->i_sb);
 218        return retval;
 219}
 220