aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ocfs2')
-rw-r--r--fs/ocfs2/ioctl.c290
-rw-r--r--fs/ocfs2/ocfs2_ioctl.h23
2 files changed, 313 insertions, 0 deletions
diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c
index 4216739e163..fd248ed53df 100644
--- a/fs/ocfs2/ioctl.c
+++ b/fs/ocfs2/ioctl.c
@@ -25,6 +25,7 @@
25#include "sysfile.h" 25#include "sysfile.h"
26#include "dir.h" 26#include "dir.h"
27#include "buffer_head_io.h" 27#include "buffer_head_io.h"
28#include "suballoc.h"
28 29
29#include <linux/ext2_fs.h> 30#include <linux/ext2_fs.h>
30 31
@@ -433,6 +434,291 @@ bail:
433 return status; 434 return status;
434} 435}
435 436
437static void o2ffg_update_histogram(struct ocfs2_info_free_chunk_list *hist,
438 unsigned int chunksize)
439{
440 int index;
441
442 index = __ilog2_u32(chunksize);
443 if (index >= OCFS2_INFO_MAX_HIST)
444 index = OCFS2_INFO_MAX_HIST - 1;
445
446 hist->fc_chunks[index]++;
447 hist->fc_clusters[index] += chunksize;
448}
449
450static void o2ffg_update_stats(struct ocfs2_info_freefrag_stats *stats,
451 unsigned int chunksize)
452{
453 if (chunksize > stats->ffs_max)
454 stats->ffs_max = chunksize;
455
456 if (chunksize < stats->ffs_min)
457 stats->ffs_min = chunksize;
458
459 stats->ffs_avg += chunksize;
460 stats->ffs_free_chunks_real++;
461}
462
463void ocfs2_info_update_ffg(struct ocfs2_info_freefrag *ffg,
464 unsigned int chunksize)
465{
466 o2ffg_update_histogram(&(ffg->iff_ffs.ffs_fc_hist), chunksize);
467 o2ffg_update_stats(&(ffg->iff_ffs), chunksize);
468}
469
470int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb,
471 struct inode *gb_inode,
472 struct ocfs2_dinode *gb_dinode,
473 struct ocfs2_chain_rec *rec,
474 struct ocfs2_info_freefrag *ffg,
475 u32 chunks_in_group)
476{
477 int status = 0, used;
478 u64 blkno;
479
480 struct buffer_head *bh = NULL;
481 struct ocfs2_group_desc *bg = NULL;
482
483 unsigned int max_bits, num_clusters;
484 unsigned int offset = 0, cluster, chunk;
485 unsigned int chunk_free, last_chunksize = 0;
486
487 if (!le32_to_cpu(rec->c_free))
488 goto bail;
489
490 do {
491 if (!bg)
492 blkno = le64_to_cpu(rec->c_blkno);
493 else
494 blkno = le64_to_cpu(bg->bg_next_group);
495
496 if (bh) {
497 brelse(bh);
498 bh = NULL;
499 }
500
501 if (o2info_coherent(&ffg->iff_req))
502 status = ocfs2_read_group_descriptor(gb_inode,
503 gb_dinode,
504 blkno, &bh);
505 else
506 status = ocfs2_read_blocks_sync(osb, blkno, 1, &bh);
507
508 if (status < 0) {
509 mlog(ML_ERROR, "Can't read the group descriptor # "
510 "%llu from device.", (unsigned long long)blkno);
511 status = -EIO;
512 goto bail;
513 }
514
515 bg = (struct ocfs2_group_desc *)bh->b_data;
516
517 if (!le16_to_cpu(bg->bg_free_bits_count))
518 continue;
519
520 max_bits = le16_to_cpu(bg->bg_bits);
521 offset = 0;
522
523 for (chunk = 0; chunk < chunks_in_group; chunk++) {
524 /*
525 * last chunk may be not an entire one.
526 */
527 if ((offset + ffg->iff_chunksize) > max_bits)
528 num_clusters = max_bits - offset;
529 else
530 num_clusters = ffg->iff_chunksize;
531
532 chunk_free = 0;
533 for (cluster = 0; cluster < num_clusters; cluster++) {
534 used = ocfs2_test_bit(offset,
535 (unsigned long *)bg->bg_bitmap);
536 /*
537 * - chunk_free counts free clusters in #N chunk.
538 * - last_chunksize records the size(in) clusters
539 * for the last real free chunk being counted.
540 */
541 if (!used) {
542 last_chunksize++;
543 chunk_free++;
544 }
545
546 if (used && last_chunksize) {
547 ocfs2_info_update_ffg(ffg,
548 last_chunksize);
549 last_chunksize = 0;
550 }
551
552 offset++;
553 }
554
555 if (chunk_free == ffg->iff_chunksize)
556 ffg->iff_ffs.ffs_free_chunks++;
557 }
558
559 /*
560 * need to update the info for last free chunk.
561 */
562 if (last_chunksize)
563 ocfs2_info_update_ffg(ffg, last_chunksize);
564
565 } while (le64_to_cpu(bg->bg_next_group));
566
567bail:
568 brelse(bh);
569
570 return status;
571}
572
573int ocfs2_info_freefrag_scan_bitmap(struct ocfs2_super *osb,
574 struct inode *gb_inode, u64 blkno,
575 struct ocfs2_info_freefrag *ffg)
576{
577 u32 chunks_in_group;
578 int status = 0, unlock = 0, i;
579
580 struct buffer_head *bh = NULL;
581 struct ocfs2_chain_list *cl = NULL;
582 struct ocfs2_chain_rec *rec = NULL;
583 struct ocfs2_dinode *gb_dinode = NULL;
584
585 if (gb_inode)
586 mutex_lock(&gb_inode->i_mutex);
587
588 if (o2info_coherent(&ffg->iff_req)) {
589 status = ocfs2_inode_lock(gb_inode, &bh, 0);
590 if (status < 0) {
591 mlog_errno(status);
592 goto bail;
593 }
594 unlock = 1;
595 } else {
596 status = ocfs2_read_blocks_sync(osb, blkno, 1, &bh);
597 if (status < 0) {
598 mlog_errno(status);
599 goto bail;
600 }
601 }
602
603 gb_dinode = (struct ocfs2_dinode *)bh->b_data;
604 cl = &(gb_dinode->id2.i_chain);
605
606 /*
607 * Chunksize(in) clusters from userspace should be
608 * less than clusters in a group.
609 */
610 if (ffg->iff_chunksize > le16_to_cpu(cl->cl_cpg)) {
611 status = -EINVAL;
612 goto bail;
613 }
614
615 memset(&ffg->iff_ffs, 0, sizeof(struct ocfs2_info_freefrag_stats));
616
617 ffg->iff_ffs.ffs_min = ~0U;
618 ffg->iff_ffs.ffs_clusters =
619 le32_to_cpu(gb_dinode->id1.bitmap1.i_total);
620 ffg->iff_ffs.ffs_free_clusters = ffg->iff_ffs.ffs_clusters -
621 le32_to_cpu(gb_dinode->id1.bitmap1.i_used);
622
623 chunks_in_group = le16_to_cpu(cl->cl_cpg) / ffg->iff_chunksize + 1;
624
625 for (i = 0; i < le16_to_cpu(cl->cl_next_free_rec); i++) {
626 rec = &(cl->cl_recs[i]);
627 status = ocfs2_info_freefrag_scan_chain(osb, gb_inode,
628 gb_dinode,
629 rec, ffg,
630 chunks_in_group);
631 if (status)
632 goto bail;
633 }
634
635 if (ffg->iff_ffs.ffs_free_chunks_real)
636 ffg->iff_ffs.ffs_avg = (ffg->iff_ffs.ffs_avg /
637 ffg->iff_ffs.ffs_free_chunks_real);
638bail:
639 if (unlock)
640 ocfs2_inode_unlock(gb_inode, 0);
641
642 if (gb_inode)
643 mutex_unlock(&gb_inode->i_mutex);
644
645 if (gb_inode)
646 iput(gb_inode);
647
648 brelse(bh);
649
650 return status;
651}
652
653int ocfs2_info_handle_freefrag(struct inode *inode,
654 struct ocfs2_info_request __user *req)
655{
656 u64 blkno = -1;
657 char namebuf[40];
658 int status = -EFAULT, type = GLOBAL_BITMAP_SYSTEM_INODE;
659
660 struct ocfs2_info_freefrag *oiff;
661 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
662 struct inode *gb_inode = NULL;
663
664 oiff = kzalloc(sizeof(struct ocfs2_info_freefrag), GFP_KERNEL);
665 if (!oiff) {
666 status = -ENOMEM;
667 mlog_errno(status);
668 goto bail;
669 }
670
671 if (o2info_from_user(*oiff, req))
672 goto bail;
673 /*
674 * chunksize from userspace should be power of 2.
675 */
676 if ((oiff->iff_chunksize & (oiff->iff_chunksize - 1)) ||
677 (!oiff->iff_chunksize)) {
678 status = -EINVAL;
679 goto bail;
680 }
681
682 if (o2info_coherent(&oiff->iff_req)) {
683 gb_inode = ocfs2_get_system_file_inode(osb, type,
684 OCFS2_INVALID_SLOT);
685 if (!gb_inode) {
686 mlog(ML_ERROR, "unable to get global_bitmap inode\n");
687 status = -EIO;
688 goto bail;
689 }
690 } else {
691 ocfs2_sprintf_system_inode_name(namebuf, sizeof(namebuf), type,
692 OCFS2_INVALID_SLOT);
693 status = ocfs2_lookup_ino_from_name(osb->sys_root_inode,
694 namebuf,
695 strlen(namebuf),
696 &blkno);
697 if (status < 0) {
698 status = -ENOENT;
699 goto bail;
700 }
701 }
702
703 status = ocfs2_info_freefrag_scan_bitmap(osb, gb_inode, blkno, oiff);
704 if (status < 0)
705 goto bail;
706
707 o2info_set_request_filled(&oiff->iff_req);
708
709 if (o2info_to_user(*oiff, req))
710 goto bail;
711
712 status = 0;
713bail:
714 if (status)
715 o2info_set_request_error(&oiff->iff_req, req);
716
717 kfree(oiff);
718
719 return status;
720}
721
436int ocfs2_info_handle_unknown(struct inode *inode, 722int ocfs2_info_handle_unknown(struct inode *inode,
437 struct ocfs2_info_request __user *req) 723 struct ocfs2_info_request __user *req)
438{ 724{
@@ -508,6 +794,10 @@ int ocfs2_info_handle_request(struct inode *inode,
508 if (oir.ir_size == sizeof(struct ocfs2_info_freeinode)) 794 if (oir.ir_size == sizeof(struct ocfs2_info_freeinode))
509 status = ocfs2_info_handle_freeinode(inode, req); 795 status = ocfs2_info_handle_freeinode(inode, req);
510 break; 796 break;
797 case OCFS2_INFO_FREEFRAG:
798 if (oir.ir_size == sizeof(struct ocfs2_info_freefrag))
799 status = ocfs2_info_handle_freefrag(inode, req);
800 break;
511 default: 801 default:
512 status = ocfs2_info_handle_unknown(inode, req); 802 status = ocfs2_info_handle_unknown(inode, req);
513 break; 803 break;
diff --git a/fs/ocfs2/ocfs2_ioctl.h b/fs/ocfs2/ocfs2_ioctl.h
index 6b4b39a8366..18b6770dc46 100644
--- a/fs/ocfs2/ocfs2_ioctl.h
+++ b/fs/ocfs2/ocfs2_ioctl.h
@@ -152,6 +152,28 @@ struct ocfs2_info_freeinode {
152 __u32 ifi_pad; 152 __u32 ifi_pad;
153}; 153};
154 154
155#define OCFS2_INFO_MAX_HIST (32)
156
157struct ocfs2_info_freefrag {
158 struct ocfs2_info_request iff_req;
159 struct ocfs2_info_freefrag_stats { /* (out) */
160 struct ocfs2_info_free_chunk_list {
161 __u32 fc_chunks[OCFS2_INFO_MAX_HIST];
162 __u32 fc_clusters[OCFS2_INFO_MAX_HIST];
163 } ffs_fc_hist;
164 __u32 ffs_clusters;
165 __u32 ffs_free_clusters;
166 __u32 ffs_free_chunks;
167 __u32 ffs_free_chunks_real;
168 __u32 ffs_min; /* Minimum free chunksize in clusters */
169 __u32 ffs_max;
170 __u32 ffs_avg;
171 __u32 ffs_pad;
172 } iff_ffs;
173 __u32 iff_chunksize; /* chunksize in clusters(in) */
174 __u32 iff_pad;
175};
176
155/* Codes for ocfs2_info_request */ 177/* Codes for ocfs2_info_request */
156enum ocfs2_info_type { 178enum ocfs2_info_type {
157 OCFS2_INFO_CLUSTERSIZE = 1, 179 OCFS2_INFO_CLUSTERSIZE = 1,
@@ -162,6 +184,7 @@ enum ocfs2_info_type {
162 OCFS2_INFO_FS_FEATURES, 184 OCFS2_INFO_FS_FEATURES,
163 OCFS2_INFO_JOURNAL_SIZE, 185 OCFS2_INFO_JOURNAL_SIZE,
164 OCFS2_INFO_FREEINODE, 186 OCFS2_INFO_FREEINODE,
187 OCFS2_INFO_FREEFRAG,
165 OCFS2_INFO_NUM_TYPES 188 OCFS2_INFO_NUM_TYPES
166}; 189};
167 190