| |
| |
| |
| |
| #include <linux/capability.h> |
| #include <linux/fs.h> |
| #include <linux/mount.h> |
| #include "reiserfs.h" |
| #include <linux/time.h> |
| #include <linux/uaccess.h> |
| #include <linux/pagemap.h> |
| #include <linux/compat.h> |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
| { |
| <------>struct inode *inode = file_inode(filp); |
| <------>unsigned int flags; |
| <------>int err = 0; |
| |
| <------>reiserfs_write_lock(inode->i_sb); |
| |
| <------>switch (cmd) { |
| <------>case REISERFS_IOC_UNPACK: |
| <------><------>if (S_ISREG(inode->i_mode)) { |
| <------><------><------>if (arg) |
| <------><------><------><------>err = reiserfs_unpack(inode, filp); |
| <------><------>} else |
| <------><------><------>err = -ENOTTY; |
| <------><------>break; |
| <------><------> |
| <------><------> * following two cases are taken from fs/ext2/ioctl.c by Remy |
| <------><------> * Card (card@masi.ibp.fr) |
| <------><------> */ |
| <------>case REISERFS_IOC_GETFLAGS: |
| <------><------>if (!reiserfs_attrs(inode->i_sb)) { |
| <------><------><------>err = -ENOTTY; |
| <------><------><------>break; |
| <------><------>} |
| |
| <------><------>flags = REISERFS_I(inode)->i_attrs; |
| <------><------>err = put_user(flags, (int __user *)arg); |
| <------><------>break; |
| <------>case REISERFS_IOC_SETFLAGS:{ |
| <------><------><------>if (!reiserfs_attrs(inode->i_sb)) { |
| <------><------><------><------>err = -ENOTTY; |
| <------><------><------><------>break; |
| <------><------><------>} |
| |
| <------><------><------>err = mnt_want_write_file(filp); |
| <------><------><------>if (err) |
| <------><------><------><------>break; |
| |
| <------><------><------>if (!inode_owner_or_capable(inode)) { |
| <------><------><------><------>err = -EPERM; |
| <------><------><------><------>goto setflags_out; |
| <------><------><------>} |
| <------><------><------>if (get_user(flags, (int __user *)arg)) { |
| <------><------><------><------>err = -EFAULT; |
| <------><------><------><------>goto setflags_out; |
| <------><------><------>} |
| <------><------><------> |
| <------><------><------> * Is it quota file? Do not allow user to mess with it |
| <------><------><------> */ |
| <------><------><------>if (IS_NOQUOTA(inode)) { |
| <------><------><------><------>err = -EPERM; |
| <------><------><------><------>goto setflags_out; |
| <------><------><------>} |
| <------><------><------>err = vfs_ioc_setflags_prepare(inode, |
| <------><------><------><------><------><------> REISERFS_I(inode)->i_attrs, |
| <------><------><------><------><------><------> flags); |
| <------><------><------>if (err) |
| <------><------><------><------>goto setflags_out; |
| <------><------><------>if ((flags & REISERFS_NOTAIL_FL) && |
| <------><------><------> S_ISREG(inode->i_mode)) { |
| <------><------><------><------>int result; |
| |
| <------><------><------><------>result = reiserfs_unpack(inode, filp); |
| <------><------><------><------>if (result) { |
| <------><------><------><------><------>err = result; |
| <------><------><------><------><------>goto setflags_out; |
| <------><------><------><------>} |
| <------><------><------>} |
| <------><------><------>sd_attrs_to_i_attrs(flags, inode); |
| <------><------><------>REISERFS_I(inode)->i_attrs = flags; |
| <------><------><------>inode->i_ctime = current_time(inode); |
| <------><------><------>mark_inode_dirty(inode); |
| setflags_out: |
| <------><------><------>mnt_drop_write_file(filp); |
| <------><------><------>break; |
| <------><------>} |
| <------>case REISERFS_IOC_GETVERSION: |
| <------><------>err = put_user(inode->i_generation, (int __user *)arg); |
| <------><------>break; |
| <------>case REISERFS_IOC_SETVERSION: |
| <------><------>if (!inode_owner_or_capable(inode)) { |
| <------><------><------>err = -EPERM; |
| <------><------><------>break; |
| <------><------>} |
| <------><------>err = mnt_want_write_file(filp); |
| <------><------>if (err) |
| <------><------><------>break; |
| <------><------>if (get_user(inode->i_generation, (int __user *)arg)) { |
| <------><------><------>err = -EFAULT; |
| <------><------><------>goto setversion_out; |
| <------><------>} |
| <------><------>inode->i_ctime = current_time(inode); |
| <------><------>mark_inode_dirty(inode); |
| setversion_out: |
| <------><------>mnt_drop_write_file(filp); |
| <------><------>break; |
| <------>default: |
| <------><------>err = -ENOTTY; |
| <------>} |
| |
| <------>reiserfs_write_unlock(inode->i_sb); |
| |
| <------>return err; |
| } |
| |
| #ifdef CONFIG_COMPAT |
| long reiserfs_compat_ioctl(struct file *file, unsigned int cmd, |
| <------><------><------><------>unsigned long arg) |
| { |
| <------> |
| <------> * These are just misnamed, they actually |
| <------> * get/put from/to user an int |
| <------> */ |
| <------>switch (cmd) { |
| <------>case REISERFS_IOC32_UNPACK: |
| <------><------>cmd = REISERFS_IOC_UNPACK; |
| <------><------>break; |
| <------>case REISERFS_IOC32_GETFLAGS: |
| <------><------>cmd = REISERFS_IOC_GETFLAGS; |
| <------><------>break; |
| <------>case REISERFS_IOC32_SETFLAGS: |
| <------><------>cmd = REISERFS_IOC_SETFLAGS; |
| <------><------>break; |
| <------>case REISERFS_IOC32_GETVERSION: |
| <------><------>cmd = REISERFS_IOC_GETVERSION; |
| <------><------>break; |
| <------>case REISERFS_IOC32_SETVERSION: |
| <------><------>cmd = REISERFS_IOC_SETVERSION; |
| <------><------>break; |
| <------>default: |
| <------><------>return -ENOIOCTLCMD; |
| <------>} |
| |
| <------>return reiserfs_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); |
| } |
| #endif |
| |
| int reiserfs_commit_write(struct file *f, struct page *page, |
| <------><------><------> unsigned from, unsigned to); |
| |
| |
| |
| |
| |
| 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; |
| <------>} |
| <------> |
| <------>if (REISERFS_I(inode)->i_flags & i_nopack_mask) { |
| <------><------>return 0; |
| <------>} |
| |
| <------> |
| <------>{ |
| <------><------>int depth = reiserfs_write_unlock_nested(inode->i_sb); |
| |
| <------><------>inode_lock(inode); |
| <------><------>reiserfs_write_lock_nested(inode->i_sb, depth); |
| <------>} |
| |
| <------>reiserfs_write_lock(inode->i_sb); |
| |
| <------>write_from = inode->i_size & (blocksize - 1); |
| <------> |
| <------>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_write_begin on that page. This will force a |
| <------> * reiserfs_get_block to unpack the tail for us. |
| <------> */ |
| <------>index = inode->i_size >> PAGE_SHIFT; |
| <------>mapping = inode->i_mapping; |
| <------>page = grab_cache_page(mapping, index); |
| <------>retval = -ENOMEM; |
| <------>if (!page) { |
| <------><------>goto out; |
| <------>} |
| <------>retval = __reiserfs_write_begin(page, write_from, 0); |
| <------>if (retval) |
| <------><------>goto out_unlock; |
| |
| <------> |
| <------>flush_dcache_page(page); |
| <------>retval = reiserfs_commit_write(NULL, page, write_from, write_from); |
| <------>REISERFS_I(inode)->i_flags |= i_nopack_mask; |
| |
| out_unlock: |
| <------>unlock_page(page); |
| <------>put_page(page); |
| |
| out: |
| <------>inode_unlock(inode); |
| <------>reiserfs_write_unlock(inode->i_sb); |
| <------>return retval; |
| } |
| |