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 768cbfbc5273bad91afe12b81471f563b288118a 382 lines 9.0 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 struct super_block *get_super_to_sync(int type) 153{ 154 struct list_head *head; 155 int cnt, dirty; 156 157restart: 158 spin_lock(&sb_lock); 159 list_for_each(head, &super_blocks) { 160 struct super_block *sb = list_entry(head, struct super_block, s_list); 161 162 /* This test just improves performance so it needn't be reliable... */ 163 for (cnt = 0, dirty = 0; cnt < MAXQUOTAS; cnt++) 164 if ((type == cnt || type == -1) && sb_has_quota_enabled(sb, cnt) 165 && info_any_dirty(&sb_dqopt(sb)->info[cnt])) 166 dirty = 1; 167 if (!dirty) 168 continue; 169 sb->s_count++; 170 spin_unlock(&sb_lock); 171 down_read(&sb->s_umount); 172 if (!sb->s_root) { 173 drop_super(sb); 174 goto restart; 175 } 176 return sb; 177 } 178 spin_unlock(&sb_lock); 179 return NULL; 180} 181 182static void quota_sync_sb(struct super_block *sb, int type) 183{ 184 int cnt; 185 struct inode *discard[MAXQUOTAS]; 186 187 sb->s_qcop->quota_sync(sb, type); 188 /* This is not very clever (and fast) but currently I don't know about 189 * any other simple way of getting quota data to disk and we must get 190 * them there for userspace to be visible... */ 191 if (sb->s_op->sync_fs) 192 sb->s_op->sync_fs(sb, 1); 193 sync_blockdev(sb->s_bdev); 194 195 /* Now when everything is written we can discard the pagecache so 196 * that userspace sees the changes. We need i_sem and so we could 197 * not do it inside dqonoff_sem. Moreover we need to be carefull 198 * about races with quotaoff() (that is the reason why we have own 199 * reference to inode). */ 200 down(&sb_dqopt(sb)->dqonoff_sem); 201 for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 202 discard[cnt] = NULL; 203 if (type != -1 && cnt != type) 204 continue; 205 if (!sb_has_quota_enabled(sb, cnt)) 206 continue; 207 discard[cnt] = igrab(sb_dqopt(sb)->files[cnt]); 208 } 209 up(&sb_dqopt(sb)->dqonoff_sem); 210 for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 211 if (discard[cnt]) { 212 down(&discard[cnt]->i_sem); 213 truncate_inode_pages(&discard[cnt]->i_data, 0); 214 up(&discard[cnt]->i_sem); 215 iput(discard[cnt]); 216 } 217 } 218} 219 220void sync_dquots(struct super_block *sb, int type) 221{ 222 if (sb) { 223 if (sb->s_qcop->quota_sync) 224 quota_sync_sb(sb, type); 225 } 226 else { 227 while ((sb = get_super_to_sync(type)) != NULL) { 228 if (sb->s_qcop->quota_sync) 229 quota_sync_sb(sb, type); 230 drop_super(sb); 231 } 232 } 233} 234 235/* Copy parameters and call proper function */ 236static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void __user *addr) 237{ 238 int ret; 239 240 switch (cmd) { 241 case Q_QUOTAON: { 242 char *pathname; 243 244 if (IS_ERR(pathname = getname(addr))) 245 return PTR_ERR(pathname); 246 ret = sb->s_qcop->quota_on(sb, type, id, pathname); 247 putname(pathname); 248 return ret; 249 } 250 case Q_QUOTAOFF: 251 return sb->s_qcop->quota_off(sb, type); 252 253 case Q_GETFMT: { 254 __u32 fmt; 255 256 down_read(&sb_dqopt(sb)->dqptr_sem); 257 if (!sb_has_quota_enabled(sb, type)) { 258 up_read(&sb_dqopt(sb)->dqptr_sem); 259 return -ESRCH; 260 } 261 fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id; 262 up_read(&sb_dqopt(sb)->dqptr_sem); 263 if (copy_to_user(addr, &fmt, sizeof(fmt))) 264 return -EFAULT; 265 return 0; 266 } 267 case Q_GETINFO: { 268 struct if_dqinfo info; 269 270 if ((ret = sb->s_qcop->get_info(sb, type, &info))) 271 return ret; 272 if (copy_to_user(addr, &info, sizeof(info))) 273 return -EFAULT; 274 return 0; 275 } 276 case Q_SETINFO: { 277 struct if_dqinfo info; 278 279 if (copy_from_user(&info, addr, sizeof(info))) 280 return -EFAULT; 281 return sb->s_qcop->set_info(sb, type, &info); 282 } 283 case Q_GETQUOTA: { 284 struct if_dqblk idq; 285 286 if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq))) 287 return ret; 288 if (copy_to_user(addr, &idq, sizeof(idq))) 289 return -EFAULT; 290 return 0; 291 } 292 case Q_SETQUOTA: { 293 struct if_dqblk idq; 294 295 if (copy_from_user(&idq, addr, sizeof(idq))) 296 return -EFAULT; 297 return sb->s_qcop->set_dqblk(sb, type, id, &idq); 298 } 299 case Q_SYNC: 300 sync_dquots(sb, type); 301 return 0; 302 303 case Q_XQUOTAON: 304 case Q_XQUOTAOFF: 305 case Q_XQUOTARM: { 306 __u32 flags; 307 308 if (copy_from_user(&flags, addr, sizeof(flags))) 309 return -EFAULT; 310 return sb->s_qcop->set_xstate(sb, flags, cmd); 311 } 312 case Q_XGETQSTAT: { 313 struct fs_quota_stat fqs; 314 315 if ((ret = sb->s_qcop->get_xstate(sb, &fqs))) 316 return ret; 317 if (copy_to_user(addr, &fqs, sizeof(fqs))) 318 return -EFAULT; 319 return 0; 320 } 321 case Q_XSETQLIM: { 322 struct fs_disk_quota fdq; 323 324 if (copy_from_user(&fdq, addr, sizeof(fdq))) 325 return -EFAULT; 326 return sb->s_qcop->set_xquota(sb, type, id, &fdq); 327 } 328 case Q_XGETQUOTA: { 329 struct fs_disk_quota fdq; 330 331 if ((ret = sb->s_qcop->get_xquota(sb, type, id, &fdq))) 332 return ret; 333 if (copy_to_user(addr, &fdq, sizeof(fdq))) 334 return -EFAULT; 335 return 0; 336 } 337 /* We never reach here unless validity check is broken */ 338 default: 339 BUG(); 340 } 341 return 0; 342} 343 344/* 345 * This is the system call interface. This communicates with 346 * the user-level programs. Currently this only supports diskquota 347 * calls. Maybe we need to add the process quotas etc. in the future, 348 * but we probably should use rlimits for that. 349 */ 350asmlinkage long sys_quotactl(unsigned int cmd, const char __user *special, qid_t id, void __user *addr) 351{ 352 uint cmds, type; 353 struct super_block *sb = NULL; 354 struct block_device *bdev; 355 char *tmp; 356 int ret; 357 358 cmds = cmd >> SUBCMDSHIFT; 359 type = cmd & SUBCMDMASK; 360 361 if (cmds != Q_SYNC || special) { 362 tmp = getname(special); 363 if (IS_ERR(tmp)) 364 return PTR_ERR(tmp); 365 bdev = lookup_bdev(tmp); 366 putname(tmp); 367 if (IS_ERR(bdev)) 368 return PTR_ERR(bdev); 369 sb = get_super(bdev); 370 bdput(bdev); 371 if (!sb) 372 return -ENODEV; 373 } 374 375 ret = check_quotactl_valid(sb, type, cmds, id); 376 if (ret >= 0) 377 ret = do_quotactl(sb, type, cmds, id, addr); 378 if (sb) 379 drop_super(sb); 380 381 return ret; 382}