All of lore.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.