add releasepage hooks to block devices which can be used by file systems
authorTheodore Ts'o <tytso@mit.edu>
Sat, 3 Jan 2009 14:47:09 +0000 (09:47 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Sat, 3 Jan 2009 14:47:09 +0000 (09:47 -0500)
Implement blkdev_releasepage() to release the buffer_heads and pages
after we release private data belonging to a mounted filesystem.

Cc: Toshiyuki Okajima <toshi.okajima@jp.fujitsu.com>
Cc: linux-fsdevel@vger.kernel.org
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
fs/block_dev.c
fs/super.c
include/linux/fs.h

index 349a26c..1dd07e6 100644 (file)
@@ -1220,6 +1220,20 @@ static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg)
        return blkdev_ioctl(bdev, mode, cmd, arg);
 }
 
+/*
+ * Try to release a page associated with block device when the system
+ * is under memory pressure.
+ */
+static int blkdev_releasepage(struct page *page, gfp_t wait)
+{
+       struct super_block *super = BDEV_I(page->mapping->host)->bdev.bd_super;
+
+       if (super && super->s_op->bdev_try_to_free_page)
+               return super->s_op->bdev_try_to_free_page(super, page, wait);
+
+       return try_to_free_buffers(page);
+}
+
 static const struct address_space_operations def_blk_aops = {
        .readpage       = blkdev_readpage,
        .writepage      = blkdev_writepage,
@@ -1227,6 +1241,7 @@ static const struct address_space_operations def_blk_aops = {
        .write_begin    = blkdev_write_begin,
        .write_end      = blkdev_write_end,
        .writepages     = generic_writepages,
+       .releasepage    = blkdev_releasepage,
        .direct_IO      = blkdev_direct_IO,
 };
 
index ddba069..d5fd449 100644 (file)
@@ -800,6 +800,7 @@ int get_sb_bdev(struct file_system_type *fs_type,
                }
 
                s->s_flags |= MS_ACTIVE;
+               bdev->bd_super = s;
        }
 
        return simple_set_mnt(mnt, s);
@@ -819,6 +820,7 @@ void kill_block_super(struct super_block *sb)
        struct block_device *bdev = sb->s_bdev;
        fmode_t mode = sb->s_mode;
 
+       bdev->bd_super = 0;
        generic_shutdown_super(sb);
        sync_blockdev(bdev);
        close_bdev_exclusive(bdev, mode);
index f2a3010..0f54ae0 100644 (file)
@@ -565,6 +565,7 @@ struct address_space {
 struct block_device {
        dev_t                   bd_dev;  /* not a kdev_t - it's a search key */
        struct inode *          bd_inode;       /* will die */
+       struct super_block *    bd_super;
        int                     bd_openers;
        struct mutex            bd_mutex;       /* open/close mutex */
        struct semaphore        bd_mount_sem;
@@ -1385,6 +1386,7 @@ struct super_operations {
        ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
        ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
 #endif
+       int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t);
 };
 
 /*