162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * quota.c - NTFS kernel quota ($Quota) handling. Part of the Linux-NTFS 462306a36Sopenharmony_ci * project. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (c) 2004 Anton Altaparmakov 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#ifdef NTFS_RW 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "index.h" 1262306a36Sopenharmony_ci#include "quota.h" 1362306a36Sopenharmony_ci#include "debug.h" 1462306a36Sopenharmony_ci#include "ntfs.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/** 1762306a36Sopenharmony_ci * ntfs_mark_quotas_out_of_date - mark the quotas out of date on an ntfs volume 1862306a36Sopenharmony_ci * @vol: ntfs volume on which to mark the quotas out of date 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * Mark the quotas out of date on the ntfs volume @vol and return 'true' on 2162306a36Sopenharmony_ci * success and 'false' on error. 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_cibool ntfs_mark_quotas_out_of_date(ntfs_volume *vol) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci ntfs_index_context *ictx; 2662306a36Sopenharmony_ci QUOTA_CONTROL_ENTRY *qce; 2762306a36Sopenharmony_ci const le32 qid = QUOTA_DEFAULTS_ID; 2862306a36Sopenharmony_ci int err; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci ntfs_debug("Entering."); 3162306a36Sopenharmony_ci if (NVolQuotaOutOfDate(vol)) 3262306a36Sopenharmony_ci goto done; 3362306a36Sopenharmony_ci if (!vol->quota_ino || !vol->quota_q_ino) { 3462306a36Sopenharmony_ci ntfs_error(vol->sb, "Quota inodes are not open."); 3562306a36Sopenharmony_ci return false; 3662306a36Sopenharmony_ci } 3762306a36Sopenharmony_ci inode_lock(vol->quota_q_ino); 3862306a36Sopenharmony_ci ictx = ntfs_index_ctx_get(NTFS_I(vol->quota_q_ino)); 3962306a36Sopenharmony_ci if (!ictx) { 4062306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to get index context."); 4162306a36Sopenharmony_ci goto err_out; 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci err = ntfs_index_lookup(&qid, sizeof(qid), ictx); 4462306a36Sopenharmony_ci if (err) { 4562306a36Sopenharmony_ci if (err == -ENOENT) 4662306a36Sopenharmony_ci ntfs_error(vol->sb, "Quota defaults entry is not " 4762306a36Sopenharmony_ci "present."); 4862306a36Sopenharmony_ci else 4962306a36Sopenharmony_ci ntfs_error(vol->sb, "Lookup of quota defaults entry " 5062306a36Sopenharmony_ci "failed."); 5162306a36Sopenharmony_ci goto err_out; 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci if (ictx->data_len < offsetof(QUOTA_CONTROL_ENTRY, sid)) { 5462306a36Sopenharmony_ci ntfs_error(vol->sb, "Quota defaults entry size is invalid. " 5562306a36Sopenharmony_ci "Run chkdsk."); 5662306a36Sopenharmony_ci goto err_out; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci qce = (QUOTA_CONTROL_ENTRY*)ictx->data; 5962306a36Sopenharmony_ci if (le32_to_cpu(qce->version) != QUOTA_VERSION) { 6062306a36Sopenharmony_ci ntfs_error(vol->sb, "Quota defaults entry version 0x%x is not " 6162306a36Sopenharmony_ci "supported.", le32_to_cpu(qce->version)); 6262306a36Sopenharmony_ci goto err_out; 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci ntfs_debug("Quota defaults flags = 0x%x.", le32_to_cpu(qce->flags)); 6562306a36Sopenharmony_ci /* If quotas are already marked out of date, no need to do anything. */ 6662306a36Sopenharmony_ci if (qce->flags & QUOTA_FLAG_OUT_OF_DATE) 6762306a36Sopenharmony_ci goto set_done; 6862306a36Sopenharmony_ci /* 6962306a36Sopenharmony_ci * If quota tracking is neither requested, nor enabled and there are no 7062306a36Sopenharmony_ci * pending deletes, no need to mark the quotas out of date. 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_ci if (!(qce->flags & (QUOTA_FLAG_TRACKING_ENABLED | 7362306a36Sopenharmony_ci QUOTA_FLAG_TRACKING_REQUESTED | 7462306a36Sopenharmony_ci QUOTA_FLAG_PENDING_DELETES))) 7562306a36Sopenharmony_ci goto set_done; 7662306a36Sopenharmony_ci /* 7762306a36Sopenharmony_ci * Set the QUOTA_FLAG_OUT_OF_DATE bit thus marking quotas out of date. 7862306a36Sopenharmony_ci * This is verified on WinXP to be sufficient to cause windows to 7962306a36Sopenharmony_ci * rescan the volume on boot and update all quota entries. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ci qce->flags |= QUOTA_FLAG_OUT_OF_DATE; 8262306a36Sopenharmony_ci /* Ensure the modified flags are written to disk. */ 8362306a36Sopenharmony_ci ntfs_index_entry_flush_dcache_page(ictx); 8462306a36Sopenharmony_ci ntfs_index_entry_mark_dirty(ictx); 8562306a36Sopenharmony_ciset_done: 8662306a36Sopenharmony_ci ntfs_index_ctx_put(ictx); 8762306a36Sopenharmony_ci inode_unlock(vol->quota_q_ino); 8862306a36Sopenharmony_ci /* 8962306a36Sopenharmony_ci * We set the flag so we do not try to mark the quotas out of date 9062306a36Sopenharmony_ci * again on remount. 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_ci NVolSetQuotaOutOfDate(vol); 9362306a36Sopenharmony_cidone: 9462306a36Sopenharmony_ci ntfs_debug("Done."); 9562306a36Sopenharmony_ci return true; 9662306a36Sopenharmony_cierr_out: 9762306a36Sopenharmony_ci if (ictx) 9862306a36Sopenharmony_ci ntfs_index_ctx_put(ictx); 9962306a36Sopenharmony_ci inode_unlock(vol->quota_q_ino); 10062306a36Sopenharmony_ci return false; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci#endif /* NTFS_RW */ 104