diff options
| -rw-r--r-- | fs/quota/quota.c | 138 |
1 files changed, 134 insertions, 4 deletions
diff --git a/fs/quota/quota.c b/fs/quota/quota.c index 00d50fca1005..83939ff4c444 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c | |||
| @@ -269,25 +269,152 @@ static int quota_disable(struct super_block *sb, void __user *addr) | |||
| 269 | return sb->s_qcop->quota_disable(sb, flags); | 269 | return sb->s_qcop->quota_disable(sb, flags); |
| 270 | } | 270 | } |
| 271 | 271 | ||
| 272 | static int quota_state_to_flags(struct qc_state *state) | ||
| 273 | { | ||
| 274 | int flags = 0; | ||
| 275 | |||
| 276 | if (state->s_state[USRQUOTA].flags & QCI_ACCT_ENABLED) | ||
| 277 | flags |= FS_QUOTA_UDQ_ACCT; | ||
| 278 | if (state->s_state[USRQUOTA].flags & QCI_LIMITS_ENFORCED) | ||
| 279 | flags |= FS_QUOTA_UDQ_ENFD; | ||
| 280 | if (state->s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED) | ||
| 281 | flags |= FS_QUOTA_GDQ_ACCT; | ||
| 282 | if (state->s_state[GRPQUOTA].flags & QCI_LIMITS_ENFORCED) | ||
| 283 | flags |= FS_QUOTA_GDQ_ENFD; | ||
| 284 | if (state->s_state[PRJQUOTA].flags & QCI_ACCT_ENABLED) | ||
| 285 | flags |= FS_QUOTA_PDQ_ACCT; | ||
| 286 | if (state->s_state[PRJQUOTA].flags & QCI_LIMITS_ENFORCED) | ||
| 287 | flags |= FS_QUOTA_PDQ_ENFD; | ||
| 288 | return flags; | ||
| 289 | } | ||
| 290 | |||
| 291 | static int quota_getstate(struct super_block *sb, struct fs_quota_stat *fqs) | ||
| 292 | { | ||
| 293 | int type; | ||
| 294 | struct qc_state state; | ||
| 295 | int ret; | ||
| 296 | |||
| 297 | ret = sb->s_qcop->get_state(sb, &state); | ||
| 298 | if (ret < 0) | ||
| 299 | return ret; | ||
| 300 | |||
| 301 | memset(fqs, 0, sizeof(*fqs)); | ||
| 302 | fqs->qs_version = FS_QSTAT_VERSION; | ||
| 303 | fqs->qs_flags = quota_state_to_flags(&state); | ||
| 304 | /* No quota enabled? */ | ||
| 305 | if (!fqs->qs_flags) | ||
| 306 | return -ENOSYS; | ||
| 307 | fqs->qs_incoredqs = state.s_incoredqs; | ||
| 308 | /* | ||
| 309 | * GETXSTATE quotactl has space for just one set of time limits so | ||
| 310 | * report them for the first enabled quota type | ||
| 311 | */ | ||
| 312 | for (type = 0; type < XQM_MAXQUOTAS; type++) | ||
| 313 | if (state.s_state[type].flags & QCI_ACCT_ENABLED) | ||
| 314 | break; | ||
| 315 | BUG_ON(type == XQM_MAXQUOTAS); | ||
| 316 | fqs->qs_btimelimit = state.s_state[type].spc_timelimit; | ||
| 317 | fqs->qs_itimelimit = state.s_state[type].ino_timelimit; | ||
| 318 | fqs->qs_rtbtimelimit = state.s_state[type].rt_spc_timelimit; | ||
| 319 | fqs->qs_bwarnlimit = state.s_state[type].spc_warnlimit; | ||
| 320 | fqs->qs_iwarnlimit = state.s_state[type].ino_warnlimit; | ||
| 321 | if (state.s_state[USRQUOTA].flags & QCI_ACCT_ENABLED) { | ||
| 322 | fqs->qs_uquota.qfs_ino = state.s_state[USRQUOTA].ino; | ||
| 323 | fqs->qs_uquota.qfs_nblks = state.s_state[USRQUOTA].blocks; | ||
| 324 | fqs->qs_uquota.qfs_nextents = state.s_state[USRQUOTA].nextents; | ||
| 325 | } | ||
| 326 | if (state.s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED) { | ||
| 327 | fqs->qs_gquota.qfs_ino = state.s_state[GRPQUOTA].ino; | ||
| 328 | fqs->qs_gquota.qfs_nblks = state.s_state[GRPQUOTA].blocks; | ||
| 329 | fqs->qs_gquota.qfs_nextents = state.s_state[GRPQUOTA].nextents; | ||
| 330 | } | ||
| 331 | if (state.s_state[PRJQUOTA].flags & QCI_ACCT_ENABLED) { | ||
| 332 | /* | ||
| 333 | * Q_XGETQSTAT doesn't have room for both group and project | ||
| 334 | * quotas. So, allow the project quota values to be copied out | ||
| 335 | * only if there is no group quota information available. | ||
| 336 | */ | ||
| 337 | if (!(state.s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED)) { | ||
| 338 | fqs->qs_gquota.qfs_ino = state.s_state[PRJQUOTA].ino; | ||
| 339 | fqs->qs_gquota.qfs_nblks = | ||
| 340 | state.s_state[PRJQUOTA].blocks; | ||
| 341 | fqs->qs_gquota.qfs_nextents = | ||
| 342 | state.s_state[PRJQUOTA].nextents; | ||
| 343 | } | ||
| 344 | } | ||
| 345 | return 0; | ||
| 346 | } | ||
| 347 | |||
| 272 | static int quota_getxstate(struct super_block *sb, void __user *addr) | 348 | static int quota_getxstate(struct super_block *sb, void __user *addr) |
| 273 | { | 349 | { |
| 274 | struct fs_quota_stat fqs; | 350 | struct fs_quota_stat fqs; |
| 275 | int ret; | 351 | int ret; |
| 276 | 352 | ||
| 277 | if (!sb->s_qcop->get_xstate) | 353 | if (!sb->s_qcop->get_xstate && !sb->s_qcop->get_state) |
| 278 | return -ENOSYS; | 354 | return -ENOSYS; |
| 279 | ret = sb->s_qcop->get_xstate(sb, &fqs); | 355 | if (sb->s_qcop->get_state) |
| 356 | ret = quota_getstate(sb, &fqs); | ||
| 357 | else | ||
| 358 | ret = sb->s_qcop->get_xstate(sb, &fqs); | ||
| 280 | if (!ret && copy_to_user(addr, &fqs, sizeof(fqs))) | 359 | if (!ret && copy_to_user(addr, &fqs, sizeof(fqs))) |
| 281 | return -EFAULT; | 360 | return -EFAULT; |
| 282 | return ret; | 361 | return ret; |
| 283 | } | 362 | } |
| 284 | 363 | ||
| 364 | static int quota_getstatev(struct super_block *sb, struct fs_quota_statv *fqs) | ||
| 365 | { | ||
| 366 | int type; | ||
| 367 | struct qc_state state; | ||
| 368 | int ret; | ||
| 369 | |||
| 370 | ret = sb->s_qcop->get_state(sb, &state); | ||
| 371 | if (ret < 0) | ||
| 372 | return ret; | ||
| 373 | |||
| 374 | memset(fqs, 0, sizeof(*fqs)); | ||
| 375 | fqs->qs_version = FS_QSTAT_VERSION; | ||
| 376 | fqs->qs_flags = quota_state_to_flags(&state); | ||
| 377 | /* No quota enabled? */ | ||
| 378 | if (!fqs->qs_flags) | ||
| 379 | return -ENOSYS; | ||
| 380 | fqs->qs_incoredqs = state.s_incoredqs; | ||
| 381 | /* | ||
| 382 | * GETXSTATV quotactl has space for just one set of time limits so | ||
| 383 | * report them for the first enabled quota type | ||
| 384 | */ | ||
| 385 | for (type = 0; type < XQM_MAXQUOTAS; type++) | ||
| 386 | if (state.s_state[type].flags & QCI_ACCT_ENABLED) | ||
| 387 | break; | ||
| 388 | BUG_ON(type == XQM_MAXQUOTAS); | ||
| 389 | fqs->qs_btimelimit = state.s_state[type].spc_timelimit; | ||
| 390 | fqs->qs_itimelimit = state.s_state[type].ino_timelimit; | ||
| 391 | fqs->qs_rtbtimelimit = state.s_state[type].rt_spc_timelimit; | ||
| 392 | fqs->qs_bwarnlimit = state.s_state[type].spc_warnlimit; | ||
| 393 | fqs->qs_iwarnlimit = state.s_state[type].ino_warnlimit; | ||
| 394 | if (state.s_state[USRQUOTA].flags & QCI_ACCT_ENABLED) { | ||
| 395 | fqs->qs_uquota.qfs_ino = state.s_state[USRQUOTA].ino; | ||
| 396 | fqs->qs_uquota.qfs_nblks = state.s_state[USRQUOTA].blocks; | ||
| 397 | fqs->qs_uquota.qfs_nextents = state.s_state[USRQUOTA].nextents; | ||
| 398 | } | ||
| 399 | if (state.s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED) { | ||
| 400 | fqs->qs_gquota.qfs_ino = state.s_state[GRPQUOTA].ino; | ||
| 401 | fqs->qs_gquota.qfs_nblks = state.s_state[GRPQUOTA].blocks; | ||
| 402 | fqs->qs_gquota.qfs_nextents = state.s_state[GRPQUOTA].nextents; | ||
| 403 | } | ||
| 404 | if (state.s_state[PRJQUOTA].flags & QCI_ACCT_ENABLED) { | ||
| 405 | fqs->qs_pquota.qfs_ino = state.s_state[PRJQUOTA].ino; | ||
| 406 | fqs->qs_pquota.qfs_nblks = state.s_state[PRJQUOTA].blocks; | ||
| 407 | fqs->qs_pquota.qfs_nextents = state.s_state[PRJQUOTA].nextents; | ||
| 408 | } | ||
| 409 | return 0; | ||
| 410 | } | ||
| 411 | |||
| 285 | static int quota_getxstatev(struct super_block *sb, void __user *addr) | 412 | static int quota_getxstatev(struct super_block *sb, void __user *addr) |
| 286 | { | 413 | { |
| 287 | struct fs_quota_statv fqs; | 414 | struct fs_quota_statv fqs; |
| 288 | int ret; | 415 | int ret; |
| 289 | 416 | ||
| 290 | if (!sb->s_qcop->get_xstatev) | 417 | if (!sb->s_qcop->get_xstatev && !sb->s_qcop->get_state) |
| 291 | return -ENOSYS; | 418 | return -ENOSYS; |
| 292 | 419 | ||
| 293 | memset(&fqs, 0, sizeof(fqs)); | 420 | memset(&fqs, 0, sizeof(fqs)); |
| @@ -301,7 +428,10 @@ static int quota_getxstatev(struct super_block *sb, void __user *addr) | |||
| 301 | default: | 428 | default: |
| 302 | return -EINVAL; | 429 | return -EINVAL; |
| 303 | } | 430 | } |
| 304 | ret = sb->s_qcop->get_xstatev(sb, &fqs); | 431 | if (sb->s_qcop->get_state) |
| 432 | ret = quota_getstatev(sb, &fqs); | ||
| 433 | else | ||
| 434 | ret = sb->s_qcop->get_xstatev(sb, &fqs); | ||
| 305 | if (!ret && copy_to_user(addr, &fqs, sizeof(fqs))) | 435 | if (!ret && copy_to_user(addr, &fqs, sizeof(fqs))) |
| 306 | return -EFAULT; | 436 | return -EFAULT; |
| 307 | return ret; | 437 | return ret; |
