⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rgrp.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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 + -