xref: /linux/fs/ntfs/quota.c (revision cdd4dc3aebeab43a72ce0bc2b5bab6f0a80b97a5)
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