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

📄 xfs_buf.c

📁 LINUX 2.6.17.4的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
	xfs_buftarg_t		*target,	xfs_off_t		ioff,	size_t			isize,	xfs_buf_flags_t		flags){	xfs_buf_t		*bp;	flags |= XBF_READ;	bp = xfs_buf_get_flags(target, ioff, isize, flags);	if (bp) {		if (!XFS_BUF_ISDONE(bp)) {			XB_TRACE(bp, "read", (unsigned long)flags);			XFS_STATS_INC(xb_get_read);			xfs_buf_iostart(bp, flags);		} else if (flags & XBF_ASYNC) {			XB_TRACE(bp, "read_async", (unsigned long)flags);			/*			 * Read ahead call which is already satisfied,			 * drop the buffer			 */			goto no_buffer;		} else {			XB_TRACE(bp, "read_done", (unsigned long)flags);			/* We do not want read in the flags */			bp->b_flags &= ~XBF_READ;		}	}	return bp; no_buffer:	if (flags & (XBF_LOCK | XBF_TRYLOCK))		xfs_buf_unlock(bp);	xfs_buf_rele(bp);	return NULL;}/* *	If we are not low on memory then do the readahead in a deadlock *	safe manner. */voidxfs_buf_readahead(	xfs_buftarg_t		*target,	xfs_off_t		ioff,	size_t			isize,	xfs_buf_flags_t		flags){	struct backing_dev_info *bdi;	bdi = target->bt_mapping->backing_dev_info;	if (bdi_read_congested(bdi))		return;	flags |= (XBF_TRYLOCK|XBF_ASYNC|XBF_READ_AHEAD);	xfs_buf_read_flags(target, ioff, isize, flags);}xfs_buf_t *xfs_buf_get_empty(	size_t			len,	xfs_buftarg_t		*target){	xfs_buf_t		*bp;	bp = xfs_buf_allocate(0);	if (bp)		_xfs_buf_initialize(bp, target, 0, len, 0);	return bp;}static inline struct page *mem_to_page(	void			*addr){	if (((unsigned long)addr < VMALLOC_START) ||	    ((unsigned long)addr >= VMALLOC_END)) {		return virt_to_page(addr);	} else {		return vmalloc_to_page(addr);	}}intxfs_buf_associate_memory(	xfs_buf_t		*bp,	void			*mem,	size_t			len){	int			rval;	int			i = 0;	size_t			ptr;	size_t			end, end_cur;	off_t			offset;	int			page_count;	page_count = PAGE_CACHE_ALIGN(len) >> PAGE_CACHE_SHIFT;	offset = (off_t) mem - ((off_t)mem & PAGE_CACHE_MASK);	if (offset && (len > PAGE_CACHE_SIZE))		page_count++;	/* Free any previous set of page pointers */	if (bp->b_pages)		_xfs_buf_free_pages(bp);	bp->b_pages = NULL;	bp->b_addr = mem;	rval = _xfs_buf_get_pages(bp, page_count, 0);	if (rval)		return rval;	bp->b_offset = offset;	ptr = (size_t) mem & PAGE_CACHE_MASK;	end = PAGE_CACHE_ALIGN((size_t) mem + len);	end_cur = end;	/* set up first page */	bp->b_pages[0] = mem_to_page(mem);	ptr += PAGE_CACHE_SIZE;	bp->b_page_count = ++i;	while (ptr < end) {		bp->b_pages[i] = mem_to_page((void *)ptr);		bp->b_page_count = ++i;		ptr += PAGE_CACHE_SIZE;	}	bp->b_locked = 0;	bp->b_count_desired = bp->b_buffer_length = len;	bp->b_flags |= XBF_MAPPED;	return 0;}xfs_buf_t *xfs_buf_get_noaddr(	size_t			len,	xfs_buftarg_t		*target){	size_t			malloc_len = len;	xfs_buf_t		*bp;	void			*data;	int			error;	bp = xfs_buf_allocate(0);	if (unlikely(bp == NULL))		goto fail;	_xfs_buf_initialize(bp, target, 0, len, 0); try_again:	data = kmem_alloc(malloc_len, KM_SLEEP | KM_MAYFAIL);	if (unlikely(data == NULL))		goto fail_free_buf;	/* check whether alignment matches.. */	if ((__psunsigned_t)data !=	    ((__psunsigned_t)data & ~target->bt_smask)) {		/* .. else double the size and try again */		kmem_free(data, malloc_len);		malloc_len <<= 1;		goto try_again;	}	error = xfs_buf_associate_memory(bp, data, len);	if (error)		goto fail_free_mem;	bp->b_flags |= _XBF_KMEM_ALLOC;	xfs_buf_unlock(bp);	XB_TRACE(bp, "no_daddr", data);	return bp; fail_free_mem:	kmem_free(data, malloc_len); fail_free_buf:	xfs_buf_free(bp); fail:	return NULL;}/* *	Increment reference count on buffer, to hold the buffer concurrently *	with another thread which may release (free) the buffer asynchronously. *	Must hold the buffer already to call this function. */voidxfs_buf_hold(	xfs_buf_t		*bp){	atomic_inc(&bp->b_hold);	XB_TRACE(bp, "hold", 0);}/* *	Releases a hold on the specified buffer.  If the *	the hold count is 1, calls xfs_buf_free. */voidxfs_buf_rele(	xfs_buf_t		*bp){	xfs_bufhash_t		*hash = bp->b_hash;	XB_TRACE(bp, "rele", bp->b_relse);	if (unlikely(!hash)) {		ASSERT(!bp->b_relse);		if (atomic_dec_and_test(&bp->b_hold))			xfs_buf_free(bp);		return;	}	if (atomic_dec_and_lock(&bp->b_hold, &hash->bh_lock)) {		if (bp->b_relse) {			atomic_inc(&bp->b_hold);			spin_unlock(&hash->bh_lock);			(*(bp->b_relse)) (bp);		} else if (bp->b_flags & XBF_FS_MANAGED) {			spin_unlock(&hash->bh_lock);		} else {			ASSERT(!(bp->b_flags & (XBF_DELWRI|_XBF_DELWRI_Q)));			list_del_init(&bp->b_hash_list);			spin_unlock(&hash->bh_lock);			xfs_buf_free(bp);		}	} else {		/*		 * Catch reference count leaks		 */		ASSERT(atomic_read(&bp->b_hold) >= 0);	}}/* *	Mutual exclusion on buffers.  Locking model: * *	Buffers associated with inodes for which buffer locking *	is not enabled are not protected by semaphores, and are *	assumed to be exclusively owned by the caller.  There is a *	spinlock in the buffer, used by the caller when concurrent *	access is possible. *//* *	Locks a buffer object, if it is not already locked. *	Note that this in no way locks the underlying pages, so it is only *	useful for synchronizing concurrent use of buffer objects, not for *	synchronizing independent access to the underlying pages. */intxfs_buf_cond_lock(	xfs_buf_t		*bp){	int			locked;	locked = down_trylock(&bp->b_sema) == 0;	if (locked) {		XB_SET_OWNER(bp);	}	XB_TRACE(bp, "cond_lock", (long)locked);	return locked ? 0 : -EBUSY;}#if defined(DEBUG) || defined(XFS_BLI_TRACE)intxfs_buf_lock_value(	xfs_buf_t		*bp){	return atomic_read(&bp->b_sema.count);}#endif/* *	Locks a buffer object. *	Note that this in no way locks the underlying pages, so it is only *	useful for synchronizing concurrent use of buffer objects, not for *	synchronizing independent access to the underlying pages. */voidxfs_buf_lock(	xfs_buf_t		*bp){	XB_TRACE(bp, "lock", 0);	if (atomic_read(&bp->b_io_remaining))		blk_run_address_space(bp->b_target->bt_mapping);	down(&bp->b_sema);	XB_SET_OWNER(bp);	XB_TRACE(bp, "locked", 0);}/* *	Releases the lock on the buffer object. *	If the buffer is marked delwri but is not queued, do so before we *	unlock the buffer as we need to set flags correctly.  We also need to *	take a reference for the delwri queue because the unlocker is going to *	drop their's and they don't know we just queued it. */voidxfs_buf_unlock(	xfs_buf_t		*bp){	if ((bp->b_flags & (XBF_DELWRI|_XBF_DELWRI_Q)) == XBF_DELWRI) {		atomic_inc(&bp->b_hold);		bp->b_flags |= XBF_ASYNC;		xfs_buf_delwri_queue(bp, 0);	}	XB_CLEAR_OWNER(bp);	up(&bp->b_sema);	XB_TRACE(bp, "unlock", 0);}/* *	Pinning Buffer Storage in Memory *	Ensure that no attempt to force a buffer to disk will succeed. */voidxfs_buf_pin(	xfs_buf_t		*bp){	atomic_inc(&bp->b_pin_count);	XB_TRACE(bp, "pin", (long)bp->b_pin_count.counter);}voidxfs_buf_unpin(	xfs_buf_t		*bp){	if (atomic_dec_and_test(&bp->b_pin_count))		wake_up_all(&bp->b_waiters);	XB_TRACE(bp, "unpin", (long)bp->b_pin_count.counter);}intxfs_buf_ispin(	xfs_buf_t		*bp){	return atomic_read(&bp->b_pin_count);}STATIC voidxfs_buf_wait_unpin(	xfs_buf_t		*bp){	DECLARE_WAITQUEUE	(wait, current);	if (atomic_read(&bp->b_pin_count) == 0)		return;	add_wait_queue(&bp->b_waiters, &wait);	for (;;) {		set_current_state(TASK_UNINTERRUPTIBLE);		if (atomic_read(&bp->b_pin_count) == 0)			break;		if (atomic_read(&bp->b_io_remaining))			blk_run_address_space(bp->b_target->bt_mapping);		schedule();	}	remove_wait_queue(&bp->b_waiters, &wait);	set_current_state(TASK_RUNNING);}/* *	Buffer Utility Routines */STATIC voidxfs_buf_iodone_work(	void			*v){	xfs_buf_t		*bp = (xfs_buf_t *)v;	if (bp->b_iodone)		(*(bp->b_iodone))(bp);	else if (bp->b_flags & XBF_ASYNC)		xfs_buf_relse(bp);}voidxfs_buf_ioend(	xfs_buf_t		*bp,	int			schedule){	bp->b_flags &= ~(XBF_READ | XBF_WRITE);	if (bp->b_error == 0)		bp->b_flags |= XBF_DONE;	XB_TRACE(bp, "iodone", bp->b_iodone);	if ((bp->b_iodone) || (bp->b_flags & XBF_ASYNC)) {		if (schedule) {			INIT_WORK(&bp->b_iodone_work, xfs_buf_iodone_work, bp);			queue_work(xfslogd_workqueue, &bp->b_iodone_work);		} else {			xfs_buf_iodone_work(bp);		}	} else {		up(&bp->b_iodonesema);	}}voidxfs_buf_ioerror(	xfs_buf_t		*bp,	int			error){	ASSERT(error >= 0 && error <= 0xffff);	bp->b_error = (unsigned short)error;	XB_TRACE(bp, "ioerror", (unsigned long)error);}/* *	Initiate I/O on a buffer, based on the flags supplied. *	The b_iodone routine in the buffer supplied will only be called *	when all of the subsidiary I/O requests, if any, have been completed. */intxfs_buf_iostart(	xfs_buf_t		*bp,	xfs_buf_flags_t		flags){	int			status = 0;	XB_TRACE(bp, "iostart", (unsigned long)flags);	if (flags & XBF_DELWRI) {		bp->b_flags &= ~(XBF_READ | XBF_WRITE | XBF_ASYNC);		bp->b_flags |= flags & (XBF_DELWRI | XBF_ASYNC);		xfs_buf_delwri_queue(bp, 1);		return status;	}	bp->b_flags &= ~(XBF_READ | XBF_WRITE | XBF_ASYNC | XBF_DELWRI | \			XBF_READ_AHEAD | _XBF_RUN_QUEUES);	bp->b_flags |= flags & (XBF_READ | XBF_WRITE | XBF_ASYNC | \			XBF_READ_AHEAD | _XBF_RUN_QUEUES);	BUG_ON(bp->b_bn == XFS_BUF_DADDR_NULL);	/* For writes allow an alternate strategy routine to precede	 * the actual I/O request (which may not be issued at all in	 * a shutdown situation, for example).	 */	status = (flags & XBF_WRITE) ?		xfs_buf_iostrategy(bp) : xfs_buf_iorequest(bp);	/* Wait for I/O if we are not an async request.	 * Note: async I/O request completion will release the buffer,	 * and that can already be done by this point.  So using the	 * buffer pointer from here on, after async I/O, is invalid.	 */	if (!status && !(flags & XBF_ASYNC))		status = xfs_buf_iowait(bp);	return status;}STATIC __inline__ int_xfs_buf_iolocked(	xfs_buf_t		*bp){	ASSERT(bp->b_flags & (XBF_READ | XBF_WRITE));	if (bp->b_flags & XBF_READ)		return bp->b_locked;	return 0;}STATIC __inline__ void_xfs_buf_ioend(	xfs_buf_t		*bp,	int			schedule){	if (atomic_dec_and_test(&bp->b_io_remaining) == 1) {		bp->b_locked = 0;		xfs_buf_ioend(bp, schedule);	}}STATIC intxfs_buf_bio_end_io(	struct bio		*bio,	unsigned int		bytes_done,	int			error){	xfs_buf_t		*bp = (xfs_buf_t *)bio->bi_private;	unsigned int		blocksize = bp->b_target->bt_bsize;	struct bio_vec		*bvec = bio->bi_io_vec + bio->bi_vcnt - 1;	if (bio->bi_size)		return 1;	if (!test_bit(BIO_UPTODATE, &bio->bi_flags))		bp->b_error = EIO;	do {		struct page	*page = bvec->bv_page;		if (unlikely(bp->b_error)) {			if (bp->b_flags & XBF_READ)				ClearPageUptodate(page);			SetPageError(page);		} else if (blocksize >= PAGE_CACHE_SIZE) {			SetPageUptodate(page);		} else if (!PagePrivate(page) &&				(bp->b_flags & _XBF_PAGE_CACHE)) {			set_page_region(page, bvec->bv_offset, bvec->bv_len);		}		if (--bvec >= bio->bi_io_vec)			prefetchw(&bvec->bv_page->flags);		if (_xfs_buf_iolocked(bp)) {			unlock_page(page);		}	} while (bvec >= bio->bi_io_vec);	_xfs_buf_ioend(bp, 1);	bio_put(bio);	return 0;}STATIC void_xfs_buf_ioapply(	xfs_buf_t		*bp){	int			i, rw, map_i, total_nr_pages, nr_pages;	struct bio		*bio;	int			offset = bp->b_offset;	int			size = bp->b_count_desired;	sector_t		sector = bp->b_bn;	unsigned int		blocksize = bp->b_target->bt_bsize;	int			locking = _xfs_buf_iolocked(bp);	total_nr_pages = bp->b_page_count;	map_i = 0;	if (bp->b_flags & _XBF_RUN_QUEUES) {		bp->b_flags &= ~_XBF_RUN_QUEUES;		rw = (bp->b_flags & XBF_READ) ? READ_SYNC : WRITE_SYNC;	} else {		rw = (bp->b_flags & XBF_READ) ? READ : WRITE;	}	if (bp->b_flags & XBF_ORDERED) {		ASSERT(!(bp->b_flags & XBF_READ));		rw = WRITE_BARRIER;	}	/* Special code path for reading a sub page size buffer in --	 * we populate up the whole page, and hence the other metadata	 * in the same page.  This optimization is only valid when the	 * filesystem block size is not smaller than the page size.	 */	if ((bp->b_buffer_length < PAGE_CACHE_SIZE) &&	    (bp->b_flags & XBF_READ) && locking &&	    (blocksize >= PAGE_CACHE_SIZE)) {		bio = bio_alloc(GFP_NOIO, 1);		bio->bi_bdev = bp->b_target->bt_bdev;		bio->bi_sector = sector - (offset >> BBSHIFT);		bio->bi_end_io = xfs_buf_bio_end_io;		bio->bi_private = bp;		bio_add_page(bio, bp->b_pages[0], PAGE_CACHE_SIZE, 0);		size = 0;		atomic_inc(&bp->b_io_remaining);		goto submit_io;	}	/* Lock down the pages which we need to for the request */	if (locking && (bp->b_flags & XBF_WRITE) && (bp->b_locked == 0)) {		for (i = 0; size; i++) {			int		nbytes = PAGE_CACHE_SIZE - offset;			struct page	*page = bp->b_pages[i];			if (nbytes > size)				nbytes = size;			lock_page(page);			size -= nbytes;			offset = 0;		}		offset = bp->b_offset;		size = bp->b_count_desired;	}next_chunk:	atomic_inc(&bp->b_io_remaining);	nr_pages = BIO_MAX_SECTORS >> (PAGE_SHIFT - BBSHIFT);	if (nr_pages > total_nr_pages)		nr_pages = total_nr_pages;	bio = bio_alloc(GFP_NOIO, nr_pages);	bio->bi_bdev = bp->b_target->bt_bdev;	bio->bi_sector = sector;	bio->bi_end_io = xfs_buf_bio_end_io;	bio->bi_private = bp;	for (; size && nr_pages; nr_pages--, map_i++) {		int	rbytes, nbytes = PAGE_CACHE_SIZE - offset;		if (nbytes > size)			nbytes = size;		rbytes = bio_add_page(bio, bp->b_pages[map_i], nbytes, offset);		if (rbytes < nbytes)			break;		offset = 0;		sector += nbytes >> BBSHIFT;		size -= nbytes;		total_nr_pages--;	}

⌨️ 快捷键说明

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