summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/fs/zfs/zap_micro.c
diff options
context:
space:
mode:
authorSanjeev Bagewadi <Sanjeev.Bagewadi@Sun.COM>2009-05-19 11:19:21 +0530
committerSanjeev Bagewadi <Sanjeev.Bagewadi@Sun.COM>2009-05-19 11:19:21 +0530
commit3d6926289465757c3da780cea696825b0d730283 (patch)
tree690ee3d922808fb44698116f95d225a2d5f12fb7 /usr/src/uts/common/fs/zfs/zap_micro.c
parentfa96bd918a96f4ac299dc0816aac8a0d40cf1ee7 (diff)
downloadillumos-gate-3d6926289465757c3da780cea696825b0d730283.tar.gz
6664765 Unable to remove files when using fat-zap and quota exceeded on ZFS filesystem
Diffstat (limited to 'usr/src/uts/common/fs/zfs/zap_micro.c')
-rw-r--r--usr/src/uts/common/fs/zfs/zap_micro.c76
1 files changed, 76 insertions, 0 deletions
diff --git a/usr/src/uts/common/fs/zfs/zap_micro.c b/usr/src/uts/common/fs/zfs/zap_micro.c
index 06d8128c7c..fbc93b423d 100644
--- a/usr/src/uts/common/fs/zfs/zap_micro.c
+++ b/usr/src/uts/common/fs/zfs/zap_micro.c
@@ -1065,3 +1065,79 @@ zap_get_stats(objset_t *os, uint64_t zapobj, zap_stats_t *zs)
zap_unlockdir(zap);
return (0);
}
+
+int
+zap_count_write(objset_t *os, uint64_t zapobj, const char *name, int add,
+ uint64_t *towrite, uint64_t *tooverwrite, uint64_t dn_datablkshift)
+{
+ zap_t *zap;
+ int err = 0;
+
+
+ /*
+ * Since, we don't have a name, we cannot figure out which blocks will
+ * be affected in this operation. So, account for the worst case :
+ * - 3 blocks overwritten: target leaf, ptrtbl block, header block
+ * - 4 new blocks written if adding:
+ * - 2 blocks for possibly split leaves,
+ * - 2 grown ptrtbl blocks
+ *
+ * This also accomodates the case where an add operation to a fairly
+ * large microzap results in a promotion to fatzap.
+ */
+ if (name == NULL) {
+ *towrite += (3 + (add ? 4 : 0)) * SPA_MAXBLOCKSIZE;
+ return (err);
+ }
+
+ /*
+ * We lock the zap with adding == FALSE. Because, if we pass
+ * the actual value of add, it could trigger a mzap_upgrade().
+ * At present we are just evaluating the possibility of this operation
+ * and hence we donot want to trigger an upgrade.
+ */
+ err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, &zap);
+ if (err)
+ return (err);
+
+ if (!zap->zap_ismicro) {
+ zap_name_t *zn = zap_name_alloc(zap, name, MT_EXACT);
+ if (zn) {
+ err = fzap_count_write(zn, add, towrite,
+ tooverwrite);
+ zap_name_free(zn);
+ } else {
+ /*
+ * We treat this case as similar to (name == NULL)
+ */
+ *towrite += (3 + (add ? 4 : 0)) * SPA_MAXBLOCKSIZE;
+ }
+ } else {
+ if (!add) {
+ if (dmu_buf_freeable(zap->zap_dbuf))
+ *tooverwrite += SPA_MAXBLOCKSIZE;
+ else
+ *towrite += SPA_MAXBLOCKSIZE;
+ } else {
+ /*
+ * We are here if we are adding and (name != NULL).
+ * It is hard to find out if this add will promote this
+ * microzap to fatzap. Hence, we assume the worst case
+ * and account for the blocks assuming this microzap
+ * would be promoted to a fatzap.
+ *
+ * 1 block overwritten : header block
+ * 4 new blocks written : 2 new split leaf, 2 grown
+ * ptrtbl blocks
+ */
+ if (dmu_buf_freeable(zap->zap_dbuf))
+ *tooverwrite += 1 << dn_datablkshift;
+ else
+ *towrite += 1 << dn_datablkshift;
+ *towrite += 4 << dn_datablkshift;
+ }
+ }
+
+ zap_unlockdir(zap);
+ return (err);
+}