filesystem freeze: implement generic freeze feature

The ioctls for the generic freeze feature are below.
o Freeze the filesystem
int ioctl(int fd, int FIFREEZE, arg)
fd: The file descriptor of the mountpoint
FIFREEZE: request code for the freeze
arg: Ignored
Return value: 0 if the operation succeeds. Otherwise, -1

o Unfreeze the filesystem
int ioctl(int fd, int FITHAW, arg)
fd: The file descriptor of the mountpoint
FITHAW: request code for unfreeze
arg: Ignored
Return value: 0 if the operation succeeds. Otherwise, -1
Error number: If the filesystem has already been unfrozen,
errno is set to EINVAL.

[akpm@linux-foundation.org: fix CONFIG_BLOCK=n]
Signed-off-by: Takashi Sato <t-sato@yk.jp.nec.com>
Signed-off-by: Masayuki Hamaguchi <m-hamaguchi@ys.jp.nec.com>
Cc: <xfs-masters@oss.sgi.com>
Cc: <linux-ext4@vger.kernel.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Dave Kleikamp <shaggy@austin.ibm.com>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Alasdair G Kergon <agk@redhat.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Takashi Sato and committed by
Linus Torvalds
fcccf502 c4be0c1d

+130 -10
+2
fs/block_dev.c
··· 285 285 INIT_LIST_HEAD(&bdev->bd_holder_list); 286 286 #endif 287 287 inode_init_once(&ei->vfs_inode); 288 + /* Initialize mutex for freeze. */ 289 + mutex_init(&bdev->bd_fsfreeze_mutex); 288 290 } 289 291 290 292 static inline void __bd_forget(struct inode *inode)
+65 -9
fs/buffer.c
··· 203 203 * happen on bdev until thaw_bdev() is called. 204 204 * If a superblock is found on this device, we take the s_umount semaphore 205 205 * on it to make sure nobody unmounts until the snapshot creation is done. 206 + * The reference counter (bd_fsfreeze_count) guarantees that only the last 207 + * unfreeze process can unfreeze the frozen filesystem actually when multiple 208 + * freeze requests arrive simultaneously. It counts up in freeze_bdev() and 209 + * count down in thaw_bdev(). When it becomes 0, thaw_bdev() will unfreeze 210 + * actually. 206 211 */ 207 212 struct super_block *freeze_bdev(struct block_device *bdev) 208 213 { 209 214 struct super_block *sb; 215 + int error = 0; 216 + 217 + mutex_lock(&bdev->bd_fsfreeze_mutex); 218 + if (bdev->bd_fsfreeze_count > 0) { 219 + bdev->bd_fsfreeze_count++; 220 + sb = get_super(bdev); 221 + mutex_unlock(&bdev->bd_fsfreeze_mutex); 222 + return sb; 223 + } 224 + bdev->bd_fsfreeze_count++; 210 225 211 226 down(&bdev->bd_mount_sem); 212 227 sb = get_super(bdev); ··· 236 221 237 222 sync_blockdev(sb->s_bdev); 238 223 239 - if (sb->s_op->freeze_fs) 240 - sb->s_op->freeze_fs(sb); 224 + if (sb->s_op->freeze_fs) { 225 + error = sb->s_op->freeze_fs(sb); 226 + if (error) { 227 + printk(KERN_ERR 228 + "VFS:Filesystem freeze failed\n"); 229 + sb->s_frozen = SB_UNFROZEN; 230 + drop_super(sb); 231 + up(&bdev->bd_mount_sem); 232 + bdev->bd_fsfreeze_count--; 233 + mutex_unlock(&bdev->bd_fsfreeze_mutex); 234 + return ERR_PTR(error); 235 + } 236 + } 241 237 } 242 238 243 239 sync_blockdev(bdev); 240 + mutex_unlock(&bdev->bd_fsfreeze_mutex); 241 + 244 242 return sb; /* thaw_bdev releases s->s_umount and bd_mount_sem */ 245 243 } 246 244 EXPORT_SYMBOL(freeze_bdev); ··· 265 237 * 266 238 * Unlocks the filesystem and marks it writeable again after freeze_bdev(). 267 239 */ 268 - void thaw_bdev(struct block_device *bdev, struct super_block *sb) 240 + int thaw_bdev(struct block_device *bdev, struct super_block *sb) 269 241 { 242 + int error = 0; 243 + 244 + mutex_lock(&bdev->bd_fsfreeze_mutex); 245 + if (!bdev->bd_fsfreeze_count) { 246 + mutex_unlock(&bdev->bd_fsfreeze_mutex); 247 + return -EINVAL; 248 + } 249 + 250 + bdev->bd_fsfreeze_count--; 251 + if (bdev->bd_fsfreeze_count > 0) { 252 + if (sb) 253 + drop_super(sb); 254 + mutex_unlock(&bdev->bd_fsfreeze_mutex); 255 + return 0; 256 + } 257 + 270 258 if (sb) { 271 259 BUG_ON(sb->s_bdev != bdev); 272 - 273 - if (sb->s_op->unfreeze_fs) 274 - sb->s_op->unfreeze_fs(sb); 275 - sb->s_frozen = SB_UNFROZEN; 276 - smp_wmb(); 277 - wake_up(&sb->s_wait_unfrozen); 260 + if (!(sb->s_flags & MS_RDONLY)) { 261 + if (sb->s_op->unfreeze_fs) { 262 + error = sb->s_op->unfreeze_fs(sb); 263 + if (error) { 264 + printk(KERN_ERR 265 + "VFS:Filesystem thaw failed\n"); 266 + sb->s_frozen = SB_FREEZE_TRANS; 267 + bdev->bd_fsfreeze_count++; 268 + mutex_unlock(&bdev->bd_fsfreeze_mutex); 269 + return error; 270 + } 271 + } 272 + sb->s_frozen = SB_UNFROZEN; 273 + smp_wmb(); 274 + wake_up(&sb->s_wait_unfrozen); 275 + } 278 276 drop_super(sb); 279 277 } 280 278 281 279 up(&bdev->bd_mount_sem); 280 + mutex_unlock(&bdev->bd_fsfreeze_mutex); 281 + return 0; 282 282 } 283 283 EXPORT_SYMBOL(thaw_bdev); 284 284
+46
fs/ioctl.c
··· 439 439 return error; 440 440 } 441 441 442 + static int ioctl_fsfreeze(struct file *filp) 443 + { 444 + struct super_block *sb = filp->f_path.dentry->d_inode->i_sb; 445 + 446 + if (!capable(CAP_SYS_ADMIN)) 447 + return -EPERM; 448 + 449 + /* If filesystem doesn't support freeze feature, return. */ 450 + if (sb->s_op->freeze_fs == NULL) 451 + return -EOPNOTSUPP; 452 + 453 + /* If a blockdevice-backed filesystem isn't specified, return. */ 454 + if (sb->s_bdev == NULL) 455 + return -EINVAL; 456 + 457 + /* Freeze */ 458 + sb = freeze_bdev(sb->s_bdev); 459 + if (IS_ERR(sb)) 460 + return PTR_ERR(sb); 461 + return 0; 462 + } 463 + 464 + static int ioctl_fsthaw(struct file *filp) 465 + { 466 + struct super_block *sb = filp->f_path.dentry->d_inode->i_sb; 467 + 468 + if (!capable(CAP_SYS_ADMIN)) 469 + return -EPERM; 470 + 471 + /* If a blockdevice-backed filesystem isn't specified, return EINVAL. */ 472 + if (sb->s_bdev == NULL) 473 + return -EINVAL; 474 + 475 + /* Thaw */ 476 + return thaw_bdev(sb->s_bdev, sb); 477 + } 478 + 442 479 /* 443 480 * When you add any new common ioctls to the switches above and below 444 481 * please update compat_sys_ioctl() too. ··· 523 486 } else 524 487 error = -ENOTTY; 525 488 break; 489 + 490 + case FIFREEZE: 491 + error = ioctl_fsfreeze(filp); 492 + break; 493 + 494 + case FITHAW: 495 + error = ioctl_fsthaw(filp); 496 + break; 497 + 526 498 default: 527 499 if (S_ISREG(filp->f_path.dentry->d_inode->i_mode)) 528 500 error = file_ioctl(filp, cmd, arg);
+10 -1
include/linux/buffer_head.h
··· 171 171 wait_queue_head_t *bh_waitq_head(struct buffer_head *bh); 172 172 int fsync_bdev(struct block_device *); 173 173 struct super_block *freeze_bdev(struct block_device *); 174 - void thaw_bdev(struct block_device *, struct super_block *); 174 + int thaw_bdev(struct block_device *, struct super_block *); 175 175 int fsync_super(struct super_block *); 176 176 int fsync_no_super(struct block_device *); 177 177 struct buffer_head *__find_get_block(struct block_device *bdev, sector_t block, ··· 346 346 static inline int sync_mapping_buffers(struct address_space *mapping) { return 0; } 347 347 static inline void invalidate_bdev(struct block_device *bdev) {} 348 348 349 + static inline struct super_block *freeze_bdev(struct block_device *sb) 350 + { 351 + return NULL; 352 + } 353 + 354 + static inline int thaw_bdev(struct block_device *bdev, struct super_block *sb) 355 + { 356 + return 0; 357 + } 349 358 350 359 #endif /* CONFIG_BLOCK */ 351 360 #endif /* _LINUX_BUFFER_HEAD_H */
+7
include/linux/fs.h
··· 234 234 #define BMAP_IOCTL 1 /* obsolete - kept for compatibility */ 235 235 #define FIBMAP _IO(0x00,1) /* bmap access */ 236 236 #define FIGETBSZ _IO(0x00,2) /* get the block size used for bmap */ 237 + #define FIFREEZE _IOWR('X', 119, int) /* Freeze */ 238 + #define FITHAW _IOWR('X', 120, int) /* Thaw */ 237 239 238 240 #define FS_IOC_GETFLAGS _IOR('f', 1, long) 239 241 #define FS_IOC_SETFLAGS _IOW('f', 2, long) ··· 593 591 * care to not mess up bd_private for that case. 594 592 */ 595 593 unsigned long bd_private; 594 + 595 + /* The counter of freeze processes */ 596 + int bd_fsfreeze_count; 597 + /* Mutex for freeze */ 598 + struct mutex bd_fsfreeze_mutex; 596 599 }; 597 600 598 601 /*