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

📄 jfs_metapage.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *   Copyright (C) International Business Machines Corp., 2000-2005 *   Portions Copyright (C) Christoph Hellwig, 2001-2002 * *   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 02111-1307 USA */#include <linux/fs.h>#include <linux/mm.h>#include <linux/bio.h>#include <linux/init.h>#include <linux/buffer_head.h>#include <linux/mempool.h>#include "jfs_incore.h"#include "jfs_superblock.h"#include "jfs_filsys.h"#include "jfs_metapage.h"#include "jfs_txnmgr.h"#include "jfs_debug.h"#ifdef CONFIG_JFS_STATISTICSstatic struct {	uint	pagealloc;	/* # of page allocations */	uint	pagefree;	/* # of page frees */	uint	lockwait;	/* # of sleeping lock_metapage() calls */} mpStat;#endif#define metapage_locked(mp) test_bit(META_locked, &(mp)->flag)#define trylock_metapage(mp) test_and_set_bit(META_locked, &(mp)->flag)static inline void unlock_metapage(struct metapage *mp){	clear_bit(META_locked, &mp->flag);	wake_up(&mp->wait);}static inline void __lock_metapage(struct metapage *mp){	DECLARE_WAITQUEUE(wait, current);	INCREMENT(mpStat.lockwait);	add_wait_queue_exclusive(&mp->wait, &wait);	do {		set_current_state(TASK_UNINTERRUPTIBLE);		if (metapage_locked(mp)) {			unlock_page(mp->page);			io_schedule();			lock_page(mp->page);		}	} while (trylock_metapage(mp));	__set_current_state(TASK_RUNNING);	remove_wait_queue(&mp->wait, &wait);}/* * Must have mp->page locked */static inline void lock_metapage(struct metapage *mp){	if (trylock_metapage(mp))		__lock_metapage(mp);}#define METAPOOL_MIN_PAGES 32static struct kmem_cache *metapage_cache;static mempool_t *metapage_mempool;#define MPS_PER_PAGE (PAGE_CACHE_SIZE >> L2PSIZE)#if MPS_PER_PAGE > 1struct meta_anchor {	int mp_count;	atomic_t io_count;	struct metapage *mp[MPS_PER_PAGE];};#define mp_anchor(page) ((struct meta_anchor *)page_private(page))static inline struct metapage *page_to_mp(struct page *page, uint offset){	if (!PagePrivate(page))		return NULL;	return mp_anchor(page)->mp[offset >> L2PSIZE];}static inline int insert_metapage(struct page *page, struct metapage *mp){	struct meta_anchor *a;	int index;	int l2mp_blocks;	/* log2 blocks per metapage */	if (PagePrivate(page))		a = mp_anchor(page);	else {		a = kzalloc(sizeof(struct meta_anchor), GFP_NOFS);		if (!a)			return -ENOMEM;		set_page_private(page, (unsigned long)a);		SetPagePrivate(page);		kmap(page);	}	if (mp) {		l2mp_blocks = L2PSIZE - page->mapping->host->i_blkbits;		index = (mp->index >> l2mp_blocks) & (MPS_PER_PAGE - 1);		a->mp_count++;		a->mp[index] = mp;	}	return 0;}static inline void remove_metapage(struct page *page, struct metapage *mp){	struct meta_anchor *a = mp_anchor(page);	int l2mp_blocks = L2PSIZE - page->mapping->host->i_blkbits;	int index;	index = (mp->index >> l2mp_blocks) & (MPS_PER_PAGE - 1);	BUG_ON(a->mp[index] != mp);	a->mp[index] = NULL;	if (--a->mp_count == 0) {		kfree(a);		set_page_private(page, 0);		ClearPagePrivate(page);		kunmap(page);	}}static inline void inc_io(struct page *page){	atomic_inc(&mp_anchor(page)->io_count);}static inline void dec_io(struct page *page, void (*handler) (struct page *)){	if (atomic_dec_and_test(&mp_anchor(page)->io_count))		handler(page);}#elsestatic inline struct metapage *page_to_mp(struct page *page, uint offset){	return PagePrivate(page) ? (struct metapage *)page_private(page) : NULL;}static inline int insert_metapage(struct page *page, struct metapage *mp){	if (mp) {		set_page_private(page, (unsigned long)mp);		SetPagePrivate(page);		kmap(page);	}	return 0;}static inline void remove_metapage(struct page *page, struct metapage *mp){	set_page_private(page, 0);	ClearPagePrivate(page);	kunmap(page);}#define inc_io(page) do {} while(0)#define dec_io(page, handler) handler(page)#endifstatic void init_once(struct kmem_cache *cachep, void *foo){	struct metapage *mp = (struct metapage *)foo;	mp->lid = 0;	mp->lsn = 0;	mp->flag = 0;	mp->data = NULL;	mp->clsn = 0;	mp->log = NULL;	set_bit(META_free, &mp->flag);	init_waitqueue_head(&mp->wait);}static inline struct metapage *alloc_metapage(gfp_t gfp_mask){	return mempool_alloc(metapage_mempool, gfp_mask);}static inline void free_metapage(struct metapage *mp){	mp->flag = 0;	set_bit(META_free, &mp->flag);	mempool_free(mp, metapage_mempool);}int __init metapage_init(void){	/*	 * Allocate the metapage structures	 */	metapage_cache = kmem_cache_create("jfs_mp", sizeof(struct metapage),					   0, 0, init_once);	if (metapage_cache == NULL)		return -ENOMEM;	metapage_mempool = mempool_create_slab_pool(METAPOOL_MIN_PAGES,						    metapage_cache);	if (metapage_mempool == NULL) {		kmem_cache_destroy(metapage_cache);		return -ENOMEM;	}	return 0;}void metapage_exit(void){	mempool_destroy(metapage_mempool);	kmem_cache_destroy(metapage_cache);}static inline void drop_metapage(struct page *page, struct metapage *mp){	if (mp->count || mp->nohomeok || test_bit(META_dirty, &mp->flag) ||	    test_bit(META_io, &mp->flag))		return;	remove_metapage(page, mp);	INCREMENT(mpStat.pagefree);	free_metapage(mp);}/* * Metapage address space operations */static sector_t metapage_get_blocks(struct inode *inode, sector_t lblock,				    unsigned int *len){	int rc = 0;	int xflag;	s64 xaddr;	sector_t file_blocks = (inode->i_size + inode->i_sb->s_blocksize - 1) >>			       inode->i_blkbits;	if (lblock >= file_blocks)		return 0;	if (lblock + *len > file_blocks)		*len = file_blocks - lblock;	if (inode->i_ino) {		rc = xtLookup(inode, (s64)lblock, *len, &xflag, &xaddr, len, 0);		if ((rc == 0) && *len)			lblock = (sector_t)xaddr;		else			lblock = 0;	} /* else no mapping */	return lblock;}static void last_read_complete(struct page *page){	if (!PageError(page))		SetPageUptodate(page);	unlock_page(page);}static void metapage_read_end_io(struct bio *bio, int err){	struct page *page = bio->bi_private;	if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) {		printk(KERN_ERR "metapage_read_end_io: I/O error\n");		SetPageError(page);	}	dec_io(page, last_read_complete);	bio_put(bio);}static void remove_from_logsync(struct metapage *mp){	struct jfs_log *log = mp->log;	unsigned long flags;/* * This can race.  Recheck that log hasn't been set to null, and after * acquiring logsync lock, recheck lsn */	if (!log)		return;	LOGSYNC_LOCK(log, flags);	if (mp->lsn) {		mp->log = NULL;		mp->lsn = 0;		mp->clsn = 0;		log->count--;		list_del(&mp->synclist);	}	LOGSYNC_UNLOCK(log, flags);}static void last_write_complete(struct page *page){	struct metapage *mp;	unsigned int offset;	for (offset = 0; offset < PAGE_CACHE_SIZE; offset += PSIZE) {		mp = page_to_mp(page, offset);		if (mp && test_bit(META_io, &mp->flag)) {			if (mp->lsn)				remove_from_logsync(mp);			clear_bit(META_io, &mp->flag);		}		/*		 * I'd like to call drop_metapage here, but I don't think it's		 * safe unless I have the page locked		 */	}	end_page_writeback(page);}static void metapage_write_end_io(struct bio *bio, int err){	struct page *page = bio->bi_private;	BUG_ON(!PagePrivate(page));	if (! test_bit(BIO_UPTODATE, &bio->bi_flags)) {		printk(KERN_ERR "metapage_write_end_io: I/O error\n");		SetPageError(page);	}	dec_io(page, last_write_complete);	bio_put(bio);}static int metapage_writepage(struct page *page, struct writeback_control *wbc){	struct bio *bio = NULL;	unsigned int block_offset;	/* block offset of mp within page */	struct inode *inode = page->mapping->host;	unsigned int blocks_per_mp = JFS_SBI(inode->i_sb)->nbperpage;	unsigned int len;	unsigned int xlen;	struct metapage *mp;	int redirty = 0;	sector_t lblock;	sector_t pblock;	sector_t next_block = 0;	sector_t page_start;	unsigned long bio_bytes = 0;	unsigned long bio_offset = 0;	unsigned int offset;	page_start = (sector_t)page->index <<		     (PAGE_CACHE_SHIFT - inode->i_blkbits);	BUG_ON(!PageLocked(page));	BUG_ON(PageWriteback(page));	for (offset = 0; offset < PAGE_CACHE_SIZE; offset += PSIZE) {		mp = page_to_mp(page, offset);		if (!mp || !test_bit(META_dirty, &mp->flag))			continue;		if (mp->nohomeok && !test_bit(META_forcewrite, &mp->flag)) {			redirty = 1;			/*			 * Make sure this page isn't blocked indefinitely.			 * If the journal isn't undergoing I/O, push it			 */			if (mp->log && !(mp->log->cflag & logGC_PAGEOUT))				jfs_flush_journal(mp->log, 0);			continue;		}		clear_bit(META_dirty, &mp->flag);		block_offset = offset >> inode->i_blkbits;		lblock = page_start + block_offset;		if (bio) {			if (xlen && lblock == next_block) {				/* Contiguous, in memory & on disk */				len = min(xlen, blocks_per_mp);				xlen -= len;				bio_bytes += len << inode->i_blkbits;				set_bit(META_io, &mp->flag);				continue;			}			/* Not contiguous */			if (bio_add_page(bio, page, bio_bytes, bio_offset) <			    bio_bytes)				goto add_failed;			/*			 * Increment counter before submitting i/o to keep			 * count from hitting zero before we're through			 */			inc_io(page);			if (!bio->bi_size)				goto dump_bio;			submit_bio(WRITE, bio);			bio = NULL;		} else {

⌨️ 快捷键说明

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