diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /fs/ocfs2/ioctl.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'fs/ocfs2/ioctl.c')
-rw-r--r-- | fs/ocfs2/ioctl.c | 821 |
1 files changed, 817 insertions, 4 deletions
diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c index 7d9d9c132cef..bc91072b7219 100644 --- a/fs/ocfs2/ioctl.c +++ b/fs/ocfs2/ioctl.c | |||
@@ -9,7 +9,6 @@ | |||
9 | #include <linux/mount.h> | 9 | #include <linux/mount.h> |
10 | #include <linux/compat.h> | 10 | #include <linux/compat.h> |
11 | 11 | ||
12 | #define MLOG_MASK_PREFIX ML_INODE | ||
13 | #include <cluster/masklog.h> | 12 | #include <cluster/masklog.h> |
14 | 13 | ||
15 | #include "ocfs2.h" | 14 | #include "ocfs2.h" |
@@ -23,9 +22,46 @@ | |||
23 | #include "ioctl.h" | 22 | #include "ioctl.h" |
24 | #include "resize.h" | 23 | #include "resize.h" |
25 | #include "refcounttree.h" | 24 | #include "refcounttree.h" |
25 | #include "sysfile.h" | ||
26 | #include "dir.h" | ||
27 | #include "buffer_head_io.h" | ||
28 | #include "suballoc.h" | ||
29 | #include "move_extents.h" | ||
26 | 30 | ||
27 | #include <linux/ext2_fs.h> | 31 | #include <linux/ext2_fs.h> |
28 | 32 | ||
33 | #define o2info_from_user(a, b) \ | ||
34 | copy_from_user(&(a), (b), sizeof(a)) | ||
35 | #define o2info_to_user(a, b) \ | ||
36 | copy_to_user((typeof(a) __user *)b, &(a), sizeof(a)) | ||
37 | |||
38 | /* | ||
39 | * This call is void because we are already reporting an error that may | ||
40 | * be -EFAULT. The error will be returned from the ioctl(2) call. It's | ||
41 | * just a best-effort to tell userspace that this request 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 | |||
29 | static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags) | 65 | static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags) |
30 | { | 66 | { |
31 | int status; | 67 | int status; |
@@ -39,7 +75,6 @@ static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags) | |||
39 | *flags = OCFS2_I(inode)->ip_attr; | 75 | *flags = OCFS2_I(inode)->ip_attr; |
40 | ocfs2_inode_unlock(inode, 0); | 76 | ocfs2_inode_unlock(inode, 0); |
41 | 77 | ||
42 | mlog_exit(status); | ||
43 | return status; | 78 | return status; |
44 | } | 79 | } |
45 | 80 | ||
@@ -62,7 +97,7 @@ static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags, | |||
62 | } | 97 | } |
63 | 98 | ||
64 | status = -EACCES; | 99 | status = -EACCES; |
65 | if (!is_owner_or_cap(inode)) | 100 | if (!inode_owner_or_capable(inode)) |
66 | goto bail_unlock; | 101 | goto bail_unlock; |
67 | 102 | ||
68 | if (!S_ISDIR(inode->i_mode)) | 103 | if (!S_ISDIR(inode->i_mode)) |
@@ -105,7 +140,743 @@ bail: | |||
105 | 140 | ||
106 | brelse(bh); | 141 | brelse(bh); |
107 | 142 | ||
108 | mlog_exit(status); | 143 | return status; |
144 | } | ||
145 | |||
146 | int ocfs2_info_handle_blocksize(struct inode *inode, | ||
147 | struct ocfs2_info_request __user *req) | ||
148 | { | ||
149 | int status = -EFAULT; | ||
150 | struct ocfs2_info_blocksize oib; | ||
151 | |||
152 | if (o2info_from_user(oib, req)) | ||
153 | goto bail; | ||
154 | |||
155 | oib.ib_blocksize = inode->i_sb->s_blocksize; | ||
156 | |||
157 | o2info_set_request_filled(&oib.ib_req); | ||
158 | |||
159 | if (o2info_to_user(oib, req)) | ||
160 | goto bail; | ||
161 | |||
162 | status = 0; | ||
163 | bail: | ||
164 | if (status) | ||
165 | o2info_set_request_error(&oib.ib_req, req); | ||
166 | |||
167 | return status; | ||
168 | } | ||
169 | |||
170 | int ocfs2_info_handle_clustersize(struct inode *inode, | ||
171 | struct ocfs2_info_request __user *req) | ||
172 | { | ||
173 | int status = -EFAULT; | ||
174 | struct ocfs2_info_clustersize oic; | ||
175 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
176 | |||
177 | if (o2info_from_user(oic, req)) | ||
178 | goto bail; | ||
179 | |||
180 | oic.ic_clustersize = osb->s_clustersize; | ||
181 | |||
182 | o2info_set_request_filled(&oic.ic_req); | ||
183 | |||
184 | if (o2info_to_user(oic, req)) | ||
185 | goto bail; | ||
186 | |||
187 | status = 0; | ||
188 | bail: | ||
189 | if (status) | ||
190 | o2info_set_request_error(&oic.ic_req, req); | ||
191 | |||
192 | return status; | ||
193 | } | ||
194 | |||
195 | int ocfs2_info_handle_maxslots(struct inode *inode, | ||
196 | struct ocfs2_info_request __user *req) | ||
197 | { | ||
198 | int status = -EFAULT; | ||
199 | struct ocfs2_info_maxslots oim; | ||
200 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
201 | |||
202 | if (o2info_from_user(oim, req)) | ||
203 | goto bail; | ||
204 | |||
205 | oim.im_max_slots = osb->max_slots; | ||
206 | |||
207 | o2info_set_request_filled(&oim.im_req); | ||
208 | |||
209 | if (o2info_to_user(oim, req)) | ||
210 | goto bail; | ||
211 | |||
212 | status = 0; | ||
213 | bail: | ||
214 | if (status) | ||
215 | o2info_set_request_error(&oim.im_req, req); | ||
216 | |||
217 | return status; | ||
218 | } | ||
219 | |||
220 | int ocfs2_info_handle_label(struct inode *inode, | ||
221 | struct ocfs2_info_request __user *req) | ||
222 | { | ||
223 | int status = -EFAULT; | ||
224 | struct ocfs2_info_label oil; | ||
225 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
226 | |||
227 | if (o2info_from_user(oil, req)) | ||
228 | goto bail; | ||
229 | |||
230 | memcpy(oil.il_label, osb->vol_label, OCFS2_MAX_VOL_LABEL_LEN); | ||
231 | |||
232 | o2info_set_request_filled(&oil.il_req); | ||
233 | |||
234 | if (o2info_to_user(oil, req)) | ||
235 | goto bail; | ||
236 | |||
237 | status = 0; | ||
238 | bail: | ||
239 | if (status) | ||
240 | o2info_set_request_error(&oil.il_req, req); | ||
241 | |||
242 | return status; | ||
243 | } | ||
244 | |||
245 | int ocfs2_info_handle_uuid(struct inode *inode, | ||
246 | struct ocfs2_info_request __user *req) | ||
247 | { | ||
248 | int status = -EFAULT; | ||
249 | struct ocfs2_info_uuid oiu; | ||
250 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
251 | |||
252 | if (o2info_from_user(oiu, req)) | ||
253 | goto bail; | ||
254 | |||
255 | memcpy(oiu.iu_uuid_str, osb->uuid_str, OCFS2_TEXT_UUID_LEN + 1); | ||
256 | |||
257 | o2info_set_request_filled(&oiu.iu_req); | ||
258 | |||
259 | if (o2info_to_user(oiu, req)) | ||
260 | goto bail; | ||
261 | |||
262 | status = 0; | ||
263 | bail: | ||
264 | if (status) | ||
265 | o2info_set_request_error(&oiu.iu_req, req); | ||
266 | |||
267 | return status; | ||
268 | } | ||
269 | |||
270 | int ocfs2_info_handle_fs_features(struct inode *inode, | ||
271 | struct ocfs2_info_request __user *req) | ||
272 | { | ||
273 | int status = -EFAULT; | ||
274 | struct ocfs2_info_fs_features oif; | ||
275 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
276 | |||
277 | if (o2info_from_user(oif, req)) | ||
278 | goto bail; | ||
279 | |||
280 | oif.if_compat_features = osb->s_feature_compat; | ||
281 | oif.if_incompat_features = osb->s_feature_incompat; | ||
282 | oif.if_ro_compat_features = osb->s_feature_ro_compat; | ||
283 | |||
284 | o2info_set_request_filled(&oif.if_req); | ||
285 | |||
286 | if (o2info_to_user(oif, req)) | ||
287 | goto bail; | ||
288 | |||
289 | status = 0; | ||
290 | bail: | ||
291 | if (status) | ||
292 | o2info_set_request_error(&oif.if_req, req); | ||
293 | |||
294 | return status; | ||
295 | } | ||
296 | |||
297 | int ocfs2_info_handle_journal_size(struct inode *inode, | ||
298 | struct ocfs2_info_request __user *req) | ||
299 | { | ||
300 | int status = -EFAULT; | ||
301 | struct ocfs2_info_journal_size oij; | ||
302 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
303 | |||
304 | if (o2info_from_user(oij, req)) | ||
305 | goto bail; | ||
306 | |||
307 | oij.ij_journal_size = osb->journal->j_inode->i_size; | ||
308 | |||
309 | o2info_set_request_filled(&oij.ij_req); | ||
310 | |||
311 | if (o2info_to_user(oij, req)) | ||
312 | goto bail; | ||
313 | |||
314 | status = 0; | ||
315 | bail: | ||
316 | if (status) | ||
317 | o2info_set_request_error(&oij.ij_req, req); | ||
318 | |||
319 | return status; | ||
320 | } | ||
321 | |||
322 | int ocfs2_info_scan_inode_alloc(struct ocfs2_super *osb, | ||
323 | struct inode *inode_alloc, u64 blkno, | ||
324 | struct ocfs2_info_freeinode *fi, u32 slot) | ||
325 | { | ||
326 | int status = 0, unlock = 0; | ||
327 | |||
328 | struct buffer_head *bh = NULL; | ||
329 | struct ocfs2_dinode *dinode_alloc = NULL; | ||
330 | |||
331 | if (inode_alloc) | ||
332 | mutex_lock(&inode_alloc->i_mutex); | ||
333 | |||
334 | if (o2info_coherent(&fi->ifi_req)) { | ||
335 | status = ocfs2_inode_lock(inode_alloc, &bh, 0); | ||
336 | if (status < 0) { | ||
337 | mlog_errno(status); | ||
338 | goto bail; | ||
339 | } | ||
340 | unlock = 1; | ||
341 | } else { | ||
342 | status = ocfs2_read_blocks_sync(osb, blkno, 1, &bh); | ||
343 | if (status < 0) { | ||
344 | mlog_errno(status); | ||
345 | goto bail; | ||
346 | } | ||
347 | } | ||
348 | |||
349 | dinode_alloc = (struct ocfs2_dinode *)bh->b_data; | ||
350 | |||
351 | fi->ifi_stat[slot].lfi_total = | ||
352 | le32_to_cpu(dinode_alloc->id1.bitmap1.i_total); | ||
353 | fi->ifi_stat[slot].lfi_free = | ||
354 | le32_to_cpu(dinode_alloc->id1.bitmap1.i_total) - | ||
355 | le32_to_cpu(dinode_alloc->id1.bitmap1.i_used); | ||
356 | |||
357 | bail: | ||
358 | if (unlock) | ||
359 | ocfs2_inode_unlock(inode_alloc, 0); | ||
360 | |||
361 | if (inode_alloc) | ||
362 | mutex_unlock(&inode_alloc->i_mutex); | ||
363 | |||
364 | brelse(bh); | ||
365 | |||
366 | return status; | ||
367 | } | ||
368 | |||
369 | int ocfs2_info_handle_freeinode(struct inode *inode, | ||
370 | struct ocfs2_info_request __user *req) | ||
371 | { | ||
372 | u32 i; | ||
373 | u64 blkno = -1; | ||
374 | char namebuf[40]; | ||
375 | int status = -EFAULT, type = INODE_ALLOC_SYSTEM_INODE; | ||
376 | struct ocfs2_info_freeinode *oifi = NULL; | ||
377 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
378 | struct inode *inode_alloc = NULL; | ||
379 | |||
380 | oifi = kzalloc(sizeof(struct ocfs2_info_freeinode), GFP_KERNEL); | ||
381 | if (!oifi) { | ||
382 | status = -ENOMEM; | ||
383 | mlog_errno(status); | ||
384 | goto bail; | ||
385 | } | ||
386 | |||
387 | if (o2info_from_user(*oifi, req)) | ||
388 | goto bail; | ||
389 | |||
390 | oifi->ifi_slotnum = osb->max_slots; | ||
391 | |||
392 | for (i = 0; i < oifi->ifi_slotnum; i++) { | ||
393 | if (o2info_coherent(&oifi->ifi_req)) { | ||
394 | inode_alloc = ocfs2_get_system_file_inode(osb, type, i); | ||
395 | if (!inode_alloc) { | ||
396 | mlog(ML_ERROR, "unable to get alloc inode in " | ||
397 | "slot %u\n", i); | ||
398 | status = -EIO; | ||
399 | goto bail; | ||
400 | } | ||
401 | } else { | ||
402 | ocfs2_sprintf_system_inode_name(namebuf, | ||
403 | sizeof(namebuf), | ||
404 | type, i); | ||
405 | status = ocfs2_lookup_ino_from_name(osb->sys_root_inode, | ||
406 | namebuf, | ||
407 | strlen(namebuf), | ||
408 | &blkno); | ||
409 | if (status < 0) { | ||
410 | status = -ENOENT; | ||
411 | goto bail; | ||
412 | } | ||
413 | } | ||
414 | |||
415 | status = ocfs2_info_scan_inode_alloc(osb, inode_alloc, blkno, oifi, i); | ||
416 | if (status < 0) | ||
417 | goto bail; | ||
418 | |||
419 | iput(inode_alloc); | ||
420 | inode_alloc = NULL; | ||
421 | } | ||
422 | |||
423 | o2info_set_request_filled(&oifi->ifi_req); | ||
424 | |||
425 | if (o2info_to_user(*oifi, req)) | ||
426 | goto bail; | ||
427 | |||
428 | status = 0; | ||
429 | bail: | ||
430 | if (status) | ||
431 | o2info_set_request_error(&oifi->ifi_req, req); | ||
432 | |||
433 | kfree(oifi); | ||
434 | |||
435 | return status; | ||
436 | } | ||
437 | |||
438 | static void o2ffg_update_histogram(struct ocfs2_info_free_chunk_list *hist, | ||
439 | unsigned int chunksize) | ||
440 | { | ||
441 | int index; | ||
442 | |||
443 | index = __ilog2_u32(chunksize); | ||
444 | if (index >= OCFS2_INFO_MAX_HIST) | ||
445 | index = OCFS2_INFO_MAX_HIST - 1; | ||
446 | |||
447 | hist->fc_chunks[index]++; | ||
448 | hist->fc_clusters[index] += chunksize; | ||
449 | } | ||
450 | |||
451 | static void o2ffg_update_stats(struct ocfs2_info_freefrag_stats *stats, | ||
452 | unsigned int chunksize) | ||
453 | { | ||
454 | if (chunksize > stats->ffs_max) | ||
455 | stats->ffs_max = chunksize; | ||
456 | |||
457 | if (chunksize < stats->ffs_min) | ||
458 | stats->ffs_min = chunksize; | ||
459 | |||
460 | stats->ffs_avg += chunksize; | ||
461 | stats->ffs_free_chunks_real++; | ||
462 | } | ||
463 | |||
464 | void ocfs2_info_update_ffg(struct ocfs2_info_freefrag *ffg, | ||
465 | unsigned int chunksize) | ||
466 | { | ||
467 | o2ffg_update_histogram(&(ffg->iff_ffs.ffs_fc_hist), chunksize); | ||
468 | o2ffg_update_stats(&(ffg->iff_ffs), chunksize); | ||
469 | } | ||
470 | |||
471 | int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb, | ||
472 | struct inode *gb_inode, | ||
473 | struct ocfs2_dinode *gb_dinode, | ||
474 | struct ocfs2_chain_rec *rec, | ||
475 | struct ocfs2_info_freefrag *ffg, | ||
476 | u32 chunks_in_group) | ||
477 | { | ||
478 | int status = 0, used; | ||
479 | u64 blkno; | ||
480 | |||
481 | struct buffer_head *bh = NULL; | ||
482 | struct ocfs2_group_desc *bg = NULL; | ||
483 | |||
484 | unsigned int max_bits, num_clusters; | ||
485 | unsigned int offset = 0, cluster, chunk; | ||
486 | unsigned int chunk_free, last_chunksize = 0; | ||
487 | |||
488 | if (!le32_to_cpu(rec->c_free)) | ||
489 | goto bail; | ||
490 | |||
491 | do { | ||
492 | if (!bg) | ||
493 | blkno = le64_to_cpu(rec->c_blkno); | ||
494 | else | ||
495 | blkno = le64_to_cpu(bg->bg_next_group); | ||
496 | |||
497 | if (bh) { | ||
498 | brelse(bh); | ||
499 | bh = NULL; | ||
500 | } | ||
501 | |||
502 | if (o2info_coherent(&ffg->iff_req)) | ||
503 | status = ocfs2_read_group_descriptor(gb_inode, | ||
504 | gb_dinode, | ||
505 | blkno, &bh); | ||
506 | else | ||
507 | status = ocfs2_read_blocks_sync(osb, blkno, 1, &bh); | ||
508 | |||
509 | if (status < 0) { | ||
510 | mlog(ML_ERROR, "Can't read the group descriptor # " | ||
511 | "%llu from device.", (unsigned long long)blkno); | ||
512 | status = -EIO; | ||
513 | goto bail; | ||
514 | } | ||
515 | |||
516 | bg = (struct ocfs2_group_desc *)bh->b_data; | ||
517 | |||
518 | if (!le16_to_cpu(bg->bg_free_bits_count)) | ||
519 | continue; | ||
520 | |||
521 | max_bits = le16_to_cpu(bg->bg_bits); | ||
522 | offset = 0; | ||
523 | |||
524 | for (chunk = 0; chunk < chunks_in_group; chunk++) { | ||
525 | /* | ||
526 | * last chunk may be not an entire one. | ||
527 | */ | ||
528 | if ((offset + ffg->iff_chunksize) > max_bits) | ||
529 | num_clusters = max_bits - offset; | ||
530 | else | ||
531 | num_clusters = ffg->iff_chunksize; | ||
532 | |||
533 | chunk_free = 0; | ||
534 | for (cluster = 0; cluster < num_clusters; cluster++) { | ||
535 | used = ocfs2_test_bit(offset, | ||
536 | (unsigned long *)bg->bg_bitmap); | ||
537 | /* | ||
538 | * - chunk_free counts free clusters in #N chunk. | ||
539 | * - last_chunksize records the size(in) clusters | ||
540 | * for the last real free chunk being counted. | ||
541 | */ | ||
542 | if (!used) { | ||
543 | last_chunksize++; | ||
544 | chunk_free++; | ||
545 | } | ||
546 | |||
547 | if (used && last_chunksize) { | ||
548 | ocfs2_info_update_ffg(ffg, | ||
549 | last_chunksize); | ||
550 | last_chunksize = 0; | ||
551 | } | ||
552 | |||
553 | offset++; | ||
554 | } | ||
555 | |||
556 | if (chunk_free == ffg->iff_chunksize) | ||
557 | ffg->iff_ffs.ffs_free_chunks++; | ||
558 | } | ||
559 | |||
560 | /* | ||
561 | * need to update the info for last free chunk. | ||
562 | */ | ||
563 | if (last_chunksize) | ||
564 | ocfs2_info_update_ffg(ffg, last_chunksize); | ||
565 | |||
566 | } while (le64_to_cpu(bg->bg_next_group)); | ||
567 | |||
568 | bail: | ||
569 | brelse(bh); | ||
570 | |||
571 | return status; | ||
572 | } | ||
573 | |||
574 | int ocfs2_info_freefrag_scan_bitmap(struct ocfs2_super *osb, | ||
575 | struct inode *gb_inode, u64 blkno, | ||
576 | struct ocfs2_info_freefrag *ffg) | ||
577 | { | ||
578 | u32 chunks_in_group; | ||
579 | int status = 0, unlock = 0, i; | ||
580 | |||
581 | struct buffer_head *bh = NULL; | ||
582 | struct ocfs2_chain_list *cl = NULL; | ||
583 | struct ocfs2_chain_rec *rec = NULL; | ||
584 | struct ocfs2_dinode *gb_dinode = NULL; | ||
585 | |||
586 | if (gb_inode) | ||
587 | mutex_lock(&gb_inode->i_mutex); | ||
588 | |||
589 | if (o2info_coherent(&ffg->iff_req)) { | ||
590 | status = ocfs2_inode_lock(gb_inode, &bh, 0); | ||
591 | if (status < 0) { | ||
592 | mlog_errno(status); | ||
593 | goto bail; | ||
594 | } | ||
595 | unlock = 1; | ||
596 | } else { | ||
597 | status = ocfs2_read_blocks_sync(osb, blkno, 1, &bh); | ||
598 | if (status < 0) { | ||
599 | mlog_errno(status); | ||
600 | goto bail; | ||
601 | } | ||
602 | } | ||
603 | |||
604 | gb_dinode = (struct ocfs2_dinode *)bh->b_data; | ||
605 | cl = &(gb_dinode->id2.i_chain); | ||
606 | |||
607 | /* | ||
608 | * Chunksize(in) clusters from userspace should be | ||
609 | * less than clusters in a group. | ||
610 | */ | ||
611 | if (ffg->iff_chunksize > le16_to_cpu(cl->cl_cpg)) { | ||
612 | status = -EINVAL; | ||
613 | goto bail; | ||
614 | } | ||
615 | |||
616 | memset(&ffg->iff_ffs, 0, sizeof(struct ocfs2_info_freefrag_stats)); | ||
617 | |||
618 | ffg->iff_ffs.ffs_min = ~0U; | ||
619 | ffg->iff_ffs.ffs_clusters = | ||
620 | le32_to_cpu(gb_dinode->id1.bitmap1.i_total); | ||
621 | ffg->iff_ffs.ffs_free_clusters = ffg->iff_ffs.ffs_clusters - | ||
622 | le32_to_cpu(gb_dinode->id1.bitmap1.i_used); | ||
623 | |||
624 | chunks_in_group = le16_to_cpu(cl->cl_cpg) / ffg->iff_chunksize + 1; | ||
625 | |||
626 | for (i = 0; i < le16_to_cpu(cl->cl_next_free_rec); i++) { | ||
627 | rec = &(cl->cl_recs[i]); | ||
628 | status = ocfs2_info_freefrag_scan_chain(osb, gb_inode, | ||
629 | gb_dinode, | ||
630 | rec, ffg, | ||
631 | chunks_in_group); | ||
632 | if (status) | ||
633 | goto bail; | ||
634 | } | ||
635 | |||
636 | if (ffg->iff_ffs.ffs_free_chunks_real) | ||
637 | ffg->iff_ffs.ffs_avg = (ffg->iff_ffs.ffs_avg / | ||
638 | ffg->iff_ffs.ffs_free_chunks_real); | ||
639 | bail: | ||
640 | if (unlock) | ||
641 | ocfs2_inode_unlock(gb_inode, 0); | ||
642 | |||
643 | if (gb_inode) | ||
644 | mutex_unlock(&gb_inode->i_mutex); | ||
645 | |||
646 | if (gb_inode) | ||
647 | iput(gb_inode); | ||
648 | |||
649 | brelse(bh); | ||
650 | |||
651 | return status; | ||
652 | } | ||
653 | |||
654 | int ocfs2_info_handle_freefrag(struct inode *inode, | ||
655 | struct ocfs2_info_request __user *req) | ||
656 | { | ||
657 | u64 blkno = -1; | ||
658 | char namebuf[40]; | ||
659 | int status = -EFAULT, type = GLOBAL_BITMAP_SYSTEM_INODE; | ||
660 | |||
661 | struct ocfs2_info_freefrag *oiff; | ||
662 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
663 | struct inode *gb_inode = NULL; | ||
664 | |||
665 | oiff = kzalloc(sizeof(struct ocfs2_info_freefrag), GFP_KERNEL); | ||
666 | if (!oiff) { | ||
667 | status = -ENOMEM; | ||
668 | mlog_errno(status); | ||
669 | goto bail; | ||
670 | } | ||
671 | |||
672 | if (o2info_from_user(*oiff, req)) | ||
673 | goto bail; | ||
674 | /* | ||
675 | * chunksize from userspace should be power of 2. | ||
676 | */ | ||
677 | if ((oiff->iff_chunksize & (oiff->iff_chunksize - 1)) || | ||
678 | (!oiff->iff_chunksize)) { | ||
679 | status = -EINVAL; | ||
680 | goto bail; | ||
681 | } | ||
682 | |||
683 | if (o2info_coherent(&oiff->iff_req)) { | ||
684 | gb_inode = ocfs2_get_system_file_inode(osb, type, | ||
685 | OCFS2_INVALID_SLOT); | ||
686 | if (!gb_inode) { | ||
687 | mlog(ML_ERROR, "unable to get global_bitmap inode\n"); | ||
688 | status = -EIO; | ||
689 | goto bail; | ||
690 | } | ||
691 | } else { | ||
692 | ocfs2_sprintf_system_inode_name(namebuf, sizeof(namebuf), type, | ||
693 | OCFS2_INVALID_SLOT); | ||
694 | status = ocfs2_lookup_ino_from_name(osb->sys_root_inode, | ||
695 | namebuf, | ||
696 | strlen(namebuf), | ||
697 | &blkno); | ||
698 | if (status < 0) { | ||
699 | status = -ENOENT; | ||
700 | goto bail; | ||
701 | } | ||
702 | } | ||
703 | |||
704 | status = ocfs2_info_freefrag_scan_bitmap(osb, gb_inode, blkno, oiff); | ||
705 | if (status < 0) | ||
706 | goto bail; | ||
707 | |||
708 | o2info_set_request_filled(&oiff->iff_req); | ||
709 | |||
710 | if (o2info_to_user(*oiff, req)) | ||
711 | goto bail; | ||
712 | |||
713 | status = 0; | ||
714 | bail: | ||
715 | if (status) | ||
716 | o2info_set_request_error(&oiff->iff_req, req); | ||
717 | |||
718 | kfree(oiff); | ||
719 | |||
720 | return status; | ||
721 | } | ||
722 | |||
723 | int ocfs2_info_handle_unknown(struct inode *inode, | ||
724 | struct ocfs2_info_request __user *req) | ||
725 | { | ||
726 | int status = -EFAULT; | ||
727 | struct ocfs2_info_request oir; | ||
728 | |||
729 | if (o2info_from_user(oir, req)) | ||
730 | goto bail; | ||
731 | |||
732 | o2info_clear_request_filled(&oir); | ||
733 | |||
734 | if (o2info_to_user(oir, req)) | ||
735 | goto bail; | ||
736 | |||
737 | status = 0; | ||
738 | bail: | ||
739 | if (status) | ||
740 | o2info_set_request_error(&oir, req); | ||
741 | |||
742 | return status; | ||
743 | } | ||
744 | |||
745 | /* | ||
746 | * Validate and distinguish OCFS2_IOC_INFO requests. | ||
747 | * | ||
748 | * - validate the magic number. | ||
749 | * - distinguish different requests. | ||
750 | * - validate size of different requests. | ||
751 | */ | ||
752 | int ocfs2_info_handle_request(struct inode *inode, | ||
753 | struct ocfs2_info_request __user *req) | ||
754 | { | ||
755 | int status = -EFAULT; | ||
756 | struct ocfs2_info_request oir; | ||
757 | |||
758 | if (o2info_from_user(oir, req)) | ||
759 | goto bail; | ||
760 | |||
761 | status = -EINVAL; | ||
762 | if (oir.ir_magic != OCFS2_INFO_MAGIC) | ||
763 | goto bail; | ||
764 | |||
765 | switch (oir.ir_code) { | ||
766 | case OCFS2_INFO_BLOCKSIZE: | ||
767 | if (oir.ir_size == sizeof(struct ocfs2_info_blocksize)) | ||
768 | status = ocfs2_info_handle_blocksize(inode, req); | ||
769 | break; | ||
770 | case OCFS2_INFO_CLUSTERSIZE: | ||
771 | if (oir.ir_size == sizeof(struct ocfs2_info_clustersize)) | ||
772 | status = ocfs2_info_handle_clustersize(inode, req); | ||
773 | break; | ||
774 | case OCFS2_INFO_MAXSLOTS: | ||
775 | if (oir.ir_size == sizeof(struct ocfs2_info_maxslots)) | ||
776 | status = ocfs2_info_handle_maxslots(inode, req); | ||
777 | break; | ||
778 | case OCFS2_INFO_LABEL: | ||
779 | if (oir.ir_size == sizeof(struct ocfs2_info_label)) | ||
780 | status = ocfs2_info_handle_label(inode, req); | ||
781 | break; | ||
782 | case OCFS2_INFO_UUID: | ||
783 | if (oir.ir_size == sizeof(struct ocfs2_info_uuid)) | ||
784 | status = ocfs2_info_handle_uuid(inode, req); | ||
785 | break; | ||
786 | case OCFS2_INFO_FS_FEATURES: | ||
787 | if (oir.ir_size == sizeof(struct ocfs2_info_fs_features)) | ||
788 | status = ocfs2_info_handle_fs_features(inode, req); | ||
789 | break; | ||
790 | case OCFS2_INFO_JOURNAL_SIZE: | ||
791 | if (oir.ir_size == sizeof(struct ocfs2_info_journal_size)) | ||
792 | status = ocfs2_info_handle_journal_size(inode, req); | ||
793 | break; | ||
794 | case OCFS2_INFO_FREEINODE: | ||
795 | if (oir.ir_size == sizeof(struct ocfs2_info_freeinode)) | ||
796 | status = ocfs2_info_handle_freeinode(inode, req); | ||
797 | break; | ||
798 | case OCFS2_INFO_FREEFRAG: | ||
799 | if (oir.ir_size == sizeof(struct ocfs2_info_freefrag)) | ||
800 | status = ocfs2_info_handle_freefrag(inode, req); | ||
801 | break; | ||
802 | default: | ||
803 | status = ocfs2_info_handle_unknown(inode, req); | ||
804 | break; | ||
805 | } | ||
806 | |||
807 | bail: | ||
808 | return status; | ||
809 | } | ||
810 | |||
811 | int ocfs2_get_request_ptr(struct ocfs2_info *info, int idx, | ||
812 | u64 *req_addr, int compat_flag) | ||
813 | { | ||
814 | int status = -EFAULT; | ||
815 | u64 __user *bp = NULL; | ||
816 | |||
817 | if (compat_flag) { | ||
818 | #ifdef CONFIG_COMPAT | ||
819 | /* | ||
820 | * pointer bp stores the base address of a pointers array, | ||
821 | * which collects all addresses of separate request. | ||
822 | */ | ||
823 | bp = (u64 __user *)(unsigned long)compat_ptr(info->oi_requests); | ||
824 | #else | ||
825 | BUG(); | ||
826 | #endif | ||
827 | } else | ||
828 | bp = (u64 __user *)(unsigned long)(info->oi_requests); | ||
829 | |||
830 | if (o2info_from_user(*req_addr, bp + idx)) | ||
831 | goto bail; | ||
832 | |||
833 | status = 0; | ||
834 | bail: | ||
835 | return status; | ||
836 | } | ||
837 | |||
838 | /* | ||
839 | * OCFS2_IOC_INFO handles an array of requests passed from userspace. | ||
840 | * | ||
841 | * ocfs2_info_handle() recevies a large info aggregation, grab and | ||
842 | * validate the request count from header, then break it into small | ||
843 | * pieces, later specific handlers can handle them one by one. | ||
844 | * | ||
845 | * Idea here is to make each separate request small enough to ensure | ||
846 | * a better backward&forward compatibility, since a small piece of | ||
847 | * request will be less likely to be broken if disk layout get changed. | ||
848 | */ | ||
849 | int ocfs2_info_handle(struct inode *inode, struct ocfs2_info *info, | ||
850 | int compat_flag) | ||
851 | { | ||
852 | int i, status = 0; | ||
853 | u64 req_addr; | ||
854 | struct ocfs2_info_request __user *reqp; | ||
855 | |||
856 | if ((info->oi_count > OCFS2_INFO_MAX_REQUEST) || | ||
857 | (!info->oi_requests)) { | ||
858 | status = -EINVAL; | ||
859 | goto bail; | ||
860 | } | ||
861 | |||
862 | for (i = 0; i < info->oi_count; i++) { | ||
863 | |||
864 | status = ocfs2_get_request_ptr(info, i, &req_addr, compat_flag); | ||
865 | if (status) | ||
866 | break; | ||
867 | |||
868 | reqp = (struct ocfs2_info_request *)(unsigned long)req_addr; | ||
869 | if (!reqp) { | ||
870 | status = -EINVAL; | ||
871 | goto bail; | ||
872 | } | ||
873 | |||
874 | status = ocfs2_info_handle_request(inode, reqp); | ||
875 | if (status) | ||
876 | break; | ||
877 | } | ||
878 | |||
879 | bail: | ||
109 | return status; | 880 | return status; |
110 | } | 881 | } |
111 | 882 | ||
@@ -120,6 +891,7 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
120 | struct reflink_arguments args; | 891 | struct reflink_arguments args; |
121 | const char *old_path, *new_path; | 892 | const char *old_path, *new_path; |
122 | bool preserve; | 893 | bool preserve; |
894 | struct ocfs2_info info; | ||
123 | 895 | ||
124 | switch (cmd) { | 896 | switch (cmd) { |
125 | case OCFS2_IOC_GETFLAGS: | 897 | case OCFS2_IOC_GETFLAGS: |
@@ -174,6 +946,37 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
174 | preserve = (args.preserve != 0); | 946 | preserve = (args.preserve != 0); |
175 | 947 | ||
176 | return ocfs2_reflink_ioctl(inode, old_path, new_path, preserve); | 948 | return ocfs2_reflink_ioctl(inode, old_path, new_path, preserve); |
949 | case OCFS2_IOC_INFO: | ||
950 | if (copy_from_user(&info, (struct ocfs2_info __user *)arg, | ||
951 | sizeof(struct ocfs2_info))) | ||
952 | return -EFAULT; | ||
953 | |||
954 | return ocfs2_info_handle(inode, &info, 0); | ||
955 | case FITRIM: | ||
956 | { | ||
957 | struct super_block *sb = inode->i_sb; | ||
958 | struct fstrim_range range; | ||
959 | int ret = 0; | ||
960 | |||
961 | if (!capable(CAP_SYS_ADMIN)) | ||
962 | return -EPERM; | ||
963 | |||
964 | if (copy_from_user(&range, (struct fstrim_range *)arg, | ||
965 | sizeof(range))) | ||
966 | return -EFAULT; | ||
967 | |||
968 | ret = ocfs2_trim_fs(sb, &range); | ||
969 | if (ret < 0) | ||
970 | return ret; | ||
971 | |||
972 | if (copy_to_user((struct fstrim_range *)arg, &range, | ||
973 | sizeof(range))) | ||
974 | return -EFAULT; | ||
975 | |||
976 | return 0; | ||
977 | } | ||
978 | case OCFS2_IOC_MOVE_EXT: | ||
979 | return ocfs2_ioctl_move_extents(filp, (void __user *)arg); | ||
177 | default: | 980 | default: |
178 | return -ENOTTY; | 981 | return -ENOTTY; |
179 | } | 982 | } |
@@ -185,6 +988,7 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
185 | bool preserve; | 988 | bool preserve; |
186 | struct reflink_arguments args; | 989 | struct reflink_arguments args; |
187 | struct inode *inode = file->f_path.dentry->d_inode; | 990 | struct inode *inode = file->f_path.dentry->d_inode; |
991 | struct ocfs2_info info; | ||
188 | 992 | ||
189 | switch (cmd) { | 993 | switch (cmd) { |
190 | case OCFS2_IOC32_GETFLAGS: | 994 | case OCFS2_IOC32_GETFLAGS: |
@@ -200,6 +1004,7 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
200 | case OCFS2_IOC_GROUP_EXTEND: | 1004 | case OCFS2_IOC_GROUP_EXTEND: |
201 | case OCFS2_IOC_GROUP_ADD: | 1005 | case OCFS2_IOC_GROUP_ADD: |
202 | case OCFS2_IOC_GROUP_ADD64: | 1006 | case OCFS2_IOC_GROUP_ADD64: |
1007 | case FITRIM: | ||
203 | break; | 1008 | break; |
204 | case OCFS2_IOC_REFLINK: | 1009 | case OCFS2_IOC_REFLINK: |
205 | if (copy_from_user(&args, (struct reflink_arguments *)arg, | 1010 | if (copy_from_user(&args, (struct reflink_arguments *)arg, |
@@ -209,6 +1014,14 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
209 | 1014 | ||
210 | return ocfs2_reflink_ioctl(inode, compat_ptr(args.old_path), | 1015 | return ocfs2_reflink_ioctl(inode, compat_ptr(args.old_path), |
211 | compat_ptr(args.new_path), preserve); | 1016 | compat_ptr(args.new_path), preserve); |
1017 | case OCFS2_IOC_INFO: | ||
1018 | if (copy_from_user(&info, (struct ocfs2_info __user *)arg, | ||
1019 | sizeof(struct ocfs2_info))) | ||
1020 | return -EFAULT; | ||
1021 | |||
1022 | return ocfs2_info_handle(inode, &info, 1); | ||
1023 | case OCFS2_IOC_MOVE_EXT: | ||
1024 | break; | ||
212 | default: | 1025 | default: |
213 | return -ENOIOCTLCMD; | 1026 | return -ENOIOCTLCMD; |
214 | } | 1027 | } |