1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "include/int_types.h"
5 #include "include/types.h"
11 #include <sys/types.h>
13 #include <sys/ioctl.h>
15 #include "include/compat.h"
16 #include "include/linux_fiemap.h"
17 #include "include/color.h"
18 #include "include/buffer.h"
19 #include "include/ceph_assert.h"
25 #include "common/errno.h"
26 #include "common/config.h"
27 #include "common/sync_filesystem.h"
29 #include "ZFSFileStoreBackend.h"
31 #define dout_context cct()
32 #define dout_subsys ceph_subsys_filestore
34 #define dout_prefix *_dout << "zfsfilestorebackend(" << get_basedir_path() << ") "
36 ZFSFileStoreBackend::ZFSFileStoreBackend(FileStore
*fs
) :
37 GenericFileStoreBackend(fs
), base_zh(NULL
), current_zh(NULL
),
38 m_filestore_zfs_snap(cct()->_conf
->filestore_zfs_snap
)
42 dout(0) << "ZFSFileStoreBackend: failed to init libzfs" << dendl
;
46 base_zh
= zfs
.path_to_zhandle(get_basedir_path().c_str(), ZFS::TYPE_FILESYSTEM
);
48 dout(0) << "ZFSFileStoreBackend: failed to get zfs handler for basedir" << dendl
;
55 ZFSFileStoreBackend::~ZFSFileStoreBackend()
60 zfs
.close(current_zh
);
63 int ZFSFileStoreBackend::update_current_zh()
66 snprintf(path
, sizeof(path
), "%s/current", zfs
.get_name(base_zh
));
67 ZFS::Handle
*zh
= zfs
.open(path
, ZFS::TYPE_FILESYSTEM
);
70 if (zfs
.is_mounted(zh
, &mnt
)) {
71 int ret
= get_current_path() == mnt
;
78 int ret
= zfs
.mount(zh
, NULL
, 0);
81 dout(0) << "update_current_zh: zfs_mount '" << zfs
.get_name(zh
)
82 << "' got " << cpp_strerror(ret
) << dendl
;
88 dout(0) << "update_current_zh: zfs_open '" << path
<< "' got NULL" << dendl
;
92 zh
= zfs
.path_to_zhandle(get_current_path().c_str(), ZFS::TYPE_FILESYSTEM
);
94 if (strcmp(zfs
.get_name(base_zh
), zfs
.get_name(zh
))) {
99 dout(0) << "update_current_zh: basedir and current/ on the same filesystem" << dendl
;
101 dout(0) << "update_current_zh: current/ not exist" << dendl
;
106 int ZFSFileStoreBackend::detect_features()
109 dout(0) << "detect_features: null zfs handle for current/" << dendl
;
113 bool ZFSFileStoreBackend::can_checkpoint()
115 return m_filestore_zfs_snap
&& current_zh
!= NULL
;
118 int ZFSFileStoreBackend::create_current()
121 int ret
= ::stat(get_current_path().c_str(), &st
);
124 if (!S_ISDIR(st
.st_mode
)) {
125 dout(0) << "create_current: current/ exists but is not a directory" << dendl
;
129 } else if (errno
!= ENOENT
) {
131 dout(0) << "create_current: cannot stat current/ " << cpp_strerror(ret
) << dendl
;
136 snprintf(path
, sizeof(path
), "%s/current", zfs
.get_name(base_zh
));
137 ret
= zfs
.create(path
, ZFS::TYPE_FILESYSTEM
);
138 if (ret
< 0 && errno
!= EEXIST
) {
140 dout(0) << "create_current: zfs_create '" << path
<< "' got " << cpp_strerror(ret
) << dendl
;
144 ret
= update_current_zh();
148 static int list_checkpoints_callback(ZFS::Handle
*zh
, void *data
)
150 list
<string
> *ls
= static_cast<list
<string
> *>(data
);
151 string str
= ZFS::get_name(zh
);
152 size_t pos
= str
.find('@');
153 ceph_assert(pos
!= string::npos
&& pos
+ 1 != str
.length());
154 ls
->push_back(str
.substr(pos
+ 1));
158 int ZFSFileStoreBackend::list_checkpoints(list
<string
>& ls
)
160 dout(10) << "list_checkpoints:" << dendl
;
165 int ret
= zfs
.iter_snapshots_sorted(current_zh
, list_checkpoints_callback
, &snaps
);
168 dout(0) << "list_checkpoints: zfs_iter_snapshots_sorted got" << cpp_strerror(ret
) << dendl
;
175 int ZFSFileStoreBackend::create_checkpoint(const string
& name
, uint64_t *cid
)
177 dout(10) << "create_checkpoint: '" << name
<< "'" << dendl
;
181 // looks like zfsonlinux doesn't flush dirty data when taking snapshot
182 int ret
= sync_filesystem(get_current_fd());
185 dout(0) << "create_checkpoint: sync_filesystem got" << cpp_strerror(ret
) << dendl
;
190 snprintf(path
, sizeof(path
), "%s@%s", zfs
.get_name(current_zh
), name
.c_str());
191 ret
= zfs
.snapshot(path
, false);
194 dout(0) << "create_checkpoint: zfs_snapshot '" << path
<< "' got" << cpp_strerror(ret
) << dendl
;
202 int ZFSFileStoreBackend::rollback_to(const string
& name
)
204 dout(10) << "rollback_to: '" << name
<< "'" << dendl
;
208 // umount current to avoid triggering online rollback deadlock
210 if (zfs
.is_mounted(current_zh
, NULL
)) {
211 ret
= zfs
.umount(current_zh
, NULL
, 0);
214 dout(0) << "rollback_to: zfs_umount '" << zfs
.get_name(current_zh
) << "' got" << cpp_strerror(ret
) << dendl
;
219 snprintf(path
, sizeof(path
), "%s@%s", zfs
.get_name(current_zh
), name
.c_str());
221 ZFS::Handle
*snap_zh
= zfs
.open(path
, ZFS::TYPE_SNAPSHOT
);
223 dout(0) << "rollback_to: zfs_open '" << path
<< "' got NULL" << dendl
;
227 ret
= zfs
.rollback(current_zh
, snap_zh
, false);
230 dout(0) << "rollback_to: zfs_rollback '" << zfs
.get_name(snap_zh
) << "' got" << cpp_strerror(ret
) << dendl
;
233 if (!zfs
.is_mounted(current_zh
, NULL
)) {
234 int ret
= zfs
.mount(current_zh
, NULL
, 0);
237 dout(0) << "update_current_zh: zfs_mount '" << zfs
.get_name(current_zh
) << "' got " << cpp_strerror(ret
) << dendl
;
246 int ZFSFileStoreBackend::destroy_checkpoint(const string
& name
)
248 dout(10) << "destroy_checkpoint: '" << name
<< "'" << dendl
;
252 int ret
= zfs
.destroy_snaps(current_zh
, name
.c_str(), true);
255 dout(0) << "destroy_checkpoint: zfs_destroy_snaps '" << name
<< "' got" << cpp_strerror(ret
) << dendl
;