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

📄 revoke.c

📁 可以在不启动LINUX的情况下直接访问EXT2和EXT3格式的磁盘
💻 C
📖 第 1 页 / 共 2 页
字号:
			BUFFER_TRACE(bh, "found on hash");	}#ifdef JBD_EXPENSIVE_CHECKING	else {		struct buffer_head *bh2;		/* If there is a different buffer_head lying around in		 * memory anywhere... */		bh2 = __find_get_block(bdev, blocknr, journal->j_blocksize);		if (bh2) {			/* ... and it has RevokeValid status... */			if (bh2 != bh && buffer_revokevalid(bh2))				/* ...then it better be revoked too,				 * since it's illegal to create a revoke				 * record against a buffer_head which is				 * not marked revoked --- that would				 * risk missing a subsequent revoke				 * cancel. */				J_ASSERT_BH(bh2, buffer_revoked(bh2));			put_bh(bh2);		}	}#endif	/* We really ought not ever to revoke twice in a row without           first having the revoke cancelled: it's illegal to free a           block twice without allocating it in between! */	if (bh) {		if (!J_EXPECT_BH(bh, !buffer_revoked(bh),				 "inconsistent data on disk")) {			if (!bh_in)				brelse(bh);			return -EIO;		}		set_buffer_revoked(bh);		set_buffer_revokevalid(bh);		if (bh_in) {			BUFFER_TRACE(bh_in, "call journal_forget");			journal_forget(handle, bh_in);		} else {			BUFFER_TRACE(bh, "call brelse");			__brelse(bh);		}	}	jbd_debug(2, "insert revoke for block %lu, bh_in=%p\n", blocknr, bh_in);	err = insert_revoke_hash(journal, blocknr,				handle->h_transaction->t_tid);	BUFFER_TRACE(bh_in, "exit");	return err;}/* * Cancel an outstanding revoke.  For use only internally by the * journaling code (called from journal_get_write_access). * * We trust buffer_revoked() on the buffer if the buffer is already * being journaled: if there is no revoke pending on the buffer, then we * don't do anything here. * * This would break if it were possible for a buffer to be revoked and * discarded, and then reallocated within the same transaction.  In such * a case we would have lost the revoked bit, but when we arrived here * the second time we would still have a pending revoke to cancel.  So, * do not trust the Revoked bit on buffers unless RevokeValid is also * set. * * The caller must have the journal locked. */int journal_cancel_revoke(handle_t *handle, struct journal_head *jh){	struct jbd_revoke_record_s *record;	journal_t *journal = handle->h_transaction->t_journal;	int need_cancel;	int did_revoke = 0;	/* akpm: debug */	struct buffer_head *bh = jh2bh(jh);	jbd_debug(4, "journal_head %p, cancelling revoke\n", jh);	/* Is the existing Revoke bit valid?  If so, we trust it, and	 * only perform the full cancel if the revoke bit is set.  If	 * not, we can't trust the revoke bit, and we need to do the	 * full search for a revoke record. */	if (test_set_buffer_revokevalid(bh)) {		need_cancel = test_clear_buffer_revoked(bh);	} else {		need_cancel = 1;		clear_buffer_revoked(bh);	}	if (need_cancel) {		record = find_revoke_record(journal, (unsigned long)bh->b_blocknr);		if (record) {			jbd_debug(4, "cancelled existing revoke on "				  "blocknr %llu\n", (u64)bh->b_blocknr);			spin_lock(&journal->j_revoke_lock);			list_del(&record->hash);			spin_unlock(&journal->j_revoke_lock);			kmem_cache_free(revoke_record_cache, record);			did_revoke = 1;		}	}#ifdef JBD_EXPENSIVE_CHECKING	/* There better not be one left behind by now! */	record = find_revoke_record(journal, bh->b_blocknr);	J_ASSERT_JH(jh, record == NULL);#endif	/* Finally, have we just cleared revoke on an unhashed	 * buffer_head?  If so, we'd better make sure we clear the	 * revoked status on any hashed alias too, otherwise the revoke	 * state machine will get very upset later on. */	if (need_cancel) {		struct buffer_head *bh2;		bh2 = __find_get_block(bh->b_bdev, bh->b_blocknr, bh->b_size);		if (bh2) {			if (bh2 != bh)				clear_buffer_revoked(bh2);			__brelse(bh2);		}	}	return did_revoke;}/* journal_switch_revoke table select j_revoke for next transaction * we do not want to suspend any processing until all revokes are * written -bzzz */void journal_switch_revoke_table(journal_t *journal){	int i;	if (journal->j_revoke == journal->j_revoke_table[0])		journal->j_revoke = journal->j_revoke_table[1];	else		journal->j_revoke = journal->j_revoke_table[0];	for (i = 0; i < journal->j_revoke->hash_size; i++)		INIT_LIST_HEAD(&journal->j_revoke->hash_table[i]);}/* * Write revoke records to the journal for all entries in the current * revoke hash, deleting the entries as we go. * * Called with the journal lock held. */void journal_write_revoke_records(journal_t *journal,				  transaction_t *transaction){	struct journal_head *descriptor;	struct jbd_revoke_record_s *record;	struct jbd_revoke_table_s *revoke;	struct list_head *hash_list;	int i, offset, count;	descriptor = NULL;	offset = 0;	count = 0;	/* select revoke table for committing transaction */	revoke = journal->j_revoke == journal->j_revoke_table[0] ?		journal->j_revoke_table[1] : journal->j_revoke_table[0];	for (i = 0; i < revoke->hash_size; i++) {		hash_list = &revoke->hash_table[i];		while (!list_empty(hash_list)) {			record = (struct jbd_revoke_record_s *)				hash_list->next;			write_one_revoke_record(journal, transaction,						&descriptor, &offset,						record);			count++;			list_del(&record->hash);			kmem_cache_free(revoke_record_cache, record);		}	}	if (descriptor)		flush_descriptor(journal, descriptor, offset);	jbd_debug(1, "Wrote %d revoke records\n", count);}/* * Write out one revoke record.  We need to create a new descriptor * block if the old one is full or if we have not already created one. */static void write_one_revoke_record(journal_t *journal,				    transaction_t *transaction,				    struct journal_head **descriptorp,				    int *offsetp,				    struct jbd_revoke_record_s *record){	struct journal_head *descriptor;	int offset;	journal_header_t *header;	/* If we are already aborting, this all becomes a noop.  We           still need to go round the loop in           journal_write_revoke_records in order to free all of the           revoke records: only the IO to the journal is omitted. */	if (is_journal_aborted(journal))		return;	descriptor = *descriptorp;	offset = *offsetp;	/* Make sure we have a descriptor with space left for the record */	if (descriptor) {		if (offset == journal->j_blocksize) {			flush_descriptor(journal, descriptor, offset);			descriptor = NULL;		}	}	if (!descriptor) {		descriptor = journal_get_descriptor_buffer(journal);		if (!descriptor)			return;		header = (journal_header_t *) &jh2bh(descriptor)->b_data[0];		header->h_magic     = cpu_to_be32(JFS_MAGIC_NUMBER);		header->h_blocktype = cpu_to_be32(JFS_REVOKE_BLOCK);		header->h_sequence  = cpu_to_be32(transaction->t_tid);		/* Record it so that we can wait for IO completion later */		JBUFFER_TRACE(descriptor, "file as BJ_LogCtl");		journal_file_buffer(descriptor, transaction, BJ_LogCtl);		offset = sizeof(journal_revoke_header_t);		*descriptorp = descriptor;	}	* ((__be32 *)(&jh2bh(descriptor)->b_data[offset])) =		cpu_to_be32(record->blocknr);	offset += 4;	*offsetp = offset;}/* * Flush a revoke descriptor out to the journal.  If we are aborting, * this is a noop; otherwise we are generating a buffer which needs to * be waited for during commit, so it has to go onto the appropriate * journal buffer list. */static void flush_descriptor(journal_t *journal,			     struct journal_head *descriptor,			     int offset){	journal_revoke_header_t *header;	struct buffer_head *bh = jh2bh(descriptor);	if (is_journal_aborted(journal)) {		put_bh(bh);		return;	}	header = (journal_revoke_header_t *) jh2bh(descriptor)->b_data;	header->r_count = cpu_to_be32(offset);	set_buffer_jwrite(bh);	BUFFER_TRACE(bh, "write");	set_buffer_dirty(bh);	ll_rw_block(SWRITE, 1, &bh);}#endif/* * Revoke support for recovery. * * Recovery needs to be able to: * *  record all revoke records, including the tid of the latest instance *  of each revoke in the journal * *  check whether a given block in a given transaction should be replayed *  (ie. has not been revoked by a revoke record in that or a subsequent *  transaction) * *  empty the revoke table after recovery. *//* * First, setting revoke records.  We create a new revoke record for * every block ever revoked in the log as we scan it for recovery, and * we update the existing records if we find multiple revokes for a * single block. */int journal_set_revoke(journal_t *journal,		       unsigned long blocknr,		       tid_t sequence){	struct jbd_revoke_record_s *record;	record = find_revoke_record(journal, blocknr);	if (record) {		/* If we have multiple occurrences, only record the		 * latest sequence number in the hashed record */		if (tid_gt(sequence, record->sequence))			record->sequence = sequence;		return 0;	}	return insert_revoke_hash(journal, blocknr, sequence);}/* * Test revoke records.  For a given block referenced in the log, has * that block been revoked?  A revoke record with a given transaction * sequence number revokes all blocks in that transaction and earlier * ones, but later transactions still need replayed. */int journal_test_revoke(journal_t *journal,			unsigned long blocknr,			tid_t sequence){	struct jbd_revoke_record_s *record;	record = find_revoke_record(journal, blocknr);	if (!record)		return 0;	if (tid_gt(sequence, record->sequence))		return 0;	return 1;}/* * Finally, once recovery is over, we need to clear the revoke table so * that it can be reused by the running filesystem. */void journal_clear_revoke(journal_t *journal){	int i;	struct list_head *hash_list;	struct jbd_revoke_record_s *record;	struct jbd_revoke_table_s *revoke;	revoke = journal->j_revoke;	for (i = 0; i < revoke->hash_size; i++) {		hash_list = &revoke->hash_table[i];		while (!list_empty(hash_list)) {			record = (struct jbd_revoke_record_s*) hash_list->next;			list_del(&record->hash);			kmem_cache_free(revoke_record_cache, record);		}	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -