📄 rgrp.c
字号:
/* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License version 2. */#include <linux/slab.h>#include <linux/spinlock.h>#include <linux/completion.h>#include <linux/buffer_head.h>#include <linux/fs.h>#include <linux/gfs2_ondisk.h>#include <linux/lm_interface.h>#include "gfs2.h"#include "incore.h"#include "glock.h"#include "glops.h"#include "lops.h"#include "meta_io.h"#include "quota.h"#include "rgrp.h"#include "super.h"#include "trans.h"#include "ops_file.h"#include "util.h"#include "log.h"#include "inode.h"#define BFITNOENT ((u32)~0)#define NO_BLOCK ((u64)~0)/* * These routines are used by the resource group routines (rgrp.c) * to keep track of block allocation. Each block is represented by two * bits. So, each byte represents GFS2_NBBY (i.e. 4) blocks. * * 0 = Free * 1 = Used (not metadata) * 2 = Unlinked (still in use) inode * 3 = Used (metadata) */static const char valid_change[16] = { /* current */ /* n */ 0, 1, 1, 1, /* e */ 1, 0, 0, 0, /* w */ 0, 0, 0, 1, 1, 0, 0, 0};static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, unsigned char old_state, unsigned char new_state);/** * gfs2_setbit - Set a bit in the bitmaps * @buffer: the buffer that holds the bitmaps * @buflen: the length (in bytes) of the buffer * @block: the block to set * @new_state: the new state of the block * */static void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, unsigned int buflen, u32 block, unsigned char new_state){ unsigned char *byte, *end, cur_state; unsigned int bit; byte = buffer + (block / GFS2_NBBY); bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE; end = buffer + buflen; gfs2_assert(rgd->rd_sbd, byte < end); cur_state = (*byte >> bit) & GFS2_BIT_MASK; if (valid_change[new_state * 4 + cur_state]) { *byte ^= cur_state << bit; *byte |= new_state << bit; } else gfs2_consist_rgrpd(rgd);}/** * gfs2_testbit - test a bit in the bitmaps * @buffer: the buffer that holds the bitmaps * @buflen: the length (in bytes) of the buffer * @block: the block to read * */static unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, unsigned int buflen, u32 block){ unsigned char *byte, *end, cur_state; unsigned int bit; byte = buffer + (block / GFS2_NBBY); bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE; end = buffer + buflen; gfs2_assert(rgd->rd_sbd, byte < end); cur_state = (*byte >> bit) & GFS2_BIT_MASK; return cur_state;}/** * gfs2_bitfit - Search an rgrp's bitmap buffer to find a bit-pair representing * a block in a given allocation state. * @buffer: the buffer that holds the bitmaps * @buflen: the length (in bytes) of the buffer * @goal: start search at this block's bit-pair (within @buffer) * @old_state: GFS2_BLKST_XXX the state of the block we're looking for. * * Scope of @goal and returned block number is only within this bitmap buffer, * not entire rgrp or filesystem. @buffer will be offset from the actual * beginning of a bitmap block buffer, skipping any header structures. * * Return: the block number (bitmap buffer scope) that was found */static u32 gfs2_bitfit(struct gfs2_rgrpd *rgd, unsigned char *buffer, unsigned int buflen, u32 goal, unsigned char old_state){ unsigned char *byte, *end, alloc; u32 blk = goal; unsigned int bit; byte = buffer + (goal / GFS2_NBBY); bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE; end = buffer + buflen; alloc = (old_state == GFS2_BLKST_FREE) ? 0x55 : 0; while (byte < end) { /* If we're looking for a free block we can eliminate all bitmap settings with 0x55, which represents four data blocks in a row. If we're looking for a data block, we can eliminate 0x00 which corresponds to four free blocks. */ if ((*byte & 0x55) == alloc) { blk += (8 - bit) >> 1; bit = 0; byte++; continue; } if (((*byte >> bit) & GFS2_BIT_MASK) == old_state) return blk; bit += GFS2_BIT_SIZE; if (bit >= 8) { bit = 0; byte++; } blk++; } return BFITNOENT;}/** * gfs2_bitcount - count the number of bits in a certain state * @buffer: the buffer that holds the bitmaps * @buflen: the length (in bytes) of the buffer * @state: the state of the block we're looking for * * Returns: The number of bits */static u32 gfs2_bitcount(struct gfs2_rgrpd *rgd, unsigned char *buffer, unsigned int buflen, unsigned char state){ unsigned char *byte = buffer; unsigned char *end = buffer + buflen; unsigned char state1 = state << 2; unsigned char state2 = state << 4; unsigned char state3 = state << 6; u32 count = 0; for (; byte < end; byte++) { if (((*byte) & 0x03) == state) count++; if (((*byte) & 0x0C) == state1) count++; if (((*byte) & 0x30) == state2) count++; if (((*byte) & 0xC0) == state3) count++; } return count;}/** * gfs2_rgrp_verify - Verify that a resource group is consistent * @sdp: the filesystem * @rgd: the rgrp * */void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd){ struct gfs2_sbd *sdp = rgd->rd_sbd; struct gfs2_bitmap *bi = NULL; u32 length = rgd->rd_length; u32 count[4], tmp; int buf, x; memset(count, 0, 4 * sizeof(u32)); /* Count # blocks in each of 4 possible allocation states */ for (buf = 0; buf < length; buf++) { bi = rgd->rd_bits + buf; for (x = 0; x < 4; x++) count[x] += gfs2_bitcount(rgd, bi->bi_bh->b_data + bi->bi_offset, bi->bi_len, x); } if (count[0] != rgd->rd_rg.rg_free) { if (gfs2_consist_rgrpd(rgd)) fs_err(sdp, "free data mismatch: %u != %u\n", count[0], rgd->rd_rg.rg_free); return; } tmp = rgd->rd_data - rgd->rd_rg.rg_free - rgd->rd_rg.rg_dinodes; if (count[1] + count[2] != tmp) { if (gfs2_consist_rgrpd(rgd)) fs_err(sdp, "used data mismatch: %u != %u\n", count[1], tmp); return; } if (count[3] != rgd->rd_rg.rg_dinodes) { if (gfs2_consist_rgrpd(rgd)) fs_err(sdp, "used metadata mismatch: %u != %u\n", count[3], rgd->rd_rg.rg_dinodes); return; } if (count[2] > count[3]) { if (gfs2_consist_rgrpd(rgd)) fs_err(sdp, "unlinked inodes > inodes: %u\n", count[2]); return; }}static inline int rgrp_contains_block(struct gfs2_rgrpd *rgd, u64 block){ u64 first = rgd->rd_data0; u64 last = first + rgd->rd_data; return first <= block && block < last;}/** * gfs2_blk2rgrpd - Find resource group for a given data/meta block number * @sdp: The GFS2 superblock * @n: The data block number * * Returns: The resource group, or NULL if not found */struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk){ struct gfs2_rgrpd *rgd; spin_lock(&sdp->sd_rindex_spin); list_for_each_entry(rgd, &sdp->sd_rindex_mru_list, rd_list_mru) { if (rgrp_contains_block(rgd, blk)) { list_move(&rgd->rd_list_mru, &sdp->sd_rindex_mru_list); spin_unlock(&sdp->sd_rindex_spin); return rgd; } } spin_unlock(&sdp->sd_rindex_spin); return NULL;}/** * gfs2_rgrpd_get_first - get the first Resource Group in the filesystem * @sdp: The GFS2 superblock * * Returns: The first rgrp in the filesystem */struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp){ gfs2_assert(sdp, !list_empty(&sdp->sd_rindex_list)); return list_entry(sdp->sd_rindex_list.next, struct gfs2_rgrpd, rd_list);}/** * gfs2_rgrpd_get_next - get the next RG * @rgd: A RG * * Returns: The next rgrp */struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd){ if (rgd->rd_list.next == &rgd->rd_sbd->sd_rindex_list) return NULL; return list_entry(rgd->rd_list.next, struct gfs2_rgrpd, rd_list);}static void clear_rgrpdi(struct gfs2_sbd *sdp){ struct list_head *head; struct gfs2_rgrpd *rgd; struct gfs2_glock *gl; spin_lock(&sdp->sd_rindex_spin); sdp->sd_rindex_forward = NULL; head = &sdp->sd_rindex_recent_list; while (!list_empty(head)) { rgd = list_entry(head->next, struct gfs2_rgrpd, rd_recent); list_del(&rgd->rd_recent); } spin_unlock(&sdp->sd_rindex_spin); head = &sdp->sd_rindex_list; while (!list_empty(head)) { rgd = list_entry(head->next, struct gfs2_rgrpd, rd_list); gl = rgd->rd_gl; list_del(&rgd->rd_list); list_del(&rgd->rd_list_mru); if (gl) { gl->gl_object = NULL; gfs2_glock_put(gl); } kfree(rgd->rd_bits); kfree(rgd); }}void gfs2_clear_rgrpd(struct gfs2_sbd *sdp){ mutex_lock(&sdp->sd_rindex_mutex); clear_rgrpdi(sdp); mutex_unlock(&sdp->sd_rindex_mutex);}static void gfs2_rindex_print(const struct gfs2_rgrpd *rgd){ printk(KERN_INFO " ri_addr = %llu\n", (unsigned long long)rgd->rd_addr); printk(KERN_INFO " ri_length = %u\n", rgd->rd_length); printk(KERN_INFO " ri_data0 = %llu\n", (unsigned long long)rgd->rd_data0); printk(KERN_INFO " ri_data = %u\n", rgd->rd_data); printk(KERN_INFO " ri_bitbytes = %u\n", rgd->rd_bitbytes);}/** * gfs2_compute_bitstructs - Compute the bitmap sizes * @rgd: The resource group descriptor * * Calculates bitmap descriptors, one for each block that contains bitmap data * * Returns: errno */static int compute_bitstructs(struct gfs2_rgrpd *rgd){ struct gfs2_sbd *sdp = rgd->rd_sbd; struct gfs2_bitmap *bi; u32 length = rgd->rd_length; /* # blocks in hdr & bitmap */ u32 bytes_left, bytes; int x; if (!length) return -EINVAL; rgd->rd_bits = kcalloc(length, sizeof(struct gfs2_bitmap), GFP_NOFS); if (!rgd->rd_bits) return -ENOMEM; bytes_left = rgd->rd_bitbytes; for (x = 0; x < length; x++) { bi = rgd->rd_bits + x; /* small rgrp; bitmap stored completely in header block */ if (length == 1) { bytes = bytes_left; bi->bi_offset = sizeof(struct gfs2_rgrp); bi->bi_start = 0; bi->bi_len = bytes; /* header block */ } else if (x == 0) { bytes = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_rgrp); bi->bi_offset = sizeof(struct gfs2_rgrp); bi->bi_start = 0; bi->bi_len = bytes; /* last block */ } else if (x + 1 == length) { bytes = bytes_left; bi->bi_offset = sizeof(struct gfs2_meta_header); bi->bi_start = rgd->rd_bitbytes - bytes_left; bi->bi_len = bytes; /* other blocks */ } else { bytes = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header); bi->bi_offset = sizeof(struct gfs2_meta_header); bi->bi_start = rgd->rd_bitbytes - bytes_left; bi->bi_len = bytes; } bytes_left -= bytes; } if (bytes_left) { gfs2_consist_rgrpd(rgd); return -EIO; } bi = rgd->rd_bits + (length - 1); if ((bi->bi_start + bi->bi_len) * GFS2_NBBY != rgd->rd_data) { if (gfs2_consist_rgrpd(rgd)) { gfs2_rindex_print(rgd); fs_err(sdp, "start=%u len=%u offset=%u\n", bi->bi_start, bi->bi_len, bi->bi_offset); } return -EIO; } return 0;}/** * gfs2_ri_total - Total up the file system space, according to the rindex. * */u64 gfs2_ri_total(struct gfs2_sbd *sdp){ u64 total_data = 0; struct inode *inode = sdp->sd_rindex; struct gfs2_inode *ip = GFS2_I(inode); char buf[sizeof(struct gfs2_rindex)]; struct file_ra_state ra_state; int error, rgrps; mutex_lock(&sdp->sd_rindex_mutex); file_ra_state_init(&ra_state, inode->i_mapping); for (rgrps = 0;; rgrps++) { loff_t pos = rgrps * sizeof(struct gfs2_rindex); if (pos + sizeof(struct gfs2_rindex) >= ip->i_di.di_size) break; error = gfs2_internal_read(ip, &ra_state, buf, &pos, sizeof(struct gfs2_rindex)); if (error != sizeof(struct gfs2_rindex)) break; total_data += be32_to_cpu(((struct gfs2_rindex *)buf)->ri_data); } mutex_unlock(&sdp->sd_rindex_mutex); return total_data;}static void gfs2_rindex_in(struct gfs2_rgrpd *rgd, const void *buf){ const struct gfs2_rindex *str = buf; rgd->rd_addr = be64_to_cpu(str->ri_addr); rgd->rd_length = be32_to_cpu(str->ri_length); rgd->rd_data0 = be64_to_cpu(str->ri_data0); rgd->rd_data = be32_to_cpu(str->ri_data); rgd->rd_bitbytes = be32_to_cpu(str->ri_bitbytes);}/** * read_rindex_entry - Pull in a new resource index entry from the disk * @gl: The glock covering the rindex inode * * Returns: 0 on success, error code otherwise */static int read_rindex_entry(struct gfs2_inode *ip, struct file_ra_state *ra_state){ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); loff_t pos = sdp->sd_rgrps * sizeof(struct gfs2_rindex); char buf[sizeof(struct gfs2_rindex)]; int error; struct gfs2_rgrpd *rgd; error = gfs2_internal_read(ip, ra_state, buf, &pos, sizeof(struct gfs2_rindex)); if (!error) return 0; if (error != sizeof(struct gfs2_rindex)) { if (error > 0) error = -EIO; return error; } rgd = kzalloc(sizeof(struct gfs2_rgrpd), GFP_NOFS); error = -ENOMEM; if (!rgd) return error; mutex_init(&rgd->rd_mutex); lops_init_le(&rgd->rd_le, &gfs2_rg_lops); rgd->rd_sbd = sdp; list_add_tail(&rgd->rd_list, &sdp->sd_rindex_list); list_add_tail(&rgd->rd_list_mru, &sdp->sd_rindex_mru_list); gfs2_rindex_in(rgd, buf); error = compute_bitstructs(rgd); if (error) return error; error = gfs2_glock_get(sdp, rgd->rd_addr, &gfs2_rgrp_glops, CREATE, &rgd->rd_gl); if (error) return error; rgd->rd_gl->gl_object = rgd; rgd->rd_rg_vn = rgd->rd_gl->gl_vn - 1; rgd->rd_flags |= GFS2_RDF_CHECK; return error;}/** * gfs2_ri_update - Pull in a new resource index from the disk * @ip: pointer to the rindex inode * * Returns: 0 on successful update, error code otherwise */static int gfs2_ri_update(struct gfs2_inode *ip){ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct inode *inode = &ip->i_inode; struct file_ra_state ra_state; u64 rgrp_count = ip->i_di.di_size; int error; if (do_div(rgrp_count, sizeof(struct gfs2_rindex))) { gfs2_consist_inode(ip); return -EIO; } clear_rgrpdi(sdp); file_ra_state_init(&ra_state, inode->i_mapping); for (sdp->sd_rgrps = 0; sdp->sd_rgrps < rgrp_count; sdp->sd_rgrps++) { error = read_rindex_entry(ip, &ra_state); if (error) { clear_rgrpdi(sdp); return error; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -