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

📄 xfs_buf.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (! (free = pb_resv_bh_cnt >= NR_RESERVED_BH)) {		spin_lock_irqsave(&pb_resv_bh_lock, flags);		if (! (free = pb_resv_bh_cnt >= NR_RESERVED_BH)) {			bh->b_pprev = &pb_resv_bh;			bh->b_next = pb_resv_bh;			pb_resv_bh = bh;			pb_resv_bh_cnt++;			if (waitqueue_active(&pb_resv_bh_wait)) {				wake_up(&pb_resv_bh_wait);			}		}		spin_unlock_irqrestore(&pb_resv_bh_lock, flags);	}	if (free) {		kmem_cache_free(bh_cachep, bh);	}}/* *	Finding and Reading Buffers *//* *	_pagebuf_find * *	Looks up, and creates if absent, a lockable buffer for *	a given range of an inode.  The buffer is returned *	locked.	 If other overlapping buffers exist, they are *	released before the new buffer is created and locked, *	which may imply that this call will block until those buffers *	are unlocked.  No I/O is implied by this call. */xfs_buf_t *_pagebuf_find(				/* find buffer for block	*/	xfs_buftarg_t		*target,/* target for block		*/	loff_t			ioff,	/* starting offset of range	*/	size_t			isize,	/* length of range		*/	page_buf_flags_t	flags,	/* PBF_TRYLOCK			*/	xfs_buf_t		*new_pb)/* newly allocated buffer	*/{	loff_t			range_base;	size_t			range_length;	int			hval;	pb_hash_t		*h;	xfs_buf_t		*pb, *n;	int			not_locked;	range_base = (ioff << BBSHIFT);	range_length = (isize << BBSHIFT);	/* Ensure we never do IOs smaller than the sector size */	BUG_ON(range_length < (1 << target->pbr_sshift));	/* Ensure we never do IOs that are not sector aligned */	BUG_ON(range_base & (loff_t)target->pbr_smask);	hval = _bhash(target->pbr_bdev, range_base);	h = &pbhash[hval];	spin_lock(&h->pb_hash_lock);	list_for_each_entry_safe(pb, n, &h->pb_hash, pb_hash_list) {		if (pb->pb_target == target &&		    pb->pb_file_offset == range_base &&		    pb->pb_buffer_length == range_length) {			/* If we look at something bring it to the			 * front of the list for next time			 */			atomic_inc(&pb->pb_hold);			list_move(&pb->pb_hash_list, &h->pb_hash);			goto found;		}	}	/* No match found */	if (new_pb) {		_pagebuf_initialize(new_pb, target, range_base,				range_length, flags);		new_pb->pb_hash_index = hval;		list_add(&new_pb->pb_hash_list, &h->pb_hash);	} else {		XFS_STATS_INC(pb_miss_locked);	}	spin_unlock(&h->pb_hash_lock);	return (new_pb);found:	spin_unlock(&h->pb_hash_lock);	/* Attempt to get the semaphore without sleeping,	 * if this does not work then we need to drop the	 * spinlock and do a hard attempt on the semaphore.	 */	not_locked = down_trylock(&pb->pb_sema);	if (not_locked) {		if (!(flags & PBF_TRYLOCK)) {			/* wait for buffer ownership */			PB_TRACE(pb, "get_lock", 0);			pagebuf_lock(pb);			XFS_STATS_INC(pb_get_locked_waited);		} else {			/* We asked for a trylock and failed, no need			 * to look at file offset and length here, we			 * know that this pagebuf at least overlaps our			 * pagebuf and is locked, therefore our buffer			 * either does not exist, or is this buffer			 */			pagebuf_rele(pb);			XFS_STATS_INC(pb_busy_locked);			return (NULL);		}	} else {		/* trylock worked */		PB_SET_OWNER(pb);	}	if (pb->pb_flags & PBF_STALE)		pb->pb_flags &= PBF_MAPPED;	PB_TRACE(pb, "got_lock", 0);	XFS_STATS_INC(pb_get_locked);	return (pb);}/* *	xfs_buf_get_flags assembles a buffer covering the specified range. * *	Storage in memory for all portions of the buffer will be allocated, *	although backing storage may not be. */xfs_buf_t *xfs_buf_get_flags(			/* allocate a buffer		*/	xfs_buftarg_t		*target,/* target for buffer		*/	loff_t			ioff,	/* starting offset of range	*/	size_t			isize,	/* length of range		*/	page_buf_flags_t	flags)	/* PBF_TRYLOCK			*/{	xfs_buf_t		*pb, *new_pb;	int			error = 0, i;	new_pb = pagebuf_allocate(flags);	if (unlikely(!new_pb))		return NULL;	pb = _pagebuf_find(target, ioff, isize, flags, new_pb);	if (pb == new_pb) {		error = _pagebuf_lookup_pages(pb, flags);		if (error)			goto no_buffer;	} else {		pagebuf_deallocate(new_pb);		if (unlikely(pb == NULL))			return NULL;	}	for (i = 0; i < pb->pb_page_count; i++)		mark_page_accessed(pb->pb_pages[i]);	if (!(pb->pb_flags & PBF_MAPPED)) {		error = _pagebuf_map_pages(pb, flags);		if (unlikely(error)) {			printk(KERN_WARNING "%s: failed to map pages\n",					__FUNCTION__);			goto no_buffer;		}	}	XFS_STATS_INC(pb_get);	/*	 * Always fill in the block number now, the mapped cases can do	 * their own overlay of this later.	 */	pb->pb_bn = ioff;	pb->pb_count_desired = pb->pb_buffer_length;	PB_TRACE(pb, "get", (unsigned long)flags);	return pb; no_buffer:	if (flags & (PBF_LOCK | PBF_TRYLOCK))		pagebuf_unlock(pb);	pagebuf_rele(pb);	return NULL;}xfs_buf_t *xfs_buf_read_flags(	xfs_buftarg_t		*target,	loff_t			ioff,	size_t			isize,	page_buf_flags_t	flags){	xfs_buf_t		*pb;	flags |= PBF_READ;	pb = xfs_buf_get_flags(target, ioff, isize, flags);	if (pb) {		if (PBF_NOT_DONE(pb)) {			PB_TRACE(pb, "read", (unsigned long)flags);			XFS_STATS_INC(pb_get_read);			pagebuf_iostart(pb, flags);		} else if (flags & PBF_ASYNC) {			PB_TRACE(pb, "read_async", (unsigned long)flags);			/*			 * Read ahead call which is already satisfied,			 * drop the buffer			 */			goto no_buffer;		} else {			PB_TRACE(pb, "read_done", (unsigned long)flags);			/* We do not want read in the flags */			pb->pb_flags &= ~PBF_READ;		}	}	return pb; no_buffer:	if (flags & (PBF_LOCK | PBF_TRYLOCK))		pagebuf_unlock(pb);	pagebuf_rele(pb);	return NULL;}/* * Create a skeletal pagebuf (no pages associated with it). */xfs_buf_t *pagebuf_lookup(	xfs_buftarg_t		*target,	loff_t			ioff,	size_t			isize,	page_buf_flags_t	flags){	xfs_buf_t		*pb;	flags |= _PBF_PRIVATE_BH;	pb = pagebuf_allocate(flags);	if (pb) {		_pagebuf_initialize(pb, target, ioff, isize, flags);	}	return pb;}/* * If we are not low on memory then do the readahead in a deadlock * safe manner. */voidpagebuf_readahead(	xfs_buftarg_t		*target,	loff_t			ioff,	size_t			isize,	page_buf_flags_t	flags){	flags |= (PBF_TRYLOCK|PBF_ASYNC|PBF_READ_AHEAD);	xfs_buf_read_flags(target, ioff, isize, flags);}xfs_buf_t *pagebuf_get_empty(	size_t			len,	xfs_buftarg_t		*target){	xfs_buf_t		*pb;	pb = pagebuf_allocate(0);	if (pb)		_pagebuf_initialize(pb, target, 0, len, 0);	return pb;}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);	}}intpagebuf_associate_memory(	xfs_buf_t		*pb,	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 (pb->pb_pages)		_pagebuf_free_pages(pb);	pb->pb_pages = NULL;	pb->pb_addr = mem;	rval = _pagebuf_get_pages(pb, page_count, 0);	if (rval)		return rval;	pb->pb_offset = offset;	ptr = (size_t) mem & PAGE_CACHE_MASK;	end = PAGE_CACHE_ALIGN((size_t) mem + len);	end_cur = end;	/* set up first page */	pb->pb_pages[0] = mem_to_page(mem);	ptr += PAGE_CACHE_SIZE;	pb->pb_page_count = ++i;	while (ptr < end) {		pb->pb_pages[i] = mem_to_page((void *)ptr);		pb->pb_page_count = ++i;		ptr += PAGE_CACHE_SIZE;	}	pb->pb_locked = 0;	pb->pb_count_desired = pb->pb_buffer_length = len;	pb->pb_flags |= PBF_MAPPED | _PBF_PRIVATE_BH;	return 0;}xfs_buf_t *pagebuf_get_no_daddr(	size_t			len,	xfs_buftarg_t		*target){	size_t			malloc_len = len;	xfs_buf_t		*bp;	void			*data;	int			error;	bp = pagebuf_allocate(0);	if (unlikely(bp == NULL))		goto fail;	_pagebuf_initialize(bp, target, 0, len, PBF_FORCEIO); 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->pbr_smask)) {		/* .. else double the size and try again */		kmem_free(data, malloc_len);		malloc_len <<= 1;		goto try_again;	}	error = pagebuf_associate_memory(bp, data, len);	if (error)		goto fail_free_mem;	bp->pb_flags |= _PBF_KMEM_ALLOC;	pagebuf_unlock(bp);	PB_TRACE(bp, "no_daddr", data);	return bp; fail_free_mem:	kmem_free(data, malloc_len); fail_free_buf:	pagebuf_free(bp); fail:	return NULL;}/* *	pagebuf_hold * *	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. */voidpagebuf_hold(	xfs_buf_t		*pb){	atomic_inc(&pb->pb_hold);	PB_TRACE(pb, "hold", 0);}/* *	pagebuf_rele * *	pagebuf_rele releases a hold on the specified buffer.  If the *	the hold count is 1, pagebuf_rele calls pagebuf_free. */voidpagebuf_rele(	xfs_buf_t		*pb){	pb_hash_t		*hash = pb_hash(pb);	PB_TRACE(pb, "rele", pb->pb_relse);	if (atomic_dec_and_lock(&pb->pb_hold, &hash->pb_hash_lock)) {		int		do_free = 1;		if (pb->pb_relse) {			atomic_inc(&pb->pb_hold);			spin_unlock(&hash->pb_hash_lock);			(*(pb->pb_relse)) (pb);			spin_lock(&hash->pb_hash_lock);			do_free = 0;		}		if (pb->pb_flags & PBF_DELWRI) {			pb->pb_flags |= PBF_ASYNC;			atomic_inc(&pb->pb_hold);			pagebuf_delwri_queue(pb, 0);			do_free = 0;		} else if (pb->pb_flags & PBF_FS_MANAGED) {			do_free = 0;		}		if (do_free) {			list_del_init(&pb->pb_hash_list);			spin_unlock(&hash->pb_hash_lock);			xfs_buf_free(pb);		} else {			spin_unlock(&hash->pb_hash_lock);		}	}}/* *	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. *//* *	pagebuf_cond_lock * *	pagebuf_cond_lock 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 page buffer objects, not for synchronizing independent *	access to the underlying pages. */intpagebuf_cond_lock(			/* lock buffer, if not locked	*/					/* returns -EBUSY if locked)	*/	xfs_buf_t		*pb){	int			locked;	locked = down_trylock(&pb->pb_sema) == 0;	if (locked) {		PB_SET_OWNER(pb);	}	PB_TRACE(pb, "cond_lock", (long)locked);	return(locked ? 0 : -EBUSY);}#ifdef DEBUG/* *	pagebuf_lock_value * *	Return lock value for a pagebuf */intpagebuf_lock_value(	xfs_buf_t		*pb){	return(atomic_read(&pb->pb_sema.count));}#endif/* *	pagebuf_lock * *	pagebuf_lock locks a buffer object.  Note that this in no way *	locks the underlying pages, so it is only useful for synchronizing *	concurrent use of page buffer objects, not for synchronizing independent *	access to the underlying pages. */intpagebuf_lock(	xfs_buf_t		*pb){	PB_TRACE(pb, "lock", 0);	if (atomic_read(&pb->pb_io_remaining))		run_task_queue(&tq_disk);	down(&pb->pb_sema);	PB_SET_OWNER(pb);	PB_TRACE(pb, "locked", 0);	return 0;}/* *	pagebuf_unlock * *	pagebuf_unlock releases the lock on the buffer object created by *	pagebuf_lock or pagebuf_cond_lock (not any *	pinning of underlying pages created by pagebuf_pin). */voidpagebuf_unlock(				/* unlock buffer		*/	xfs_buf_t		*pb)	/* buffer to unlock		*/{	PB_CLEAR_OWNER(pb);	up(&pb->pb_sema);	PB_TRACE(pb, "unlock", 0);}/* *	Pinning Buffer Storage in Memory *//* *	pagebuf_pin * *	pagebuf_pin locks all of the memory represented by a buffer in *	memory.  Multiple calls to pagebuf_pin and pagebuf_unpin, for *	the same or different buffers affecting a given page, will *	properly count the number of outstanding "pin" requests.  The *	buffer may be released after the pagebuf_pin and a different *	buffer used when calling pagebuf_unpin, if desired. *	pagebuf_pin should be used by the file system when it wants be *	assured that no attempt will be made to force the affected *	memory to disk.	 It does not assure that a given logical page *	will not be moved to a different physical page. */voidpagebuf_pin(	xfs_buf_t		*pb){	atomic_inc(&pb->pb_pin_count);	PB_TRACE(pb, "pin", (long)pb->pb_pin_count.counter);}/* *	pagebuf_unpin * *	pagebuf_unpin reverses the locking of memory performed by *	pagebuf_pin.  Note that both functions affected the logical *	pages associated with the buffer, not the buffer itself. */voidpagebuf_unpin(	xfs_buf_t		*pb){	if (atomic_dec_and_test(&pb->pb_pin_count)) {		wake_up_all(&pb->pb_waiters);	}	PB_TRACE(pb, "unpin", (long)pb->pb_pin_count.counter);}intpagebuf_ispin(	xfs_buf_t		*pb){	return atomic_read(&pb->pb_pin_count);}/* *	pagebuf_wait_unpin * *	pagebuf_wait_unpin waits until all of the memory associated *	with the buffer is not longer locked in memory.  It returns *	immediately if none of the affected pages are locked. */static inline void_pagebuf_wait_unpin(

⌨️ 快捷键说明

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