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