📄 alloc.c
字号:
/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * alloc.c * * Extent allocs and frees * * Copyright (C) 2002, 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */#include <linux/fs.h>#include <linux/types.h>#include <linux/slab.h>#include <linux/highmem.h>#include <linux/swap.h>#define MLOG_MASK_PREFIX ML_DISK_ALLOC#include <cluster/masklog.h>#include "ocfs2.h"#include "alloc.h"#include "aops.h"#include "dlmglue.h"#include "extent_map.h"#include "inode.h"#include "journal.h"#include "localalloc.h"#include "suballoc.h"#include "sysfile.h"#include "file.h"#include "super.h"#include "uptodate.h"#include "buffer_head_io.h"static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc);static int ocfs2_cache_extent_block_free(struct ocfs2_cached_dealloc_ctxt *ctxt, struct ocfs2_extent_block *eb);/* * Structures which describe a path through a btree, and functions to * manipulate them. * * The idea here is to be as generic as possible with the tree * manipulation code. */struct ocfs2_path_item { struct buffer_head *bh; struct ocfs2_extent_list *el;};#define OCFS2_MAX_PATH_DEPTH 5struct ocfs2_path { int p_tree_depth; struct ocfs2_path_item p_node[OCFS2_MAX_PATH_DEPTH];};#define path_root_bh(_path) ((_path)->p_node[0].bh)#define path_root_el(_path) ((_path)->p_node[0].el)#define path_leaf_bh(_path) ((_path)->p_node[(_path)->p_tree_depth].bh)#define path_leaf_el(_path) ((_path)->p_node[(_path)->p_tree_depth].el)#define path_num_items(_path) ((_path)->p_tree_depth + 1)/* * Reset the actual path elements so that we can re-use the structure * to build another path. Generally, this involves freeing the buffer * heads. */static void ocfs2_reinit_path(struct ocfs2_path *path, int keep_root){ int i, start = 0, depth = 0; struct ocfs2_path_item *node; if (keep_root) start = 1; for(i = start; i < path_num_items(path); i++) { node = &path->p_node[i]; brelse(node->bh); node->bh = NULL; node->el = NULL; } /* * Tree depth may change during truncate, or insert. If we're * keeping the root extent list, then make sure that our path * structure reflects the proper depth. */ if (keep_root) depth = le16_to_cpu(path_root_el(path)->l_tree_depth); path->p_tree_depth = depth;}static void ocfs2_free_path(struct ocfs2_path *path){ if (path) { ocfs2_reinit_path(path, 0); kfree(path); }}/* * All the elements of src into dest. After this call, src could be freed * without affecting dest. * * Both paths should have the same root. Any non-root elements of dest * will be freed. */static void ocfs2_cp_path(struct ocfs2_path *dest, struct ocfs2_path *src){ int i; BUG_ON(path_root_bh(dest) != path_root_bh(src)); BUG_ON(path_root_el(dest) != path_root_el(src)); ocfs2_reinit_path(dest, 1); for(i = 1; i < OCFS2_MAX_PATH_DEPTH; i++) { dest->p_node[i].bh = src->p_node[i].bh; dest->p_node[i].el = src->p_node[i].el; if (dest->p_node[i].bh) get_bh(dest->p_node[i].bh); }}/* * Make the *dest path the same as src and re-initialize src path to * have a root only. */static void ocfs2_mv_path(struct ocfs2_path *dest, struct ocfs2_path *src){ int i; BUG_ON(path_root_bh(dest) != path_root_bh(src)); for(i = 1; i < OCFS2_MAX_PATH_DEPTH; i++) { brelse(dest->p_node[i].bh); dest->p_node[i].bh = src->p_node[i].bh; dest->p_node[i].el = src->p_node[i].el; src->p_node[i].bh = NULL; src->p_node[i].el = NULL; }}/* * Insert an extent block at given index. * * This will not take an additional reference on eb_bh. */static inline void ocfs2_path_insert_eb(struct ocfs2_path *path, int index, struct buffer_head *eb_bh){ struct ocfs2_extent_block *eb = (struct ocfs2_extent_block *)eb_bh->b_data; /* * Right now, no root bh is an extent block, so this helps * catch code errors with dinode trees. The assertion can be * safely removed if we ever need to insert extent block * structures at the root. */ BUG_ON(index == 0); path->p_node[index].bh = eb_bh; path->p_node[index].el = &eb->h_list;}static struct ocfs2_path *ocfs2_new_path(struct buffer_head *root_bh, struct ocfs2_extent_list *root_el){ struct ocfs2_path *path; BUG_ON(le16_to_cpu(root_el->l_tree_depth) >= OCFS2_MAX_PATH_DEPTH); path = kzalloc(sizeof(*path), GFP_NOFS); if (path) { path->p_tree_depth = le16_to_cpu(root_el->l_tree_depth); get_bh(root_bh); path_root_bh(path) = root_bh; path_root_el(path) = root_el; } return path;}/* * Allocate and initialize a new path based on a disk inode tree. */static struct ocfs2_path *ocfs2_new_inode_path(struct buffer_head *di_bh){ struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; struct ocfs2_extent_list *el = &di->id2.i_list; return ocfs2_new_path(di_bh, el);}/* * Convenience function to journal all components in a path. */static int ocfs2_journal_access_path(struct inode *inode, handle_t *handle, struct ocfs2_path *path){ int i, ret = 0; if (!path) goto out; for(i = 0; i < path_num_items(path); i++) { ret = ocfs2_journal_access(handle, inode, path->p_node[i].bh, OCFS2_JOURNAL_ACCESS_WRITE); if (ret < 0) { mlog_errno(ret); goto out; } }out: return ret;}/* * Return the index of the extent record which contains cluster #v_cluster. * -1 is returned if it was not found. * * Should work fine on interior and exterior nodes. */int ocfs2_search_extent_list(struct ocfs2_extent_list *el, u32 v_cluster){ int ret = -1; int i; struct ocfs2_extent_rec *rec; u32 rec_end, rec_start, clusters; for(i = 0; i < le16_to_cpu(el->l_next_free_rec); i++) { rec = &el->l_recs[i]; rec_start = le32_to_cpu(rec->e_cpos); clusters = ocfs2_rec_clusters(el, rec); rec_end = rec_start + clusters; if (v_cluster >= rec_start && v_cluster < rec_end) { ret = i; break; } } return ret;}enum ocfs2_contig_type { CONTIG_NONE = 0, CONTIG_LEFT, CONTIG_RIGHT, CONTIG_LEFTRIGHT,};/* * NOTE: ocfs2_block_extent_contig(), ocfs2_extents_adjacent() and * ocfs2_extent_contig only work properly against leaf nodes! */static int ocfs2_block_extent_contig(struct super_block *sb, struct ocfs2_extent_rec *ext, u64 blkno){ u64 blk_end = le64_to_cpu(ext->e_blkno); blk_end += ocfs2_clusters_to_blocks(sb, le16_to_cpu(ext->e_leaf_clusters)); return blkno == blk_end;}static int ocfs2_extents_adjacent(struct ocfs2_extent_rec *left, struct ocfs2_extent_rec *right){ u32 left_range; left_range = le32_to_cpu(left->e_cpos) + le16_to_cpu(left->e_leaf_clusters); return (left_range == le32_to_cpu(right->e_cpos));}static enum ocfs2_contig_type ocfs2_extent_contig(struct inode *inode, struct ocfs2_extent_rec *ext, struct ocfs2_extent_rec *insert_rec){ u64 blkno = le64_to_cpu(insert_rec->e_blkno); /* * Refuse to coalesce extent records with different flag * fields - we don't want to mix unwritten extents with user * data. */ if (ext->e_flags != insert_rec->e_flags) return CONTIG_NONE; if (ocfs2_extents_adjacent(ext, insert_rec) && ocfs2_block_extent_contig(inode->i_sb, ext, blkno)) return CONTIG_RIGHT; blkno = le64_to_cpu(ext->e_blkno); if (ocfs2_extents_adjacent(insert_rec, ext) && ocfs2_block_extent_contig(inode->i_sb, insert_rec, blkno)) return CONTIG_LEFT; return CONTIG_NONE;}/* * NOTE: We can have pretty much any combination of contiguousness and * appending. * * The usefulness of APPEND_TAIL is more in that it lets us know that * we'll have to update the path to that leaf. */enum ocfs2_append_type { APPEND_NONE = 0, APPEND_TAIL,};enum ocfs2_split_type { SPLIT_NONE = 0, SPLIT_LEFT, SPLIT_RIGHT,};struct ocfs2_insert_type { enum ocfs2_split_type ins_split; enum ocfs2_append_type ins_appending; enum ocfs2_contig_type ins_contig; int ins_contig_index; int ins_tree_depth;};struct ocfs2_merge_ctxt { enum ocfs2_contig_type c_contig_type; int c_has_empty_extent; int c_split_covers_rec;};/* * How many free extents have we got before we need more meta data? */int ocfs2_num_free_extents(struct ocfs2_super *osb, struct inode *inode, struct ocfs2_dinode *fe){ int retval; struct ocfs2_extent_list *el; struct ocfs2_extent_block *eb; struct buffer_head *eb_bh = NULL; mlog_entry_void(); if (!OCFS2_IS_VALID_DINODE(fe)) { OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, fe); retval = -EIO; goto bail; } if (fe->i_last_eb_blk) { retval = ocfs2_read_block(osb, le64_to_cpu(fe->i_last_eb_blk), &eb_bh, OCFS2_BH_CACHED, inode); if (retval < 0) { mlog_errno(retval); goto bail; } eb = (struct ocfs2_extent_block *) eb_bh->b_data; el = &eb->h_list; } else el = &fe->id2.i_list; BUG_ON(el->l_tree_depth != 0); retval = le16_to_cpu(el->l_count) - le16_to_cpu(el->l_next_free_rec);bail: if (eb_bh) brelse(eb_bh); mlog_exit(retval); return retval;}/* expects array to already be allocated * * sets h_signature, h_blkno, h_suballoc_bit, h_suballoc_slot, and * l_count for you */static int ocfs2_create_new_meta_bhs(struct ocfs2_super *osb, handle_t *handle, struct inode *inode, int wanted, struct ocfs2_alloc_context *meta_ac, struct buffer_head *bhs[]){ int count, status, i; u16 suballoc_bit_start; u32 num_got; u64 first_blkno; struct ocfs2_extent_block *eb; mlog_entry_void(); count = 0; while (count < wanted) { status = ocfs2_claim_metadata(osb, handle, meta_ac, wanted - count, &suballoc_bit_start, &num_got, &first_blkno); if (status < 0) { mlog_errno(status); goto bail; } for(i = count; i < (num_got + count); i++) { bhs[i] = sb_getblk(osb->sb, first_blkno); if (bhs[i] == NULL) { status = -EIO; mlog_errno(status); goto bail; } ocfs2_set_new_buffer_uptodate(inode, bhs[i]); status = ocfs2_journal_access(handle, inode, bhs[i], OCFS2_JOURNAL_ACCESS_CREATE); if (status < 0) { mlog_errno(status); goto bail; } memset(bhs[i]->b_data, 0, osb->sb->s_blocksize); eb = (struct ocfs2_extent_block *) bhs[i]->b_data; /* Ok, setup the minimal stuff here. */ strcpy(eb->h_signature, OCFS2_EXTENT_BLOCK_SIGNATURE); eb->h_blkno = cpu_to_le64(first_blkno); eb->h_fs_generation = cpu_to_le32(osb->fs_generation); eb->h_suballoc_slot = cpu_to_le16(osb->slot_num); eb->h_suballoc_bit = cpu_to_le16(suballoc_bit_start); eb->h_list.l_count = cpu_to_le16(ocfs2_extent_recs_per_eb(osb->sb)); suballoc_bit_start++; first_blkno++; /* We'll also be dirtied by the caller, so * this isn't absolutely necessary. */ status = ocfs2_journal_dirty(handle, bhs[i]); if (status < 0) { mlog_errno(status); goto bail; } } count += num_got; } status = 0;bail: if (status < 0) { for(i = 0; i < wanted; i++) { if (bhs[i]) brelse(bhs[i]); bhs[i] = NULL; } } mlog_exit(status); return status;}/* * Helper function for ocfs2_add_branch() and ocfs2_shift_tree_depth(). * * Returns the sum of the rightmost extent rec logical offset and * cluster count. * * ocfs2_add_branch() uses this to determine what logical cluster * value should be populated into the leftmost new branch records.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -