diff options
Diffstat (limited to 'fs/buffer.c')
| -rw-r--r-- | fs/buffer.c | 55 | 
1 files changed, 52 insertions, 3 deletions
diff --git a/fs/buffer.c b/fs/buffer.c index d2a4d1bb2d57..4d7433534f5c 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -83,6 +83,40 @@ void unlock_buffer(struct buffer_head *bh)  EXPORT_SYMBOL(unlock_buffer);  /* + * Returns if the page has dirty or writeback buffers. If all the buffers + * are unlocked and clean then the PageDirty information is stale. If + * any of the pages are locked, it is assumed they are locked for IO. + */ +void buffer_check_dirty_writeback(struct page *page, +				     bool *dirty, bool *writeback) +{ +	struct buffer_head *head, *bh; +	*dirty = false; +	*writeback = false; + +	BUG_ON(!PageLocked(page)); + +	if (!page_has_buffers(page)) +		return; + +	if (PageWriteback(page)) +		*writeback = true; + +	head = page_buffers(page); +	bh = head; +	do { +		if (buffer_locked(bh)) +			*writeback = true; + +		if (buffer_dirty(bh)) +			*dirty = true; + +		bh = bh->b_this_page; +	} while (bh != head); +} +EXPORT_SYMBOL(buffer_check_dirty_writeback); + +/*   * Block until a buffer comes unlocked.  This doesn't stop it   * from becoming locked again - you have to lock it yourself   * if you want to preserve its state. @@ -1454,7 +1488,8 @@ static void discard_buffer(struct buffer_head * bh)   * block_invalidatepage - invalidate part or all of a buffer-backed page   *   * @page: the page which is affected - * @offset: the index of the truncation point + * @offset: start of the range to invalidate + * @length: length of the range to invalidate   *   * block_invalidatepage() is called when all or part of the page has become   * invalidated by a truncate operation. @@ -1465,15 +1500,22 @@ static void discard_buffer(struct buffer_head * bh)   * point.  Because the caller is about to free (and possibly reuse) those   * blocks on-disk.   */ -void block_invalidatepage(struct page *page, unsigned long offset) +void block_invalidatepage(struct page *page, unsigned int offset, +			  unsigned int length)  {  	struct buffer_head *head, *bh, *next;  	unsigned int curr_off = 0; +	unsigned int stop = length + offset;  	BUG_ON(!PageLocked(page));  	if (!page_has_buffers(page))  		goto out; +	/* +	 * Check for overflow +	 */ +	BUG_ON(stop > PAGE_CACHE_SIZE || stop < length); +  	head = page_buffers(page);  	bh = head;  	do { @@ -1481,6 +1523,12 @@ void block_invalidatepage(struct page *page, unsigned long offset)  		next = bh->b_this_page;  		/* +		 * Are we still fully in range ? +		 */ +		if (next_off > stop) +			goto out; + +		/*  		 * is this block fully invalidated?  		 */  		if (offset <= curr_off) @@ -1501,6 +1549,7 @@ out:  }  EXPORT_SYMBOL(block_invalidatepage); +  /*   * We attach and possibly dirty the buffers atomically wrt   * __set_page_dirty_buffers() via private_lock.  try_to_free_buffers @@ -2841,7 +2890,7 @@ int block_write_full_page_endio(struct page *page, get_block_t *get_block,  		 * they may have been added in ext3_writepage().  Make them  		 * freeable here, so the page does not leak.  		 */ -		do_invalidatepage(page, 0); +		do_invalidatepage(page, 0, PAGE_CACHE_SIZE);  		unlock_page(page);  		return 0; /* don't care */  	}  | 

