]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/fs-ioctl.c
Update bcachefs sources to 380885b0b8 bcachefs: Fix counting iterators for reflink...
[bcachefs-tools-debian] / libbcachefs / fs-ioctl.c
1 // SPDX-License-Identifier: GPL-2.0
2 #ifndef NO_BCACHEFS_FS
3
4 #include "bcachefs.h"
5 #include "chardev.h"
6 #include "dirent.h"
7 #include "fs.h"
8 #include "fs-ioctl.h"
9 #include "quota.h"
10
11 #include <linux/compat.h>
12 #include <linux/mount.h>
13
14 #define FS_IOC_GOINGDOWN             _IOR('X', 125, __u32)
15
16 struct flags_set {
17         unsigned                mask;
18         unsigned                flags;
19
20         unsigned                projid;
21 };
22
23 static int bch2_inode_flags_set(struct bch_inode_info *inode,
24                                 struct bch_inode_unpacked *bi,
25                                 void *p)
26 {
27         struct bch_fs *c = inode->v.i_sb->s_fs_info;
28         /*
29          * We're relying on btree locking here for exclusion with other ioctl
30          * calls - use the flags in the btree (@bi), not inode->i_flags:
31          */
32         struct flags_set *s = p;
33         unsigned newflags = s->flags;
34         unsigned oldflags = bi->bi_flags & s->mask;
35
36         if (((newflags ^ oldflags) & (BCH_INODE_APPEND|BCH_INODE_IMMUTABLE)) &&
37             !capable(CAP_LINUX_IMMUTABLE))
38                 return -EPERM;
39
40         if (!S_ISREG(bi->bi_mode) &&
41             !S_ISDIR(bi->bi_mode) &&
42             (newflags & (BCH_INODE_NODUMP|BCH_INODE_NOATIME)) != newflags)
43                 return -EINVAL;
44
45         bi->bi_flags &= ~s->mask;
46         bi->bi_flags |= newflags;
47
48         bi->bi_ctime = timespec_to_bch2_time(c, current_time(&inode->v));
49         return 0;
50 }
51
52 static int bch2_ioc_getflags(struct bch_inode_info *inode, int __user *arg)
53 {
54         unsigned flags = map_flags(bch_flags_to_uflags, inode->ei_inode.bi_flags);
55
56         return put_user(flags, arg);
57 }
58
59 static int bch2_ioc_setflags(struct bch_fs *c,
60                              struct file *file,
61                              struct bch_inode_info *inode,
62                              void __user *arg)
63 {
64         struct flags_set s = { .mask = map_defined(bch_flags_to_uflags) };
65         unsigned uflags;
66         int ret;
67
68         if (get_user(uflags, (int __user *) arg))
69                 return -EFAULT;
70
71         s.flags = map_flags_rev(bch_flags_to_uflags, uflags);
72         if (uflags)
73                 return -EOPNOTSUPP;
74
75         ret = mnt_want_write_file(file);
76         if (ret)
77                 return ret;
78
79         inode_lock(&inode->v);
80         if (!inode_owner_or_capable(&inode->v)) {
81                 ret = -EACCES;
82                 goto setflags_out;
83         }
84
85         mutex_lock(&inode->ei_update_lock);
86         ret = bch2_write_inode(c, inode, bch2_inode_flags_set, &s,
87                                ATTR_CTIME);
88         mutex_unlock(&inode->ei_update_lock);
89
90 setflags_out:
91         inode_unlock(&inode->v);
92         mnt_drop_write_file(file);
93         return ret;
94 }
95
96 static int bch2_ioc_fsgetxattr(struct bch_inode_info *inode,
97                                struct fsxattr __user *arg)
98 {
99         struct fsxattr fa = { 0 };
100
101         fa.fsx_xflags = map_flags(bch_flags_to_xflags, inode->ei_inode.bi_flags);
102         fa.fsx_projid = inode->ei_qid.q[QTYP_PRJ];
103
104         return copy_to_user(arg, &fa, sizeof(fa));
105 }
106
107 static int fssetxattr_inode_update_fn(struct bch_inode_info *inode,
108                                       struct bch_inode_unpacked *bi,
109                                       void *p)
110 {
111         struct flags_set *s = p;
112
113         if (s->projid != bi->bi_project) {
114                 bi->bi_fields_set |= 1U << Inode_opt_project;
115                 bi->bi_project = s->projid;
116         }
117
118         return bch2_inode_flags_set(inode, bi, p);
119 }
120
121 static int bch2_ioc_fssetxattr(struct bch_fs *c,
122                                struct file *file,
123                                struct bch_inode_info *inode,
124                                struct fsxattr __user *arg)
125 {
126         struct flags_set s = { .mask = map_defined(bch_flags_to_xflags) };
127         struct fsxattr fa;
128         int ret;
129
130         if (copy_from_user(&fa, arg, sizeof(fa)))
131                 return -EFAULT;
132
133         s.flags = map_flags_rev(bch_flags_to_xflags, fa.fsx_xflags);
134         if (fa.fsx_xflags)
135                 return -EOPNOTSUPP;
136
137         if (fa.fsx_projid >= U32_MAX)
138                 return -EINVAL;
139
140         s.projid = fa.fsx_projid + 1;
141
142         ret = mnt_want_write_file(file);
143         if (ret)
144                 return ret;
145
146         inode_lock(&inode->v);
147         if (!inode_owner_or_capable(&inode->v)) {
148                 ret = -EACCES;
149                 goto err;
150         }
151
152         mutex_lock(&inode->ei_update_lock);
153         ret = bch2_set_projid(c, inode, s.projid);
154         if (ret)
155                 goto err_unlock;
156
157         ret = bch2_write_inode(c, inode, fssetxattr_inode_update_fn, &s,
158                                ATTR_CTIME);
159 err_unlock:
160         mutex_unlock(&inode->ei_update_lock);
161 err:
162         inode_unlock(&inode->v);
163         mnt_drop_write_file(file);
164         return ret;
165 }
166
167 static int bch2_ioc_reinherit_attrs(struct bch_fs *c,
168                                     struct file *file,
169                                     struct bch_inode_info *src,
170                                     const char __user *name)
171 {
172         struct bch_inode_info *dst;
173         struct inode *vinode = NULL;
174         char *kname = NULL;
175         struct qstr qstr;
176         int ret = 0;
177         u64 inum;
178
179         kname = kmalloc(BCH_NAME_MAX + 1, GFP_KERNEL);
180         if (!kname)
181                 return -ENOMEM;
182
183         ret = strncpy_from_user(kname, name, BCH_NAME_MAX);
184         if (unlikely(ret < 0))
185                 goto err1;
186
187         qstr.len        = ret;
188         qstr.name       = kname;
189
190         ret = -ENOENT;
191         inum = bch2_dirent_lookup(c, src->v.i_ino,
192                                   &src->ei_str_hash,
193                                   &qstr);
194         if (!inum)
195                 goto err1;
196
197         vinode = bch2_vfs_inode_get(c, inum);
198         ret = PTR_ERR_OR_ZERO(vinode);
199         if (ret)
200                 goto err1;
201
202         dst = to_bch_ei(vinode);
203
204         ret = mnt_want_write_file(file);
205         if (ret)
206                 goto err2;
207
208         bch2_lock_inodes(INODE_UPDATE_LOCK, src, dst);
209
210         if (inode_attr_changing(src, dst, Inode_opt_project)) {
211                 ret = bch2_fs_quota_transfer(c, dst,
212                                              src->ei_qid,
213                                              1 << QTYP_PRJ,
214                                              KEY_TYPE_QUOTA_PREALLOC);
215                 if (ret)
216                         goto err3;
217         }
218
219         ret = bch2_write_inode(c, dst, bch2_reinherit_attrs_fn, src, 0);
220 err3:
221         bch2_unlock_inodes(INODE_UPDATE_LOCK, src, dst);
222
223         /* return true if we did work */
224         if (ret >= 0)
225                 ret = !ret;
226
227         mnt_drop_write_file(file);
228 err2:
229         iput(vinode);
230 err1:
231         kfree(kname);
232
233         return ret;
234 }
235
236 long bch2_fs_file_ioctl(struct file *file, unsigned cmd, unsigned long arg)
237 {
238         struct bch_inode_info *inode = file_bch_inode(file);
239         struct super_block *sb = inode->v.i_sb;
240         struct bch_fs *c = sb->s_fs_info;
241
242         switch (cmd) {
243         case FS_IOC_GETFLAGS:
244                 return bch2_ioc_getflags(inode, (int __user *) arg);
245
246         case FS_IOC_SETFLAGS:
247                 return bch2_ioc_setflags(c, file, inode, (int __user *) arg);
248
249         case FS_IOC_FSGETXATTR:
250                 return bch2_ioc_fsgetxattr(inode, (void __user *) arg);
251         case FS_IOC_FSSETXATTR:
252                 return bch2_ioc_fssetxattr(c, file, inode,
253                                            (void __user *) arg);
254
255         case BCHFS_IOC_REINHERIT_ATTRS:
256                 return bch2_ioc_reinherit_attrs(c, file, inode,
257                                                 (void __user *) arg);
258
259         case FS_IOC_GETVERSION:
260                 return -ENOTTY;
261         case FS_IOC_SETVERSION:
262                 return -ENOTTY;
263
264         case FS_IOC_GOINGDOWN:
265                 if (!capable(CAP_SYS_ADMIN))
266                         return -EPERM;
267
268                 down_write(&sb->s_umount);
269                 sb->s_flags |= SB_RDONLY;
270                 if (bch2_fs_emergency_read_only(c))
271                         bch_err(c, "emergency read only due to ioctl");
272                 up_write(&sb->s_umount);
273                 return 0;
274
275         default:
276                 return bch2_fs_ioctl(c, cmd, (void __user *) arg);
277         }
278 }
279
280 #ifdef CONFIG_COMPAT
281 long bch2_compat_fs_ioctl(struct file *file, unsigned cmd, unsigned long arg)
282 {
283         /* These are just misnamed, they actually get/put from/to user an int */
284         switch (cmd) {
285         case FS_IOC_GETFLAGS:
286                 cmd = FS_IOC_GETFLAGS;
287                 break;
288         case FS_IOC32_SETFLAGS:
289                 cmd = FS_IOC_SETFLAGS;
290                 break;
291         default:
292                 return -ENOIOCTLCMD;
293         }
294         return bch2_fs_file_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
295 }
296 #endif
297
298 #endif /* NO_BCACHEFS_FS */