12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042 |
- /* -*- 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>
- #define MLOG_MASK_PREFIX ML_DISK_ALLOC
- #include <cluster/masklog.h>
- #include "ocfs2.h"
- #include "alloc.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 int ocfs2_extent_contig(struct inode *inode,
- struct ocfs2_extent_rec *ext,
- u64 blkno);
- static int ocfs2_create_new_meta_bhs(struct ocfs2_super *osb,
- struct ocfs2_journal_handle *handle,
- struct inode *inode,
- int wanted,
- struct ocfs2_alloc_context *meta_ac,
- struct buffer_head *bhs[]);
- static int ocfs2_add_branch(struct ocfs2_super *osb,
- struct ocfs2_journal_handle *handle,
- struct inode *inode,
- struct buffer_head *fe_bh,
- struct buffer_head *eb_bh,
- struct buffer_head *last_eb_bh,
- struct ocfs2_alloc_context *meta_ac);
- static int ocfs2_shift_tree_depth(struct ocfs2_super *osb,
- struct ocfs2_journal_handle *handle,
- struct inode *inode,
- struct buffer_head *fe_bh,
- struct ocfs2_alloc_context *meta_ac,
- struct buffer_head **ret_new_eb_bh);
- static int ocfs2_do_insert_extent(struct ocfs2_super *osb,
- struct ocfs2_journal_handle *handle,
- struct inode *inode,
- struct buffer_head *fe_bh,
- u64 blkno,
- u32 new_clusters);
- static int ocfs2_find_branch_target(struct ocfs2_super *osb,
- struct inode *inode,
- struct buffer_head *fe_bh,
- struct buffer_head **target_bh);
- static int ocfs2_find_new_last_ext_blk(struct ocfs2_super *osb,
- struct inode *inode,
- struct ocfs2_dinode *fe,
- unsigned int new_i_clusters,
- struct buffer_head *old_last_eb,
- struct buffer_head **new_last_eb);
- static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc);
- static int ocfs2_extent_contig(struct inode *inode,
- struct ocfs2_extent_rec *ext,
- u64 blkno)
- {
- return blkno == (le64_to_cpu(ext->e_blkno) +
- ocfs2_clusters_to_blocks(inode->i_sb,
- le32_to_cpu(ext->e_clusters)));
- }
- /*
- * 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,
- struct ocfs2_journal_handle *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);
- #ifndef OCFS2_USE_ALL_METADATA_SUBALLOCATORS
- /* we always use slot zero's suballocator */
- eb->h_suballoc_slot = 0;
- #else
- eb->h_suballoc_slot = cpu_to_le16(osb->slot_num);
- #endif
- 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;
- }
- /*
- * Add an entire tree branch to our inode. eb_bh is the extent block
- * to start at, if we don't want to start the branch at the dinode
- * structure.
- *
- * last_eb_bh is required as we have to update it's next_leaf pointer
- * for the new last extent block.
- *
- * the new branch will be 'empty' in the sense that every block will
- * contain a single record with e_clusters == 0.
- */
- static int ocfs2_add_branch(struct ocfs2_super *osb,
- struct ocfs2_journal_handle *handle,
- struct inode *inode,
- struct buffer_head *fe_bh,
- struct buffer_head *eb_bh,
- struct buffer_head *last_eb_bh,
- struct ocfs2_alloc_context *meta_ac)
- {
- int status, new_blocks, i;
- u64 next_blkno, new_last_eb_blk;
- struct buffer_head *bh;
- struct buffer_head **new_eb_bhs = NULL;
- struct ocfs2_dinode *fe;
- struct ocfs2_extent_block *eb;
- struct ocfs2_extent_list *eb_el;
- struct ocfs2_extent_list *el;
- mlog_entry_void();
- BUG_ON(!last_eb_bh);
- fe = (struct ocfs2_dinode *) fe_bh->b_data;
- if (eb_bh) {
- eb = (struct ocfs2_extent_block *) eb_bh->b_data;
- el = &eb->h_list;
- } else
- el = &fe->id2.i_list;
- /* we never add a branch to a leaf. */
- BUG_ON(!el->l_tree_depth);
- new_blocks = le16_to_cpu(el->l_tree_depth);
- /* allocate the number of new eb blocks we need */
- new_eb_bhs = kcalloc(new_blocks, sizeof(struct buffer_head *),
- GFP_KERNEL);
- if (!new_eb_bhs) {
- status = -ENOMEM;
- mlog_errno(status);
- goto bail;
- }
- status = ocfs2_create_new_meta_bhs(osb, handle, inode, new_blocks,
- meta_ac, new_eb_bhs);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- /* Note: new_eb_bhs[new_blocks - 1] is the guy which will be
- * linked with the rest of the tree.
- * conversly, new_eb_bhs[0] is the new bottommost leaf.
- *
- * when we leave the loop, new_last_eb_blk will point to the
- * newest leaf, and next_blkno will point to the topmost extent
- * block. */
- next_blkno = new_last_eb_blk = 0;
- for(i = 0; i < new_blocks; i++) {
- bh = new_eb_bhs[i];
- eb = (struct ocfs2_extent_block *) bh->b_data;
- if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
- OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
- status = -EIO;
- goto bail;
- }
- eb_el = &eb->h_list;
- status = ocfs2_journal_access(handle, inode, bh,
- OCFS2_JOURNAL_ACCESS_CREATE);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- eb->h_next_leaf_blk = 0;
- eb_el->l_tree_depth = cpu_to_le16(i);
- eb_el->l_next_free_rec = cpu_to_le16(1);
- eb_el->l_recs[0].e_cpos = fe->i_clusters;
- eb_el->l_recs[0].e_blkno = cpu_to_le64(next_blkno);
- eb_el->l_recs[0].e_clusters = cpu_to_le32(0);
- if (!eb_el->l_tree_depth)
- new_last_eb_blk = le64_to_cpu(eb->h_blkno);
- status = ocfs2_journal_dirty(handle, bh);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- next_blkno = le64_to_cpu(eb->h_blkno);
- }
- /* This is a bit hairy. We want to update up to three blocks
- * here without leaving any of them in an inconsistent state
- * in case of error. We don't have to worry about
- * journal_dirty erroring as it won't unless we've aborted the
- * handle (in which case we would never be here) so reserving
- * the write with journal_access is all we need to do. */
- status = ocfs2_journal_access(handle, inode, last_eb_bh,
- OCFS2_JOURNAL_ACCESS_WRITE);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- status = ocfs2_journal_access(handle, inode, fe_bh,
- OCFS2_JOURNAL_ACCESS_WRITE);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- if (eb_bh) {
- status = ocfs2_journal_access(handle, inode, eb_bh,
- OCFS2_JOURNAL_ACCESS_WRITE);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- }
- /* Link the new branch into the rest of the tree (el will
- * either be on the fe, or the extent block passed in. */
- i = le16_to_cpu(el->l_next_free_rec);
- el->l_recs[i].e_blkno = cpu_to_le64(next_blkno);
- el->l_recs[i].e_cpos = fe->i_clusters;
- el->l_recs[i].e_clusters = 0;
- le16_add_cpu(&el->l_next_free_rec, 1);
- /* fe needs a new last extent block pointer, as does the
- * next_leaf on the previously last-extent-block. */
- fe->i_last_eb_blk = cpu_to_le64(new_last_eb_blk);
- eb = (struct ocfs2_extent_block *) last_eb_bh->b_data;
- eb->h_next_leaf_blk = cpu_to_le64(new_last_eb_blk);
- status = ocfs2_journal_dirty(handle, last_eb_bh);
- if (status < 0)
- mlog_errno(status);
- status = ocfs2_journal_dirty(handle, fe_bh);
- if (status < 0)
- mlog_errno(status);
- if (eb_bh) {
- status = ocfs2_journal_dirty(handle, eb_bh);
- if (status < 0)
- mlog_errno(status);
- }
- status = 0;
- bail:
- if (new_eb_bhs) {
- for (i = 0; i < new_blocks; i++)
- if (new_eb_bhs[i])
- brelse(new_eb_bhs[i]);
- kfree(new_eb_bhs);
- }
- mlog_exit(status);
- return status;
- }
- /*
- * adds another level to the allocation tree.
- * returns back the new extent block so you can add a branch to it
- * after this call.
- */
- static int ocfs2_shift_tree_depth(struct ocfs2_super *osb,
- struct ocfs2_journal_handle *handle,
- struct inode *inode,
- struct buffer_head *fe_bh,
- struct ocfs2_alloc_context *meta_ac,
- struct buffer_head **ret_new_eb_bh)
- {
- int status, i;
- struct buffer_head *new_eb_bh = NULL;
- struct ocfs2_dinode *fe;
- struct ocfs2_extent_block *eb;
- struct ocfs2_extent_list *fe_el;
- struct ocfs2_extent_list *eb_el;
- mlog_entry_void();
- status = ocfs2_create_new_meta_bhs(osb, handle, inode, 1, meta_ac,
- &new_eb_bh);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- eb = (struct ocfs2_extent_block *) new_eb_bh->b_data;
- if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
- OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
- status = -EIO;
- goto bail;
- }
- eb_el = &eb->h_list;
- fe = (struct ocfs2_dinode *) fe_bh->b_data;
- fe_el = &fe->id2.i_list;
- status = ocfs2_journal_access(handle, inode, new_eb_bh,
- OCFS2_JOURNAL_ACCESS_CREATE);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- /* copy the fe data into the new extent block */
- eb_el->l_tree_depth = fe_el->l_tree_depth;
- eb_el->l_next_free_rec = fe_el->l_next_free_rec;
- for(i = 0; i < le16_to_cpu(fe_el->l_next_free_rec); i++) {
- eb_el->l_recs[i].e_cpos = fe_el->l_recs[i].e_cpos;
- eb_el->l_recs[i].e_clusters = fe_el->l_recs[i].e_clusters;
- eb_el->l_recs[i].e_blkno = fe_el->l_recs[i].e_blkno;
- }
- status = ocfs2_journal_dirty(handle, new_eb_bh);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- status = ocfs2_journal_access(handle, inode, fe_bh,
- OCFS2_JOURNAL_ACCESS_WRITE);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- /* update fe now */
- le16_add_cpu(&fe_el->l_tree_depth, 1);
- fe_el->l_recs[0].e_cpos = 0;
- fe_el->l_recs[0].e_blkno = eb->h_blkno;
- fe_el->l_recs[0].e_clusters = fe->i_clusters;
- for(i = 1; i < le16_to_cpu(fe_el->l_next_free_rec); i++) {
- fe_el->l_recs[i].e_cpos = 0;
- fe_el->l_recs[i].e_clusters = 0;
- fe_el->l_recs[i].e_blkno = 0;
- }
- fe_el->l_next_free_rec = cpu_to_le16(1);
- /* If this is our 1st tree depth shift, then last_eb_blk
- * becomes the allocated extent block */
- if (fe_el->l_tree_depth == cpu_to_le16(1))
- fe->i_last_eb_blk = eb->h_blkno;
- status = ocfs2_journal_dirty(handle, fe_bh);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- *ret_new_eb_bh = new_eb_bh;
- new_eb_bh = NULL;
- status = 0;
- bail:
- if (new_eb_bh)
- brelse(new_eb_bh);
- mlog_exit(status);
- return status;
- }
- /*
- * Expects the tree to already have room in the rightmost leaf for the
- * extent. Updates all the extent blocks (and the dinode) on the way
- * down.
- */
- static int ocfs2_do_insert_extent(struct ocfs2_super *osb,
- struct ocfs2_journal_handle *handle,
- struct inode *inode,
- struct buffer_head *fe_bh,
- u64 start_blk,
- u32 new_clusters)
- {
- int status, i, num_bhs = 0;
- u64 next_blkno;
- u16 next_free;
- struct buffer_head **eb_bhs = NULL;
- struct ocfs2_dinode *fe;
- struct ocfs2_extent_block *eb;
- struct ocfs2_extent_list *el;
- mlog_entry_void();
- status = ocfs2_journal_access(handle, inode, fe_bh,
- OCFS2_JOURNAL_ACCESS_WRITE);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- fe = (struct ocfs2_dinode *) fe_bh->b_data;
- el = &fe->id2.i_list;
- if (el->l_tree_depth) {
- /* This is another operation where we want to be
- * careful about our tree updates. An error here means
- * none of the previous changes we made should roll
- * forward. As a result, we have to record the buffers
- * for this part of the tree in an array and reserve a
- * journal write to them before making any changes. */
- num_bhs = le16_to_cpu(fe->id2.i_list.l_tree_depth);
- eb_bhs = kcalloc(num_bhs, sizeof(struct buffer_head *),
- GFP_KERNEL);
- if (!eb_bhs) {
- status = -ENOMEM;
- mlog_errno(status);
- goto bail;
- }
- i = 0;
- while(el->l_tree_depth) {
- next_free = le16_to_cpu(el->l_next_free_rec);
- if (next_free == 0) {
- ocfs2_error(inode->i_sb,
- "Dinode %llu has a bad extent list",
- (unsigned long long)OCFS2_I(inode)->ip_blkno);
- status = -EIO;
- goto bail;
- }
- next_blkno = le64_to_cpu(el->l_recs[next_free - 1].e_blkno);
- BUG_ON(i >= num_bhs);
- status = ocfs2_read_block(osb, next_blkno, &eb_bhs[i],
- OCFS2_BH_CACHED, inode);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- eb = (struct ocfs2_extent_block *) eb_bhs[i]->b_data;
- if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
- OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb,
- eb);
- status = -EIO;
- goto bail;
- }
- status = ocfs2_journal_access(handle, inode, eb_bhs[i],
- OCFS2_JOURNAL_ACCESS_WRITE);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- el = &eb->h_list;
- i++;
- /* When we leave this loop, eb_bhs[num_bhs - 1] will
- * hold the bottom-most leaf extent block. */
- }
- BUG_ON(el->l_tree_depth);
- el = &fe->id2.i_list;
- /* If we have tree depth, then the fe update is
- * trivial, and we want to switch el out for the
- * bottom-most leaf in order to update it with the
- * actual extent data below. */
- next_free = le16_to_cpu(el->l_next_free_rec);
- if (next_free == 0) {
- ocfs2_error(inode->i_sb,
- "Dinode %llu has a bad extent list",
- (unsigned long long)OCFS2_I(inode)->ip_blkno);
- status = -EIO;
- goto bail;
- }
- le32_add_cpu(&el->l_recs[next_free - 1].e_clusters,
- new_clusters);
- /* (num_bhs - 1) to avoid the leaf */
- for(i = 0; i < (num_bhs - 1); i++) {
- eb = (struct ocfs2_extent_block *) eb_bhs[i]->b_data;
- el = &eb->h_list;
- /* finally, make our actual change to the
- * intermediate extent blocks. */
- next_free = le16_to_cpu(el->l_next_free_rec);
- le32_add_cpu(&el->l_recs[next_free - 1].e_clusters,
- new_clusters);
- status = ocfs2_journal_dirty(handle, eb_bhs[i]);
- if (status < 0)
- mlog_errno(status);
- }
- BUG_ON(i != (num_bhs - 1));
- /* note that the leaf block wasn't touched in
- * the loop above */
- eb = (struct ocfs2_extent_block *) eb_bhs[num_bhs - 1]->b_data;
- el = &eb->h_list;
- BUG_ON(el->l_tree_depth);
- }
- /* yay, we can finally add the actual extent now! */
- i = le16_to_cpu(el->l_next_free_rec) - 1;
- if (le16_to_cpu(el->l_next_free_rec) &&
- ocfs2_extent_contig(inode, &el->l_recs[i], start_blk)) {
- le32_add_cpu(&el->l_recs[i].e_clusters, new_clusters);
- } else if (le16_to_cpu(el->l_next_free_rec) &&
- (le32_to_cpu(el->l_recs[i].e_clusters) == 0)) {
- /* having an empty extent at eof is legal. */
- if (el->l_recs[i].e_cpos != fe->i_clusters) {
- ocfs2_error(inode->i_sb,
- "Dinode %llu trailing extent is bad: "
- "cpos (%u) != number of clusters (%u)",
- (unsigned long long)OCFS2_I(inode)->ip_blkno,
- le32_to_cpu(el->l_recs[i].e_cpos),
- le32_to_cpu(fe->i_clusters));
- status = -EIO;
- goto bail;
- }
- el->l_recs[i].e_blkno = cpu_to_le64(start_blk);
- el->l_recs[i].e_clusters = cpu_to_le32(new_clusters);
- } else {
- /* No contiguous record, or no empty record at eof, so
- * we add a new one. */
- BUG_ON(le16_to_cpu(el->l_next_free_rec) >=
- le16_to_cpu(el->l_count));
- i = le16_to_cpu(el->l_next_free_rec);
- el->l_recs[i].e_blkno = cpu_to_le64(start_blk);
- el->l_recs[i].e_clusters = cpu_to_le32(new_clusters);
- el->l_recs[i].e_cpos = fe->i_clusters;
- le16_add_cpu(&el->l_next_free_rec, 1);
- }
- /*
- * extent_map errors are not fatal, so they are ignored outside
- * of flushing the thing.
- */
- status = ocfs2_extent_map_append(inode, &el->l_recs[i],
- new_clusters);
- if (status) {
- mlog_errno(status);
- ocfs2_extent_map_drop(inode, le32_to_cpu(fe->i_clusters));
- }
- status = ocfs2_journal_dirty(handle, fe_bh);
- if (status < 0)
- mlog_errno(status);
- if (fe->id2.i_list.l_tree_depth) {
- status = ocfs2_journal_dirty(handle, eb_bhs[num_bhs - 1]);
- if (status < 0)
- mlog_errno(status);
- }
- status = 0;
- bail:
- if (eb_bhs) {
- for (i = 0; i < num_bhs; i++)
- if (eb_bhs[i])
- brelse(eb_bhs[i]);
- kfree(eb_bhs);
- }
- mlog_exit(status);
- return status;
- }
- /*
- * Should only be called when there is no space left in any of the
- * leaf nodes. What we want to do is find the lowest tree depth
- * non-leaf extent block with room for new records. There are three
- * valid results of this search:
- *
- * 1) a lowest extent block is found, then we pass it back in
- * *lowest_eb_bh and return '0'
- *
- * 2) the search fails to find anything, but the dinode has room. We
- * pass NULL back in *lowest_eb_bh, but still return '0'
- *
- * 3) the search fails to find anything AND the dinode is full, in
- * which case we return > 0
- *
- * return status < 0 indicates an error.
- */
- static int ocfs2_find_branch_target(struct ocfs2_super *osb,
- struct inode *inode,
- struct buffer_head *fe_bh,
- struct buffer_head **target_bh)
- {
- int status = 0, i;
- u64 blkno;
- struct ocfs2_dinode *fe;
- struct ocfs2_extent_block *eb;
- struct ocfs2_extent_list *el;
- struct buffer_head *bh = NULL;
- struct buffer_head *lowest_bh = NULL;
- mlog_entry_void();
- *target_bh = NULL;
- fe = (struct ocfs2_dinode *) fe_bh->b_data;
- el = &fe->id2.i_list;
- while(le16_to_cpu(el->l_tree_depth) > 1) {
- if (le16_to_cpu(el->l_next_free_rec) == 0) {
- ocfs2_error(inode->i_sb, "Dinode %llu has empty "
- "extent list (next_free_rec == 0)",
- (unsigned long long)OCFS2_I(inode)->ip_blkno);
- status = -EIO;
- goto bail;
- }
- i = le16_to_cpu(el->l_next_free_rec) - 1;
- blkno = le64_to_cpu(el->l_recs[i].e_blkno);
- if (!blkno) {
- ocfs2_error(inode->i_sb, "Dinode %llu has extent "
- "list where extent # %d has no physical "
- "block start",
- (unsigned long long)OCFS2_I(inode)->ip_blkno, i);
- status = -EIO;
- goto bail;
- }
- if (bh) {
- brelse(bh);
- bh = NULL;
- }
- status = ocfs2_read_block(osb, blkno, &bh, OCFS2_BH_CACHED,
- inode);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- eb = (struct ocfs2_extent_block *) bh->b_data;
- if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
- OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
- status = -EIO;
- goto bail;
- }
- el = &eb->h_list;
- if (le16_to_cpu(el->l_next_free_rec) <
- le16_to_cpu(el->l_count)) {
- if (lowest_bh)
- brelse(lowest_bh);
- lowest_bh = bh;
- get_bh(lowest_bh);
- }
- }
- /* If we didn't find one and the fe doesn't have any room,
- * then return '1' */
- if (!lowest_bh
- && (fe->id2.i_list.l_next_free_rec == fe->id2.i_list.l_count))
- status = 1;
- *target_bh = lowest_bh;
- bail:
- if (bh)
- brelse(bh);
- mlog_exit(status);
- return status;
- }
- /* the caller needs to update fe->i_clusters */
- int ocfs2_insert_extent(struct ocfs2_super *osb,
- struct ocfs2_journal_handle *handle,
- struct inode *inode,
- struct buffer_head *fe_bh,
- u64 start_blk,
- u32 new_clusters,
- struct ocfs2_alloc_context *meta_ac)
- {
- int status, i, shift;
- struct buffer_head *last_eb_bh = NULL;
- struct buffer_head *bh = NULL;
- struct ocfs2_dinode *fe;
- struct ocfs2_extent_block *eb;
- struct ocfs2_extent_list *el;
- mlog_entry_void();
- mlog(0, "add %u clusters starting at block %llu to inode %llu\n",
- new_clusters, (unsigned long long)start_blk,
- (unsigned long long)OCFS2_I(inode)->ip_blkno);
- fe = (struct ocfs2_dinode *) fe_bh->b_data;
- el = &fe->id2.i_list;
- if (el->l_tree_depth) {
- /* jump to end of tree */
- status = ocfs2_read_block(osb, le64_to_cpu(fe->i_last_eb_blk),
- &last_eb_bh, OCFS2_BH_CACHED, inode);
- if (status < 0) {
- mlog_exit(status);
- goto bail;
- }
- eb = (struct ocfs2_extent_block *) last_eb_bh->b_data;
- el = &eb->h_list;
- }
- /* Can we allocate without adding/shifting tree bits? */
- i = le16_to_cpu(el->l_next_free_rec) - 1;
- if (le16_to_cpu(el->l_next_free_rec) == 0
- || (le16_to_cpu(el->l_next_free_rec) < le16_to_cpu(el->l_count))
- || le32_to_cpu(el->l_recs[i].e_clusters) == 0
- || ocfs2_extent_contig(inode, &el->l_recs[i], start_blk))
- goto out_add;
- mlog(0, "ocfs2_allocate_extent: couldn't do a simple add, traversing "
- "tree now.\n");
- shift = ocfs2_find_branch_target(osb, inode, fe_bh, &bh);
- if (shift < 0) {
- status = shift;
- mlog_errno(status);
- goto bail;
- }
- /* We traveled all the way to the bottom of the allocation tree
- * and didn't find room for any more extents - we need to add
- * another tree level */
- if (shift) {
- /* if we hit a leaf, we'd better be empty :) */
- BUG_ON(le16_to_cpu(el->l_next_free_rec) !=
- le16_to_cpu(el->l_count));
- BUG_ON(bh);
- mlog(0, "ocfs2_allocate_extent: need to shift tree depth "
- "(current = %u)\n",
- le16_to_cpu(fe->id2.i_list.l_tree_depth));
- /* ocfs2_shift_tree_depth will return us a buffer with
- * the new extent block (so we can pass that to
- * ocfs2_add_branch). */
- status = ocfs2_shift_tree_depth(osb, handle, inode, fe_bh,
- meta_ac, &bh);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- /* Special case: we have room now if we shifted from
- * tree_depth 0 */
- if (fe->id2.i_list.l_tree_depth == cpu_to_le16(1))
- goto out_add;
- }
- /* call ocfs2_add_branch to add the final part of the tree with
- * the new data. */
- mlog(0, "ocfs2_allocate_extent: add branch. bh = %p\n", bh);
- status = ocfs2_add_branch(osb, handle, inode, fe_bh, bh, last_eb_bh,
- meta_ac);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- out_add:
- /* Finally, we can add clusters. */
- status = ocfs2_do_insert_extent(osb, handle, inode, fe_bh,
- start_blk, new_clusters);
- if (status < 0)
- mlog_errno(status);
- bail:
- if (bh)
- brelse(bh);
- if (last_eb_bh)
- brelse(last_eb_bh);
- mlog_exit(status);
- return status;
- }
- static inline int ocfs2_truncate_log_needs_flush(struct ocfs2_super *osb)
- {
- struct buffer_head *tl_bh = osb->osb_tl_bh;
- struct ocfs2_dinode *di;
- struct ocfs2_truncate_log *tl;
- di = (struct ocfs2_dinode *) tl_bh->b_data;
- tl = &di->id2.i_dealloc;
- mlog_bug_on_msg(le16_to_cpu(tl->tl_used) > le16_to_cpu(tl->tl_count),
- "slot %d, invalid truncate log parameters: used = "
- "%u, count = %u\n", osb->slot_num,
- le16_to_cpu(tl->tl_used), le16_to_cpu(tl->tl_count));
- return le16_to_cpu(tl->tl_used) == le16_to_cpu(tl->tl_count);
- }
- static int ocfs2_truncate_log_can_coalesce(struct ocfs2_truncate_log *tl,
- unsigned int new_start)
- {
- unsigned int tail_index;
- unsigned int current_tail;
- /* No records, nothing to coalesce */
- if (!le16_to_cpu(tl->tl_used))
- return 0;
- tail_index = le16_to_cpu(tl->tl_used) - 1;
- current_tail = le32_to_cpu(tl->tl_recs[tail_index].t_start);
- current_tail += le32_to_cpu(tl->tl_recs[tail_index].t_clusters);
- return current_tail == new_start;
- }
- static int ocfs2_truncate_log_append(struct ocfs2_super *osb,
- struct ocfs2_journal_handle *handle,
- u64 start_blk,
- unsigned int num_clusters)
- {
- int status, index;
- unsigned int start_cluster, tl_count;
- struct inode *tl_inode = osb->osb_tl_inode;
- struct buffer_head *tl_bh = osb->osb_tl_bh;
- struct ocfs2_dinode *di;
- struct ocfs2_truncate_log *tl;
- mlog_entry("start_blk = %llu, num_clusters = %u\n",
- (unsigned long long)start_blk, num_clusters);
- BUG_ON(mutex_trylock(&tl_inode->i_mutex));
- start_cluster = ocfs2_blocks_to_clusters(osb->sb, start_blk);
- di = (struct ocfs2_dinode *) tl_bh->b_data;
- tl = &di->id2.i_dealloc;
- if (!OCFS2_IS_VALID_DINODE(di)) {
- OCFS2_RO_ON_INVALID_DINODE(osb->sb, di);
- status = -EIO;
- goto bail;
- }
- tl_count = le16_to_cpu(tl->tl_count);
- mlog_bug_on_msg(tl_count > ocfs2_truncate_recs_per_inode(osb->sb) ||
- tl_count == 0,
- "Truncate record count on #%llu invalid "
- "wanted %u, actual %u\n",
- (unsigned long long)OCFS2_I(tl_inode)->ip_blkno,
- ocfs2_truncate_recs_per_inode(osb->sb),
- le16_to_cpu(tl->tl_count));
- /* Caller should have known to flush before calling us. */
- index = le16_to_cpu(tl->tl_used);
- if (index >= tl_count) {
- status = -ENOSPC;
- mlog_errno(status);
- goto bail;
- }
- status = ocfs2_journal_access(handle, tl_inode, tl_bh,
- OCFS2_JOURNAL_ACCESS_WRITE);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- mlog(0, "Log truncate of %u clusters starting at cluster %u to "
- "%llu (index = %d)\n", num_clusters, start_cluster,
- (unsigned long long)OCFS2_I(tl_inode)->ip_blkno, index);
- if (ocfs2_truncate_log_can_coalesce(tl, start_cluster)) {
- /*
- * Move index back to the record we are coalescing with.
- * ocfs2_truncate_log_can_coalesce() guarantees nonzero
- */
- index--;
- num_clusters += le32_to_cpu(tl->tl_recs[index].t_clusters);
- mlog(0, "Coalesce with index %u (start = %u, clusters = %u)\n",
- index, le32_to_cpu(tl->tl_recs[index].t_start),
- num_clusters);
- } else {
- tl->tl_recs[index].t_start = cpu_to_le32(start_cluster);
- tl->tl_used = cpu_to_le16(index + 1);
- }
- tl->tl_recs[index].t_clusters = cpu_to_le32(num_clusters);
- status = ocfs2_journal_dirty(handle, tl_bh);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- bail:
- mlog_exit(status);
- return status;
- }
- static int ocfs2_replay_truncate_records(struct ocfs2_super *osb,
- struct ocfs2_journal_handle *handle,
- struct inode *data_alloc_inode,
- struct buffer_head *data_alloc_bh)
- {
- int status = 0;
- int i;
- unsigned int num_clusters;
- u64 start_blk;
- struct ocfs2_truncate_rec rec;
- struct ocfs2_dinode *di;
- struct ocfs2_truncate_log *tl;
- struct inode *tl_inode = osb->osb_tl_inode;
- struct buffer_head *tl_bh = osb->osb_tl_bh;
- mlog_entry_void();
- di = (struct ocfs2_dinode *) tl_bh->b_data;
- tl = &di->id2.i_dealloc;
- i = le16_to_cpu(tl->tl_used) - 1;
- while (i >= 0) {
- /* Caller has given us at least enough credits to
- * update the truncate log dinode */
- status = ocfs2_journal_access(handle, tl_inode, tl_bh,
- OCFS2_JOURNAL_ACCESS_WRITE);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- tl->tl_used = cpu_to_le16(i);
- status = ocfs2_journal_dirty(handle, tl_bh);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- /* TODO: Perhaps we can calculate the bulk of the
- * credits up front rather than extending like
- * this. */
- status = ocfs2_extend_trans(handle,
- OCFS2_TRUNCATE_LOG_FLUSH_ONE_REC);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- rec = tl->tl_recs[i];
- start_blk = ocfs2_clusters_to_blocks(data_alloc_inode->i_sb,
- le32_to_cpu(rec.t_start));
- num_clusters = le32_to_cpu(rec.t_clusters);
- /* if start_blk is not set, we ignore the record as
- * invalid. */
- if (start_blk) {
- mlog(0, "free record %d, start = %u, clusters = %u\n",
- i, le32_to_cpu(rec.t_start), num_clusters);
- status = ocfs2_free_clusters(handle, data_alloc_inode,
- data_alloc_bh, start_blk,
- num_clusters);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- }
- i--;
- }
- bail:
- mlog_exit(status);
- return status;
- }
- /* Expects you to already be holding tl_inode->i_mutex */
- static int __ocfs2_flush_truncate_log(struct ocfs2_super *osb)
- {
- int status;
- unsigned int num_to_flush;
- struct ocfs2_journal_handle *handle = NULL;
- struct inode *tl_inode = osb->osb_tl_inode;
- struct inode *data_alloc_inode = NULL;
- struct buffer_head *tl_bh = osb->osb_tl_bh;
- struct buffer_head *data_alloc_bh = NULL;
- struct ocfs2_dinode *di;
- struct ocfs2_truncate_log *tl;
- mlog_entry_void();
- BUG_ON(mutex_trylock(&tl_inode->i_mutex));
- di = (struct ocfs2_dinode *) tl_bh->b_data;
- tl = &di->id2.i_dealloc;
- if (!OCFS2_IS_VALID_DINODE(di)) {
- OCFS2_RO_ON_INVALID_DINODE(osb->sb, di);
- status = -EIO;
- goto bail;
- }
- num_to_flush = le16_to_cpu(tl->tl_used);
- mlog(0, "Flush %u records from truncate log #%llu\n",
- num_to_flush, (unsigned long long)OCFS2_I(tl_inode)->ip_blkno);
- if (!num_to_flush) {
- status = 0;
- goto bail;
- }
- handle = ocfs2_alloc_handle(osb);
- if (!handle) {
- status = -ENOMEM;
- mlog_errno(status);
- goto bail;
- }
- data_alloc_inode = ocfs2_get_system_file_inode(osb,
- GLOBAL_BITMAP_SYSTEM_INODE,
- OCFS2_INVALID_SLOT);
- if (!data_alloc_inode) {
- status = -EINVAL;
- mlog(ML_ERROR, "Could not get bitmap inode!\n");
- goto bail;
- }
- ocfs2_handle_add_inode(handle, data_alloc_inode);
- status = ocfs2_meta_lock(data_alloc_inode, handle, &data_alloc_bh, 1);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- handle = ocfs2_start_trans(osb, handle, OCFS2_TRUNCATE_LOG_UPDATE);
- if (IS_ERR(handle)) {
- status = PTR_ERR(handle);
- handle = NULL;
- mlog_errno(status);
- goto bail;
- }
- status = ocfs2_replay_truncate_records(osb, handle, data_alloc_inode,
- data_alloc_bh);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- bail:
- if (handle)
- ocfs2_commit_trans(handle);
- if (data_alloc_inode)
- iput(data_alloc_inode);
- if (data_alloc_bh)
- brelse(data_alloc_bh);
- mlog_exit(status);
- return status;
- }
- int ocfs2_flush_truncate_log(struct ocfs2_super *osb)
- {
- int status;
- struct inode *tl_inode = osb->osb_tl_inode;
- mutex_lock(&tl_inode->i_mutex);
- status = __ocfs2_flush_truncate_log(osb);
- mutex_unlock(&tl_inode->i_mutex);
- return status;
- }
- static void ocfs2_truncate_log_worker(void *data)
- {
- int status;
- struct ocfs2_super *osb = data;
- mlog_entry_void();
- status = ocfs2_flush_truncate_log(osb);
- if (status < 0)
- mlog_errno(status);
- mlog_exit(status);
- }
- #define OCFS2_TRUNCATE_LOG_FLUSH_INTERVAL (2 * HZ)
- void ocfs2_schedule_truncate_log_flush(struct ocfs2_super *osb,
- int cancel)
- {
- if (osb->osb_tl_inode) {
- /* We want to push off log flushes while truncates are
- * still running. */
- if (cancel)
- cancel_delayed_work(&osb->osb_truncate_log_wq);
- queue_delayed_work(ocfs2_wq, &osb->osb_truncate_log_wq,
- OCFS2_TRUNCATE_LOG_FLUSH_INTERVAL);
- }
- }
- static int ocfs2_get_truncate_log_info(struct ocfs2_super *osb,
- int slot_num,
- struct inode **tl_inode,
- struct buffer_head **tl_bh)
- {
- int status;
- struct inode *inode = NULL;
- struct buffer_head *bh = NULL;
- inode = ocfs2_get_system_file_inode(osb,
- TRUNCATE_LOG_SYSTEM_INODE,
- slot_num);
- if (!inode) {
- status = -EINVAL;
- mlog(ML_ERROR, "Could not get load truncate log inode!\n");
- goto bail;
- }
- status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, &bh,
- OCFS2_BH_CACHED, inode);
- if (status < 0) {
- iput(inode);
- mlog_errno(status);
- goto bail;
- }
- *tl_inode = inode;
- *tl_bh = bh;
- bail:
- mlog_exit(status);
- return status;
- }
- /* called during the 1st stage of node recovery. we stamp a clean
- * truncate log and pass back a copy for processing later. if the
- * truncate log does not require processing, a *tl_copy is set to
- * NULL. */
- int ocfs2_begin_truncate_log_recovery(struct ocfs2_super *osb,
- int slot_num,
- struct ocfs2_dinode **tl_copy)
- {
- int status;
- struct inode *tl_inode = NULL;
- struct buffer_head *tl_bh = NULL;
- struct ocfs2_dinode *di;
- struct ocfs2_truncate_log *tl;
- *tl_copy = NULL;
- mlog(0, "recover truncate log from slot %d\n", slot_num);
- status = ocfs2_get_truncate_log_info(osb, slot_num, &tl_inode, &tl_bh);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- di = (struct ocfs2_dinode *) tl_bh->b_data;
- tl = &di->id2.i_dealloc;
- if (!OCFS2_IS_VALID_DINODE(di)) {
- OCFS2_RO_ON_INVALID_DINODE(tl_inode->i_sb, di);
- status = -EIO;
- goto bail;
- }
- if (le16_to_cpu(tl->tl_used)) {
- mlog(0, "We'll have %u logs to recover\n",
- le16_to_cpu(tl->tl_used));
- *tl_copy = kmalloc(tl_bh->b_size, GFP_KERNEL);
- if (!(*tl_copy)) {
- status = -ENOMEM;
- mlog_errno(status);
- goto bail;
- }
- /* Assuming the write-out below goes well, this copy
- * will be passed back to recovery for processing. */
- memcpy(*tl_copy, tl_bh->b_data, tl_bh->b_size);
- /* All we need to do to clear the truncate log is set
- * tl_used. */
- tl->tl_used = 0;
- status = ocfs2_write_block(osb, tl_bh, tl_inode);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- }
- bail:
- if (tl_inode)
- iput(tl_inode);
- if (tl_bh)
- brelse(tl_bh);
- if (status < 0 && (*tl_copy)) {
- kfree(*tl_copy);
- *tl_copy = NULL;
- }
- mlog_exit(status);
- return status;
- }
- int ocfs2_complete_truncate_log_recovery(struct ocfs2_super *osb,
- struct ocfs2_dinode *tl_copy)
- {
- int status = 0;
- int i;
- unsigned int clusters, num_recs, start_cluster;
- u64 start_blk;
- struct ocfs2_journal_handle *handle;
- struct inode *tl_inode = osb->osb_tl_inode;
- struct ocfs2_truncate_log *tl;
- mlog_entry_void();
- if (OCFS2_I(tl_inode)->ip_blkno == le64_to_cpu(tl_copy->i_blkno)) {
- mlog(ML_ERROR, "Asked to recover my own truncate log!\n");
- return -EINVAL;
- }
- tl = &tl_copy->id2.i_dealloc;
- num_recs = le16_to_cpu(tl->tl_used);
- mlog(0, "cleanup %u records from %llu\n", num_recs,
- (unsigned long long)tl_copy->i_blkno);
- mutex_lock(&tl_inode->i_mutex);
- for(i = 0; i < num_recs; i++) {
- if (ocfs2_truncate_log_needs_flush(osb)) {
- status = __ocfs2_flush_truncate_log(osb);
- if (status < 0) {
- mlog_errno(status);
- goto bail_up;
- }
- }
- handle = ocfs2_start_trans(osb, NULL,
- OCFS2_TRUNCATE_LOG_UPDATE);
- if (IS_ERR(handle)) {
- status = PTR_ERR(handle);
- mlog_errno(status);
- goto bail_up;
- }
- clusters = le32_to_cpu(tl->tl_recs[i].t_clusters);
- start_cluster = le32_to_cpu(tl->tl_recs[i].t_start);
- start_blk = ocfs2_clusters_to_blocks(osb->sb, start_cluster);
- status = ocfs2_truncate_log_append(osb, handle,
- start_blk, clusters);
- ocfs2_commit_trans(handle);
- if (status < 0) {
- mlog_errno(status);
- goto bail_up;
- }
- }
- bail_up:
- mutex_unlock(&tl_inode->i_mutex);
- mlog_exit(status);
- return status;
- }
- void ocfs2_truncate_log_shutdown(struct ocfs2_super *osb)
- {
- int status;
- struct inode *tl_inode = osb->osb_tl_inode;
- mlog_entry_void();
- if (tl_inode) {
- cancel_delayed_work(&osb->osb_truncate_log_wq);
- flush_workqueue(ocfs2_wq);
- status = ocfs2_flush_truncate_log(osb);
- if (status < 0)
- mlog_errno(status);
- brelse(osb->osb_tl_bh);
- iput(osb->osb_tl_inode);
- }
- mlog_exit_void();
- }
- int ocfs2_truncate_log_init(struct ocfs2_super *osb)
- {
- int status;
- struct inode *tl_inode = NULL;
- struct buffer_head *tl_bh = NULL;
- mlog_entry_void();
- status = ocfs2_get_truncate_log_info(osb,
- osb->slot_num,
- &tl_inode,
- &tl_bh);
- if (status < 0)
- mlog_errno(status);
- /* ocfs2_truncate_log_shutdown keys on the existence of
- * osb->osb_tl_inode so we don't set any of the osb variables
- * until we're sure all is well. */
- INIT_WORK(&osb->osb_truncate_log_wq, ocfs2_truncate_log_worker, osb);
- osb->osb_tl_bh = tl_bh;
- osb->osb_tl_inode = tl_inode;
- mlog_exit(status);
- return status;
- }
- /* This function will figure out whether the currently last extent
- * block will be deleted, and if it will, what the new last extent
- * block will be so we can update his h_next_leaf_blk field, as well
- * as the dinodes i_last_eb_blk */
- static int ocfs2_find_new_last_ext_blk(struct ocfs2_super *osb,
- struct inode *inode,
- struct ocfs2_dinode *fe,
- u32 new_i_clusters,
- struct buffer_head *old_last_eb,
- struct buffer_head **new_last_eb)
- {
- int i, status = 0;
- u64 block = 0;
- struct ocfs2_extent_block *eb;
- struct ocfs2_extent_list *el;
- struct buffer_head *bh = NULL;
- *new_last_eb = NULL;
- if (!OCFS2_IS_VALID_DINODE(fe)) {
- OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, fe);
- status = -EIO;
- goto bail;
- }
- /* we have no tree, so of course, no last_eb. */
- if (!fe->id2.i_list.l_tree_depth)
- goto bail;
- /* trunc to zero special case - this makes tree_depth = 0
- * regardless of what it is. */
- if (!new_i_clusters)
- goto bail;
- eb = (struct ocfs2_extent_block *) old_last_eb->b_data;
- el = &(eb->h_list);
- BUG_ON(!el->l_next_free_rec);
- /* Make sure that this guy will actually be empty after we
- * clear away the data. */
- if (le32_to_cpu(el->l_recs[0].e_cpos) < new_i_clusters)
- goto bail;
- /* Ok, at this point, we know that last_eb will definitely
- * change, so lets traverse the tree and find the second to
- * last extent block. */
- el = &(fe->id2.i_list);
- /* go down the tree, */
- do {
- for(i = (le16_to_cpu(el->l_next_free_rec) - 1); i >= 0; i--) {
- if (le32_to_cpu(el->l_recs[i].e_cpos) <
- new_i_clusters) {
- block = le64_to_cpu(el->l_recs[i].e_blkno);
- break;
- }
- }
- BUG_ON(i < 0);
- if (bh) {
- brelse(bh);
- bh = NULL;
- }
- status = ocfs2_read_block(osb, block, &bh, OCFS2_BH_CACHED,
- inode);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- eb = (struct ocfs2_extent_block *) bh->b_data;
- el = &eb->h_list;
- if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
- OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
- status = -EIO;
- goto bail;
- }
- } while (el->l_tree_depth);
- *new_last_eb = bh;
- get_bh(*new_last_eb);
- mlog(0, "returning block %llu\n",
- (unsigned long long)le64_to_cpu(eb->h_blkno));
- bail:
- if (bh)
- brelse(bh);
- return status;
- }
- static int ocfs2_do_truncate(struct ocfs2_super *osb,
- unsigned int clusters_to_del,
- struct inode *inode,
- struct buffer_head *fe_bh,
- struct buffer_head *old_last_eb_bh,
- struct ocfs2_journal_handle *handle,
- struct ocfs2_truncate_context *tc)
- {
- int status, i, depth;
- struct ocfs2_dinode *fe;
- struct ocfs2_extent_block *eb;
- struct ocfs2_extent_block *last_eb = NULL;
- struct ocfs2_extent_list *el;
- struct buffer_head *eb_bh = NULL;
- struct buffer_head *last_eb_bh = NULL;
- u64 next_eb = 0;
- u64 delete_blk = 0;
- fe = (struct ocfs2_dinode *) fe_bh->b_data;
- status = ocfs2_find_new_last_ext_blk(osb,
- inode,
- fe,
- le32_to_cpu(fe->i_clusters) -
- clusters_to_del,
- old_last_eb_bh,
- &last_eb_bh);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- if (last_eb_bh)
- last_eb = (struct ocfs2_extent_block *) last_eb_bh->b_data;
- status = ocfs2_journal_access(handle, inode, fe_bh,
- OCFS2_JOURNAL_ACCESS_WRITE);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- el = &(fe->id2.i_list);
- spin_lock(&OCFS2_I(inode)->ip_lock);
- OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters) -
- clusters_to_del;
- spin_unlock(&OCFS2_I(inode)->ip_lock);
- le32_add_cpu(&fe->i_clusters, -clusters_to_del);
- fe->i_mtime = cpu_to_le64(CURRENT_TIME.tv_sec);
- fe->i_mtime_nsec = cpu_to_le32(CURRENT_TIME.tv_nsec);
- i = le16_to_cpu(el->l_next_free_rec) - 1;
- BUG_ON(le32_to_cpu(el->l_recs[i].e_clusters) < clusters_to_del);
- le32_add_cpu(&el->l_recs[i].e_clusters, -clusters_to_del);
- /* tree depth zero, we can just delete the clusters, otherwise
- * we need to record the offset of the next level extent block
- * as we may overwrite it. */
- if (!el->l_tree_depth)
- delete_blk = le64_to_cpu(el->l_recs[i].e_blkno)
- + ocfs2_clusters_to_blocks(osb->sb,
- le32_to_cpu(el->l_recs[i].e_clusters));
- else
- next_eb = le64_to_cpu(el->l_recs[i].e_blkno);
- if (!el->l_recs[i].e_clusters) {
- /* if we deleted the whole extent record, then clear
- * out the other fields and update the extent
- * list. For depth > 0 trees, we've already recorded
- * the extent block in 'next_eb' */
- el->l_recs[i].e_cpos = 0;
- el->l_recs[i].e_blkno = 0;
- BUG_ON(!el->l_next_free_rec);
- le16_add_cpu(&el->l_next_free_rec, -1);
- }
- depth = le16_to_cpu(el->l_tree_depth);
- if (!fe->i_clusters) {
- /* trunc to zero is a special case. */
- el->l_tree_depth = 0;
- fe->i_last_eb_blk = 0;
- } else if (last_eb)
- fe->i_last_eb_blk = last_eb->h_blkno;
- status = ocfs2_journal_dirty(handle, fe_bh);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- if (last_eb) {
- /* If there will be a new last extent block, then by
- * definition, there cannot be any leaves to the right of
- * him. */
- status = ocfs2_journal_access(handle, inode, last_eb_bh,
- OCFS2_JOURNAL_ACCESS_WRITE);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- last_eb->h_next_leaf_blk = 0;
- status = ocfs2_journal_dirty(handle, last_eb_bh);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- }
- /* if our tree depth > 0, update all the tree blocks below us. */
- while (depth) {
- mlog(0, "traveling tree (depth = %d, next_eb = %llu)\n",
- depth, (unsigned long long)next_eb);
- status = ocfs2_read_block(osb, next_eb, &eb_bh,
- OCFS2_BH_CACHED, inode);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- eb = (struct ocfs2_extent_block *)eb_bh->b_data;
- if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
- OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
- status = -EIO;
- goto bail;
- }
- el = &(eb->h_list);
- status = ocfs2_journal_access(handle, inode, eb_bh,
- OCFS2_JOURNAL_ACCESS_WRITE);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- BUG_ON(le16_to_cpu(el->l_next_free_rec) == 0);
- BUG_ON(depth != (le16_to_cpu(el->l_tree_depth) + 1));
- i = le16_to_cpu(el->l_next_free_rec) - 1;
- mlog(0, "extent block %llu, before: record %d: "
- "(%u, %u, %llu), next = %u\n",
- (unsigned long long)le64_to_cpu(eb->h_blkno), i,
- le32_to_cpu(el->l_recs[i].e_cpos),
- le32_to_cpu(el->l_recs[i].e_clusters),
- (unsigned long long)le64_to_cpu(el->l_recs[i].e_blkno),
- le16_to_cpu(el->l_next_free_rec));
- BUG_ON(le32_to_cpu(el->l_recs[i].e_clusters) < clusters_to_del);
- le32_add_cpu(&el->l_recs[i].e_clusters, -clusters_to_del);
- next_eb = le64_to_cpu(el->l_recs[i].e_blkno);
- /* bottom-most block requires us to delete data.*/
- if (!el->l_tree_depth)
- delete_blk = le64_to_cpu(el->l_recs[i].e_blkno)
- + ocfs2_clusters_to_blocks(osb->sb,
- le32_to_cpu(el->l_recs[i].e_clusters));
- if (!el->l_recs[i].e_clusters) {
- el->l_recs[i].e_cpos = 0;
- el->l_recs[i].e_blkno = 0;
- BUG_ON(!el->l_next_free_rec);
- le16_add_cpu(&el->l_next_free_rec, -1);
- }
- mlog(0, "extent block %llu, after: record %d: "
- "(%u, %u, %llu), next = %u\n",
- (unsigned long long)le64_to_cpu(eb->h_blkno), i,
- le32_to_cpu(el->l_recs[i].e_cpos),
- le32_to_cpu(el->l_recs[i].e_clusters),
- (unsigned long long)le64_to_cpu(el->l_recs[i].e_blkno),
- le16_to_cpu(el->l_next_free_rec));
- status = ocfs2_journal_dirty(handle, eb_bh);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- if (!el->l_next_free_rec) {
- mlog(0, "deleting this extent block.\n");
- ocfs2_remove_from_cache(inode, eb_bh);
- BUG_ON(eb->h_suballoc_slot);
- BUG_ON(el->l_recs[0].e_clusters);
- BUG_ON(el->l_recs[0].e_cpos);
- BUG_ON(el->l_recs[0].e_blkno);
- status = ocfs2_free_extent_block(handle,
- tc->tc_ext_alloc_inode,
- tc->tc_ext_alloc_bh,
- eb);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- }
- brelse(eb_bh);
- eb_bh = NULL;
- depth--;
- }
- BUG_ON(!delete_blk);
- status = ocfs2_truncate_log_append(osb, handle, delete_blk,
- clusters_to_del);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- status = 0;
- bail:
- if (!status)
- ocfs2_extent_map_trunc(inode, le32_to_cpu(fe->i_clusters));
- else
- ocfs2_extent_map_drop(inode, 0);
- mlog_exit(status);
- return status;
- }
- /*
- * It is expected, that by the time you call this function,
- * inode->i_size and fe->i_size have been adjusted.
- *
- * WARNING: This will kfree the truncate context
- */
- int ocfs2_commit_truncate(struct ocfs2_super *osb,
- struct inode *inode,
- struct buffer_head *fe_bh,
- struct ocfs2_truncate_context *tc)
- {
- int status, i, credits, tl_sem = 0;
- u32 clusters_to_del, target_i_clusters;
- u64 last_eb = 0;
- struct ocfs2_dinode *fe;
- struct ocfs2_extent_block *eb;
- struct ocfs2_extent_list *el;
- struct buffer_head *last_eb_bh;
- struct ocfs2_journal_handle *handle = NULL;
- struct inode *tl_inode = osb->osb_tl_inode;
- mlog_entry_void();
- down_write(&OCFS2_I(inode)->ip_alloc_sem);
- target_i_clusters = ocfs2_clusters_for_bytes(osb->sb,
- i_size_read(inode));
- last_eb_bh = tc->tc_last_eb_bh;
- tc->tc_last_eb_bh = NULL;
- fe = (struct ocfs2_dinode *) fe_bh->b_data;
- if (fe->id2.i_list.l_tree_depth) {
- eb = (struct ocfs2_extent_block *) last_eb_bh->b_data;
- el = &eb->h_list;
- } else
- el = &fe->id2.i_list;
- last_eb = le64_to_cpu(fe->i_last_eb_blk);
- start:
- mlog(0, "ocfs2_commit_truncate: fe->i_clusters = %u, "
- "last_eb = %llu, fe->i_last_eb_blk = %llu, "
- "fe->id2.i_list.l_tree_depth = %u last_eb_bh = %p\n",
- le32_to_cpu(fe->i_clusters), (unsigned long long)last_eb,
- (unsigned long long)le64_to_cpu(fe->i_last_eb_blk),
- le16_to_cpu(fe->id2.i_list.l_tree_depth), last_eb_bh);
- if (last_eb != le64_to_cpu(fe->i_last_eb_blk)) {
- mlog(0, "last_eb changed!\n");
- BUG_ON(!fe->id2.i_list.l_tree_depth);
- last_eb = le64_to_cpu(fe->i_last_eb_blk);
- /* i_last_eb_blk may have changed, read it if
- * necessary. We don't have to worry about the
- * truncate to zero case here (where there becomes no
- * last_eb) because we never loop back after our work
- * is done. */
- if (last_eb_bh) {
- brelse(last_eb_bh);
- last_eb_bh = NULL;
- }
- status = ocfs2_read_block(osb, last_eb,
- &last_eb_bh, OCFS2_BH_CACHED,
- inode);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- eb = (struct ocfs2_extent_block *) last_eb_bh->b_data;
- if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
- OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
- status = -EIO;
- goto bail;
- }
- el = &(eb->h_list);
- }
- /* by now, el will point to the extent list on the bottom most
- * portion of this tree. */
- i = le16_to_cpu(el->l_next_free_rec) - 1;
- if (le32_to_cpu(el->l_recs[i].e_cpos) >= target_i_clusters)
- clusters_to_del = le32_to_cpu(el->l_recs[i].e_clusters);
- else
- clusters_to_del = (le32_to_cpu(el->l_recs[i].e_clusters) +
- le32_to_cpu(el->l_recs[i].e_cpos)) -
- target_i_clusters;
- mlog(0, "clusters_to_del = %u in this pass\n", clusters_to_del);
- mutex_lock(&tl_inode->i_mutex);
- tl_sem = 1;
- /* ocfs2_truncate_log_needs_flush guarantees us at least one
- * record is free for use. If there isn't any, we flush to get
- * an empty truncate log. */
- if (ocfs2_truncate_log_needs_flush(osb)) {
- status = __ocfs2_flush_truncate_log(osb);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- }
- credits = ocfs2_calc_tree_trunc_credits(osb->sb, clusters_to_del,
- fe, el);
- handle = ocfs2_start_trans(osb, NULL, credits);
- if (IS_ERR(handle)) {
- status = PTR_ERR(handle);
- handle = NULL;
- mlog_errno(status);
- goto bail;
- }
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
- status = ocfs2_mark_inode_dirty(handle, inode, fe_bh);
- if (status < 0)
- mlog_errno(status);
- status = ocfs2_do_truncate(osb, clusters_to_del, inode, fe_bh,
- last_eb_bh, handle, tc);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- mutex_unlock(&tl_inode->i_mutex);
- tl_sem = 0;
- ocfs2_commit_trans(handle);
- handle = NULL;
- BUG_ON(le32_to_cpu(fe->i_clusters) < target_i_clusters);
- if (le32_to_cpu(fe->i_clusters) > target_i_clusters)
- goto start;
- bail:
- up_write(&OCFS2_I(inode)->ip_alloc_sem);
- ocfs2_schedule_truncate_log_flush(osb, 1);
- if (tl_sem)
- mutex_unlock(&tl_inode->i_mutex);
- if (handle)
- ocfs2_commit_trans(handle);
- if (last_eb_bh)
- brelse(last_eb_bh);
- /* This will drop the ext_alloc cluster lock for us */
- ocfs2_free_truncate_context(tc);
- mlog_exit(status);
- return status;
- }
- /*
- * Expects the inode to already be locked. This will figure out which
- * inodes need to be locked and will put them on the returned truncate
- * context.
- */
- int ocfs2_prepare_truncate(struct ocfs2_super *osb,
- struct inode *inode,
- struct buffer_head *fe_bh,
- struct ocfs2_truncate_context **tc)
- {
- int status, metadata_delete;
- unsigned int new_i_clusters;
- struct ocfs2_dinode *fe;
- struct ocfs2_extent_block *eb;
- struct ocfs2_extent_list *el;
- struct buffer_head *last_eb_bh = NULL;
- struct inode *ext_alloc_inode = NULL;
- struct buffer_head *ext_alloc_bh = NULL;
- mlog_entry_void();
- *tc = NULL;
- new_i_clusters = ocfs2_clusters_for_bytes(osb->sb,
- i_size_read(inode));
- fe = (struct ocfs2_dinode *) fe_bh->b_data;
- mlog(0, "fe->i_clusters = %u, new_i_clusters = %u, fe->i_size ="
- "%llu\n", fe->i_clusters, new_i_clusters,
- (unsigned long long)fe->i_size);
- if (le32_to_cpu(fe->i_clusters) <= new_i_clusters) {
- ocfs2_error(inode->i_sb, "Dinode %llu has cluster count "
- "%u and size %llu whereas struct inode has "
- "cluster count %u and size %llu which caused an "
- "invalid truncate to %u clusters.",
- (unsigned long long)le64_to_cpu(fe->i_blkno),
- le32_to_cpu(fe->i_clusters),
- (unsigned long long)le64_to_cpu(fe->i_size),
- OCFS2_I(inode)->ip_clusters, i_size_read(inode),
- new_i_clusters);
- mlog_meta_lvb(ML_ERROR, &OCFS2_I(inode)->ip_meta_lockres);
- status = -EIO;
- goto bail;
- }
- *tc = kcalloc(1, sizeof(struct ocfs2_truncate_context), GFP_KERNEL);
- if (!(*tc)) {
- status = -ENOMEM;
- mlog_errno(status);
- goto bail;
- }
- metadata_delete = 0;
- if (fe->id2.i_list.l_tree_depth) {
- /* If we have a tree, then the truncate may result in
- * metadata deletes. Figure this out from the
- * rightmost leaf block.*/
- status = ocfs2_read_block(osb, le64_to_cpu(fe->i_last_eb_blk),
- &last_eb_bh, OCFS2_BH_CACHED, inode);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- eb = (struct ocfs2_extent_block *) last_eb_bh->b_data;
- if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
- OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
- brelse(last_eb_bh);
- status = -EIO;
- goto bail;
- }
- el = &(eb->h_list);
- if (le32_to_cpu(el->l_recs[0].e_cpos) >= new_i_clusters)
- metadata_delete = 1;
- }
- (*tc)->tc_last_eb_bh = last_eb_bh;
- if (metadata_delete) {
- mlog(0, "Will have to delete metadata for this trunc. "
- "locking allocator.\n");
- ext_alloc_inode = ocfs2_get_system_file_inode(osb, EXTENT_ALLOC_SYSTEM_INODE, 0);
- if (!ext_alloc_inode) {
- status = -ENOMEM;
- mlog_errno(status);
- goto bail;
- }
- mutex_lock(&ext_alloc_inode->i_mutex);
- (*tc)->tc_ext_alloc_inode = ext_alloc_inode;
- status = ocfs2_meta_lock(ext_alloc_inode,
- NULL,
- &ext_alloc_bh,
- 1);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- (*tc)->tc_ext_alloc_bh = ext_alloc_bh;
- (*tc)->tc_ext_alloc_locked = 1;
- }
- status = 0;
- bail:
- if (status < 0) {
- if (*tc)
- ocfs2_free_truncate_context(*tc);
- *tc = NULL;
- }
- mlog_exit_void();
- return status;
- }
- static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc)
- {
- if (tc->tc_ext_alloc_inode) {
- if (tc->tc_ext_alloc_locked)
- ocfs2_meta_unlock(tc->tc_ext_alloc_inode, 1);
- mutex_unlock(&tc->tc_ext_alloc_inode->i_mutex);
- iput(tc->tc_ext_alloc_inode);
- }
- if (tc->tc_ext_alloc_bh)
- brelse(tc->tc_ext_alloc_bh);
- if (tc->tc_last_eb_bh)
- brelse(tc->tc_last_eb_bh);
- kfree(tc);
- }
|