OPTION(journal_zero_on_create, OPT_BOOL, false)
OPTION(journal_ignore_corruption, OPT_BOOL, false) // assume journal is not corrupt
OPTION(rbd_cache, OPT_BOOL, false) // whether to enable caching (writeback unless rbd_cache_max_dirty is 0)
+OPTION(rbd_cache_writethrough_until_flush, OPT_BOOL, false) // whether to make writeback caching writethrough until flush is called, to be sure the user of librbd will send flushs so that writeback is safe
OPTION(rbd_cache_size, OPT_LONGLONG, 32<<20) // cache size in bytes
OPTION(rbd_cache_max_dirty, OPT_LONGLONG, 24<<20) // dirty limit in bytes - set to 0 for write-through caching
OPTION(rbd_cache_target_dirty, OPT_LONGLONG, 16<<20) // target dirty limit in bytes
snap_id(CEPH_NOSNAP),
snap_exists(true),
read_only(ro),
+ flush_encountered(false),
exclusive_locked(false),
name(image_name),
wctx(NULL),
if (cct->_conf->rbd_cache) {
Mutex::Locker l(cache_lock);
- ldout(cct, 20) << "enabling writeback caching..." << dendl;
+ ldout(cct, 20) << "enabling caching..." << dendl;
writeback_handler = new LibrbdWriteback(this, cache_lock);
+
+ uint64_t init_max_dirty = cct->_conf->rbd_cache_max_dirty;
+ if (cct->_conf->rbd_cache_writethrough_until_flush)
+ init_max_dirty = 0;
+ ldout(cct, 20) << "Initial cache settings:"
+ << " size=" << cct->_conf->rbd_cache_size
+ << " num_objects=" << 10
+ << " max_dirty=" << init_max_dirty
+ << " target_dirty=" << cct->_conf->rbd_cache_target_dirty
+ << " max_dirty_age="
+ << cct->_conf->rbd_cache_max_dirty_age << dendl;
+
object_cacher = new ObjectCacher(cct, pname, *writeback_handler, cache_lock,
NULL, NULL,
cct->_conf->rbd_cache_size,
10, /* reset this in init */
- cct->_conf->rbd_cache_max_dirty,
+ init_max_dirty,
cct->_conf->rbd_cache_target_dirty,
cct->_conf->rbd_cache_max_dirty_age);
object_set = new ObjectCacher::ObjectSet(NULL, data_ctx.get_id(), 0);
return r;
}
+ void ImageCtx::user_flushed() {
+ if (object_cacher && cct->_conf->rbd_cache_writethrough_until_flush) {
+ md_lock.get_read();
+ bool flushed_before = flush_encountered;
+ md_lock.put_read();
+
+ uint64_t max_dirty = cct->_conf->rbd_cache_max_dirty;
+ if (!flushed_before && max_dirty > 0) {
+ md_lock.get_write();
+ flush_encountered = true;
+ md_lock.put_write();
+
+ ldout(cct, 10) << "saw first user flush, enabling writeback" << dendl;
+ Mutex::Locker l(cache_lock);
+ object_cacher->set_max_dirty(max_dirty);
+ }
+ }
+ }
+
int ImageCtx::flush_cache() {
int r = 0;
Mutex mylock("librbd::ImageCtx::flush_cache");
bool snap_exists; // false if our snap_id was deleted
// whether the image was opened read-only. cannot be changed after opening
bool read_only;
+ bool flush_encountered;
std::map<rados::cls::lock::locker_id_t,
rados::cls::lock::locker_info_t> lockers;
uint64_t off, Context *onfinish);
void write_to_cache(object_t o, bufferlist& bl, size_t len, uint64_t off);
int read_from_cache(object_t o, bufferlist *bl, size_t len, uint64_t off);
+ void user_flushed();
int flush_cache();
void shutdown_cache();
void invalidate_cache();