1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * linux/fs/ocfs2/ioctl.c |
4 | * |
5 | * Copyright (C) 2006 Herbert Poetzl |
6 | * adapted from Remy Card's ext2/ioctl.c |
7 | */ |
8 | |
9 | #include <linux/fs.h> |
10 | #include <linux/mount.h> |
11 | #include <linux/blkdev.h> |
12 | #include <linux/compat.h> |
13 | #include <linux/fileattr.h> |
14 | |
15 | #include <cluster/masklog.h> |
16 | |
17 | #include "ocfs2.h" |
18 | #include "alloc.h" |
19 | #include "dlmglue.h" |
20 | #include "file.h" |
21 | #include "inode.h" |
22 | #include "journal.h" |
23 | |
24 | #include "ocfs2_fs.h" |
25 | #include "ioctl.h" |
26 | #include "resize.h" |
27 | #include "refcounttree.h" |
28 | #include "sysfile.h" |
29 | #include "dir.h" |
30 | #include "buffer_head_io.h" |
31 | #include "suballoc.h" |
32 | #include "move_extents.h" |
33 | |
34 | #define o2info_from_user(a, b) \ |
35 | copy_from_user(&(a), (b), sizeof(a)) |
36 | #define o2info_to_user(a, b) \ |
37 | copy_to_user((typeof(a) __user *)b, &(a), sizeof(a)) |
38 | |
39 | /* |
40 | * This is just a best-effort to tell userspace that this request |
41 | * caused the error. |
42 | */ |
43 | static inline void o2info_set_request_error(struct ocfs2_info_request *kreq, |
44 | struct ocfs2_info_request __user *req) |
45 | { |
46 | kreq->ir_flags |= OCFS2_INFO_FL_ERROR; |
47 | (void)put_user(kreq->ir_flags, (__u32 __user *)&(req->ir_flags)); |
48 | } |
49 | |
50 | static inline void o2info_set_request_filled(struct ocfs2_info_request *req) |
51 | { |
52 | req->ir_flags |= OCFS2_INFO_FL_FILLED; |
53 | } |
54 | |
55 | static inline void o2info_clear_request_filled(struct ocfs2_info_request *req) |
56 | { |
57 | req->ir_flags &= ~OCFS2_INFO_FL_FILLED; |
58 | } |
59 | |
60 | static inline int o2info_coherent(struct ocfs2_info_request *req) |
61 | { |
62 | return (!(req->ir_flags & OCFS2_INFO_FL_NON_COHERENT)); |
63 | } |
64 | |
65 | int ocfs2_fileattr_get(struct dentry *dentry, struct fileattr *fa) |
66 | { |
67 | struct inode *inode = d_inode(dentry); |
68 | unsigned int flags; |
69 | int status; |
70 | |
71 | status = ocfs2_inode_lock(inode, NULL, 0); |
72 | if (status < 0) { |
73 | mlog_errno(status); |
74 | return status; |
75 | } |
76 | ocfs2_get_inode_flags(oi: OCFS2_I(inode)); |
77 | flags = OCFS2_I(inode)->ip_attr; |
78 | ocfs2_inode_unlock(inode, ex: 0); |
79 | |
80 | fileattr_fill_flags(fa, flags: flags & OCFS2_FL_VISIBLE); |
81 | |
82 | return status; |
83 | } |
84 | |
85 | int ocfs2_fileattr_set(struct mnt_idmap *idmap, |
86 | struct dentry *dentry, struct fileattr *fa) |
87 | { |
88 | struct inode *inode = d_inode(dentry); |
89 | unsigned int flags = fa->flags; |
90 | struct ocfs2_inode_info *ocfs2_inode = OCFS2_I(inode); |
91 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); |
92 | handle_t *handle = NULL; |
93 | struct buffer_head *bh = NULL; |
94 | unsigned oldflags; |
95 | int status; |
96 | |
97 | if (fileattr_has_fsx(fa)) |
98 | return -EOPNOTSUPP; |
99 | |
100 | status = ocfs2_inode_lock(inode, &bh, 1); |
101 | if (status < 0) { |
102 | mlog_errno(status); |
103 | goto bail; |
104 | } |
105 | |
106 | if (!S_ISDIR(inode->i_mode)) |
107 | flags &= ~OCFS2_DIRSYNC_FL; |
108 | |
109 | oldflags = ocfs2_inode->ip_attr; |
110 | flags = flags & OCFS2_FL_MODIFIABLE; |
111 | flags |= oldflags & ~OCFS2_FL_MODIFIABLE; |
112 | |
113 | /* Check already done by VFS, but repeat with ocfs lock */ |
114 | status = -EPERM; |
115 | if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL) && |
116 | !capable(CAP_LINUX_IMMUTABLE)) |
117 | goto bail_unlock; |
118 | |
119 | handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); |
120 | if (IS_ERR(ptr: handle)) { |
121 | status = PTR_ERR(ptr: handle); |
122 | mlog_errno(status); |
123 | goto bail_unlock; |
124 | } |
125 | |
126 | ocfs2_inode->ip_attr = flags; |
127 | ocfs2_set_inode_flags(inode); |
128 | |
129 | status = ocfs2_mark_inode_dirty(handle, inode, bh); |
130 | if (status < 0) |
131 | mlog_errno(status); |
132 | |
133 | ocfs2_commit_trans(osb, handle); |
134 | |
135 | bail_unlock: |
136 | ocfs2_inode_unlock(inode, ex: 1); |
137 | bail: |
138 | brelse(bh); |
139 | |
140 | return status; |
141 | } |
142 | |
143 | static int ocfs2_info_handle_blocksize(struct inode *inode, |
144 | struct ocfs2_info_request __user *req) |
145 | { |
146 | struct ocfs2_info_blocksize oib; |
147 | |
148 | if (o2info_from_user(oib, req)) |
149 | return -EFAULT; |
150 | |
151 | oib.ib_blocksize = inode->i_sb->s_blocksize; |
152 | |
153 | o2info_set_request_filled(req: &oib.ib_req); |
154 | |
155 | if (o2info_to_user(oib, req)) |
156 | return -EFAULT; |
157 | |
158 | return 0; |
159 | } |
160 | |
161 | static int ocfs2_info_handle_clustersize(struct inode *inode, |
162 | struct ocfs2_info_request __user *req) |
163 | { |
164 | struct ocfs2_info_clustersize oic; |
165 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); |
166 | |
167 | if (o2info_from_user(oic, req)) |
168 | return -EFAULT; |
169 | |
170 | oic.ic_clustersize = osb->s_clustersize; |
171 | |
172 | o2info_set_request_filled(req: &oic.ic_req); |
173 | |
174 | if (o2info_to_user(oic, req)) |
175 | return -EFAULT; |
176 | |
177 | return 0; |
178 | } |
179 | |
180 | static int ocfs2_info_handle_maxslots(struct inode *inode, |
181 | struct ocfs2_info_request __user *req) |
182 | { |
183 | struct ocfs2_info_maxslots oim; |
184 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); |
185 | |
186 | if (o2info_from_user(oim, req)) |
187 | return -EFAULT; |
188 | |
189 | oim.im_max_slots = osb->max_slots; |
190 | |
191 | o2info_set_request_filled(req: &oim.im_req); |
192 | |
193 | if (o2info_to_user(oim, req)) |
194 | return -EFAULT; |
195 | |
196 | return 0; |
197 | } |
198 | |
199 | static int ocfs2_info_handle_label(struct inode *inode, |
200 | struct ocfs2_info_request __user *req) |
201 | { |
202 | struct ocfs2_info_label oil; |
203 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); |
204 | |
205 | if (o2info_from_user(oil, req)) |
206 | return -EFAULT; |
207 | |
208 | memcpy(oil.il_label, osb->vol_label, OCFS2_MAX_VOL_LABEL_LEN); |
209 | |
210 | o2info_set_request_filled(req: &oil.il_req); |
211 | |
212 | if (o2info_to_user(oil, req)) |
213 | return -EFAULT; |
214 | |
215 | return 0; |
216 | } |
217 | |
218 | static int ocfs2_info_handle_uuid(struct inode *inode, |
219 | struct ocfs2_info_request __user *req) |
220 | { |
221 | struct ocfs2_info_uuid oiu; |
222 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); |
223 | |
224 | if (o2info_from_user(oiu, req)) |
225 | return -EFAULT; |
226 | |
227 | memcpy(oiu.iu_uuid_str, osb->uuid_str, OCFS2_TEXT_UUID_LEN + 1); |
228 | |
229 | o2info_set_request_filled(req: &oiu.iu_req); |
230 | |
231 | if (o2info_to_user(oiu, req)) |
232 | return -EFAULT; |
233 | |
234 | return 0; |
235 | } |
236 | |
237 | static int ocfs2_info_handle_fs_features(struct inode *inode, |
238 | struct ocfs2_info_request __user *req) |
239 | { |
240 | struct ocfs2_info_fs_features oif; |
241 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); |
242 | |
243 | if (o2info_from_user(oif, req)) |
244 | return -EFAULT; |
245 | |
246 | oif.if_compat_features = osb->s_feature_compat; |
247 | oif.if_incompat_features = osb->s_feature_incompat; |
248 | oif.if_ro_compat_features = osb->s_feature_ro_compat; |
249 | |
250 | o2info_set_request_filled(req: &oif.if_req); |
251 | |
252 | if (o2info_to_user(oif, req)) |
253 | return -EFAULT; |
254 | |
255 | return 0; |
256 | } |
257 | |
258 | static int ocfs2_info_handle_journal_size(struct inode *inode, |
259 | struct ocfs2_info_request __user *req) |
260 | { |
261 | struct ocfs2_info_journal_size oij; |
262 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); |
263 | |
264 | if (o2info_from_user(oij, req)) |
265 | return -EFAULT; |
266 | |
267 | oij.ij_journal_size = i_size_read(inode: osb->journal->j_inode); |
268 | |
269 | o2info_set_request_filled(req: &oij.ij_req); |
270 | |
271 | if (o2info_to_user(oij, req)) |
272 | return -EFAULT; |
273 | |
274 | return 0; |
275 | } |
276 | |
277 | static int ocfs2_info_scan_inode_alloc(struct ocfs2_super *osb, |
278 | struct inode *inode_alloc, u64 blkno, |
279 | struct ocfs2_info_freeinode *fi, |
280 | u32 slot) |
281 | { |
282 | int status = 0, unlock = 0; |
283 | |
284 | struct buffer_head *bh = NULL; |
285 | struct ocfs2_dinode *dinode_alloc = NULL; |
286 | |
287 | if (inode_alloc) |
288 | inode_lock(inode: inode_alloc); |
289 | |
290 | if (inode_alloc && o2info_coherent(req: &fi->ifi_req)) { |
291 | status = ocfs2_inode_lock(inode_alloc, &bh, 0); |
292 | if (status < 0) { |
293 | mlog_errno(status); |
294 | goto bail; |
295 | } |
296 | unlock = 1; |
297 | } else { |
298 | status = ocfs2_read_blocks_sync(osb, block: blkno, nr: 1, bhs: &bh); |
299 | if (status < 0) { |
300 | mlog_errno(status); |
301 | goto bail; |
302 | } |
303 | } |
304 | |
305 | dinode_alloc = (struct ocfs2_dinode *)bh->b_data; |
306 | |
307 | fi->ifi_stat[slot].lfi_total = |
308 | le32_to_cpu(dinode_alloc->id1.bitmap1.i_total); |
309 | fi->ifi_stat[slot].lfi_free = |
310 | le32_to_cpu(dinode_alloc->id1.bitmap1.i_total) - |
311 | le32_to_cpu(dinode_alloc->id1.bitmap1.i_used); |
312 | |
313 | bail: |
314 | if (unlock) |
315 | ocfs2_inode_unlock(inode: inode_alloc, ex: 0); |
316 | |
317 | if (inode_alloc) |
318 | inode_unlock(inode: inode_alloc); |
319 | |
320 | brelse(bh); |
321 | |
322 | return status; |
323 | } |
324 | |
325 | static int ocfs2_info_handle_freeinode(struct inode *inode, |
326 | struct ocfs2_info_request __user *req) |
327 | { |
328 | u32 i; |
329 | u64 blkno = -1; |
330 | char namebuf[40]; |
331 | int status, type = INODE_ALLOC_SYSTEM_INODE; |
332 | struct ocfs2_info_freeinode *oifi = NULL; |
333 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); |
334 | struct inode *inode_alloc = NULL; |
335 | |
336 | oifi = kzalloc(size: sizeof(struct ocfs2_info_freeinode), GFP_KERNEL); |
337 | if (!oifi) { |
338 | status = -ENOMEM; |
339 | mlog_errno(status); |
340 | goto out_err; |
341 | } |
342 | |
343 | if (o2info_from_user(*oifi, req)) { |
344 | status = -EFAULT; |
345 | goto out_free; |
346 | } |
347 | |
348 | oifi->ifi_slotnum = osb->max_slots; |
349 | |
350 | for (i = 0; i < oifi->ifi_slotnum; i++) { |
351 | if (o2info_coherent(req: &oifi->ifi_req)) { |
352 | inode_alloc = ocfs2_get_system_file_inode(osb, type, slot: i); |
353 | if (!inode_alloc) { |
354 | mlog(ML_ERROR, "unable to get alloc inode in " |
355 | "slot %u\n" , i); |
356 | status = -EIO; |
357 | goto bail; |
358 | } |
359 | } else { |
360 | ocfs2_sprintf_system_inode_name(buf: namebuf, |
361 | len: sizeof(namebuf), |
362 | type, slot: i); |
363 | status = ocfs2_lookup_ino_from_name(dir: osb->sys_root_inode, |
364 | name: namebuf, |
365 | strlen(namebuf), |
366 | blkno: &blkno); |
367 | if (status < 0) { |
368 | status = -ENOENT; |
369 | goto bail; |
370 | } |
371 | } |
372 | |
373 | status = ocfs2_info_scan_inode_alloc(osb, inode_alloc, blkno, fi: oifi, slot: i); |
374 | |
375 | iput(inode_alloc); |
376 | inode_alloc = NULL; |
377 | |
378 | if (status < 0) |
379 | goto bail; |
380 | } |
381 | |
382 | o2info_set_request_filled(req: &oifi->ifi_req); |
383 | |
384 | if (o2info_to_user(*oifi, req)) { |
385 | status = -EFAULT; |
386 | goto out_free; |
387 | } |
388 | |
389 | status = 0; |
390 | bail: |
391 | if (status) |
392 | o2info_set_request_error(kreq: &oifi->ifi_req, req); |
393 | out_free: |
394 | kfree(objp: oifi); |
395 | out_err: |
396 | return status; |
397 | } |
398 | |
399 | static void o2ffg_update_histogram(struct ocfs2_info_free_chunk_list *hist, |
400 | unsigned int chunksize) |
401 | { |
402 | u32 index; |
403 | |
404 | index = __ilog2_u32(n: chunksize); |
405 | if (index >= OCFS2_INFO_MAX_HIST) |
406 | index = OCFS2_INFO_MAX_HIST - 1; |
407 | |
408 | hist->fc_chunks[index]++; |
409 | hist->fc_clusters[index] += chunksize; |
410 | } |
411 | |
412 | static void o2ffg_update_stats(struct ocfs2_info_freefrag_stats *stats, |
413 | unsigned int chunksize) |
414 | { |
415 | if (chunksize > stats->ffs_max) |
416 | stats->ffs_max = chunksize; |
417 | |
418 | if (chunksize < stats->ffs_min) |
419 | stats->ffs_min = chunksize; |
420 | |
421 | stats->ffs_avg += chunksize; |
422 | stats->ffs_free_chunks_real++; |
423 | } |
424 | |
425 | static void ocfs2_info_update_ffg(struct ocfs2_info_freefrag *ffg, |
426 | unsigned int chunksize) |
427 | { |
428 | o2ffg_update_histogram(hist: &(ffg->iff_ffs.ffs_fc_hist), chunksize); |
429 | o2ffg_update_stats(stats: &(ffg->iff_ffs), chunksize); |
430 | } |
431 | |
432 | static int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb, |
433 | struct inode *gb_inode, |
434 | struct ocfs2_dinode *gb_dinode, |
435 | struct ocfs2_chain_rec *rec, |
436 | struct ocfs2_info_freefrag *ffg, |
437 | u32 chunks_in_group) |
438 | { |
439 | int status = 0, used; |
440 | u64 blkno; |
441 | |
442 | struct buffer_head *bh = NULL; |
443 | struct ocfs2_group_desc *bg = NULL; |
444 | |
445 | unsigned int max_bits, num_clusters; |
446 | unsigned int offset = 0, cluster, chunk; |
447 | unsigned int chunk_free, last_chunksize = 0; |
448 | |
449 | if (!le32_to_cpu(rec->c_free)) |
450 | goto bail; |
451 | |
452 | do { |
453 | if (!bg) |
454 | blkno = le64_to_cpu(rec->c_blkno); |
455 | else |
456 | blkno = le64_to_cpu(bg->bg_next_group); |
457 | |
458 | if (bh) { |
459 | brelse(bh); |
460 | bh = NULL; |
461 | } |
462 | |
463 | if (o2info_coherent(req: &ffg->iff_req)) |
464 | status = ocfs2_read_group_descriptor(inode: gb_inode, |
465 | di: gb_dinode, |
466 | gd_blkno: blkno, bh: &bh); |
467 | else |
468 | status = ocfs2_read_blocks_sync(osb, block: blkno, nr: 1, bhs: &bh); |
469 | |
470 | if (status < 0) { |
471 | mlog(ML_ERROR, "Can't read the group descriptor # " |
472 | "%llu from device." , (unsigned long long)blkno); |
473 | status = -EIO; |
474 | goto bail; |
475 | } |
476 | |
477 | bg = (struct ocfs2_group_desc *)bh->b_data; |
478 | |
479 | if (!le16_to_cpu(bg->bg_free_bits_count)) |
480 | continue; |
481 | |
482 | max_bits = le16_to_cpu(bg->bg_bits); |
483 | offset = 0; |
484 | |
485 | for (chunk = 0; chunk < chunks_in_group; chunk++) { |
486 | /* |
487 | * last chunk may be not an entire one. |
488 | */ |
489 | if ((offset + ffg->iff_chunksize) > max_bits) |
490 | num_clusters = max_bits - offset; |
491 | else |
492 | num_clusters = ffg->iff_chunksize; |
493 | |
494 | chunk_free = 0; |
495 | for (cluster = 0; cluster < num_clusters; cluster++) { |
496 | used = ocfs2_test_bit(nr: offset, |
497 | addr: (unsigned long *)bg->bg_bitmap); |
498 | /* |
499 | * - chunk_free counts free clusters in #N chunk. |
500 | * - last_chunksize records the size(in) clusters |
501 | * for the last real free chunk being counted. |
502 | */ |
503 | if (!used) { |
504 | last_chunksize++; |
505 | chunk_free++; |
506 | } |
507 | |
508 | if (used && last_chunksize) { |
509 | ocfs2_info_update_ffg(ffg, |
510 | chunksize: last_chunksize); |
511 | last_chunksize = 0; |
512 | } |
513 | |
514 | offset++; |
515 | } |
516 | |
517 | if (chunk_free == ffg->iff_chunksize) |
518 | ffg->iff_ffs.ffs_free_chunks++; |
519 | } |
520 | |
521 | /* |
522 | * need to update the info for last free chunk. |
523 | */ |
524 | if (last_chunksize) |
525 | ocfs2_info_update_ffg(ffg, chunksize: last_chunksize); |
526 | |
527 | } while (le64_to_cpu(bg->bg_next_group)); |
528 | |
529 | bail: |
530 | brelse(bh); |
531 | |
532 | return status; |
533 | } |
534 | |
535 | static int ocfs2_info_freefrag_scan_bitmap(struct ocfs2_super *osb, |
536 | struct inode *gb_inode, u64 blkno, |
537 | struct ocfs2_info_freefrag *ffg) |
538 | { |
539 | u32 chunks_in_group; |
540 | int status = 0, unlock = 0, i; |
541 | |
542 | struct buffer_head *bh = NULL; |
543 | struct ocfs2_chain_list *cl = NULL; |
544 | struct ocfs2_chain_rec *rec = NULL; |
545 | struct ocfs2_dinode *gb_dinode = NULL; |
546 | |
547 | if (gb_inode) |
548 | inode_lock(inode: gb_inode); |
549 | |
550 | if (o2info_coherent(req: &ffg->iff_req)) { |
551 | status = ocfs2_inode_lock(gb_inode, &bh, 0); |
552 | if (status < 0) { |
553 | mlog_errno(status); |
554 | goto bail; |
555 | } |
556 | unlock = 1; |
557 | } else { |
558 | status = ocfs2_read_blocks_sync(osb, block: blkno, nr: 1, bhs: &bh); |
559 | if (status < 0) { |
560 | mlog_errno(status); |
561 | goto bail; |
562 | } |
563 | } |
564 | |
565 | gb_dinode = (struct ocfs2_dinode *)bh->b_data; |
566 | cl = &(gb_dinode->id2.i_chain); |
567 | |
568 | /* |
569 | * Chunksize(in) clusters from userspace should be |
570 | * less than clusters in a group. |
571 | */ |
572 | if (ffg->iff_chunksize > le16_to_cpu(cl->cl_cpg)) { |
573 | status = -EINVAL; |
574 | goto bail; |
575 | } |
576 | |
577 | memset(&ffg->iff_ffs, 0, sizeof(struct ocfs2_info_freefrag_stats)); |
578 | |
579 | ffg->iff_ffs.ffs_min = ~0U; |
580 | ffg->iff_ffs.ffs_clusters = |
581 | le32_to_cpu(gb_dinode->id1.bitmap1.i_total); |
582 | ffg->iff_ffs.ffs_free_clusters = ffg->iff_ffs.ffs_clusters - |
583 | le32_to_cpu(gb_dinode->id1.bitmap1.i_used); |
584 | |
585 | chunks_in_group = le16_to_cpu(cl->cl_cpg) / ffg->iff_chunksize + 1; |
586 | |
587 | for (i = 0; i < le16_to_cpu(cl->cl_next_free_rec); i++) { |
588 | rec = &(cl->cl_recs[i]); |
589 | status = ocfs2_info_freefrag_scan_chain(osb, gb_inode, |
590 | gb_dinode, |
591 | rec, ffg, |
592 | chunks_in_group); |
593 | if (status) |
594 | goto bail; |
595 | } |
596 | |
597 | if (ffg->iff_ffs.ffs_free_chunks_real) |
598 | ffg->iff_ffs.ffs_avg = (ffg->iff_ffs.ffs_avg / |
599 | ffg->iff_ffs.ffs_free_chunks_real); |
600 | bail: |
601 | if (unlock) |
602 | ocfs2_inode_unlock(inode: gb_inode, ex: 0); |
603 | |
604 | if (gb_inode) |
605 | inode_unlock(inode: gb_inode); |
606 | |
607 | iput(gb_inode); |
608 | brelse(bh); |
609 | |
610 | return status; |
611 | } |
612 | |
613 | static int ocfs2_info_handle_freefrag(struct inode *inode, |
614 | struct ocfs2_info_request __user *req) |
615 | { |
616 | u64 blkno = -1; |
617 | char namebuf[40]; |
618 | int status, type = GLOBAL_BITMAP_SYSTEM_INODE; |
619 | |
620 | struct ocfs2_info_freefrag *oiff; |
621 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); |
622 | struct inode *gb_inode = NULL; |
623 | |
624 | oiff = kzalloc(size: sizeof(struct ocfs2_info_freefrag), GFP_KERNEL); |
625 | if (!oiff) { |
626 | status = -ENOMEM; |
627 | mlog_errno(status); |
628 | goto out_err; |
629 | } |
630 | |
631 | if (o2info_from_user(*oiff, req)) { |
632 | status = -EFAULT; |
633 | goto out_free; |
634 | } |
635 | /* |
636 | * chunksize from userspace should be power of 2. |
637 | */ |
638 | if ((oiff->iff_chunksize & (oiff->iff_chunksize - 1)) || |
639 | (!oiff->iff_chunksize)) { |
640 | status = -EINVAL; |
641 | goto bail; |
642 | } |
643 | |
644 | if (o2info_coherent(req: &oiff->iff_req)) { |
645 | gb_inode = ocfs2_get_system_file_inode(osb, type, |
646 | OCFS2_INVALID_SLOT); |
647 | if (!gb_inode) { |
648 | mlog(ML_ERROR, "unable to get global_bitmap inode\n" ); |
649 | status = -EIO; |
650 | goto bail; |
651 | } |
652 | } else { |
653 | ocfs2_sprintf_system_inode_name(buf: namebuf, len: sizeof(namebuf), type, |
654 | OCFS2_INVALID_SLOT); |
655 | status = ocfs2_lookup_ino_from_name(dir: osb->sys_root_inode, |
656 | name: namebuf, |
657 | strlen(namebuf), |
658 | blkno: &blkno); |
659 | if (status < 0) { |
660 | status = -ENOENT; |
661 | goto bail; |
662 | } |
663 | } |
664 | |
665 | status = ocfs2_info_freefrag_scan_bitmap(osb, gb_inode, blkno, ffg: oiff); |
666 | if (status < 0) |
667 | goto bail; |
668 | |
669 | o2info_set_request_filled(req: &oiff->iff_req); |
670 | |
671 | if (o2info_to_user(*oiff, req)) { |
672 | status = -EFAULT; |
673 | goto out_free; |
674 | } |
675 | |
676 | status = 0; |
677 | bail: |
678 | if (status) |
679 | o2info_set_request_error(kreq: &oiff->iff_req, req); |
680 | out_free: |
681 | kfree(objp: oiff); |
682 | out_err: |
683 | return status; |
684 | } |
685 | |
686 | static int ocfs2_info_handle_unknown(struct inode *inode, |
687 | struct ocfs2_info_request __user *req) |
688 | { |
689 | struct ocfs2_info_request oir; |
690 | |
691 | if (o2info_from_user(oir, req)) |
692 | return -EFAULT; |
693 | |
694 | o2info_clear_request_filled(req: &oir); |
695 | |
696 | if (o2info_to_user(oir, req)) |
697 | return -EFAULT; |
698 | |
699 | return 0; |
700 | } |
701 | |
702 | /* |
703 | * Validate and distinguish OCFS2_IOC_INFO requests. |
704 | * |
705 | * - validate the magic number. |
706 | * - distinguish different requests. |
707 | * - validate size of different requests. |
708 | */ |
709 | static int ocfs2_info_handle_request(struct inode *inode, |
710 | struct ocfs2_info_request __user *req) |
711 | { |
712 | int status = -EFAULT; |
713 | struct ocfs2_info_request oir; |
714 | |
715 | if (o2info_from_user(oir, req)) |
716 | goto bail; |
717 | |
718 | status = -EINVAL; |
719 | if (oir.ir_magic != OCFS2_INFO_MAGIC) |
720 | goto bail; |
721 | |
722 | switch (oir.ir_code) { |
723 | case OCFS2_INFO_BLOCKSIZE: |
724 | if (oir.ir_size == sizeof(struct ocfs2_info_blocksize)) |
725 | status = ocfs2_info_handle_blocksize(inode, req); |
726 | break; |
727 | case OCFS2_INFO_CLUSTERSIZE: |
728 | if (oir.ir_size == sizeof(struct ocfs2_info_clustersize)) |
729 | status = ocfs2_info_handle_clustersize(inode, req); |
730 | break; |
731 | case OCFS2_INFO_MAXSLOTS: |
732 | if (oir.ir_size == sizeof(struct ocfs2_info_maxslots)) |
733 | status = ocfs2_info_handle_maxslots(inode, req); |
734 | break; |
735 | case OCFS2_INFO_LABEL: |
736 | if (oir.ir_size == sizeof(struct ocfs2_info_label)) |
737 | status = ocfs2_info_handle_label(inode, req); |
738 | break; |
739 | case OCFS2_INFO_UUID: |
740 | if (oir.ir_size == sizeof(struct ocfs2_info_uuid)) |
741 | status = ocfs2_info_handle_uuid(inode, req); |
742 | break; |
743 | case OCFS2_INFO_FS_FEATURES: |
744 | if (oir.ir_size == sizeof(struct ocfs2_info_fs_features)) |
745 | status = ocfs2_info_handle_fs_features(inode, req); |
746 | break; |
747 | case OCFS2_INFO_JOURNAL_SIZE: |
748 | if (oir.ir_size == sizeof(struct ocfs2_info_journal_size)) |
749 | status = ocfs2_info_handle_journal_size(inode, req); |
750 | break; |
751 | case OCFS2_INFO_FREEINODE: |
752 | if (oir.ir_size == sizeof(struct ocfs2_info_freeinode)) |
753 | status = ocfs2_info_handle_freeinode(inode, req); |
754 | break; |
755 | case OCFS2_INFO_FREEFRAG: |
756 | if (oir.ir_size == sizeof(struct ocfs2_info_freefrag)) |
757 | status = ocfs2_info_handle_freefrag(inode, req); |
758 | break; |
759 | default: |
760 | status = ocfs2_info_handle_unknown(inode, req); |
761 | break; |
762 | } |
763 | |
764 | bail: |
765 | return status; |
766 | } |
767 | |
768 | static int ocfs2_get_request_ptr(struct ocfs2_info *info, int idx, |
769 | u64 *req_addr, int compat_flag) |
770 | { |
771 | int status = -EFAULT; |
772 | u64 __user *bp = NULL; |
773 | |
774 | if (compat_flag) { |
775 | #ifdef CONFIG_COMPAT |
776 | /* |
777 | * pointer bp stores the base address of a pointers array, |
778 | * which collects all addresses of separate request. |
779 | */ |
780 | bp = (u64 __user *)(unsigned long)compat_ptr(uptr: info->oi_requests); |
781 | #else |
782 | BUG(); |
783 | #endif |
784 | } else |
785 | bp = (u64 __user *)(unsigned long)(info->oi_requests); |
786 | |
787 | if (o2info_from_user(*req_addr, bp + idx)) |
788 | goto bail; |
789 | |
790 | status = 0; |
791 | bail: |
792 | return status; |
793 | } |
794 | |
795 | /* |
796 | * OCFS2_IOC_INFO handles an array of requests passed from userspace. |
797 | * |
798 | * ocfs2_info_handle() recevies a large info aggregation, grab and |
799 | * validate the request count from header, then break it into small |
800 | * pieces, later specific handlers can handle them one by one. |
801 | * |
802 | * Idea here is to make each separate request small enough to ensure |
803 | * a better backward&forward compatibility, since a small piece of |
804 | * request will be less likely to be broken if disk layout get changed. |
805 | */ |
806 | static noinline_for_stack int |
807 | ocfs2_info_handle(struct inode *inode, struct ocfs2_info *info, int compat_flag) |
808 | { |
809 | int i, status = 0; |
810 | u64 req_addr; |
811 | struct ocfs2_info_request __user *reqp; |
812 | |
813 | if ((info->oi_count > OCFS2_INFO_MAX_REQUEST) || |
814 | (!info->oi_requests)) { |
815 | status = -EINVAL; |
816 | goto bail; |
817 | } |
818 | |
819 | for (i = 0; i < info->oi_count; i++) { |
820 | |
821 | status = ocfs2_get_request_ptr(info, idx: i, req_addr: &req_addr, compat_flag); |
822 | if (status) |
823 | break; |
824 | |
825 | reqp = (struct ocfs2_info_request __user *)(unsigned long)req_addr; |
826 | if (!reqp) { |
827 | status = -EINVAL; |
828 | goto bail; |
829 | } |
830 | |
831 | status = ocfs2_info_handle_request(inode, req: reqp); |
832 | if (status) |
833 | break; |
834 | } |
835 | |
836 | bail: |
837 | return status; |
838 | } |
839 | |
840 | long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
841 | { |
842 | struct inode *inode = file_inode(f: filp); |
843 | void __user *argp = (void __user *)arg; |
844 | int status; |
845 | |
846 | switch (cmd) { |
847 | case OCFS2_IOC_RESVSP: |
848 | case OCFS2_IOC_RESVSP64: |
849 | case OCFS2_IOC_UNRESVSP: |
850 | case OCFS2_IOC_UNRESVSP64: |
851 | { |
852 | struct ocfs2_space_resv sr; |
853 | |
854 | if (copy_from_user(to: &sr, from: (int __user *) arg, n: sizeof(sr))) |
855 | return -EFAULT; |
856 | |
857 | return ocfs2_change_file_space(file: filp, cmd, sr: &sr); |
858 | } |
859 | case OCFS2_IOC_GROUP_EXTEND: |
860 | { |
861 | int new_clusters; |
862 | |
863 | if (!capable(CAP_SYS_RESOURCE)) |
864 | return -EPERM; |
865 | |
866 | if (get_user(new_clusters, (int __user *)arg)) |
867 | return -EFAULT; |
868 | |
869 | status = mnt_want_write_file(file: filp); |
870 | if (status) |
871 | return status; |
872 | status = ocfs2_group_extend(inode, new_clusters); |
873 | mnt_drop_write_file(file: filp); |
874 | return status; |
875 | } |
876 | case OCFS2_IOC_GROUP_ADD: |
877 | case OCFS2_IOC_GROUP_ADD64: |
878 | { |
879 | struct ocfs2_new_group_input input; |
880 | |
881 | if (!capable(CAP_SYS_RESOURCE)) |
882 | return -EPERM; |
883 | |
884 | if (copy_from_user(to: &input, from: (int __user *) arg, n: sizeof(input))) |
885 | return -EFAULT; |
886 | |
887 | status = mnt_want_write_file(file: filp); |
888 | if (status) |
889 | return status; |
890 | status = ocfs2_group_add(inode, input: &input); |
891 | mnt_drop_write_file(file: filp); |
892 | return status; |
893 | } |
894 | case OCFS2_IOC_REFLINK: |
895 | { |
896 | struct reflink_arguments args; |
897 | const char __user *old_path; |
898 | const char __user *new_path; |
899 | bool preserve; |
900 | |
901 | if (copy_from_user(to: &args, from: argp, n: sizeof(args))) |
902 | return -EFAULT; |
903 | old_path = (const char __user *)(unsigned long)args.old_path; |
904 | new_path = (const char __user *)(unsigned long)args.new_path; |
905 | preserve = (args.preserve != 0); |
906 | |
907 | return ocfs2_reflink_ioctl(inode, oldname: old_path, newname: new_path, preserve); |
908 | } |
909 | case OCFS2_IOC_INFO: |
910 | { |
911 | struct ocfs2_info info; |
912 | |
913 | if (copy_from_user(to: &info, from: argp, n: sizeof(struct ocfs2_info))) |
914 | return -EFAULT; |
915 | |
916 | return ocfs2_info_handle(inode, info: &info, compat_flag: 0); |
917 | } |
918 | case FITRIM: |
919 | { |
920 | struct super_block *sb = inode->i_sb; |
921 | struct fstrim_range range; |
922 | int ret = 0; |
923 | |
924 | if (!capable(CAP_SYS_ADMIN)) |
925 | return -EPERM; |
926 | |
927 | if (!bdev_max_discard_sectors(bdev: sb->s_bdev)) |
928 | return -EOPNOTSUPP; |
929 | |
930 | if (copy_from_user(to: &range, from: argp, n: sizeof(range))) |
931 | return -EFAULT; |
932 | |
933 | range.minlen = max_t(u64, bdev_discard_granularity(sb->s_bdev), |
934 | range.minlen); |
935 | ret = ocfs2_trim_fs(sb, range: &range); |
936 | if (ret < 0) |
937 | return ret; |
938 | |
939 | if (copy_to_user(to: argp, from: &range, n: sizeof(range))) |
940 | return -EFAULT; |
941 | |
942 | return 0; |
943 | } |
944 | case OCFS2_IOC_MOVE_EXT: |
945 | return ocfs2_ioctl_move_extents(filp, argp); |
946 | default: |
947 | return -ENOTTY; |
948 | } |
949 | } |
950 | |
951 | #ifdef CONFIG_COMPAT |
952 | long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg) |
953 | { |
954 | bool preserve; |
955 | struct reflink_arguments args; |
956 | struct inode *inode = file_inode(f: file); |
957 | struct ocfs2_info info; |
958 | void __user *argp = (void __user *)arg; |
959 | |
960 | switch (cmd) { |
961 | case OCFS2_IOC_RESVSP: |
962 | case OCFS2_IOC_RESVSP64: |
963 | case OCFS2_IOC_UNRESVSP: |
964 | case OCFS2_IOC_UNRESVSP64: |
965 | case OCFS2_IOC_GROUP_EXTEND: |
966 | case OCFS2_IOC_GROUP_ADD: |
967 | case OCFS2_IOC_GROUP_ADD64: |
968 | break; |
969 | case OCFS2_IOC_REFLINK: |
970 | if (copy_from_user(to: &args, from: argp, n: sizeof(args))) |
971 | return -EFAULT; |
972 | preserve = (args.preserve != 0); |
973 | |
974 | return ocfs2_reflink_ioctl(inode, oldname: compat_ptr(uptr: args.old_path), |
975 | newname: compat_ptr(uptr: args.new_path), preserve); |
976 | case OCFS2_IOC_INFO: |
977 | if (copy_from_user(to: &info, from: argp, n: sizeof(struct ocfs2_info))) |
978 | return -EFAULT; |
979 | |
980 | return ocfs2_info_handle(inode, info: &info, compat_flag: 1); |
981 | case FITRIM: |
982 | case OCFS2_IOC_MOVE_EXT: |
983 | break; |
984 | default: |
985 | return -ENOIOCTLCMD; |
986 | } |
987 | |
988 | return ocfs2_ioctl(filp: file, cmd, arg); |
989 | } |
990 | #endif |
991 | |