1 // SPDX-License-Identifier: GPL-2.0
10 #include <linux/compat.h>
11 #include <linux/mount.h>
13 #define FS_IOC_GOINGDOWN _IOR('X', 125, __u32)
22 static int bch2_inode_flags_set(struct bch_inode_info *inode,
23 struct bch_inode_unpacked *bi,
26 struct bch_fs *c = inode->v.i_sb->s_fs_info;
28 * We're relying on btree locking here for exclusion with other ioctl
29 * calls - use the flags in the btree (@bi), not inode->i_flags:
31 struct flags_set *s = p;
32 unsigned newflags = s->flags;
33 unsigned oldflags = bi->bi_flags & s->mask;
35 if (((newflags ^ oldflags) & (BCH_INODE_APPEND|BCH_INODE_IMMUTABLE)) &&
36 !capable(CAP_LINUX_IMMUTABLE))
39 if (!S_ISREG(bi->bi_mode) &&
40 !S_ISDIR(bi->bi_mode) &&
41 (newflags & (BCH_INODE_NODUMP|BCH_INODE_NOATIME)) != newflags)
44 bi->bi_flags &= ~s->mask;
45 bi->bi_flags |= newflags;
47 bi->bi_ctime = timespec_to_bch2_time(c, current_time(&inode->v));
51 static int bch2_ioc_getflags(struct bch_inode_info *inode, int __user *arg)
53 unsigned flags = map_flags(bch_flags_to_uflags, inode->ei_inode.bi_flags);
55 return put_user(flags, arg);
58 static int bch2_ioc_setflags(struct bch_fs *c,
60 struct bch_inode_info *inode,
63 struct flags_set s = { .mask = map_defined(bch_flags_to_uflags) };
67 if (get_user(uflags, (int __user *) arg))
70 s.flags = map_flags_rev(bch_flags_to_uflags, uflags);
74 ret = mnt_want_write_file(file);
78 inode_lock(&inode->v);
79 if (!inode_owner_or_capable(file_mnt_idmap(file), &inode->v)) {
84 mutex_lock(&inode->ei_update_lock);
85 ret = bch2_write_inode(c, inode, bch2_inode_flags_set, &s,
87 mutex_unlock(&inode->ei_update_lock);
90 inode_unlock(&inode->v);
91 mnt_drop_write_file(file);
95 static int bch2_ioc_fsgetxattr(struct bch_inode_info *inode,
96 struct fsxattr __user *arg)
98 struct fsxattr fa = { 0 };
100 fa.fsx_xflags = map_flags(bch_flags_to_xflags, inode->ei_inode.bi_flags);
101 fa.fsx_projid = inode->ei_qid.q[QTYP_PRJ];
103 return copy_to_user(arg, &fa, sizeof(fa));
106 static int bch2_set_projid(struct bch_fs *c,
107 struct bch_inode_info *inode,
110 struct bch_qid qid = inode->ei_qid;
112 qid.q[QTYP_PRJ] = projid;
114 return bch2_fs_quota_transfer(c, inode, qid,
116 KEY_TYPE_QUOTA_PREALLOC);
119 static int fssetxattr_inode_update_fn(struct bch_inode_info *inode,
120 struct bch_inode_unpacked *bi,
123 struct flags_set *s = p;
125 bi->bi_project = s->projid;
127 return bch2_inode_flags_set(inode, bi, p);
130 static int bch2_ioc_fssetxattr(struct bch_fs *c,
132 struct bch_inode_info *inode,
133 struct fsxattr __user *arg)
135 struct flags_set s = { .mask = map_defined(bch_flags_to_xflags) };
139 if (copy_from_user(&fa, arg, sizeof(fa)))
142 s.flags = map_flags_rev(bch_flags_to_xflags, fa.fsx_xflags);
146 s.projid = fa.fsx_projid;
148 ret = mnt_want_write_file(file);
152 inode_lock(&inode->v);
153 if (!inode_owner_or_capable(file_mnt_idmap(file), &inode->v)) {
158 mutex_lock(&inode->ei_update_lock);
159 ret = bch2_set_projid(c, inode, fa.fsx_projid);
163 ret = bch2_write_inode(c, inode, fssetxattr_inode_update_fn, &s,
166 mutex_unlock(&inode->ei_update_lock);
168 inode_unlock(&inode->v);
169 mnt_drop_write_file(file);
173 long bch2_fs_file_ioctl(struct file *file, unsigned cmd, unsigned long arg)
175 struct bch_inode_info *inode = file_bch_inode(file);
176 struct super_block *sb = inode->v.i_sb;
177 struct bch_fs *c = sb->s_fs_info;
180 case FS_IOC_GETFLAGS:
181 return bch2_ioc_getflags(inode, (int __user *) arg);
183 case FS_IOC_SETFLAGS:
184 return bch2_ioc_setflags(c, file, inode, (int __user *) arg);
186 case FS_IOC_FSGETXATTR:
187 return bch2_ioc_fsgetxattr(inode, (void __user *) arg);
188 case FS_IOC_FSSETXATTR:
189 return bch2_ioc_fssetxattr(c, file, inode, (void __user *) arg);
191 case FS_IOC_GETVERSION:
193 case FS_IOC_SETVERSION:
196 case FS_IOC_GOINGDOWN:
197 if (!capable(CAP_SYS_ADMIN))
200 down_write(&sb->s_umount);
201 sb->s_flags |= SB_RDONLY;
202 bch2_fs_emergency_read_only(c);
203 up_write(&sb->s_umount);
207 return bch2_fs_ioctl(c, cmd, (void __user *) arg);
212 long bch2_compat_fs_ioctl(struct file *file, unsigned cmd, unsigned long arg)
214 /* These are just misnamed, they actually get/put from/to user an int */
216 case FS_IOC_GETFLAGS:
217 cmd = FS_IOC_GETFLAGS;
219 case FS_IOC32_SETFLAGS:
220 cmd = FS_IOC_SETFLAGS;
225 return bch2_fs_file_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
229 #endif /* NO_BCACHEFS_FS */