btrfs-progs: receive: implement FILEATTR command

The initial proposal for file attributes was built on simply doing
SETFLAGS but this builds on an old and non-extensible interface that has
no direct mapping for all inode flags. There's a unified interface
fileattr that covers file attributes and xflags, it should be possible
to add new bits.

On the protocol level the value is copied as-is in the original inode
but this does not provide enough information how to apply the bits on
the receiving side. Eg. IMMUTABLE flag prevents any changes to the file
and has to be handled manually.

The receiving side does not apply the bits yet, only parses it from the
stream.

Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
David Sterba 2022-06-21 17:35:03 +02:00
parent 0353c83056
commit ef719df5bb
5 changed files with 22 additions and 15 deletions

View File

@ -339,9 +339,9 @@ static int print_fallocate(const char *path, int mode, u64 offset, u64 len,
mode, offset, len); mode, offset, len);
} }
static int print_setflags(const char *path, int flags, void *user) static int print_fileattr(const char *path, u64 attr, void *user)
{ {
return PRINT_DUMP(user, path, "setflags", "flags=%d", flags); return PRINT_DUMP(user, path, "fileattr", "fileattr=0x%llu", attr);
} }
struct btrfs_send_ops btrfs_print_send_ops = { struct btrfs_send_ops btrfs_print_send_ops = {
@ -368,5 +368,5 @@ struct btrfs_send_ops btrfs_print_send_ops = {
.update_extent = print_update_extent, .update_extent = print_update_extent,
.encoded_write = print_encoded_write, .encoded_write = print_encoded_write,
.fallocate = print_fallocate, .fallocate = print_fallocate,
.setflags = print_setflags, .fileattr = print_fileattr,
}; };

View File

@ -1309,7 +1309,7 @@ static int process_fallocate(const char *path, int mode, u64 offset, u64 len,
return 0; return 0;
} }
static int process_setflags(const char *path, int flags, void *user) static int process_fileattr(const char *path, u64 attr, void *user)
{ {
int ret; int ret;
struct btrfs_receive *rctx = user; struct btrfs_receive *rctx = user;
@ -1317,16 +1317,17 @@ static int process_setflags(const char *path, int flags, void *user)
ret = path_cat_out(full_path, rctx->full_subvol_path, path); ret = path_cat_out(full_path, rctx->full_subvol_path, path);
if (ret < 0) { if (ret < 0) {
error("setflags: path invalid: %s", path); error("fileattr: path invalid: %s", path);
return ret; return ret;
} }
ret = open_inode_for_write(rctx, full_path); ret = open_inode_for_write(rctx, full_path);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = ioctl(rctx->write_fd, FS_IOC_SETFLAGS, &flags); ret = -EOPNOTSUPP;
/* ret = ioctl(rctx->write_fd, FS_IOC_SETFLAGS, &flags); */
if (ret < 0) { if (ret < 0) {
ret = -errno; ret = -errno;
error("setflags: setflags ioctl on %s failed: %m", path); error("fileattr: set file attributes on %s failed: %m", path);
return ret; return ret;
} }
return 0; return 0;
@ -1356,7 +1357,7 @@ static struct btrfs_send_ops send_ops = {
.update_extent = process_update_extent, .update_extent = process_update_extent,
.encoded_write = process_encoded_write, .encoded_write = process_encoded_write,
.fallocate = process_fallocate, .fallocate = process_fallocate,
.setflags = process_setflags, .fileattr = process_fileattr,
}; };
static int do_receive(struct btrfs_receive *rctx, const char *tomnt, static int do_receive(struct btrfs_receive *rctx, const char *tomnt,

View File

@ -372,10 +372,10 @@ static int read_and_process_cmd(struct btrfs_send_stream *sctx)
u64 unencoded_file_len; u64 unencoded_file_len;
u64 unencoded_len; u64 unencoded_len;
u64 unencoded_offset; u64 unencoded_offset;
u64 fileattr;
int len; int len;
int xattr_len; int xattr_len;
int fallocate_mode; int fallocate_mode;
int setflags_flags;
ret = read_cmd(sctx); ret = read_cmd(sctx);
if (ret) if (ret)
@ -548,10 +548,10 @@ static int read_and_process_cmd(struct btrfs_send_stream *sctx)
ret = sctx->ops->fallocate(path, fallocate_mode, offset, tmp, ret = sctx->ops->fallocate(path, fallocate_mode, offset, tmp,
sctx->user); sctx->user);
break; break;
case BTRFS_SEND_C_SETFLAGS: case BTRFS_SEND_C_FILEATTR:
TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path); TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
TLV_GET_U32(sctx, BTRFS_SEND_A_SETFLAGS_FLAGS, &setflags_flags); TLV_GET_U32(sctx, BTRFS_SEND_A_FILEATTR, &fileattr);
ret = sctx->ops->setflags(path, setflags_flags, sctx->user); ret = sctx->ops->fileattr(path, fileattr, sctx->user);
break; break;
} }

View File

@ -59,7 +59,7 @@ struct btrfs_send_ops {
u32 encryption, void *user); u32 encryption, void *user);
int (*fallocate)(const char *path, int mode, u64 offset, u64 len, int (*fallocate)(const char *path, int mode, u64 offset, u64 len,
void *user); void *user);
int (*setflags)(const char *path, int flags, void *user); int (*fileattr)(const char *path, u64 attr, void *user);
}; };
int btrfs_read_and_process_send_stream(int fd, int btrfs_read_and_process_send_stream(int fd,

View File

@ -98,7 +98,7 @@ enum btrfs_send_cmd {
/* Version 2 */ /* Version 2 */
BTRFS_SEND_C_FALLOCATE = 23, BTRFS_SEND_C_FALLOCATE = 23,
BTRFS_SEND_C_SETFLAGS = 24, BTRFS_SEND_C_FILEATTR = 24,
BTRFS_SEND_C_ENCODED_WRITE = 25, BTRFS_SEND_C_ENCODED_WRITE = 25,
BTRFS_SEND_C_MAX_V2 = 25, BTRFS_SEND_C_MAX_V2 = 25,
@ -151,7 +151,13 @@ enum {
/* Version 2 */ /* Version 2 */
BTRFS_SEND_A_FALLOCATE_MODE = 25, BTRFS_SEND_A_FALLOCATE_MODE = 25,
BTRFS_SEND_A_SETFLAGS_FLAGS = 26, /*
* File attributes from the FS_*_FL namespace (i_flags, xflags),
* translated to BTRFS_INODE_* bits (BTRFS_INODE_FLAG_MASK) and stored
* in btrfs_inode_item::flags (represented by btrfs_inode::flags and
* btrfs_inode::ro_flags).
*/
BTRFS_SEND_A_FILEATTR = 26,
BTRFS_SEND_A_UNENCODED_FILE_LEN = 27, BTRFS_SEND_A_UNENCODED_FILE_LEN = 27,
BTRFS_SEND_A_UNENCODED_LEN = 28, BTRFS_SEND_A_UNENCODED_LEN = 28,