From 6aae7985eb8ecb6faecb20376500f1026960a801 Mon Sep 17 00:00:00 2001 From: Sweet Tea Dorminy Date: Mon, 4 Mar 2024 12:20:19 -0500 Subject: [PATCH] fall back to user ioctl for ino path lookup --- cmds/receive.c | 2 +- cmds/subvolume-list.c | 48 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/cmds/receive.c b/cmds/receive.c index e4430b07..051eca6a 100644 --- a/cmds/receive.c +++ b/cmds/receive.c @@ -1285,7 +1285,7 @@ static int process_encoded_write(const char *path, const void *data, u64 offset, if (ret >= 0) return 0; /* Fall back for these errors, fail hard for anything else. */ - if (errno != ENOSPC && errno != ENOTTY && errno != EINVAL) { + if (errno != ENOSPC && errno != ENOTTY && errno != EINVAL && errno != EPERM) { ret = -errno; error("encoded_write: writing to %s failed: %m", path); return ret; diff --git a/cmds/subvolume-list.c b/cmds/subvolume-list.c index 5a91f41d..c3bc7b70 100644 --- a/cmds/subvolume-list.c +++ b/cmds/subvolume-list.c @@ -759,6 +759,49 @@ static int resolve_root(struct rb_root *rl, struct root_info *ri, return 0; } +/* + * as user, for a single root_info, ask the kernel to give us a path name + * inside it's ref_root for the dir_id where it lives. + * + * This fills in root_info->path with the path to the directory and and + * appends this root's name. + */ +static int lookup_ino_path_user(int fd, struct root_info *ri) +{ + struct btrfs_ioctl_ino_lookup_user_args args; + int ret; + + if (ri->path) + return 0; + + if (!ri->ref_tree) + return -ENOENT; + + memset(&args, 0, sizeof(args)); + args.treeid = ri->ref_tree; + args.dirid = ri->dir_id; + + ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP_USER, &args); + if (ret < 0) { + if (errno == ENOENT) { + ri->ref_tree = 0; + return -ENOENT; + } + error("failed to lookup path for root %llu: %m", ri->ref_tree); + return ret; + } + + ri->path = malloc(strlen(args.name) + strlen(args.path) + 1); + if (!ri->path) { + error_msg(ERROR_MSG_MEMORY, NULL); + exit(1); + } + + strcpy(ri->path, args.path); + strcat(ri->path, args.name); + return 0; +} + /* * for a single root_info, ask the kernel to give us a path name * inside it's ref_root for the dir_id where it lives. @@ -783,6 +826,11 @@ static int lookup_ino_path(int fd, struct root_info *ri) ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args); if (ret < 0) { + if (errno == EPERM) { + /* Let's try again with the user ioctl */ + return lookup_ino_path_user(fd, ri); + } + if (errno == ENOENT) { ri->ref_tree = 0; return -ENOENT; -- 2.44.0