|
21 | 21 | #define FSOP_GOING_FLAGS_LOGFLUSH 0x1 /* flush log but not data */ |
22 | 22 | #define FSOP_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */ |
23 | 23 |
|
24 | | -struct flags_set { |
25 | | - unsigned mask; |
26 | | - unsigned flags; |
27 | | - |
28 | | - unsigned projid; |
29 | | - |
30 | | - bool set_projinherit; |
31 | | - bool projinherit; |
32 | | -}; |
33 | | - |
34 | | -static int bch2_inode_flags_set(struct btree_trans *trans, |
35 | | - struct bch_inode_info *inode, |
36 | | - struct bch_inode_unpacked *bi, |
37 | | - void *p) |
38 | | -{ |
39 | | - struct bch_fs *c = inode->v.i_sb->s_fs_info; |
40 | | - /* |
41 | | - * We're relying on btree locking here for exclusion with other ioctl |
42 | | - * calls - use the flags in the btree (@bi), not inode->i_flags: |
43 | | - */ |
44 | | - struct flags_set *s = p; |
45 | | - unsigned newflags = s->flags; |
46 | | - unsigned oldflags = bi->bi_flags & s->mask; |
47 | | - |
48 | | - if (((newflags ^ oldflags) & (BCH_INODE_append|BCH_INODE_immutable)) && |
49 | | - !capable(CAP_LINUX_IMMUTABLE)) |
50 | | - return -EPERM; |
51 | | - |
52 | | - if (!S_ISREG(bi->bi_mode) && |
53 | | - !S_ISDIR(bi->bi_mode) && |
54 | | - (newflags & (BCH_INODE_nodump|BCH_INODE_noatime)) != newflags) |
55 | | - return -EINVAL; |
56 | | - |
57 | | - if ((newflags ^ oldflags) & BCH_INODE_casefolded) { |
58 | | -#ifdef CONFIG_UNICODE |
59 | | - int ret = 0; |
60 | | - /* Not supported on individual files. */ |
61 | | - if (!S_ISDIR(bi->bi_mode)) |
62 | | - return -EOPNOTSUPP; |
63 | | - |
64 | | - /* |
65 | | - * Make sure the dir is empty, as otherwise we'd need to |
66 | | - * rehash everything and update the dirent keys. |
67 | | - */ |
68 | | - ret = bch2_empty_dir_trans(trans, inode_inum(inode)); |
69 | | - if (ret < 0) |
70 | | - return ret; |
71 | | - |
72 | | - ret = bch2_request_incompat_feature(c, bcachefs_metadata_version_casefolding); |
73 | | - if (ret) |
74 | | - return ret; |
75 | | - |
76 | | - bch2_check_set_feature(c, BCH_FEATURE_casefolding); |
77 | | -#else |
78 | | - printk(KERN_ERR "Cannot use casefolding on a kernel without CONFIG_UNICODE\n"); |
79 | | - return -EOPNOTSUPP; |
80 | | -#endif |
81 | | - } |
82 | | - |
83 | | - if (s->set_projinherit) { |
84 | | - bi->bi_fields_set &= ~(1 << Inode_opt_project); |
85 | | - bi->bi_fields_set |= ((int) s->projinherit << Inode_opt_project); |
86 | | - } |
87 | | - |
88 | | - bi->bi_flags &= ~s->mask; |
89 | | - bi->bi_flags |= newflags; |
90 | | - |
91 | | - bi->bi_ctime = timespec_to_bch2_time(c, current_time(&inode->v)); |
92 | | - return 0; |
93 | | -} |
94 | | - |
95 | | -static int bch2_ioc_getflags(struct bch_inode_info *inode, int __user *arg) |
96 | | -{ |
97 | | - unsigned flags = map_flags(bch_flags_to_uflags, inode->ei_inode.bi_flags); |
98 | | - |
99 | | - return put_user(flags, arg); |
100 | | -} |
101 | | - |
102 | | -static int bch2_ioc_setflags(struct bch_fs *c, |
103 | | - struct file *file, |
104 | | - struct bch_inode_info *inode, |
105 | | - void __user *arg) |
106 | | -{ |
107 | | - struct flags_set s = { .mask = map_defined(bch_flags_to_uflags) }; |
108 | | - unsigned uflags; |
109 | | - int ret; |
110 | | - |
111 | | - if (get_user(uflags, (int __user *) arg)) |
112 | | - return -EFAULT; |
113 | | - |
114 | | - s.flags = map_flags_rev(bch_flags_to_uflags, uflags); |
115 | | - if (uflags) |
116 | | - return -EOPNOTSUPP; |
117 | | - |
118 | | - ret = mnt_want_write_file(file); |
119 | | - if (ret) |
120 | | - return ret; |
121 | | - |
122 | | - inode_lock(&inode->v); |
123 | | - if (!inode_owner_or_capable(file_mnt_idmap(file), &inode->v)) { |
124 | | - ret = -EACCES; |
125 | | - goto setflags_out; |
126 | | - } |
127 | | - |
128 | | - mutex_lock(&inode->ei_update_lock); |
129 | | - ret = bch2_subvol_is_ro(c, inode->ei_inum.subvol) ?: |
130 | | - bch2_write_inode(c, inode, bch2_inode_flags_set, &s, |
131 | | - ATTR_CTIME); |
132 | | - mutex_unlock(&inode->ei_update_lock); |
133 | | - |
134 | | -setflags_out: |
135 | | - inode_unlock(&inode->v); |
136 | | - mnt_drop_write_file(file); |
137 | | - return ret; |
138 | | -} |
139 | | - |
140 | | -static int bch2_ioc_fsgetxattr(struct bch_inode_info *inode, |
141 | | - struct fsxattr __user *arg) |
142 | | -{ |
143 | | - struct fsxattr fa = { 0 }; |
144 | | - |
145 | | - fa.fsx_xflags = map_flags(bch_flags_to_xflags, inode->ei_inode.bi_flags); |
146 | | - |
147 | | - if (inode->ei_inode.bi_fields_set & (1 << Inode_opt_project)) |
148 | | - fa.fsx_xflags |= FS_XFLAG_PROJINHERIT; |
149 | | - |
150 | | - fa.fsx_projid = inode->ei_qid.q[QTYP_PRJ]; |
151 | | - |
152 | | - if (copy_to_user(arg, &fa, sizeof(fa))) |
153 | | - return -EFAULT; |
154 | | - |
155 | | - return 0; |
156 | | -} |
157 | | - |
158 | | -static int fssetxattr_inode_update_fn(struct btree_trans *trans, |
159 | | - struct bch_inode_info *inode, |
160 | | - struct bch_inode_unpacked *bi, |
161 | | - void *p) |
162 | | -{ |
163 | | - struct flags_set *s = p; |
164 | | - |
165 | | - if (s->projid != bi->bi_project) { |
166 | | - bi->bi_fields_set |= 1U << Inode_opt_project; |
167 | | - bi->bi_project = s->projid; |
168 | | - } |
169 | | - |
170 | | - return bch2_inode_flags_set(trans, inode, bi, p); |
171 | | -} |
172 | | - |
173 | | -static int bch2_ioc_fssetxattr(struct bch_fs *c, |
174 | | - struct file *file, |
175 | | - struct bch_inode_info *inode, |
176 | | - struct fsxattr __user *arg) |
177 | | -{ |
178 | | - struct flags_set s = { .mask = map_defined(bch_flags_to_xflags) }; |
179 | | - struct fsxattr fa; |
180 | | - int ret; |
181 | | - |
182 | | - if (copy_from_user(&fa, arg, sizeof(fa))) |
183 | | - return -EFAULT; |
184 | | - |
185 | | - s.set_projinherit = true; |
186 | | - s.projinherit = (fa.fsx_xflags & FS_XFLAG_PROJINHERIT) != 0; |
187 | | - fa.fsx_xflags &= ~FS_XFLAG_PROJINHERIT; |
188 | | - |
189 | | - s.flags = map_flags_rev(bch_flags_to_xflags, fa.fsx_xflags); |
190 | | - if (fa.fsx_xflags) |
191 | | - return -EOPNOTSUPP; |
192 | | - |
193 | | - if (fa.fsx_projid >= U32_MAX) |
194 | | - return -EINVAL; |
195 | | - |
196 | | - /* |
197 | | - * inode fields accessible via the xattr interface are stored with a +1 |
198 | | - * bias, so that 0 means unset: |
199 | | - */ |
200 | | - s.projid = fa.fsx_projid + 1; |
201 | | - |
202 | | - ret = mnt_want_write_file(file); |
203 | | - if (ret) |
204 | | - return ret; |
205 | | - |
206 | | - inode_lock(&inode->v); |
207 | | - if (!inode_owner_or_capable(file_mnt_idmap(file), &inode->v)) { |
208 | | - ret = -EACCES; |
209 | | - goto err; |
210 | | - } |
211 | | - |
212 | | - mutex_lock(&inode->ei_update_lock); |
213 | | - ret = bch2_subvol_is_ro(c, inode->ei_inum.subvol) ?: |
214 | | - bch2_set_projid(c, inode, fa.fsx_projid) ?: |
215 | | - bch2_write_inode(c, inode, fssetxattr_inode_update_fn, &s, |
216 | | - ATTR_CTIME); |
217 | | - mutex_unlock(&inode->ei_update_lock); |
218 | | -err: |
219 | | - inode_unlock(&inode->v); |
220 | | - mnt_drop_write_file(file); |
221 | | - return ret; |
222 | | -} |
223 | | - |
224 | 24 | static int bch2_reinherit_attrs_fn(struct btree_trans *trans, |
225 | 25 | struct bch_inode_info *inode, |
226 | 26 | struct bch_inode_unpacked *bi, |
@@ -558,23 +358,6 @@ long bch2_fs_file_ioctl(struct file *file, unsigned cmd, unsigned long arg) |
558 | 358 | long ret; |
559 | 359 |
|
560 | 360 | switch (cmd) { |
561 | | - case FS_IOC_GETFLAGS: |
562 | | - ret = bch2_ioc_getflags(inode, (int __user *) arg); |
563 | | - break; |
564 | | - |
565 | | - case FS_IOC_SETFLAGS: |
566 | | - ret = bch2_ioc_setflags(c, file, inode, (int __user *) arg); |
567 | | - break; |
568 | | - |
569 | | - case FS_IOC_FSGETXATTR: |
570 | | - ret = bch2_ioc_fsgetxattr(inode, (void __user *) arg); |
571 | | - break; |
572 | | - |
573 | | - case FS_IOC_FSSETXATTR: |
574 | | - ret = bch2_ioc_fssetxattr(c, file, inode, |
575 | | - (void __user *) arg); |
576 | | - break; |
577 | | - |
578 | 361 | case BCHFS_IOC_REINHERIT_ATTRS: |
579 | 362 | ret = bch2_ioc_reinherit_attrs(c, file, inode, |
580 | 363 | (void __user *) arg); |
|
0 commit comments