diff options
Diffstat (limited to 'fs/ocfs2/alloc.c')
-rw-r--r-- | fs/ocfs2/alloc.c | 159 |
1 files changed, 96 insertions, 63 deletions
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index d1cbb27808e2..6f0999015a44 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c | |||
@@ -7532,10 +7532,11 @@ static int ocfs2_trim_group(struct super_block *sb, | |||
7532 | return count; | 7532 | return count; |
7533 | } | 7533 | } |
7534 | 7534 | ||
7535 | int ocfs2_trim_fs(struct super_block *sb, struct fstrim_range *range) | 7535 | static |
7536 | int ocfs2_trim_mainbm(struct super_block *sb, struct fstrim_range *range) | ||
7536 | { | 7537 | { |
7537 | struct ocfs2_super *osb = OCFS2_SB(sb); | 7538 | struct ocfs2_super *osb = OCFS2_SB(sb); |
7538 | u64 start, len, trimmed, first_group, last_group, group; | 7539 | u64 start, len, trimmed = 0, first_group, last_group = 0, group = 0; |
7539 | int ret, cnt; | 7540 | int ret, cnt; |
7540 | u32 first_bit, last_bit, minlen; | 7541 | u32 first_bit, last_bit, minlen; |
7541 | struct buffer_head *main_bm_bh = NULL; | 7542 | struct buffer_head *main_bm_bh = NULL; |
@@ -7543,7 +7544,6 @@ int ocfs2_trim_fs(struct super_block *sb, struct fstrim_range *range) | |||
7543 | struct buffer_head *gd_bh = NULL; | 7544 | struct buffer_head *gd_bh = NULL; |
7544 | struct ocfs2_dinode *main_bm; | 7545 | struct ocfs2_dinode *main_bm; |
7545 | struct ocfs2_group_desc *gd = NULL; | 7546 | struct ocfs2_group_desc *gd = NULL; |
7546 | struct ocfs2_trim_fs_info info, *pinfo = NULL; | ||
7547 | 7547 | ||
7548 | start = range->start >> osb->s_clustersize_bits; | 7548 | start = range->start >> osb->s_clustersize_bits; |
7549 | len = range->len >> osb->s_clustersize_bits; | 7549 | len = range->len >> osb->s_clustersize_bits; |
@@ -7552,6 +7552,9 @@ int ocfs2_trim_fs(struct super_block *sb, struct fstrim_range *range) | |||
7552 | if (minlen >= osb->bitmap_cpg || range->len < sb->s_blocksize) | 7552 | if (minlen >= osb->bitmap_cpg || range->len < sb->s_blocksize) |
7553 | return -EINVAL; | 7553 | return -EINVAL; |
7554 | 7554 | ||
7555 | trace_ocfs2_trim_mainbm(start, len, minlen); | ||
7556 | |||
7557 | next_group: | ||
7555 | main_bm_inode = ocfs2_get_system_file_inode(osb, | 7558 | main_bm_inode = ocfs2_get_system_file_inode(osb, |
7556 | GLOBAL_BITMAP_SYSTEM_INODE, | 7559 | GLOBAL_BITMAP_SYSTEM_INODE, |
7557 | OCFS2_INVALID_SLOT); | 7560 | OCFS2_INVALID_SLOT); |
@@ -7570,64 +7573,34 @@ int ocfs2_trim_fs(struct super_block *sb, struct fstrim_range *range) | |||
7570 | } | 7573 | } |
7571 | main_bm = (struct ocfs2_dinode *)main_bm_bh->b_data; | 7574 | main_bm = (struct ocfs2_dinode *)main_bm_bh->b_data; |
7572 | 7575 | ||
7573 | if (start >= le32_to_cpu(main_bm->i_clusters)) { | 7576 | /* |
7574 | ret = -EINVAL; | 7577 | * Do some check before trim the first group. |
7575 | goto out_unlock; | 7578 | */ |
7576 | } | 7579 | if (!group) { |
7577 | 7580 | if (start >= le32_to_cpu(main_bm->i_clusters)) { | |
7578 | len = range->len >> osb->s_clustersize_bits; | 7581 | ret = -EINVAL; |
7579 | if (start + len > le32_to_cpu(main_bm->i_clusters)) | ||
7580 | len = le32_to_cpu(main_bm->i_clusters) - start; | ||
7581 | |||
7582 | trace_ocfs2_trim_fs(start, len, minlen); | ||
7583 | |||
7584 | ocfs2_trim_fs_lock_res_init(osb); | ||
7585 | ret = ocfs2_trim_fs_lock(osb, NULL, 1); | ||
7586 | if (ret < 0) { | ||
7587 | if (ret != -EAGAIN) { | ||
7588 | mlog_errno(ret); | ||
7589 | ocfs2_trim_fs_lock_res_uninit(osb); | ||
7590 | goto out_unlock; | 7582 | goto out_unlock; |
7591 | } | 7583 | } |
7592 | 7584 | ||
7593 | mlog(ML_NOTICE, "Wait for trim on device (%s) to " | 7585 | if (start + len > le32_to_cpu(main_bm->i_clusters)) |
7594 | "finish, which is running from another node.\n", | 7586 | len = le32_to_cpu(main_bm->i_clusters) - start; |
7595 | osb->dev_str); | ||
7596 | ret = ocfs2_trim_fs_lock(osb, &info, 0); | ||
7597 | if (ret < 0) { | ||
7598 | mlog_errno(ret); | ||
7599 | ocfs2_trim_fs_lock_res_uninit(osb); | ||
7600 | goto out_unlock; | ||
7601 | } | ||
7602 | 7587 | ||
7603 | if (info.tf_valid && info.tf_success && | 7588 | /* |
7604 | info.tf_start == start && info.tf_len == len && | 7589 | * Determine first and last group to examine based on |
7605 | info.tf_minlen == minlen) { | 7590 | * start and len |
7606 | /* Avoid sending duplicated trim to a shared device */ | 7591 | */ |
7607 | mlog(ML_NOTICE, "The same trim on device (%s) was " | 7592 | first_group = ocfs2_which_cluster_group(main_bm_inode, start); |
7608 | "just done from node (%u), return.\n", | 7593 | if (first_group == osb->first_cluster_group_blkno) |
7609 | osb->dev_str, info.tf_nodenum); | 7594 | first_bit = start; |
7610 | range->len = info.tf_trimlen; | 7595 | else |
7611 | goto out_trimunlock; | 7596 | first_bit = start - ocfs2_blocks_to_clusters(sb, |
7612 | } | 7597 | first_group); |
7598 | last_group = ocfs2_which_cluster_group(main_bm_inode, | ||
7599 | start + len - 1); | ||
7600 | group = first_group; | ||
7613 | } | 7601 | } |
7614 | 7602 | ||
7615 | info.tf_nodenum = osb->node_num; | 7603 | do { |
7616 | info.tf_start = start; | ||
7617 | info.tf_len = len; | ||
7618 | info.tf_minlen = minlen; | ||
7619 | |||
7620 | /* Determine first and last group to examine based on start and len */ | ||
7621 | first_group = ocfs2_which_cluster_group(main_bm_inode, start); | ||
7622 | if (first_group == osb->first_cluster_group_blkno) | ||
7623 | first_bit = start; | ||
7624 | else | ||
7625 | first_bit = start - ocfs2_blocks_to_clusters(sb, first_group); | ||
7626 | last_group = ocfs2_which_cluster_group(main_bm_inode, start + len - 1); | ||
7627 | last_bit = osb->bitmap_cpg; | ||
7628 | |||
7629 | trimmed = 0; | ||
7630 | for (group = first_group; group <= last_group;) { | ||
7631 | if (first_bit + len >= osb->bitmap_cpg) | 7604 | if (first_bit + len >= osb->bitmap_cpg) |
7632 | last_bit = osb->bitmap_cpg; | 7605 | last_bit = osb->bitmap_cpg; |
7633 | else | 7606 | else |
@@ -7659,21 +7632,81 @@ int ocfs2_trim_fs(struct super_block *sb, struct fstrim_range *range) | |||
7659 | group = ocfs2_clusters_to_blocks(sb, osb->bitmap_cpg); | 7632 | group = ocfs2_clusters_to_blocks(sb, osb->bitmap_cpg); |
7660 | else | 7633 | else |
7661 | group += ocfs2_clusters_to_blocks(sb, osb->bitmap_cpg); | 7634 | group += ocfs2_clusters_to_blocks(sb, osb->bitmap_cpg); |
7662 | } | 7635 | } while (0); |
7663 | range->len = trimmed * sb->s_blocksize; | ||
7664 | 7636 | ||
7665 | info.tf_trimlen = range->len; | ||
7666 | info.tf_success = (ret ? 0 : 1); | ||
7667 | pinfo = &info; | ||
7668 | out_trimunlock: | ||
7669 | ocfs2_trim_fs_unlock(osb, pinfo); | ||
7670 | ocfs2_trim_fs_lock_res_uninit(osb); | ||
7671 | out_unlock: | 7637 | out_unlock: |
7672 | ocfs2_inode_unlock(main_bm_inode, 0); | 7638 | ocfs2_inode_unlock(main_bm_inode, 0); |
7673 | brelse(main_bm_bh); | 7639 | brelse(main_bm_bh); |
7640 | main_bm_bh = NULL; | ||
7674 | out_mutex: | 7641 | out_mutex: |
7675 | inode_unlock(main_bm_inode); | 7642 | inode_unlock(main_bm_inode); |
7676 | iput(main_bm_inode); | 7643 | iput(main_bm_inode); |
7644 | |||
7645 | /* | ||
7646 | * If all the groups trim are not done or failed, but we should release | ||
7647 | * main_bm related locks for avoiding the current IO starve, then go to | ||
7648 | * trim the next group | ||
7649 | */ | ||
7650 | if (ret >= 0 && group <= last_group) | ||
7651 | goto next_group; | ||
7677 | out: | 7652 | out: |
7653 | range->len = trimmed * sb->s_blocksize; | ||
7654 | return ret; | ||
7655 | } | ||
7656 | |||
7657 | int ocfs2_trim_fs(struct super_block *sb, struct fstrim_range *range) | ||
7658 | { | ||
7659 | int ret; | ||
7660 | struct ocfs2_super *osb = OCFS2_SB(sb); | ||
7661 | struct ocfs2_trim_fs_info info, *pinfo = NULL; | ||
7662 | |||
7663 | ocfs2_trim_fs_lock_res_init(osb); | ||
7664 | |||
7665 | trace_ocfs2_trim_fs(range->start, range->len, range->minlen); | ||
7666 | |||
7667 | ret = ocfs2_trim_fs_lock(osb, NULL, 1); | ||
7668 | if (ret < 0) { | ||
7669 | if (ret != -EAGAIN) { | ||
7670 | mlog_errno(ret); | ||
7671 | ocfs2_trim_fs_lock_res_uninit(osb); | ||
7672 | return ret; | ||
7673 | } | ||
7674 | |||
7675 | mlog(ML_NOTICE, "Wait for trim on device (%s) to " | ||
7676 | "finish, which is running from another node.\n", | ||
7677 | osb->dev_str); | ||
7678 | ret = ocfs2_trim_fs_lock(osb, &info, 0); | ||
7679 | if (ret < 0) { | ||
7680 | mlog_errno(ret); | ||
7681 | ocfs2_trim_fs_lock_res_uninit(osb); | ||
7682 | return ret; | ||
7683 | } | ||
7684 | |||
7685 | if (info.tf_valid && info.tf_success && | ||
7686 | info.tf_start == range->start && | ||
7687 | info.tf_len == range->len && | ||
7688 | info.tf_minlen == range->minlen) { | ||
7689 | /* Avoid sending duplicated trim to a shared device */ | ||
7690 | mlog(ML_NOTICE, "The same trim on device (%s) was " | ||
7691 | "just done from node (%u), return.\n", | ||
7692 | osb->dev_str, info.tf_nodenum); | ||
7693 | range->len = info.tf_trimlen; | ||
7694 | goto out; | ||
7695 | } | ||
7696 | } | ||
7697 | |||
7698 | info.tf_nodenum = osb->node_num; | ||
7699 | info.tf_start = range->start; | ||
7700 | info.tf_len = range->len; | ||
7701 | info.tf_minlen = range->minlen; | ||
7702 | |||
7703 | ret = ocfs2_trim_mainbm(sb, range); | ||
7704 | |||
7705 | info.tf_trimlen = range->len; | ||
7706 | info.tf_success = (ret < 0 ? 0 : 1); | ||
7707 | pinfo = &info; | ||
7708 | out: | ||
7709 | ocfs2_trim_fs_unlock(osb, pinfo); | ||
7710 | ocfs2_trim_fs_lock_res_uninit(osb); | ||
7678 | return ret; | 7711 | return ret; |
7679 | } | 7712 | } |