11e9ea7e0SNamjae Jeon // SPDX-License-Identifier: GPL-2.0-or-later 21e9ea7e0SNamjae Jeon /* 3*5218cd10SNamjae Jeon * NTFS kernel quota ($Quota) handling. 41e9ea7e0SNamjae Jeon * 51e9ea7e0SNamjae Jeon * Copyright (c) 2004 Anton Altaparmakov 61e9ea7e0SNamjae Jeon */ 71e9ea7e0SNamjae Jeon 81e9ea7e0SNamjae Jeon #include "index.h" 91e9ea7e0SNamjae Jeon #include "quota.h" 101e9ea7e0SNamjae Jeon #include "debug.h" 111e9ea7e0SNamjae Jeon #include "ntfs.h" 121e9ea7e0SNamjae Jeon 13*5218cd10SNamjae Jeon /* 141e9ea7e0SNamjae Jeon * ntfs_mark_quotas_out_of_date - mark the quotas out of date on an ntfs volume 151e9ea7e0SNamjae Jeon * @vol: ntfs volume on which to mark the quotas out of date 161e9ea7e0SNamjae Jeon * 171e9ea7e0SNamjae Jeon * Mark the quotas out of date on the ntfs volume @vol and return 'true' on 181e9ea7e0SNamjae Jeon * success and 'false' on error. 191e9ea7e0SNamjae Jeon */ 20*5218cd10SNamjae Jeon bool ntfs_mark_quotas_out_of_date(struct ntfs_volume *vol) 211e9ea7e0SNamjae Jeon { 22*5218cd10SNamjae Jeon struct ntfs_index_context *ictx; 23*5218cd10SNamjae Jeon struct quota_control_entry *qce; 24*5218cd10SNamjae Jeon const __le32 qid = QUOTA_DEFAULTS_ID; 251e9ea7e0SNamjae Jeon int err; 261e9ea7e0SNamjae Jeon 271e9ea7e0SNamjae Jeon ntfs_debug("Entering."); 281e9ea7e0SNamjae Jeon if (NVolQuotaOutOfDate(vol)) 291e9ea7e0SNamjae Jeon goto done; 301e9ea7e0SNamjae Jeon if (!vol->quota_ino || !vol->quota_q_ino) { 311e9ea7e0SNamjae Jeon ntfs_error(vol->sb, "Quota inodes are not open."); 321e9ea7e0SNamjae Jeon return false; 331e9ea7e0SNamjae Jeon } 341e9ea7e0SNamjae Jeon inode_lock(vol->quota_q_ino); 35*5218cd10SNamjae Jeon ictx = ntfs_index_ctx_get(NTFS_I(vol->quota_q_ino), I30, 4); 361e9ea7e0SNamjae Jeon if (!ictx) { 371e9ea7e0SNamjae Jeon ntfs_error(vol->sb, "Failed to get index context."); 381e9ea7e0SNamjae Jeon goto err_out; 391e9ea7e0SNamjae Jeon } 401e9ea7e0SNamjae Jeon err = ntfs_index_lookup(&qid, sizeof(qid), ictx); 411e9ea7e0SNamjae Jeon if (err) { 421e9ea7e0SNamjae Jeon if (err == -ENOENT) 43*5218cd10SNamjae Jeon ntfs_error(vol->sb, "Quota defaults entry is not present."); 441e9ea7e0SNamjae Jeon else 45*5218cd10SNamjae Jeon ntfs_error(vol->sb, "Lookup of quota defaults entry failed."); 461e9ea7e0SNamjae Jeon goto err_out; 471e9ea7e0SNamjae Jeon } 48*5218cd10SNamjae Jeon if (ictx->data_len < offsetof(struct quota_control_entry, sid)) { 49*5218cd10SNamjae Jeon ntfs_error(vol->sb, "Quota defaults entry size is invalid. Run chkdsk."); 501e9ea7e0SNamjae Jeon goto err_out; 511e9ea7e0SNamjae Jeon } 52*5218cd10SNamjae Jeon qce = (struct quota_control_entry *)ictx->data; 531e9ea7e0SNamjae Jeon if (le32_to_cpu(qce->version) != QUOTA_VERSION) { 54*5218cd10SNamjae Jeon ntfs_error(vol->sb, 55*5218cd10SNamjae Jeon "Quota defaults entry version 0x%x is not supported.", 56*5218cd10SNamjae Jeon le32_to_cpu(qce->version)); 571e9ea7e0SNamjae Jeon goto err_out; 581e9ea7e0SNamjae Jeon } 591e9ea7e0SNamjae Jeon ntfs_debug("Quota defaults flags = 0x%x.", le32_to_cpu(qce->flags)); 601e9ea7e0SNamjae Jeon /* If quotas are already marked out of date, no need to do anything. */ 611e9ea7e0SNamjae Jeon if (qce->flags & QUOTA_FLAG_OUT_OF_DATE) 621e9ea7e0SNamjae Jeon goto set_done; 631e9ea7e0SNamjae Jeon /* 641e9ea7e0SNamjae Jeon * If quota tracking is neither requested, nor enabled and there are no 651e9ea7e0SNamjae Jeon * pending deletes, no need to mark the quotas out of date. 661e9ea7e0SNamjae Jeon */ 671e9ea7e0SNamjae Jeon if (!(qce->flags & (QUOTA_FLAG_TRACKING_ENABLED | 681e9ea7e0SNamjae Jeon QUOTA_FLAG_TRACKING_REQUESTED | 691e9ea7e0SNamjae Jeon QUOTA_FLAG_PENDING_DELETES))) 701e9ea7e0SNamjae Jeon goto set_done; 711e9ea7e0SNamjae Jeon /* 721e9ea7e0SNamjae Jeon * Set the QUOTA_FLAG_OUT_OF_DATE bit thus marking quotas out of date. 731e9ea7e0SNamjae Jeon * This is verified on WinXP to be sufficient to cause windows to 741e9ea7e0SNamjae Jeon * rescan the volume on boot and update all quota entries. 751e9ea7e0SNamjae Jeon */ 761e9ea7e0SNamjae Jeon qce->flags |= QUOTA_FLAG_OUT_OF_DATE; 771e9ea7e0SNamjae Jeon /* Ensure the modified flags are written to disk. */ 781e9ea7e0SNamjae Jeon ntfs_index_entry_mark_dirty(ictx); 791e9ea7e0SNamjae Jeon set_done: 801e9ea7e0SNamjae Jeon ntfs_index_ctx_put(ictx); 811e9ea7e0SNamjae Jeon inode_unlock(vol->quota_q_ino); 821e9ea7e0SNamjae Jeon /* 831e9ea7e0SNamjae Jeon * We set the flag so we do not try to mark the quotas out of date 841e9ea7e0SNamjae Jeon * again on remount. 851e9ea7e0SNamjae Jeon */ 861e9ea7e0SNamjae Jeon NVolSetQuotaOutOfDate(vol); 871e9ea7e0SNamjae Jeon done: 881e9ea7e0SNamjae Jeon ntfs_debug("Done."); 891e9ea7e0SNamjae Jeon return true; 901e9ea7e0SNamjae Jeon err_out: 911e9ea7e0SNamjae Jeon if (ictx) 921e9ea7e0SNamjae Jeon ntfs_index_ctx_put(ictx); 931e9ea7e0SNamjae Jeon inode_unlock(vol->quota_q_ino); 941e9ea7e0SNamjae Jeon return false; 951e9ea7e0SNamjae Jeon } 96