public inbox for linux-bcachefs@vger.kernel.org
 help / color / mirror / Atom feed
From: Kent Overstreet <kent.overstreet@linux.dev>
To: linux-bcachefs@vger.kernel.org
Cc: Kent Overstreet <kent.overstreet@linux.dev>
Subject: [PATCH 2/3] bcachefs: v2 versions of subvolume ioctls
Date: Fri, 29 Aug 2025 02:54:06 -0400	[thread overview]
Message-ID: <20250829065409.3248746-3-kent.overstreet@linux.dev> (raw)
In-Reply-To: <20250829065409.3248746-1-kent.overstreet@linux.dev>

Like we recently did for the device ioctl, add v2 versions that can
return error strings.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
---
 fs/bcachefs/bcachefs_ioctl.h | 12 +++++
 fs/bcachefs/chardev.c        | 16 +++----
 fs/bcachefs/chardev.h        |  3 ++
 fs/bcachefs/fs-ioctl.c       | 91 +++++++++++++++++++++++++++++++++---
 4 files changed, 108 insertions(+), 14 deletions(-)

diff --git a/fs/bcachefs/bcachefs_ioctl.h b/fs/bcachefs/bcachefs_ioctl.h
index 5dc562f2a881..6043a8d93b1e 100644
--- a/fs/bcachefs/bcachefs_ioctl.h
+++ b/fs/bcachefs/bcachefs_ioctl.h
@@ -87,7 +87,9 @@ struct bch_ioctl_incremental {
 #define BCH_IOCTL_DISK_RESIZE_JOURNAL_v2 _IOW(0xbc,	28, struct bch_ioctl_disk_resize_journal_v2)
 
 #define BCH_IOCTL_SUBVOLUME_CREATE	_IOW(0xbc,	16, struct bch_ioctl_subvolume)
+#define BCH_IOCTL_SUBVOLUME_CREATE_v2	_IOW(0xbc,	29, struct bch_ioctl_subvolume_v2)
 #define BCH_IOCTL_SUBVOLUME_DESTROY	_IOW(0xbc,	17, struct bch_ioctl_subvolume)
+#define BCH_IOCTL_SUBVOLUME_DESTROY_v2	_IOW(0xbc,	30, struct bch_ioctl_subvolume_v2)
 
 #define BCH_IOCTL_DEV_USAGE_V2		_IOWR(0xbc,	18, struct bch_ioctl_dev_usage_v2)
 
@@ -451,6 +453,16 @@ struct bch_ioctl_subvolume {
 	__u64			src_ptr;
 };
 
+struct bch_ioctl_subvolume_v2 {
+	__u32			flags;
+	__u32			dirfd;
+	__u16			mode;
+	__u16			pad[3];
+	__u64			dst_ptr;
+	__u64			src_ptr;
+	struct bch_ioctl_err_msg	err;
+};
+
 #define BCH_SUBVOL_SNAPSHOT_CREATE	(1U << 0)
 #define BCH_SUBVOL_SNAPSHOT_RO		(1U << 1)
 
diff --git a/fs/bcachefs/chardev.c b/fs/bcachefs/chardev.c
index f6f90d421f27..108c362a0ff4 100644
--- a/fs/bcachefs/chardev.c
+++ b/fs/bcachefs/chardev.c
@@ -187,7 +187,7 @@ static long bch2_ioctl_stop(struct bch_fs *c)
 }
 #endif
 
-static int copy_ioctl_err_msg(struct bch_ioctl_err_msg *dst, struct printbuf *src, int ret)
+int bch2_copy_ioctl_err_msg(struct bch_ioctl_err_msg *dst, struct printbuf *src, int ret)
 {
 	if (ret) {
 		prt_printf(src, "error=%s", bch2_err_str(ret));
@@ -243,7 +243,7 @@ static long bch2_ioctl_disk_add_v2(struct bch_fs *c, struct bch_ioctl_disk_v2 ar
 	CLASS(printbuf, err)();
 	ret = bch2_dev_add(c, path, &err);
 	kfree(path);
-	return copy_ioctl_err_msg(&arg.err, &err, ret);
+	return bch2_copy_ioctl_err_msg(&arg.err, &err, ret);
 }
 
 static long bch2_ioctl_disk_remove(struct bch_fs *c, struct bch_ioctl_disk arg)
@@ -287,7 +287,7 @@ static long bch2_ioctl_disk_remove_v2(struct bch_fs *c, struct bch_ioctl_disk_v2
 
 	CLASS(printbuf, err)();
 	int ret = bch2_dev_remove(c, ca, arg.flags, &err);
-	return copy_ioctl_err_msg(&arg.err, &err, ret);
+	return bch2_copy_ioctl_err_msg(&arg.err, &err, ret);
 }
 
 static long bch2_ioctl_disk_online(struct bch_fs *c, struct bch_ioctl_disk arg)
@@ -333,7 +333,7 @@ static long bch2_ioctl_disk_online_v2(struct bch_fs *c, struct bch_ioctl_disk_v2
 	CLASS(printbuf, err)();
 	ret = bch2_dev_online(c, path, &err);
 	kfree(path);
-	return copy_ioctl_err_msg(&arg.err, &err, ret);
+	return bch2_copy_ioctl_err_msg(&arg.err, &err, ret);
 }
 
 static long bch2_ioctl_disk_offline(struct bch_fs *c, struct bch_ioctl_disk arg)
@@ -377,7 +377,7 @@ static long bch2_ioctl_disk_offline_v2(struct bch_fs *c, struct bch_ioctl_disk_v
 
 	CLASS(printbuf, err)();
 	int ret = bch2_dev_offline(c, ca, arg.flags, &err);
-	return copy_ioctl_err_msg(&arg.err, &err, ret);
+	return bch2_copy_ioctl_err_msg(&arg.err, &err, ret);
 }
 
 static long bch2_ioctl_disk_set_state(struct bch_fs *c,
@@ -429,7 +429,7 @@ static long bch2_ioctl_disk_set_state_v2(struct bch_fs *c,
 
 	ret = bch2_dev_set_state(c, ca, arg.new_state, arg.flags, &err);
 err:
-	return copy_ioctl_err_msg(&arg.err, &err, ret);
+	return bch2_copy_ioctl_err_msg(&arg.err, &err, ret);
 }
 
 struct bch_data_ctx {
@@ -783,7 +783,7 @@ static long bch2_ioctl_disk_resize_v2(struct bch_fs *c,
 
 	CLASS(printbuf, err)();
 	int ret = bch2_dev_resize(c, ca, arg.nbuckets, &err);
-	return copy_ioctl_err_msg(&arg.err, &err, ret);
+	return bch2_copy_ioctl_err_msg(&arg.err, &err, ret);
 }
 
 static long bch2_ioctl_disk_resize_journal(struct bch_fs *c,
@@ -825,7 +825,7 @@ static long bch2_ioctl_disk_resize_journal_v2(struct bch_fs *c,
 
 	CLASS(printbuf, err)();
 	int ret = bch2_set_nr_journal_buckets(c, ca, arg.nbuckets);
-	return copy_ioctl_err_msg(&arg.err, &err, ret);
+	return bch2_copy_ioctl_err_msg(&arg.err, &err, ret);
 }
 
 #define BCH_IOCTL(_name, _argtype)					\
diff --git a/fs/bcachefs/chardev.h b/fs/bcachefs/chardev.h
index 0f563ca53c36..cdd63e7618e9 100644
--- a/fs/bcachefs/chardev.h
+++ b/fs/bcachefs/chardev.h
@@ -4,6 +4,9 @@
 
 #ifndef NO_BCACHEFS_FS
 
+struct printbuf;
+int bch2_copy_ioctl_err_msg(struct bch_ioctl_err_msg *, struct printbuf *, int);
+
 long bch2_fs_ioctl(struct bch_fs *, unsigned, void __user *);
 
 void bch2_fs_chardev_exit(struct bch_fs *);
diff --git a/fs/bcachefs/fs-ioctl.c b/fs/bcachefs/fs-ioctl.c
index 8b9d3c7d1f57..20b46126c066 100644
--- a/fs/bcachefs/fs-ioctl.c
+++ b/fs/bcachefs/fs-ioctl.c
@@ -199,8 +199,9 @@ static int bch2_ioc_goingdown(struct bch_fs *c, u32 __user *arg)
 	return ret;
 }
 
-static long bch2_ioctl_subvolume_create(struct bch_fs *c, struct file *filp,
-					struct bch_ioctl_subvolume arg)
+static long __bch2_ioctl_subvolume_create(struct bch_fs *c, struct file *filp,
+					  struct bch_ioctl_subvolume_v2 arg,
+					  struct printbuf *err)
 {
 	struct inode *dir;
 	struct bch_inode_info *inode;
@@ -214,13 +215,17 @@ static long bch2_ioctl_subvolume_create(struct bch_fs *c, struct file *filp,
 	unsigned create_flags = BCH_CREATE_SUBVOL;
 
 	if (arg.flags & ~(BCH_SUBVOL_SNAPSHOT_CREATE|
-			  BCH_SUBVOL_SNAPSHOT_RO))
+			  BCH_SUBVOL_SNAPSHOT_RO)) {
+		prt_str(err, "invalid flasg");
 		return -EINVAL;
+	}
 
 	if (!(arg.flags & BCH_SUBVOL_SNAPSHOT_CREATE) &&
 	    (arg.src_ptr ||
-	     (arg.flags & BCH_SUBVOL_SNAPSHOT_RO)))
+	     (arg.flags & BCH_SUBVOL_SNAPSHOT_RO))) {
+		prt_str(err, "invalid flasg");
 		return -EINVAL;
+	}
 
 	if (arg.flags & BCH_SUBVOL_SNAPSHOT_CREATE)
 		create_flags |= BCH_CREATE_SNAPSHOT;
@@ -243,6 +248,7 @@ static long bch2_ioctl_subvolume_create(struct bch_fs *c, struct file *filp,
 
 		if (src_path.dentry->d_sb->s_fs_info != c) {
 			path_put(&src_path);
+			prt_str(err, "src_path not on dst filesystem");
 			error = -EXDEV;
 			goto err1;
 		}
@@ -258,6 +264,7 @@ static long bch2_ioctl_subvolume_create(struct bch_fs *c, struct file *filp,
 		goto err2;
 
 	if (dst_dentry->d_sb->s_fs_info != c) {
+		prt_str(err, "dst_path not on dst filesystem");
 		error = -EXDEV;
 		goto err3;
 	}
@@ -276,6 +283,7 @@ static long bch2_ioctl_subvolume_create(struct bch_fs *c, struct file *filp,
 	s_user_ns = dir->i_sb->s_user_ns;
 	if (!kuid_has_mapping(s_user_ns, current_fsuid()) ||
 	    !kgid_has_mapping(s_user_ns, current_fsgid())) {
+		prt_str(err, "current uid/gid not mapped into fs namespace");
 		error = -EOVERFLOW;
 		goto err3;
 	}
@@ -315,8 +323,35 @@ static long bch2_ioctl_subvolume_create(struct bch_fs *c, struct file *filp,
 	return error;
 }
 
-static long bch2_ioctl_subvolume_destroy(struct bch_fs *c, struct file *filp,
-				struct bch_ioctl_subvolume arg)
+static long bch2_ioctl_subvolume_create(struct bch_fs *c, struct file *filp,
+					struct bch_ioctl_subvolume arg)
+{
+	struct bch_ioctl_subvolume_v2 arg_v2 = {
+		.flags		= arg.flags,
+		.dirfd		= arg.dirfd,
+		.mode		= arg.mode,
+		.dst_ptr	= arg.dst_ptr,
+		.src_ptr	= arg.src_ptr,
+	};
+
+	CLASS(printbuf, err)();
+	long ret = __bch2_ioctl_subvolume_create(c, filp, arg_v2, &err);
+	if (ret)
+		bch_err_msg(c, ret, "%s", err.buf);
+	return ret;
+}
+
+static long bch2_ioctl_subvolume_create_v2(struct bch_fs *c, struct file *filp,
+					   struct bch_ioctl_subvolume_v2 arg)
+{
+	CLASS(printbuf, err)();
+	long ret = __bch2_ioctl_subvolume_create(c, filp, arg, &err);
+	return bch2_copy_ioctl_err_msg(&arg.err, &err, ret);
+}
+
+static long __bch2_ioctl_subvolume_destroy(struct bch_fs *c, struct file *filp,
+					   struct bch_ioctl_subvolume_v2 arg,
+					   struct printbuf *err)
 {
 	const char __user *name = (void __user *)(unsigned long)arg.dst_ptr;
 	struct path path;
@@ -350,6 +385,32 @@ static long bch2_ioctl_subvolume_destroy(struct bch_fs *c, struct file *filp,
 	return ret;
 }
 
+static long bch2_ioctl_subvolume_destroy(struct bch_fs *c, struct file *filp,
+					 struct bch_ioctl_subvolume arg)
+{
+	struct bch_ioctl_subvolume_v2 arg_v2 = {
+		.flags		= arg.flags,
+		.dirfd		= arg.dirfd,
+		.mode		= arg.mode,
+		.dst_ptr	= arg.dst_ptr,
+		.src_ptr	= arg.src_ptr,
+	};
+
+	CLASS(printbuf, err)();
+	long ret = __bch2_ioctl_subvolume_destroy(c, filp, arg_v2, &err);
+	if (ret)
+		bch_err_msg(c, ret, "%s", err.buf);
+	return ret;
+}
+
+static long bch2_ioctl_subvolume_destroy_v2(struct bch_fs *c, struct file *filp,
+					    struct bch_ioctl_subvolume_v2 arg)
+{
+	CLASS(printbuf, err)();
+	long ret = __bch2_ioctl_subvolume_destroy(c, filp, arg, &err);
+	return bch2_copy_ioctl_err_msg(&arg.err, &err, ret);
+}
+
 long bch2_fs_file_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 {
 	struct bch_inode_info *inode = file_bch_inode(file);
@@ -391,6 +452,15 @@ long bch2_fs_file_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 		break;
 	}
 
+	case BCH_IOCTL_SUBVOLUME_CREATE_v2: {
+		struct bch_ioctl_subvolume_v2 i;
+
+		ret = copy_from_user(&i, (void __user *) arg, sizeof(i))
+			? -EFAULT
+			: bch2_ioctl_subvolume_create_v2(c, file, i);
+		break;
+	}
+
 	case BCH_IOCTL_SUBVOLUME_DESTROY: {
 		struct bch_ioctl_subvolume i;
 
@@ -400,6 +470,15 @@ long bch2_fs_file_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 		break;
 	}
 
+	case BCH_IOCTL_SUBVOLUME_DESTROY_v2: {
+		struct bch_ioctl_subvolume_v2 i;
+
+		ret = copy_from_user(&i, (void __user *) arg, sizeof(i))
+			? -EFAULT
+			: bch2_ioctl_subvolume_destroy_v2(c, file, i);
+		break;
+	}
+
 	default:
 		ret = bch2_fs_ioctl(c, cmd, (void __user *) arg);
 		break;
-- 
2.50.1


  parent reply	other threads:[~2025-08-29  6:54 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-08-29  6:54 [PATCH 0/3] better error messages for ioctls Kent Overstreet
2025-08-29  6:54 ` [PATCH 1/3] bcachefs: Add v2 ioctls that return error strings Kent Overstreet
2025-08-29  6:54 ` Kent Overstreet [this message]
2025-08-29  6:54 ` [PATCH 3/3] bcachefs: Plumb error messages through data drop paths Kent Overstreet

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250829065409.3248746-3-kent.overstreet@linux.dev \
    --to=kent.overstreet@linux.dev \
    --cc=linux-bcachefs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox