forked from openSUSE/snapper
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- added experimental bcachefs support
- Loading branch information
Showing
14 changed files
with
631 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
7.4.0 | ||
7.4.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
|
||
bcachefs support is experimental | ||
|
||
TODOs (at least): | ||
|
||
- ioctl for snapshot creation takes path instead of fd | ||
|
||
- read-only snapshots not supported by bcachefs | ||
- background comparison started anyway | ||
|
||
- check if a directory is a snapshot | ||
|
||
- get ioctl defines from a header file or use a library | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,8 @@ | ||
------------------------------------------------------------------- | ||
Wed Feb 14 09:14:32 CET 2024 - [email protected] | ||
|
||
- added experimental bcachefs support (gh#openSUSE/snapper#858) | ||
|
||
------------------------------------------------------------------- | ||
Wed Feb 07 11:16:40 CET 2024 - [email protected] | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,323 @@ | ||
/* | ||
* Copyright (c) 2024 SUSE LLC | ||
* | ||
* All Rights Reserved. | ||
* | ||
* This program is free software; you can redistribute it and/or modify it | ||
* under the terms of version 2 of the GNU General Public License as published | ||
* by the Free Software Foundation. | ||
* | ||
* This program is distributed in the hope that it will be useful, but WITHOUT | ||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
* more details. | ||
* | ||
* You should have received a copy of the GNU General Public License along | ||
* with this program; if not, contact Novell, Inc. | ||
* | ||
* To contact Novell about this file by physical or electronic mail, you may | ||
* find current contact information at www.novell.com. | ||
*/ | ||
|
||
|
||
#include "config.h" | ||
|
||
#include <unistd.h> | ||
#include <fcntl.h> | ||
#include <sys/ioctl.h> | ||
#include <sys/stat.h> | ||
#include <sys/types.h> | ||
|
||
#include "snapper/Log.h" | ||
#include "snapper/Bcachefs.h" | ||
#include "snapper/BcachefsUtils.h" | ||
#include "snapper/File.h" | ||
#include "snapper/Snapper.h" | ||
#include "snapper/SnapperTmpl.h" | ||
|
||
#include "snapper/Acls.h" | ||
#include "snapper/Exception.h" | ||
#ifdef ENABLE_SELINUX | ||
#include "snapper/Selinux.h" | ||
#endif | ||
|
||
|
||
namespace snapper | ||
{ | ||
using namespace std; | ||
|
||
using namespace BcachefsUtils; | ||
|
||
|
||
Filesystem* | ||
Bcachefs::create(const string& fstype, const string& subvolume, const string& root_prefix) | ||
{ | ||
if (fstype == "bcachefs") | ||
return new Bcachefs(subvolume, root_prefix); | ||
|
||
return nullptr; | ||
} | ||
|
||
|
||
Bcachefs::Bcachefs(const string& subvolume, const string& root_prefix) | ||
: Filesystem(subvolume, root_prefix) | ||
{ | ||
} | ||
|
||
|
||
void | ||
Bcachefs::createConfig() const | ||
{ | ||
SDir subvolume_dir = openSubvolumeDir(); | ||
|
||
try | ||
{ | ||
create_subvolume(subvolume_dir.fd(), ".snapshots"); | ||
} | ||
catch (const runtime_error_with_errno& e) | ||
{ | ||
y2err("create subvolume failed, " << e.what()); | ||
|
||
switch (e.error_number) | ||
{ | ||
case EEXIST: | ||
SN_THROW(CreateConfigFailedException("creating bcachefs subvolume .snapshots failed " | ||
"since it already exists")); | ||
break; | ||
|
||
default: | ||
SN_THROW(CreateConfigFailedException("creating bcachefs subvolume .snapshots failed")); | ||
} | ||
} | ||
|
||
SFile x(subvolume_dir, ".snapshots"); | ||
|
||
#ifdef ENABLE_SELINUX | ||
try | ||
{ | ||
SnapperContexts scontexts; | ||
|
||
x.fsetfilecon(scontexts.subvolume_context()); | ||
} | ||
catch (const SelinuxException& e) | ||
{ | ||
SN_CAUGHT(e); | ||
// fall through intentional | ||
} | ||
#endif | ||
|
||
struct stat stat; | ||
if (x.stat(&stat, 0) == 0) | ||
x.chmod(stat.st_mode & ~0027, 0); | ||
} | ||
|
||
|
||
void | ||
Bcachefs::deleteConfig() const | ||
{ | ||
SDir subvolume_dir = openSubvolumeDir(); | ||
|
||
try | ||
{ | ||
delete_subvolume(subvolume_dir.fd(), ".snapshots"); | ||
} | ||
catch (const runtime_error& e) | ||
{ | ||
y2err("delete subvolume failed, " << e.what()); | ||
SN_THROW(DeleteConfigFailedException("deleting bcachefs snapshot failed")); | ||
} | ||
} | ||
|
||
|
||
string | ||
Bcachefs::snapshotDir(unsigned int num) const | ||
{ | ||
return (subvolume == "/" ? "" : subvolume) + "/.snapshots/" + decString(num) + | ||
"/snapshot"; | ||
} | ||
|
||
|
||
SDir | ||
Bcachefs::openSubvolumeDir() const | ||
{ | ||
SDir subvolume_dir = Filesystem::openSubvolumeDir(); | ||
|
||
struct stat stat; | ||
if (subvolume_dir.stat(&stat) != 0) | ||
{ | ||
SN_THROW(IOErrorException("stat on subvolume directory failed")); | ||
} | ||
|
||
if (!is_subvolume(stat)) | ||
{ | ||
SN_THROW(IOErrorException("subvolume is not a bcachefs subvolume")); | ||
} | ||
|
||
return subvolume_dir; | ||
} | ||
|
||
|
||
SDir | ||
Bcachefs::openInfosDir() const | ||
{ | ||
SDir subvolume_dir = openSubvolumeDir(); | ||
SDir infos_dir(subvolume_dir, ".snapshots"); | ||
|
||
struct stat stat; | ||
if (infos_dir.stat(&stat) != 0) | ||
{ | ||
SN_THROW(IOErrorException("stat on info directory failed")); | ||
} | ||
|
||
if (!is_subvolume(stat)) | ||
{ | ||
SN_THROW(IOErrorException(".snapshots is not a bcachefs subvolume")); | ||
} | ||
|
||
if (stat.st_uid != 0) | ||
{ | ||
y2err(".snapshots must have owner root"); | ||
SN_THROW(IOErrorException(".snapshots must have owner root")); | ||
} | ||
|
||
if (stat.st_gid != 0 && stat.st_mode & S_IWGRP) | ||
{ | ||
y2err(".snapshots must have group root or must not be group-writable"); | ||
SN_THROW(IOErrorException(".snapshots must have group root or must not be group-writable")); | ||
} | ||
|
||
if (stat.st_mode & S_IWOTH) | ||
{ | ||
y2err(".snapshots must not be world-writable"); | ||
SN_THROW(IOErrorException(".snapshots must not be world-writable")); | ||
} | ||
|
||
return infos_dir; | ||
} | ||
|
||
|
||
SDir | ||
Bcachefs::openSnapshotDir(unsigned int num) const | ||
{ | ||
SDir info_dir = openInfoDir(num); | ||
SDir snapshot_dir(info_dir, "snapshot"); | ||
|
||
return snapshot_dir; | ||
} | ||
|
||
|
||
void | ||
Bcachefs::createSnapshot(unsigned int num, unsigned int num_parent, bool read_only, bool quota, | ||
bool empty) const | ||
{ | ||
if (num_parent == 0) | ||
{ | ||
SDir subvolume_dir = openSubvolumeDir(); | ||
SDir info_dir = openInfoDir(num); | ||
|
||
try | ||
{ | ||
if (empty) | ||
create_subvolume(info_dir.fd(), "snapshot"); | ||
else | ||
create_snapshot(subvolume_dir.fd(), subvolume, info_dir.fd(), "snapshot", read_only); | ||
} | ||
catch (const runtime_error& e) | ||
{ | ||
y2err("create snapshot failed, " << e.what()); | ||
SN_THROW(CreateSnapshotFailedException()); | ||
} | ||
} | ||
else | ||
{ | ||
SDir snapshot_dir = openSnapshotDir(num_parent); | ||
SDir info_dir = openInfoDir(num); | ||
|
||
try | ||
{ | ||
create_snapshot(snapshot_dir.fd(), subvolume, info_dir.fd(), "snapshot", read_only); | ||
} | ||
catch (const runtime_error& e) | ||
{ | ||
y2err("create snapshot failed, " << e.what()); | ||
SN_THROW(CreateSnapshotFailedException()); | ||
} | ||
} | ||
} | ||
|
||
|
||
void | ||
Bcachefs::deleteSnapshot(unsigned int num) const | ||
{ | ||
SDir info_dir = openInfoDir(num); | ||
|
||
try | ||
{ | ||
delete_subvolume(info_dir.fd(), "snapshot"); | ||
} | ||
catch (const runtime_error& e) | ||
{ | ||
y2err("delete snapshot failed, " << e.what()); | ||
SN_THROW(DeleteSnapshotFailedException()); | ||
} | ||
} | ||
|
||
|
||
bool | ||
Bcachefs::isSnapshotMounted(unsigned int num) const | ||
{ | ||
return true; | ||
} | ||
|
||
|
||
void | ||
Bcachefs::mountSnapshot(unsigned int num) const | ||
{ | ||
} | ||
|
||
|
||
void | ||
Bcachefs::umountSnapshot(unsigned int num) const | ||
{ | ||
} | ||
|
||
|
||
bool | ||
Bcachefs::isSnapshotReadOnly(unsigned int num) const | ||
{ | ||
SDir snapshot_dir = openSnapshotDir(num); | ||
return is_subvolume_read_only(snapshot_dir.fd()); | ||
} | ||
|
||
|
||
void | ||
Bcachefs::setSnapshotReadOnly(unsigned int num, bool read_only) const | ||
{ | ||
SDir snapshot_dir = openSnapshotDir(num); | ||
set_subvolume_read_only(snapshot_dir.fd(), read_only); | ||
} | ||
|
||
|
||
bool | ||
Bcachefs::checkSnapshot(unsigned int num) const | ||
{ | ||
try | ||
{ | ||
SDir info_dir = openInfoDir(num); | ||
|
||
struct stat stat; | ||
int r = info_dir.stat("snapshot", &stat, AT_SYMLINK_NOFOLLOW); | ||
return r == 0 && is_subvolume(stat); | ||
} | ||
catch (const IOErrorException& e) | ||
{ | ||
SN_CAUGHT(e); | ||
|
||
// TODO the openInfoDir above logs an error although when this | ||
// function is used from nextNumber the failure is ok | ||
|
||
return false; | ||
} | ||
} | ||
|
||
} |
Oops, something went wrong.