X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Freiserfs%2Fioctl.c;h=e2dbca07676eff3c9d2735e93fdc326398a9d155;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=965518ed93aafd55ec39d7f5dda0d0160328f32b;hpb=cee37fe97739d85991964371c1f3a745c00dd236;p=linux-2.6.git diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c index 965518ed9..e2dbca076 100644 --- a/fs/reiserfs/ioctl.c +++ b/fs/reiserfs/ioctl.c @@ -2,14 +2,16 @@ * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ +#include #include +#include #include #include #include #include #include -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,71 +21,80 @@ 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, oldflags; 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 ); - flags &= REISERFS_FL_USER_VISIBLE; - return put_user(flags, (int __user *) arg); - case REISERFS_IOC_SETFLAGS: { - if (IS_RDONLY(inode)) - return -EROFS; - - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) - return -EPERM; - - if (get_user(flags, (int __user *) arg)) - return -EFAULT; + if (!reiserfs_attrs(inode->i_sb)) + return -ENOTTY; - oldflags = REISERFS_I(inode) -> i_attrs; - if ( ( (oldflags & REISERFS_IMMUTABLE_FL) || - ( (flags ^ oldflags) & - (REISERFS_IMMUTABLE_FL | REISERFS_IUNLINK_FL | - REISERFS_APPEND_FL) ) ) && - !capable( CAP_LINUX_IMMUTABLE ) ) - return -EPERM; - - if( ( flags & REISERFS_NOTAIL_FL ) && - S_ISREG( inode -> i_mode ) ) { + flags = REISERFS_I(inode)->i_attrs; + i_attrs_to_sd_attrs(inode, (__u16 *) & flags); + flags &= REISERFS_FL_USER_VISIBLE; + return put_user(flags, (int __user *)arg); + case REISERFS_IOC_SETFLAGS:{ + if (!reiserfs_attrs(inode->i_sb)) + return -ENOTTY; + + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) + return -EROFS; + + if ((current->fsuid != inode->i_uid) + && !capable(CAP_FOWNER)) + return -EPERM; + + if (get_user(flags, (int __user *)arg)) + return -EFAULT; + + oldflags = REISERFS_I(inode) -> i_attrs; + if (((oldflags & REISERFS_IMMUTABLE_FL) || + ((flags ^ oldflags) & + (REISERFS_IMMUTABLE_FL | REISERFS_IUNLINK_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; + } + + flags = flags & REISERFS_FL_USER_MODIFIABLE; + flags |= oldflags & ~REISERFS_FL_USER_MODIFIABLE; + 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; } - - flags = flags & REISERFS_FL_USER_MODIFYABLE; - flags |= oldflags & ~REISERFS_FL_USER_MODIFYABLE; - 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)) + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) 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; @@ -97,63 +108,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; + } + reiserfs_write_lock(inode->i_sb); + + /* we need to make sure nobody is changing the file size beneath + ** us + */ + mutex_lock(&inode->i_mutex); + + 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; }