===== xfs_buf.c 1.107 vs 1.116 ===== --- 1.107/fs/xfs/linux/xfs_buf.c 2004-04-21 07:12:40 +02:00 +++ 1.116/fs/xfs/linux-2.6/xfs_buf.c 2004-05-28 03:45:07 +02:00 @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include @@ -165,8 +164,6 @@ * Mapping of multi-page buffers into contiguous virtual space */ -STATIC void *pagebuf_mapout_locked(xfs_buf_t *); - typedef struct a_list { void *vm_addr; struct a_list *next; @@ -288,67 +285,53 @@ } /* - * Walk a pagebuf releasing all the pages contained within it. + * Frees pb_pages if it was malloced. */ -STATIC inline void -_pagebuf_freepages( - xfs_buf_t *pb) +STATIC void +_pagebuf_free_pages( + xfs_buf_t *bp) { - int buf_index; - - for (buf_index = 0; buf_index < pb->pb_page_count; buf_index++) { - struct page *page = pb->pb_pages[buf_index]; - - if (page) { - pb->pb_pages[buf_index] = NULL; - page_cache_release(page); - } + if (bp->pb_pages != bp->pb_page_array) { + kmem_free(bp->pb_pages, + bp->pb_page_count * sizeof(struct page *)); } } /* - * pagebuf_free + * Releases the specified buffer. * - * pagebuf_free releases the specified buffer. The modification - * state of any associated pages is left unchanged. + * The modification state of any associated pages is left unchanged. + * The buffer most not be on any hash - use pagebuf_rele instead for + * hashed and refcounted buffers */ void pagebuf_free( - xfs_buf_t *pb) + xfs_buf_t *bp) { - PB_TRACE(pb, "free", 0); - - ASSERT(list_empty(&pb->pb_hash_list)); - - /* release any virtual mapping */ ; - if (pb->pb_flags & _PBF_ADDR_ALLOCATED) { - void *vaddr = pagebuf_mapout_locked(pb); - if (vaddr) { - free_address(vaddr); - } - } + PB_TRACE(bp, "free", 0); - if (pb->pb_flags & _PBF_MEM_ALLOCATED) { - if (pb->pb_pages) { - if (pb->pb_flags & _PBF_MEM_SLAB) { - /* - * XXX: bp->pb_count_desired might be incorrect - * (see pagebuf_associate_memory for details), - * but fortunately the Linux version of - * kmem_free ignores the len argument.. - */ - kmem_free(pb->pb_addr, pb->pb_count_desired); - } else { - _pagebuf_freepages(pb); - } - if (pb->pb_pages != pb->pb_page_array) - kfree(pb->pb_pages); - pb->pb_pages = NULL; - } - pb->pb_flags &= ~(_PBF_MEM_ALLOCATED|_PBF_MEM_SLAB); + ASSERT(list_empty(&bp->pb_hash_list)); + + if (bp->pb_flags & _PBF_PAGE_CACHE) { + uint i; + + if ((bp->pb_flags & PBF_MAPPED) && (bp->pb_page_count > 1)) + free_address(bp->pb_addr - bp->pb_offset); + + for (i = 0; i < bp->pb_page_count; i++) + page_cache_release(bp->pb_pages[i]); + _pagebuf_free_pages(bp); + } else if (bp->pb_flags & _PBF_KMEM_ALLOC) { + /* + * XXX(hch): bp->pb_count_desired might be incorrect (see + * pagebuf_associate_memory for details), but fortunately + * the Linux version of kmem_free ignores the len argument.. + */ + kmem_free(bp->pb_addr, bp->pb_count_desired); + _pagebuf_free_pages(bp); } - pagebuf_deallocate(pb); + pagebuf_deallocate(bp); } /* @@ -376,6 +359,7 @@ error = _pagebuf_get_pages(bp, page_count, flags); if (unlikely(error)) return error; + bp->pb_flags |= _PBF_PAGE_CACHE; offset = bp->pb_offset; first = bp->pb_file_offset >> PAGE_CACHE_SHIFT; @@ -387,8 +371,12 @@ retry: page = find_or_create_page(mapping, first + i, gfp_mask); if (unlikely(page == NULL)) { - if (flags & PBF_READ_AHEAD) + if (flags & PBF_READ_AHEAD) { + bp->pb_page_count = i; + for (i = 0; i < bp->pb_page_count; i++) + unlock_page(bp->pb_pages[i]); return -ENOMEM; + } /* * This could deadlock. @@ -403,7 +391,7 @@ XFS_STATS_INC(pb_page_retries); pagebuf_daemon_wakeup(); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(10); goto retry; } @@ -412,7 +400,6 @@ nbytes = min_t(size_t, size, PAGE_CACHE_SIZE - offset); size -= nbytes; - offset = 0; if (!PageUptodate(page)) { page_count--; @@ -426,6 +413,7 @@ * In this case page->private holds a bitmap * of uptodate sectors within the page */ + ASSERT(blocksize < PAGE_CACHE_SIZE); range = (offset + nbytes) >> sectorshift; for (j = offset >> sectorshift; j < range; j++) if (!test_bit(j, &page->private)) @@ -436,6 +424,7 @@ } bp->pb_pages[i] = page; + offset = 0; } if (!bp->pb_locked) { @@ -443,8 +432,6 @@ unlock_page(bp->pb_pages[i]); } - bp->pb_flags |= (_PBF_PAGECACHE|_PBF_MEM_ALLOCATED); - if (page_count) { /* if we have any uptodate pages, mark that in the buffer */ bp->pb_flags &= ~PBF_NONE; @@ -478,7 +465,7 @@ if (unlikely(bp->pb_addr == NULL)) return -ENOMEM; bp->pb_addr += bp->pb_offset; - bp->pb_flags |= PBF_MAPPED | _PBF_ADDR_ALLOCATED; + bp->pb_flags |= PBF_MAPPED; } return 0; @@ -584,10 +571,7 @@ } if (pb->pb_flags & PBF_STALE) - pb->pb_flags &= PBF_MAPPED | \ - _PBF_ADDR_ALLOCATED | \ - _PBF_MEM_ALLOCATED | \ - _PBF_MEM_SLAB; + pb->pb_flags &= PBF_MAPPED; PB_TRACE(pb, "got_lock", 0); XFS_STATS_INC(pb_get_locked); return (pb); @@ -789,9 +773,9 @@ page_count++; /* Free any previous set of page pointers */ - if (pb->pb_pages && (pb->pb_pages != pb->pb_page_array)) { - kfree(pb->pb_pages); - } + if (pb->pb_pages) + _pagebuf_free_pages(pb); + pb->pb_pages = NULL; pb->pb_addr = mem; @@ -831,16 +815,13 @@ void *data; int error; - if (unlikely(len > 0x20000)) - goto fail; - 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); + data = kmem_alloc(malloc_len, KM_SLEEP | KM_MAYFAIL); if (unlikely(data == NULL)) goto fail_free_buf; @@ -856,7 +837,7 @@ error = pagebuf_associate_memory(bp, data, len); if (error) goto fail_free_mem; - bp->pb_flags |= (_PBF_MEM_ALLOCATED | _PBF_MEM_SLAB); + bp->pb_flags |= _PBF_KMEM_ALLOC; pagebuf_unlock(bp); @@ -1083,7 +1064,7 @@ add_wait_queue(&pb->pb_waiters, &wait); for (;;) { - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); if (atomic_read(&pb->pb_pin_count) == 0) break; if (atomic_read(&pb->pb_io_remaining)) @@ -1091,7 +1072,7 @@ schedule(); } remove_wait_queue(&pb->pb_waiters, &wait); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); } /* @@ -1189,9 +1170,9 @@ } pb->pb_flags &= ~(PBF_READ | PBF_WRITE | PBF_ASYNC | PBF_DELWRI | \ - PBF_READ_AHEAD | PBF_RUN_QUEUES); + PBF_READ_AHEAD | _PBF_RUN_QUEUES); pb->pb_flags |= flags & (PBF_READ | PBF_WRITE | PBF_ASYNC | \ - PBF_READ_AHEAD | PBF_RUN_QUEUES); + PBF_READ_AHEAD | _PBF_RUN_QUEUES); BUG_ON(pb->pb_bn == XFS_BUF_DADDR_NULL); @@ -1378,8 +1359,8 @@ pagebuf_ioerror(pb, EIO); } - if (pb->pb_flags & PBF_RUN_QUEUES) { - pb->pb_flags &= ~PBF_RUN_QUEUES; + if (pb->pb_flags & _PBF_RUN_QUEUES) { + pb->pb_flags &= ~_PBF_RUN_QUEUES; if (atomic_read(&pb->pb_io_remaining) > 1) blk_run_address_space(pb->pb_target->pbr_mapping); } @@ -1436,25 +1417,6 @@ return pb->pb_error; } -STATIC void * -pagebuf_mapout_locked( - xfs_buf_t *pb) -{ - void *old_addr = NULL; - - if (pb->pb_flags & PBF_MAPPED) { - if (pb->pb_flags & _PBF_ADDR_ALLOCATED) - old_addr = pb->pb_addr - pb->pb_offset; - pb->pb_addr = NULL; - pb->pb_flags &= ~(PBF_MAPPED | _PBF_ADDR_ALLOCATED); - } - - return old_addr; /* Caller must free the address space, - * we are under a spin lock, probably - * not safe to do vfree here - */ -} - caddr_t pagebuf_offset( xfs_buf_t *pb, @@ -1509,6 +1471,64 @@ } } +/* + * Handling of buftargs. + */ + +void +xfs_free_buftarg( + xfs_buftarg_t *btp, + int external) +{ + xfs_flush_buftarg(btp, 1); + if (external) + xfs_blkdev_put(btp->pbr_bdev); + kmem_free(btp, sizeof(*btp)); +} + +void +xfs_incore_relse( + xfs_buftarg_t *btp, + int delwri_only, + int wait) +{ + invalidate_bdev(btp->pbr_bdev, 1); + truncate_inode_pages(btp->pbr_mapping, 0LL); +} + +void +xfs_setsize_buftarg( + xfs_buftarg_t *btp, + unsigned int blocksize, + unsigned int sectorsize) +{ + btp->pbr_bsize = blocksize; + btp->pbr_sshift = ffs(sectorsize) - 1; + btp->pbr_smask = sectorsize - 1; + + if (set_blocksize(btp->pbr_bdev, sectorsize)) { + printk(KERN_WARNING + "XFS: Cannot set_blocksize to %u on device %s\n", + sectorsize, XFS_BUFTARG_NAME(btp)); + } +} + +xfs_buftarg_t * +xfs_alloc_buftarg( + struct block_device *bdev) +{ + xfs_buftarg_t *btp; + + btp = kmem_zalloc(sizeof(*btp), KM_SLEEP); + + btp->pbr_dev = bdev->bd_dev; + btp->pbr_bdev = bdev; + btp->pbr_mapping = bdev->bd_inode->i_mapping; + xfs_setsize_buftarg(btp, PAGE_CACHE_SIZE, bdev_hardsect_size(bdev)); + + return btp; +} + /* * Pagebuf delayed write buffer handling @@ -1579,6 +1599,7 @@ void *data) { struct list_head tmp; + unsigned long age; xfs_buf_t *pb, *n; /* Set up the thread */ @@ -1596,8 +1617,9 @@ refrigerator(PF_FREEZE); set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(xfs_flush_interval); + schedule_timeout((xfs_buf_timer_centisecs * HZ) / 100); + age = (xfs_buf_age_centisecs * HZ) / 100; spin_lock(&pbd_delwrite_lock); list_for_each_entry_safe(pb, n, &pbd_delwrite_queue, pb_list) { PB_TRACE(pb, "walkq1", (long)pagebuf_ispin(pb)); @@ -1606,8 +1628,7 @@ if (!pagebuf_ispin(pb) && !pagebuf_cond_lock(pb)) { if (!force_flush && time_before(jiffies, - pb->pb_queuetime + - xfs_age_buffer)) { + pb->pb_queuetime + age)) { pagebuf_unlock(pb); break; } @@ -1635,11 +1656,15 @@ complete_and_exit(&pagebuf_daemon_done, 0); } -void -pagebuf_delwri_flush( +/* + * Go through all incore buffers, and release buffers if they belong to + * the given device. This is used in filesystem error handling to + * preserve the consistency of its metadata. + */ +int +xfs_flush_buftarg( xfs_buftarg_t *target, - int wait, - int *pinptr) + int wait) { struct list_head tmp; xfs_buf_t *pb, *n; @@ -1695,8 +1720,7 @@ if (wait) blk_run_address_space(target->pbr_mapping); - if (pinptr) - *pinptr = pincount; + return pincount; } STATIC int