|
16 | 16 | #include "xfs_trans.h"
|
17 | 17 | #include "xfs_qm.h"
|
18 | 18 | #include "xfs_error.h"
|
| 19 | +#include "xfs_health.h" |
| 20 | +#include "xfs_metadir.h" |
| 21 | +#include "xfs_metafile.h" |
19 | 22 |
|
20 | 23 | int
|
21 | 24 | xfs_calc_dquots_per_chunk(
|
@@ -323,3 +326,190 @@ xfs_dquot_to_disk_ts(
|
323 | 326 |
|
324 | 327 | return cpu_to_be32(t);
|
325 | 328 | }
|
| 329 | + |
| 330 | +inline unsigned int |
| 331 | +xfs_dqinode_sick_mask(xfs_dqtype_t type) |
| 332 | +{ |
| 333 | + switch (type) { |
| 334 | + case XFS_DQTYPE_USER: |
| 335 | + return XFS_SICK_FS_UQUOTA; |
| 336 | + case XFS_DQTYPE_GROUP: |
| 337 | + return XFS_SICK_FS_GQUOTA; |
| 338 | + case XFS_DQTYPE_PROJ: |
| 339 | + return XFS_SICK_FS_PQUOTA; |
| 340 | + } |
| 341 | + |
| 342 | + ASSERT(0); |
| 343 | + return 0; |
| 344 | +} |
| 345 | + |
| 346 | +/* |
| 347 | + * Load the inode for a given type of quota, assuming that the sb fields have |
| 348 | + * been sorted out. This is not true when switching quota types on a V4 |
| 349 | + * filesystem, so do not use this function for that. If metadir is enabled, |
| 350 | + * @dp must be the /quota metadir. |
| 351 | + * |
| 352 | + * Returns -ENOENT if the quota inode field is NULLFSINO; 0 and an inode on |
| 353 | + * success; or a negative errno. |
| 354 | + */ |
| 355 | +int |
| 356 | +xfs_dqinode_load( |
| 357 | + struct xfs_trans *tp, |
| 358 | + struct xfs_inode *dp, |
| 359 | + xfs_dqtype_t type, |
| 360 | + struct xfs_inode **ipp) |
| 361 | +{ |
| 362 | + struct xfs_mount *mp = tp->t_mountp; |
| 363 | + struct xfs_inode *ip; |
| 364 | + enum xfs_metafile_type metafile_type = xfs_dqinode_metafile_type(type); |
| 365 | + int error; |
| 366 | + |
| 367 | + if (!xfs_has_metadir(mp)) { |
| 368 | + xfs_ino_t ino; |
| 369 | + |
| 370 | + switch (type) { |
| 371 | + case XFS_DQTYPE_USER: |
| 372 | + ino = mp->m_sb.sb_uquotino; |
| 373 | + break; |
| 374 | + case XFS_DQTYPE_GROUP: |
| 375 | + ino = mp->m_sb.sb_gquotino; |
| 376 | + break; |
| 377 | + case XFS_DQTYPE_PROJ: |
| 378 | + ino = mp->m_sb.sb_pquotino; |
| 379 | + break; |
| 380 | + default: |
| 381 | + ASSERT(0); |
| 382 | + return -EFSCORRUPTED; |
| 383 | + } |
| 384 | + |
| 385 | + /* Should have set 0 to NULLFSINO when loading superblock */ |
| 386 | + if (ino == NULLFSINO) |
| 387 | + return -ENOENT; |
| 388 | + |
| 389 | + error = xfs_trans_metafile_iget(tp, ino, metafile_type, &ip); |
| 390 | + } else { |
| 391 | + error = xfs_metadir_load(tp, dp, xfs_dqinode_path(type), |
| 392 | + metafile_type, &ip); |
| 393 | + if (error == -ENOENT) |
| 394 | + return error; |
| 395 | + } |
| 396 | + if (error) { |
| 397 | + if (xfs_metadata_is_sick(error)) |
| 398 | + xfs_fs_mark_sick(mp, xfs_dqinode_sick_mask(type)); |
| 399 | + return error; |
| 400 | + } |
| 401 | + |
| 402 | + if (XFS_IS_CORRUPT(mp, ip->i_df.if_format != XFS_DINODE_FMT_EXTENTS && |
| 403 | + ip->i_df.if_format != XFS_DINODE_FMT_BTREE)) { |
| 404 | + xfs_irele(ip); |
| 405 | + xfs_fs_mark_sick(mp, xfs_dqinode_sick_mask(type)); |
| 406 | + return -EFSCORRUPTED; |
| 407 | + } |
| 408 | + |
| 409 | + if (XFS_IS_CORRUPT(mp, ip->i_projid != 0)) { |
| 410 | + xfs_irele(ip); |
| 411 | + xfs_fs_mark_sick(mp, xfs_dqinode_sick_mask(type)); |
| 412 | + return -EFSCORRUPTED; |
| 413 | + } |
| 414 | + |
| 415 | + *ipp = ip; |
| 416 | + return 0; |
| 417 | +} |
| 418 | + |
| 419 | +/* Create a metadata directory quota inode. */ |
| 420 | +int |
| 421 | +xfs_dqinode_metadir_create( |
| 422 | + struct xfs_inode *dp, |
| 423 | + xfs_dqtype_t type, |
| 424 | + struct xfs_inode **ipp) |
| 425 | +{ |
| 426 | + struct xfs_metadir_update upd = { |
| 427 | + .dp = dp, |
| 428 | + .metafile_type = xfs_dqinode_metafile_type(type), |
| 429 | + .path = xfs_dqinode_path(type), |
| 430 | + }; |
| 431 | + int error; |
| 432 | + |
| 433 | + error = xfs_metadir_start_create(&upd); |
| 434 | + if (error) |
| 435 | + return error; |
| 436 | + |
| 437 | + error = xfs_metadir_create(&upd, S_IFREG); |
| 438 | + if (error) |
| 439 | + return error; |
| 440 | + |
| 441 | + xfs_trans_log_inode(upd.tp, upd.ip, XFS_ILOG_CORE); |
| 442 | + |
| 443 | + error = xfs_metadir_commit(&upd); |
| 444 | + if (error) |
| 445 | + return error; |
| 446 | + |
| 447 | + xfs_finish_inode_setup(upd.ip); |
| 448 | + *ipp = upd.ip; |
| 449 | + return 0; |
| 450 | +} |
| 451 | + |
| 452 | +#ifndef __KERNEL__ |
| 453 | +/* Link a metadata directory quota inode. */ |
| 454 | +int |
| 455 | +xfs_dqinode_metadir_link( |
| 456 | + struct xfs_inode *dp, |
| 457 | + xfs_dqtype_t type, |
| 458 | + struct xfs_inode *ip) |
| 459 | +{ |
| 460 | + struct xfs_metadir_update upd = { |
| 461 | + .dp = dp, |
| 462 | + .metafile_type = xfs_dqinode_metafile_type(type), |
| 463 | + .path = xfs_dqinode_path(type), |
| 464 | + .ip = ip, |
| 465 | + }; |
| 466 | + int error; |
| 467 | + |
| 468 | + error = xfs_metadir_start_link(&upd); |
| 469 | + if (error) |
| 470 | + return error; |
| 471 | + |
| 472 | + error = xfs_metadir_link(&upd); |
| 473 | + if (error) |
| 474 | + return error; |
| 475 | + |
| 476 | + xfs_trans_log_inode(upd.tp, upd.ip, XFS_ILOG_CORE); |
| 477 | + |
| 478 | + return xfs_metadir_commit(&upd); |
| 479 | +} |
| 480 | +#endif /* __KERNEL__ */ |
| 481 | + |
| 482 | +/* Create the parent directory for all quota inodes and load it. */ |
| 483 | +int |
| 484 | +xfs_dqinode_mkdir_parent( |
| 485 | + struct xfs_mount *mp, |
| 486 | + struct xfs_inode **dpp) |
| 487 | +{ |
| 488 | + if (!mp->m_metadirip) { |
| 489 | + xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR); |
| 490 | + return -EFSCORRUPTED; |
| 491 | + } |
| 492 | + |
| 493 | + return xfs_metadir_mkdir(mp->m_metadirip, "quota", dpp); |
| 494 | +} |
| 495 | + |
| 496 | +/* |
| 497 | + * Load the parent directory of all quota inodes. Pass the inode to the caller |
| 498 | + * because quota functions (e.g. QUOTARM) can be called on the quota files even |
| 499 | + * if quotas are not enabled. |
| 500 | + */ |
| 501 | +int |
| 502 | +xfs_dqinode_load_parent( |
| 503 | + struct xfs_trans *tp, |
| 504 | + struct xfs_inode **dpp) |
| 505 | +{ |
| 506 | + struct xfs_mount *mp = tp->t_mountp; |
| 507 | + |
| 508 | + if (!mp->m_metadirip) { |
| 509 | + xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR); |
| 510 | + return -EFSCORRUPTED; |
| 511 | + } |
| 512 | + |
| 513 | + return xfs_metadir_load(tp, mp->m_metadirip, "quota", XFS_METAFILE_DIR, |
| 514 | + dpp); |
| 515 | +} |
0 commit comments