 include/linux/blkdev.h |    2 ++
 mm/swapfile.c          |    5 +++++
 2 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 465d6ba..4fcdd5e 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1088,6 +1088,8 @@ struct block_device_operations {
 	int (*media_changed) (struct gendisk *);
 	int (*revalidate_disk) (struct gendisk *);
 	int (*getgeo)(struct block_device *, struct hd_geometry *);
+	/* this callback is with swap_lock and sometimes page table lock held */
+	void (*swap_slot_free_notify) (struct block_device *, unsigned long);
 	struct module *owner;
 };
 
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 312fafe..fc4feee 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -480,6 +480,7 @@ static int swap_entry_free(struct swap_info_struct *p, swp_entry_t ent)
 		count--;
 		p->swap_map[offset] = count;
 		if (!count) {
+			struct gendisk *disk = p->bdev->bd_disk;
 			if (offset < p->lowest_bit)
 				p->lowest_bit = offset;
 			if (offset > p->highest_bit)
@@ -489,6 +490,10 @@ static int swap_entry_free(struct swap_info_struct *p, swp_entry_t ent)
 			nr_swap_pages++;
 			p->inuse_pages--;
 			mem_cgroup_uncharge_swap(ent);
+			if (disk->fops->swap_slot_free_notify)
+				disk->fops->swap_slot_free_notify(p->bdev,
+								offset);
+
 		}
 	}
 	return count;
