aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2
diff options
context:
space:
mode:
authorTristan Ye <tristan.ye@oracle.com>2011-05-24 03:27:17 -0400
committerTristan Ye <tristan.ye@oracle.com>2011-05-25 00:18:07 -0400
commitd24a10b9f8ed548981696cd36e2b4f16e6f360b1 (patch)
tree4189d2be951b63a6ff480fdabd031605ce342e92 /fs/ocfs2
parent3e5db17d4da7f45c454940096d9e429cca12ef9f (diff)
Ocfs2: Add a new code 'OCFS2_INFO_FREEFRAG' for o2info ioctl.
This new code is a bit more complicated than former ones, the goal is to show user all statistics required to take a deep insight into filesystem on how the disk is being fragmentaed. The goal is achieved by scaning global bitmap from (cluster)group to group to figure out following factors in the filesystem: - How many free chunks in a fixed size as user requested. - How many real free chunks in all size. - Min/Max/Avg size(in) clusters of free chunks. - How do free chunks distribute(in size) in terms of a histogram, just like following: --------------------------------------------------------- Extent Size Range : Free extents Free Clusters Percent 32K... 64K- : 1 1 0.00% 1M... 2M- : 9 288 0.03% 8M... 16M- : 2 831 0.09% 32M... 64M- : 1 2047 0.23% 128M... 256M- : 1 8191 0.92% 256M... 512M- : 2 21706 2.43% 512M... 1024M- : 27 858623 96.29% --------------------------------------------------------- Userspace ioctl() call eventually gets the above info returned by passing a 'struct ocfs2_info_freefrag' with the chunk_size being specified first. Signed-off-by: Tristan Ye <tristan.ye@oracle.com>
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