X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fxfs%2Flinux-2.6%2Fxfs_buf.c;h=4c0a72c305c531a8ab59dee51e88f3ef52eb40df;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=b6dc7d9dca7da3cc0c74cf4fd4af9ef25858433d;hpb=e812ccbe0c915857ebea6a632bfadc631f7504a9;p=linux-2.6.git diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index b6dc7d9dc..4c0a72c30 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -65,7 +65,8 @@ */ STATIC kmem_cache_t *pagebuf_cache; -STATIC void pagebuf_daemon_wakeup(void); +STATIC kmem_shaker_t pagebuf_shake; +STATIC int pagebuf_daemon_wakeup(int, unsigned int); STATIC void pagebuf_delwri_queue(xfs_buf_t *, int); STATIC struct workqueue_struct *pagebuf_logio_workqueue; STATIC struct workqueue_struct *pagebuf_dataio_workqueue; @@ -384,13 +385,13 @@ _pagebuf_lookup_pages( * But until all the XFS lowlevel code is revamped to * handle buffer allocation failures we can't do much. */ - if (!(++retries % 100)) { - printk(KERN_ERR "possibly deadlocking in %s\n", - __FUNCTION__); - } + if (!(++retries % 100)) + printk(KERN_ERR + "possible deadlock in %s (mode:0x%x)\n", + __FUNCTION__, gfp_mask); XFS_STATS_INC(pb_page_retries); - pagebuf_daemon_wakeup(); + pagebuf_daemon_wakeup(0, gfp_mask); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(10); goto retry; @@ -625,11 +626,8 @@ pagebuf_get( /* allocate a buffer */ pb = _pagebuf_find(target, ioff, isize, flags, new_pb); if (pb == new_pb) { error = _pagebuf_lookup_pages(pb, flags); - if (unlikely(error)) { - printk(KERN_WARNING - "pagebuf_get: failed to lookup pages\n"); + if (error) goto no_buffer; - } } else { pagebuf_deallocate(new_pb); if (unlikely(pb == NULL)) @@ -1483,6 +1481,7 @@ xfs_free_buftarg( xfs_flush_buftarg(btp, 1); if (external) xfs_blkdev_put(btp->pbr_bdev); + iput(btp->pbr_mapping->host); kmem_free(btp, sizeof(*btp)); } @@ -1496,7 +1495,7 @@ xfs_incore_relse( truncate_inode_pages(btp->pbr_mapping, 0LL); } -void +int xfs_setsize_buftarg( xfs_buftarg_t *btp, unsigned int blocksize, @@ -1510,7 +1509,42 @@ xfs_setsize_buftarg( printk(KERN_WARNING "XFS: Cannot set_blocksize to %u on device %s\n", sectorsize, XFS_BUFTARG_NAME(btp)); + return EINVAL; + } + return 0; +} + +STATIC int +xfs_mapping_buftarg( + xfs_buftarg_t *btp, + struct block_device *bdev) +{ + struct backing_dev_info *bdi; + struct inode *inode; + struct address_space *mapping; + static struct address_space_operations mapping_aops = { + .sync_page = block_sync_page, + }; + + inode = new_inode(bdev->bd_inode->i_sb); + if (!inode) { + printk(KERN_WARNING + "XFS: Cannot allocate mapping inode for device %s\n", + XFS_BUFTARG_NAME(btp)); + return ENOMEM; } + inode->i_mode = S_IFBLK; + inode->i_bdev = bdev; + inode->i_rdev = bdev->bd_dev; + bdi = blk_get_backing_dev_info(bdev); + if (!bdi) + bdi = &default_backing_dev_info; + mapping = &inode->i_data; + mapping->a_ops = &mapping_aops; + mapping->backing_dev_info = bdi; + mapping_set_gfp_mask(mapping, GFP_KERNEL); + btp->pbr_mapping = mapping; + return 0; } xfs_buftarg_t * @@ -1523,10 +1557,15 @@ xfs_alloc_buftarg( 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)); - + if (xfs_setsize_buftarg(btp, PAGE_CACHE_SIZE, bdev_hardsect_size(bdev))) + goto error; + if (xfs_mapping_buftarg(btp, bdev)) + goto error; return btp; + +error: + kmem_free(btp, sizeof(*btp)); + return NULL; } @@ -1566,11 +1605,20 @@ void pagebuf_delwri_dequeue( xfs_buf_t *pb) { - PB_TRACE(pb, "delwri_uq", 0); + int dequeued = 0; + spin_lock(&pbd_delwrite_lock); - list_del_init(&pb->pb_list); + if ((pb->pb_flags & PBF_DELWRI) && !list_empty(&pb->pb_list)) { + list_del_init(&pb->pb_list); + dequeued = 1; + } pb->pb_flags &= ~PBF_DELWRI; spin_unlock(&pbd_delwrite_lock); + + if (dequeued) + pagebuf_rele(pb); + + PB_TRACE(pb, "delwri_dq", (long)dequeued); } STATIC void @@ -1586,12 +1634,16 @@ STATIC struct task_struct *pagebuf_daemon_task; STATIC int pagebuf_daemon_active; STATIC int force_flush; -STATIC void -pagebuf_daemon_wakeup(void) + +STATIC int +pagebuf_daemon_wakeup( + int priority, + unsigned int mask) { force_flush = 1; barrier(); wake_up_process(pagebuf_daemon_task); + return 0; } STATIC int @@ -1600,6 +1652,7 @@ pagebuf_daemon( { struct list_head tmp; unsigned long age; + xfs_buftarg_t *target; xfs_buf_t *pb, *n; /* Set up the thread */ @@ -1642,9 +1695,12 @@ pagebuf_daemon( while (!list_empty(&tmp)) { pb = list_entry(tmp.next, xfs_buf_t, pb_list); + target = pb->pb_target; + list_del_init(&pb->pb_list); pagebuf_iostrategy(pb); - blk_run_address_space(pb->pb_target->pbr_mapping); + + blk_run_address_space(target->pbr_mapping); } if (as_list_len > 0) @@ -1775,21 +1831,28 @@ pagebuf_init(void) pagebuf_cache = kmem_cache_create("xfs_buf_t", sizeof(xfs_buf_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (pagebuf_cache == NULL) { - printk("pagebuf: couldn't init pagebuf cache\n"); + printk("XFS: couldn't init xfs_buf_t cache\n"); pagebuf_terminate(); return -ENOMEM; } - for (i = 0; i < NHASH; i++) { - spin_lock_init(&pbhash[i].pb_hash_lock); - INIT_LIST_HEAD(&pbhash[i].pb_hash); - } - #ifdef PAGEBUF_TRACE pagebuf_trace_buf = ktrace_alloc(PAGEBUF_TRACE_SIZE, KM_SLEEP); #endif pagebuf_daemon_start(); + + pagebuf_shake = kmem_shake_register(pagebuf_daemon_wakeup); + if (pagebuf_shake == NULL) { + pagebuf_terminate(); + return -ENOMEM; + } + + for (i = 0; i < NHASH; i++) { + spin_lock_init(&pbhash[i].pb_hash_lock); + INIT_LIST_HEAD(&pbhash[i].pb_hash); + } + return 0; } @@ -1808,5 +1871,6 @@ pagebuf_terminate(void) ktrace_free(pagebuf_trace_buf); #endif - kmem_cache_destroy(pagebuf_cache); + kmem_zone_destroy(pagebuf_cache); + kmem_shake_deregister(pagebuf_shake); }