Commit 137718ec authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] lockfs - vfs bits

From: Christoph Hellwig <hch@lst.de>

These are the generic lockfs bits.  Basically it takes the XFS freezing
statemachine into the VFS.  It's all behind the kernel-doc documented
freeze_bdev and thaw_bdev interfaces.

Based on an older patch from Chris Mason.
parent 4aa3ba95
...@@ -251,6 +251,7 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) ...@@ -251,6 +251,7 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
{ {
memset(bdev, 0, sizeof(*bdev)); memset(bdev, 0, sizeof(*bdev));
sema_init(&bdev->bd_sem, 1); sema_init(&bdev->bd_sem, 1);
sema_init(&bdev->bd_mount_sem, 1);
INIT_LIST_HEAD(&bdev->bd_inodes); INIT_LIST_HEAD(&bdev->bd_inodes);
INIT_LIST_HEAD(&bdev->bd_list); INIT_LIST_HEAD(&bdev->bd_list);
inode_init_once(&ei->vfs_inode); inode_init_once(&ei->vfs_inode);
......
...@@ -227,6 +227,77 @@ int fsync_bdev(struct block_device *bdev) ...@@ -227,6 +227,77 @@ int fsync_bdev(struct block_device *bdev)
return sync_blockdev(bdev); return sync_blockdev(bdev);
} }
/**
* freeze_bdev -- lock a filesystem and force it into a consistent state
* @bdev: blockdevice to lock
*
* This takes the block device bd_mount_sem to make sure no new mounts
* happen on bdev until thaw_bdev() is called.
* If a superblock is found on this device, we take the s_umount semaphore
* on it to make sure nobody unmounts until the snapshot creation is done.
*/
struct super_block *freeze_bdev(struct block_device *bdev)
{
struct super_block *sb;
down(&bdev->bd_mount_sem);
sb = get_super(bdev);
if (sb && !(sb->s_flags & MS_RDONLY)) {
sb->s_frozen = SB_FREEZE_WRITE;
wmb();
sync_inodes_sb(sb, 0);
DQUOT_SYNC(sb);
lock_super(sb);
if (sb->s_dirt && sb->s_op->write_super)
sb->s_op->write_super(sb);
unlock_super(sb);
if (sb->s_op->sync_fs)
sb->s_op->sync_fs(sb, 1);
sync_blockdev(sb->s_bdev);
sync_inodes_sb(sb, 1);
sb->s_frozen = SB_FREEZE_TRANS;
wmb();
sync_blockdev(sb->s_bdev);
if (sb->s_op->write_super_lockfs)
sb->s_op->write_super_lockfs(sb);
}
sync_blockdev(bdev);
return sb; /* thaw_bdev releases s->s_umount and bd_mount_sem */
}
EXPORT_SYMBOL(freeze_bdev);
/**
* thaw_bdev -- unlock filesystem
* @bdev: blockdevice to unlock
* @sb: associated superblock
*
* Unlocks the filesystem and marks it writeable again after freeze_bdev().
*/
void thaw_bdev(struct block_device *bdev, struct super_block *sb)
{
if (sb) {
BUG_ON(sb->s_bdev != bdev);
if (sb->s_op->unlockfs)
sb->s_op->unlockfs(sb);
sb->s_frozen = SB_UNFROZEN;
wmb();
wake_up(&sb->s_wait_unfrozen);
drop_super(sb);
}
up(&bdev->bd_mount_sem);
}
EXPORT_SYMBOL(thaw_bdev);
/* /*
* sync everything. Start out by waking pdflush, because that writes back * sync everything. Start out by waking pdflush, because that writes back
* all queues in parallel. * all queues in parallel.
......
...@@ -77,6 +77,7 @@ static struct super_block *alloc_super(void) ...@@ -77,6 +77,7 @@ static struct super_block *alloc_super(void)
sema_init(&s->s_dquot.dqio_sem, 1); sema_init(&s->s_dquot.dqio_sem, 1);
sema_init(&s->s_dquot.dqonoff_sem, 1); sema_init(&s->s_dquot.dqonoff_sem, 1);
init_rwsem(&s->s_dquot.dqptr_sem); init_rwsem(&s->s_dquot.dqptr_sem);
init_waitqueue_head(&s->s_wait_unfrozen);
s->s_maxbytes = MAX_NON_LFS; s->s_maxbytes = MAX_NON_LFS;
s->dq_op = sb_dquot_ops; s->dq_op = sb_dquot_ops;
s->s_qcop = sb_quotactl_ops; s->s_qcop = sb_quotactl_ops;
...@@ -623,7 +624,14 @@ struct super_block *get_sb_bdev(struct file_system_type *fs_type, ...@@ -623,7 +624,14 @@ struct super_block *get_sb_bdev(struct file_system_type *fs_type,
if (IS_ERR(bdev)) if (IS_ERR(bdev))
return (struct super_block *)bdev; return (struct super_block *)bdev;
/*
* once the super is inserted into the list by sget, s_umount
* will protect the lockfs code from trying to start a snapshot
* while we are mounting
*/
down(&bdev->bd_mount_sem);
s = sget(fs_type, test_bdev_super, set_bdev_super, bdev); s = sget(fs_type, test_bdev_super, set_bdev_super, bdev);
up(&bdev->bd_mount_sem);
if (IS_ERR(s)) if (IS_ERR(s))
goto out; goto out;
......
...@@ -157,6 +157,8 @@ void __wait_on_buffer(struct buffer_head *); ...@@ -157,6 +157,8 @@ void __wait_on_buffer(struct buffer_head *);
wait_queue_head_t *bh_waitq_head(struct buffer_head *bh); wait_queue_head_t *bh_waitq_head(struct buffer_head *bh);
void wake_up_buffer(struct buffer_head *bh); void wake_up_buffer(struct buffer_head *bh);
int fsync_bdev(struct block_device *); int fsync_bdev(struct block_device *);
struct super_block *freeze_bdev(struct block_device *);
void thaw_bdev(struct block_device *, struct super_block *);
int fsync_super(struct super_block *); int fsync_super(struct super_block *);
int fsync_no_super(struct block_device *); int fsync_no_super(struct block_device *);
struct buffer_head *__find_get_block(struct block_device *, sector_t, int); struct buffer_head *__find_get_block(struct block_device *, sector_t, int);
......
...@@ -345,6 +345,7 @@ struct block_device { ...@@ -345,6 +345,7 @@ struct block_device {
struct inode * bd_inode; /* will die */ struct inode * bd_inode; /* will die */
int bd_openers; int bd_openers;
struct semaphore bd_sem; /* open/close mutex */ struct semaphore bd_sem; /* open/close mutex */
struct semaphore bd_mount_sem; /* mount mutex */
struct list_head bd_inodes; struct list_head bd_inodes;
void * bd_holder; void * bd_holder;
int bd_holders; int bd_holders;
...@@ -749,6 +750,9 @@ struct super_block { ...@@ -749,6 +750,9 @@ struct super_block {
struct list_head s_instances; struct list_head s_instances;
struct quota_info s_dquot; /* Diskquota specific options */ struct quota_info s_dquot; /* Diskquota specific options */
int s_frozen;
wait_queue_head_t s_wait_unfrozen;
char s_id[32]; /* Informational name */ char s_id[32]; /* Informational name */
void *s_fs_info; /* Filesystem private info */ void *s_fs_info; /* Filesystem private info */
...@@ -760,6 +764,18 @@ struct super_block { ...@@ -760,6 +764,18 @@ struct super_block {
struct semaphore s_vfs_rename_sem; /* Kludge */ struct semaphore s_vfs_rename_sem; /* Kludge */
}; };
/*
* Snapshotting support.
*/
enum {
SB_UNFROZEN = 0,
SB_FREEZE_WRITE = 1,
SB_FREEZE_TRANS = 2,
};
#define vfs_check_frozen(sb, level) \
wait_event((sb)->s_wait_unfrozen, ((sb)->s_frozen < (level)))
/* /*
* Superblock locking. * Superblock locking.
*/ */
......
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