Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 77b2555b52a894a2e39a42e43d993df875c46a6a 370 lines 8.8 kB view raw
1/* 2 * Quota code necessary even when VFS quota support is not compiled 3 * into the kernel. The interesting stuff is over in dquot.c, here 4 * we have symbols for initial quotactl(2) handling, the sysctl(2) 5 * variables, etc - things needed even when quota support disabled. 6 */ 7 8#include <linux/fs.h> 9#include <linux/namei.h> 10#include <linux/slab.h> 11#include <asm/current.h> 12#include <asm/uaccess.h> 13#include <linux/kernel.h> 14#include <linux/smp_lock.h> 15#include <linux/security.h> 16#include <linux/syscalls.h> 17#include <linux/buffer_head.h> 18 19/* Check validity of generic quotactl commands */ 20static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id) 21{ 22 if (type >= MAXQUOTAS) 23 return -EINVAL; 24 if (!sb && cmd != Q_SYNC) 25 return -ENODEV; 26 /* Is operation supported? */ 27 if (sb && !sb->s_qcop) 28 return -ENOSYS; 29 30 switch (cmd) { 31 case Q_GETFMT: 32 break; 33 case Q_QUOTAON: 34 if (!sb->s_qcop->quota_on) 35 return -ENOSYS; 36 break; 37 case Q_QUOTAOFF: 38 if (!sb->s_qcop->quota_off) 39 return -ENOSYS; 40 break; 41 case Q_SETINFO: 42 if (!sb->s_qcop->set_info) 43 return -ENOSYS; 44 break; 45 case Q_GETINFO: 46 if (!sb->s_qcop->get_info) 47 return -ENOSYS; 48 break; 49 case Q_SETQUOTA: 50 if (!sb->s_qcop->set_dqblk) 51 return -ENOSYS; 52 break; 53 case Q_GETQUOTA: 54 if (!sb->s_qcop->get_dqblk) 55 return -ENOSYS; 56 break; 57 case Q_SYNC: 58 if (sb && !sb->s_qcop->quota_sync) 59 return -ENOSYS; 60 break; 61 default: 62 return -EINVAL; 63 } 64 65 /* Is quota turned on for commands which need it? */ 66 switch (cmd) { 67 case Q_GETFMT: 68 case Q_GETINFO: 69 case Q_QUOTAOFF: 70 case Q_SETINFO: 71 case Q_SETQUOTA: 72 case Q_GETQUOTA: 73 /* This is just informative test so we are satisfied without a lock */ 74 if (!sb_has_quota_enabled(sb, type)) 75 return -ESRCH; 76 } 77 78 /* Check privileges */ 79 if (cmd == Q_GETQUOTA) { 80 if (((type == USRQUOTA && current->euid != id) || 81 (type == GRPQUOTA && !in_egroup_p(id))) && 82 !capable(CAP_SYS_ADMIN)) 83 return -EPERM; 84 } 85 else if (cmd != Q_GETFMT && cmd != Q_SYNC && cmd != Q_GETINFO) 86 if (!capable(CAP_SYS_ADMIN)) 87 return -EPERM; 88 89 return 0; 90} 91 92/* Check validity of XFS Quota Manager commands */ 93static int xqm_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id) 94{ 95 if (type >= XQM_MAXQUOTAS) 96 return -EINVAL; 97 if (!sb) 98 return -ENODEV; 99 if (!sb->s_qcop) 100 return -ENOSYS; 101 102 switch (cmd) { 103 case Q_XQUOTAON: 104 case Q_XQUOTAOFF: 105 case Q_XQUOTARM: 106 if (!sb->s_qcop->set_xstate) 107 return -ENOSYS; 108 break; 109 case Q_XGETQSTAT: 110 if (!sb->s_qcop->get_xstate) 111 return -ENOSYS; 112 break; 113 case Q_XSETQLIM: 114 if (!sb->s_qcop->set_xquota) 115 return -ENOSYS; 116 break; 117 case Q_XGETQUOTA: 118 if (!sb->s_qcop->get_xquota) 119 return -ENOSYS; 120 break; 121 default: 122 return -EINVAL; 123 } 124 125 /* Check privileges */ 126 if (cmd == Q_XGETQUOTA) { 127 if (((type == XQM_USRQUOTA && current->euid != id) || 128 (type == XQM_GRPQUOTA && !in_egroup_p(id))) && 129 !capable(CAP_SYS_ADMIN)) 130 return -EPERM; 131 } else if (cmd != Q_XGETQSTAT) { 132 if (!capable(CAP_SYS_ADMIN)) 133 return -EPERM; 134 } 135 136 return 0; 137} 138 139static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id) 140{ 141 int error; 142 143 if (XQM_COMMAND(cmd)) 144 error = xqm_quotactl_valid(sb, type, cmd, id); 145 else 146 error = generic_quotactl_valid(sb, type, cmd, id); 147 if (!error) 148 error = security_quotactl(cmd, type, id, sb); 149 return error; 150} 151 152static void quota_sync_sb(struct super_block *sb, int type) 153{ 154 int cnt; 155 struct inode *discard[MAXQUOTAS]; 156 157 sb->s_qcop->quota_sync(sb, type); 158 /* This is not very clever (and fast) but currently I don't know about 159 * any other simple way of getting quota data to disk and we must get 160 * them there for userspace to be visible... */ 161 if (sb->s_op->sync_fs) 162 sb->s_op->sync_fs(sb, 1); 163 sync_blockdev(sb->s_bdev); 164 165 /* Now when everything is written we can discard the pagecache so 166 * that userspace sees the changes. We need i_sem and so we could 167 * not do it inside dqonoff_sem. Moreover we need to be carefull 168 * about races with quotaoff() (that is the reason why we have own 169 * reference to inode). */ 170 down(&sb_dqopt(sb)->dqonoff_sem); 171 for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 172 discard[cnt] = NULL; 173 if (type != -1 && cnt != type) 174 continue; 175 if (!sb_has_quota_enabled(sb, cnt)) 176 continue; 177 discard[cnt] = igrab(sb_dqopt(sb)->files[cnt]); 178 } 179 up(&sb_dqopt(sb)->dqonoff_sem); 180 for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 181 if (discard[cnt]) { 182 down(&discard[cnt]->i_sem); 183 truncate_inode_pages(&discard[cnt]->i_data, 0); 184 up(&discard[cnt]->i_sem); 185 iput(discard[cnt]); 186 } 187 } 188} 189 190void sync_dquots(struct super_block *sb, int type) 191{ 192 int cnt, dirty; 193 194 if (sb) { 195 if (sb->s_qcop->quota_sync) 196 quota_sync_sb(sb, type); 197 return; 198 } 199 200 spin_lock(&sb_lock); 201restart: 202 list_for_each_entry(sb, &super_blocks, s_list) { 203 /* This test just improves performance so it needn't be reliable... */ 204 for (cnt = 0, dirty = 0; cnt < MAXQUOTAS; cnt++) 205 if ((type == cnt || type == -1) && sb_has_quota_enabled(sb, cnt) 206 && info_any_dirty(&sb_dqopt(sb)->info[cnt])) 207 dirty = 1; 208 if (!dirty) 209 continue; 210 sb->s_count++; 211 spin_unlock(&sb_lock); 212 down_read(&sb->s_umount); 213 if (sb->s_root && sb->s_qcop->quota_sync) 214 quota_sync_sb(sb, type); 215 up_read(&sb->s_umount); 216 spin_lock(&sb_lock); 217 if (__put_super_and_need_restart(sb)) 218 goto restart; 219 } 220 spin_unlock(&sb_lock); 221} 222 223/* Copy parameters and call proper function */ 224static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void __user *addr) 225{ 226 int ret; 227 228 switch (cmd) { 229 case Q_QUOTAON: { 230 char *pathname; 231 232 if (IS_ERR(pathname = getname(addr))) 233 return PTR_ERR(pathname); 234 ret = sb->s_qcop->quota_on(sb, type, id, pathname); 235 putname(pathname); 236 return ret; 237 } 238 case Q_QUOTAOFF: 239 return sb->s_qcop->quota_off(sb, type); 240 241 case Q_GETFMT: { 242 __u32 fmt; 243 244 down_read(&sb_dqopt(sb)->dqptr_sem); 245 if (!sb_has_quota_enabled(sb, type)) { 246 up_read(&sb_dqopt(sb)->dqptr_sem); 247 return -ESRCH; 248 } 249 fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id; 250 up_read(&sb_dqopt(sb)->dqptr_sem); 251 if (copy_to_user(addr, &fmt, sizeof(fmt))) 252 return -EFAULT; 253 return 0; 254 } 255 case Q_GETINFO: { 256 struct if_dqinfo info; 257 258 if ((ret = sb->s_qcop->get_info(sb, type, &info))) 259 return ret; 260 if (copy_to_user(addr, &info, sizeof(info))) 261 return -EFAULT; 262 return 0; 263 } 264 case Q_SETINFO: { 265 struct if_dqinfo info; 266 267 if (copy_from_user(&info, addr, sizeof(info))) 268 return -EFAULT; 269 return sb->s_qcop->set_info(sb, type, &info); 270 } 271 case Q_GETQUOTA: { 272 struct if_dqblk idq; 273 274 if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq))) 275 return ret; 276 if (copy_to_user(addr, &idq, sizeof(idq))) 277 return -EFAULT; 278 return 0; 279 } 280 case Q_SETQUOTA: { 281 struct if_dqblk idq; 282 283 if (copy_from_user(&idq, addr, sizeof(idq))) 284 return -EFAULT; 285 return sb->s_qcop->set_dqblk(sb, type, id, &idq); 286 } 287 case Q_SYNC: 288 sync_dquots(sb, type); 289 return 0; 290 291 case Q_XQUOTAON: 292 case Q_XQUOTAOFF: 293 case Q_XQUOTARM: { 294 __u32 flags; 295 296 if (copy_from_user(&flags, addr, sizeof(flags))) 297 return -EFAULT; 298 return sb->s_qcop->set_xstate(sb, flags, cmd); 299 } 300 case Q_XGETQSTAT: { 301 struct fs_quota_stat fqs; 302 303 if ((ret = sb->s_qcop->get_xstate(sb, &fqs))) 304 return ret; 305 if (copy_to_user(addr, &fqs, sizeof(fqs))) 306 return -EFAULT; 307 return 0; 308 } 309 case Q_XSETQLIM: { 310 struct fs_disk_quota fdq; 311 312 if (copy_from_user(&fdq, addr, sizeof(fdq))) 313 return -EFAULT; 314 return sb->s_qcop->set_xquota(sb, type, id, &fdq); 315 } 316 case Q_XGETQUOTA: { 317 struct fs_disk_quota fdq; 318 319 if ((ret = sb->s_qcop->get_xquota(sb, type, id, &fdq))) 320 return ret; 321 if (copy_to_user(addr, &fdq, sizeof(fdq))) 322 return -EFAULT; 323 return 0; 324 } 325 /* We never reach here unless validity check is broken */ 326 default: 327 BUG(); 328 } 329 return 0; 330} 331 332/* 333 * This is the system call interface. This communicates with 334 * the user-level programs. Currently this only supports diskquota 335 * calls. Maybe we need to add the process quotas etc. in the future, 336 * but we probably should use rlimits for that. 337 */ 338asmlinkage long sys_quotactl(unsigned int cmd, const char __user *special, qid_t id, void __user *addr) 339{ 340 uint cmds, type; 341 struct super_block *sb = NULL; 342 struct block_device *bdev; 343 char *tmp; 344 int ret; 345 346 cmds = cmd >> SUBCMDSHIFT; 347 type = cmd & SUBCMDMASK; 348 349 if (cmds != Q_SYNC || special) { 350 tmp = getname(special); 351 if (IS_ERR(tmp)) 352 return PTR_ERR(tmp); 353 bdev = lookup_bdev(tmp); 354 putname(tmp); 355 if (IS_ERR(bdev)) 356 return PTR_ERR(bdev); 357 sb = get_super(bdev); 358 bdput(bdev); 359 if (!sb) 360 return -ENODEV; 361 } 362 363 ret = check_quotactl_valid(sb, type, cmds, id); 364 if (ret >= 0) 365 ret = do_quotactl(sb, type, cmds, id, addr); 366 if (sb) 367 drop_super(sb); 368 369 return ret; 370}