v0.81
-----
+- Disallow nonsensical 'tier cache-mode' transitions. From this point
+ onward, 'writeback' can only transition to 'forward' and 'forward'
+ can transition to 1) 'writeback' if there are dirty objects, or 2) any if
+ there are no dirty objects.
ceph osd tier add data cache
ceph osd tier add data cache2
expect_false ceph osd tier add metadata cache
+# test some state transitions
ceph osd tier cache-mode cache writeback
+ceph osd tier cache-mode cache forward
+ceph osd tier cache-mode cache readonly
+ceph osd tier cache-mode cache forward
+ceph osd tier cache-mode cache none
+ceph osd tier cache-mode cache writeback
+expect_false ceph osd tier cache-mode cache none
+expect_false ceph osd tier cache-mode cache readonly
+# test with dirty objects in the tier pool
+# tier pool currently set to 'writeback'
+rados -p cache put /etc/passwd /etc/passwd
+ceph tell osd.* flush_pg_stats || true
+# 1 dirty object in pool 'cache'
+ceph osd tier cache-mode cache forward
+expect_false ceph osd tier cache-mode cache none
+expect_false ceph osd tier cache-mode cache readonly
+ceph osd tier cache-mode cache writeback
+# remove object from tier pool
+rados -p cache rm /etc/passwd
+rados -p cache cache-flush-evict-all
+ceph tell osd.* flush_pg_stats || true
+# no dirty objects in pool 'cache'
+ceph osd tier cache-mode cache forward
+ceph osd tier cache-mode cache none
ceph osd tier cache-mode cache readonly
TRIES=0
while ! ceph osd pool set cache pg_num 3 --yes-i-really-mean-it 2>$TMPFILE
goto reply;
}
+ /* Mode description:
+ *
+ * none: No cache-mode defined
+ * forward: Forward all reads and writes to base pool
+ * writeback: Cache writes, promote reads from base pool
+ * readonly: Forward writes to base pool
+ *
+ * Hence, these are the allowed transitions:
+ *
+ * none -> any
+ * forward -> writeback || any IF num_objects_dirty == 0
+ * writeback -> forward
+ * readonly -> any
+ */
+
+ // We check if the transition is valid against the current pool mode, as
+ // it is the only committed state thus far. We will blantly squash
+ // whatever mode is on the pending state.
+
+ if (p->cache_mode == pg_pool_t::CACHEMODE_WRITEBACK &&
+ mode != pg_pool_t::CACHEMODE_FORWARD) {
+ ss << "unable to set cache-mode '" << pg_pool_t::get_cache_mode_name(mode)
+ << "' on a '" << pg_pool_t::get_cache_mode_name(p->cache_mode)
+ << "' pool; only '"
+ << pg_pool_t::get_cache_mode_name(pg_pool_t::CACHEMODE_FORWARD)
+ << "' allowed.";
+ err = -EINVAL;
+ goto reply;
+ }
+ if (p->cache_mode == pg_pool_t::CACHEMODE_FORWARD &&
+ mode != pg_pool_t::CACHEMODE_WRITEBACK) {
+
+ const pool_stat_t& tier_stats =
+ mon->pgmon()->pg_map.get_pg_pool_sum_stat(pool_id);
+
+ if (tier_stats.stats.sum.num_objects_dirty > 0) {
+ ss << "unable to set cache-mode '"
+ << pg_pool_t::get_cache_mode_name(mode) << "' on pool '" << poolstr
+ << "': dirty objects found";
+ err = -EBUSY;
+ goto reply;
+ }
+ }
+
// go
pending_inc.get_new_pool(pool_id, p)->cache_mode = mode;
ss << "set cache-mode for pool '" << poolstr