Commit 1fa40b01 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Tim Shimmin

[XFS] Only use refcounted pages for I/O

Many block drivers (aoe, iscsi) really want refcountable pages in bios,
which is what almost everyone send down. XFS unfortunately has a few
places where it sends down buffers that may come from kmalloc, which
breaks them.

Fix the places that use kmalloc()d buffers.

SGI-PV: 964546
SGI-Modid: xfs-linux-melb:xfs-kern:28562a
Signed-Off-By: default avatarChristoph Hellwig <hch@infradead.org>
Signed-off-by: default avatarDavid Chinner <dgc@sgi.com>
Signed-off-by: default avatarTim Shimmin <tes@sgi.com>
parent 4eb6bf6b
...@@ -314,7 +314,7 @@ xfs_buf_free( ...@@ -314,7 +314,7 @@ xfs_buf_free(
ASSERT(list_empty(&bp->b_hash_list)); ASSERT(list_empty(&bp->b_hash_list));
if (bp->b_flags & _XBF_PAGE_CACHE) { if (bp->b_flags & (_XBF_PAGE_CACHE|_XBF_PAGES)) {
uint i; uint i;
if ((bp->b_flags & XBF_MAPPED) && (bp->b_page_count > 1)) if ((bp->b_flags & XBF_MAPPED) && (bp->b_page_count > 1))
...@@ -323,18 +323,11 @@ xfs_buf_free( ...@@ -323,18 +323,11 @@ xfs_buf_free(
for (i = 0; i < bp->b_page_count; i++) { for (i = 0; i < bp->b_page_count; i++) {
struct page *page = bp->b_pages[i]; struct page *page = bp->b_pages[i];
ASSERT(!PagePrivate(page)); if (bp->b_flags & _XBF_PAGE_CACHE)
ASSERT(!PagePrivate(page));
page_cache_release(page); page_cache_release(page);
} }
_xfs_buf_free_pages(bp); _xfs_buf_free_pages(bp);
} else if (bp->b_flags & _XBF_KMEM_ALLOC) {
/*
* XXX(hch): bp->b_count_desired might be incorrect (see
* xfs_buf_associate_memory for details), but fortunately
* the Linux version of kmem_free ignores the len argument..
*/
kmem_free(bp->b_addr, bp->b_count_desired);
_xfs_buf_free_pages(bp);
} }
xfs_buf_deallocate(bp); xfs_buf_deallocate(bp);
...@@ -764,41 +757,41 @@ xfs_buf_get_noaddr( ...@@ -764,41 +757,41 @@ xfs_buf_get_noaddr(
size_t len, size_t len,
xfs_buftarg_t *target) xfs_buftarg_t *target)
{ {
size_t malloc_len = len; unsigned long page_count = PAGE_ALIGN(len) >> PAGE_SHIFT;
int error, i;
xfs_buf_t *bp; xfs_buf_t *bp;
void *data;
int error;
bp = xfs_buf_allocate(0); bp = xfs_buf_allocate(0);
if (unlikely(bp == NULL)) if (unlikely(bp == NULL))
goto fail; goto fail;
_xfs_buf_initialize(bp, target, 0, len, 0); _xfs_buf_initialize(bp, target, 0, len, 0);
try_again: error = _xfs_buf_get_pages(bp, page_count, 0);
data = kmem_alloc(malloc_len, KM_SLEEP | KM_MAYFAIL | KM_LARGE); if (error)
if (unlikely(data == NULL))
goto fail_free_buf; goto fail_free_buf;
/* check whether alignment matches.. */ for (i = 0; i < page_count; i++) {
if ((__psunsigned_t)data != bp->b_pages[i] = alloc_page(GFP_KERNEL);
((__psunsigned_t)data & ~target->bt_smask)) { if (!bp->b_pages[i])
/* .. else double the size and try again */ goto fail_free_mem;
kmem_free(data, malloc_len);
malloc_len <<= 1;
goto try_again;
} }
bp->b_flags |= _XBF_PAGES;
error = xfs_buf_associate_memory(bp, data, len); error = _xfs_buf_map_pages(bp, XBF_MAPPED);
if (error) if (unlikely(error)) {
printk(KERN_WARNING "%s: failed to map pages\n",
__FUNCTION__);
goto fail_free_mem; goto fail_free_mem;
bp->b_flags |= _XBF_KMEM_ALLOC; }
xfs_buf_unlock(bp); xfs_buf_unlock(bp);
XB_TRACE(bp, "no_daddr", data); XB_TRACE(bp, "no_daddr", len);
return bp; return bp;
fail_free_mem: fail_free_mem:
kmem_free(data, malloc_len); while (--i >= 0)
__free_page(bp->b_pages[i]);
fail_free_buf: fail_free_buf:
xfs_buf_free(bp); xfs_buf_free(bp);
fail: fail:
......
...@@ -63,7 +63,7 @@ typedef enum { ...@@ -63,7 +63,7 @@ typedef enum {
/* flags used only internally */ /* flags used only internally */
_XBF_PAGE_CACHE = (1 << 17),/* backed by pagecache */ _XBF_PAGE_CACHE = (1 << 17),/* backed by pagecache */
_XBF_KMEM_ALLOC = (1 << 18),/* backed by kmem_alloc() */ _XBF_PAGES = (1 << 18), /* backed by refcounted pages */
_XBF_RUN_QUEUES = (1 << 19),/* run block device task queue */ _XBF_RUN_QUEUES = (1 << 19),/* run block device task queue */
_XBF_DELWRI_Q = (1 << 21), /* buffer on delwri queue */ _XBF_DELWRI_Q = (1 << 21), /* buffer on delwri queue */
} xfs_buf_flags_t; } xfs_buf_flags_t;
......
...@@ -1199,11 +1199,18 @@ xlog_alloc_log(xfs_mount_t *mp, ...@@ -1199,11 +1199,18 @@ xlog_alloc_log(xfs_mount_t *mp,
*iclogp = (xlog_in_core_t *) *iclogp = (xlog_in_core_t *)
kmem_zalloc(sizeof(xlog_in_core_t), KM_SLEEP); kmem_zalloc(sizeof(xlog_in_core_t), KM_SLEEP);
iclog = *iclogp; iclog = *iclogp;
iclog->hic_data = (xlog_in_core_2_t *)
kmem_zalloc(iclogsize, KM_SLEEP | KM_LARGE);
iclog->ic_prev = prev_iclog; iclog->ic_prev = prev_iclog;
prev_iclog = iclog; prev_iclog = iclog;
bp = xfs_buf_get_noaddr(log->l_iclog_size, mp->m_logdev_targp);
if (!XFS_BUF_CPSEMA(bp))
ASSERT(0);
XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone);
XFS_BUF_SET_BDSTRAT_FUNC(bp, xlog_bdstrat_cb);
XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1);
iclog->ic_bp = bp;
iclog->hic_data = bp->b_addr;
log->l_iclog_bak[i] = (xfs_caddr_t)&(iclog->ic_header); log->l_iclog_bak[i] = (xfs_caddr_t)&(iclog->ic_header);
head = &iclog->ic_header; head = &iclog->ic_header;
...@@ -1216,11 +1223,6 @@ xlog_alloc_log(xfs_mount_t *mp, ...@@ -1216,11 +1223,6 @@ xlog_alloc_log(xfs_mount_t *mp,
INT_SET(head->h_fmt, ARCH_CONVERT, XLOG_FMT); INT_SET(head->h_fmt, ARCH_CONVERT, XLOG_FMT);
memcpy(&head->h_fs_uuid, &mp->m_sb.sb_uuid, sizeof(uuid_t)); memcpy(&head->h_fs_uuid, &mp->m_sb.sb_uuid, sizeof(uuid_t));
bp = xfs_buf_get_empty(log->l_iclog_size, mp->m_logdev_targp);
XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone);
XFS_BUF_SET_BDSTRAT_FUNC(bp, xlog_bdstrat_cb);
XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1);
iclog->ic_bp = bp;
iclog->ic_size = XFS_BUF_SIZE(bp) - log->l_iclog_hsize; iclog->ic_size = XFS_BUF_SIZE(bp) - log->l_iclog_hsize;
iclog->ic_state = XLOG_STATE_ACTIVE; iclog->ic_state = XLOG_STATE_ACTIVE;
...@@ -1528,7 +1530,6 @@ xlog_dealloc_log(xlog_t *log) ...@@ -1528,7 +1530,6 @@ xlog_dealloc_log(xlog_t *log)
} }
#endif #endif
next_iclog = iclog->ic_next; next_iclog = iclog->ic_next;
kmem_free(iclog->hic_data, log->l_iclog_size);
kmem_free(iclog, sizeof(xlog_in_core_t)); kmem_free(iclog, sizeof(xlog_in_core_t));
iclog = next_iclog; iclog = next_iclog;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment