diff options
Diffstat (limited to 'fs/buffer.c')
| -rw-r--r-- | fs/buffer.c | 153 |
1 files changed, 47 insertions, 106 deletions
diff --git a/fs/buffer.c b/fs/buffer.c index 62cfd17dc5fe..3b3ab5281920 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
| @@ -160,12 +160,7 @@ int sync_blockdev(struct block_device *bdev) | |||
| 160 | } | 160 | } |
| 161 | EXPORT_SYMBOL(sync_blockdev); | 161 | EXPORT_SYMBOL(sync_blockdev); |
| 162 | 162 | ||
| 163 | /* | 163 | static void __fsync_super(struct super_block *sb) |
| 164 | * Write out and wait upon all dirty data associated with this | ||
| 165 | * superblock. Filesystem data as well as the underlying block | ||
| 166 | * device. Takes the superblock lock. | ||
| 167 | */ | ||
| 168 | int fsync_super(struct super_block *sb) | ||
| 169 | { | 164 | { |
| 170 | sync_inodes_sb(sb, 0); | 165 | sync_inodes_sb(sb, 0); |
| 171 | DQUOT_SYNC(sb); | 166 | DQUOT_SYNC(sb); |
| @@ -177,7 +172,16 @@ int fsync_super(struct super_block *sb) | |||
| 177 | sb->s_op->sync_fs(sb, 1); | 172 | sb->s_op->sync_fs(sb, 1); |
| 178 | sync_blockdev(sb->s_bdev); | 173 | sync_blockdev(sb->s_bdev); |
| 179 | sync_inodes_sb(sb, 1); | 174 | sync_inodes_sb(sb, 1); |
| 175 | } | ||
| 180 | 176 | ||
| 177 | /* | ||
| 178 | * Write out and wait upon all dirty data associated with this | ||
| 179 | * superblock. Filesystem data as well as the underlying block | ||
| 180 | * device. Takes the superblock lock. | ||
| 181 | */ | ||
| 182 | int fsync_super(struct super_block *sb) | ||
| 183 | { | ||
| 184 | __fsync_super(sb); | ||
| 181 | return sync_blockdev(sb->s_bdev); | 185 | return sync_blockdev(sb->s_bdev); |
| 182 | } | 186 | } |
| 183 | 187 | ||
| @@ -201,7 +205,7 @@ int fsync_bdev(struct block_device *bdev) | |||
| 201 | * freeze_bdev -- lock a filesystem and force it into a consistent state | 205 | * freeze_bdev -- lock a filesystem and force it into a consistent state |
| 202 | * @bdev: blockdevice to lock | 206 | * @bdev: blockdevice to lock |
| 203 | * | 207 | * |
| 204 | * This takes the block device bd_mount_sem to make sure no new mounts | 208 | * This takes the block device bd_mount_mutex to make sure no new mounts |
| 205 | * happen on bdev until thaw_bdev() is called. | 209 | * happen on bdev until thaw_bdev() is called. |
| 206 | * If a superblock is found on this device, we take the s_umount semaphore | 210 | * If a superblock is found on this device, we take the s_umount semaphore |
| 207 | * on it to make sure nobody unmounts until the snapshot creation is done. | 211 | * on it to make sure nobody unmounts until the snapshot creation is done. |
| @@ -210,25 +214,13 @@ struct super_block *freeze_bdev(struct block_device *bdev) | |||
| 210 | { | 214 | { |
| 211 | struct super_block *sb; | 215 | struct super_block *sb; |
| 212 | 216 | ||
| 213 | down(&bdev->bd_mount_sem); | 217 | mutex_lock(&bdev->bd_mount_mutex); |
| 214 | sb = get_super(bdev); | 218 | sb = get_super(bdev); |
| 215 | if (sb && !(sb->s_flags & MS_RDONLY)) { | 219 | if (sb && !(sb->s_flags & MS_RDONLY)) { |
| 216 | sb->s_frozen = SB_FREEZE_WRITE; | 220 | sb->s_frozen = SB_FREEZE_WRITE; |
| 217 | smp_wmb(); | 221 | smp_wmb(); |
| 218 | 222 | ||
| 219 | sync_inodes_sb(sb, 0); | 223 | __fsync_super(sb); |
| 220 | DQUOT_SYNC(sb); | ||
| 221 | |||
| 222 | lock_super(sb); | ||
| 223 | if (sb->s_dirt && sb->s_op->write_super) | ||
| 224 | sb->s_op->write_super(sb); | ||
| 225 | unlock_super(sb); | ||
| 226 | |||
| 227 | if (sb->s_op->sync_fs) | ||
| 228 | sb->s_op->sync_fs(sb, 1); | ||
| 229 | |||
| 230 | sync_blockdev(sb->s_bdev); | ||
| 231 | sync_inodes_sb(sb, 1); | ||
| 232 | 224 | ||
| 233 | sb->s_frozen = SB_FREEZE_TRANS; | 225 | sb->s_frozen = SB_FREEZE_TRANS; |
| 234 | smp_wmb(); | 226 | smp_wmb(); |
| @@ -264,7 +256,7 @@ void thaw_bdev(struct block_device *bdev, struct super_block *sb) | |||
| 264 | drop_super(sb); | 256 | drop_super(sb); |
| 265 | } | 257 | } |
| 266 | 258 | ||
| 267 | up(&bdev->bd_mount_sem); | 259 | mutex_unlock(&bdev->bd_mount_mutex); |
| 268 | } | 260 | } |
| 269 | EXPORT_SYMBOL(thaw_bdev); | 261 | EXPORT_SYMBOL(thaw_bdev); |
| 270 | 262 | ||
| @@ -327,31 +319,24 @@ int file_fsync(struct file *filp, struct dentry *dentry, int datasync) | |||
| 327 | return ret; | 319 | return ret; |
| 328 | } | 320 | } |
| 329 | 321 | ||
| 330 | static long do_fsync(unsigned int fd, int datasync) | 322 | long do_fsync(struct file *file, int datasync) |
| 331 | { | 323 | { |
| 332 | struct file * file; | 324 | int ret; |
| 333 | struct address_space *mapping; | 325 | int err; |
| 334 | int ret, err; | 326 | struct address_space *mapping = file->f_mapping; |
| 335 | |||
| 336 | ret = -EBADF; | ||
| 337 | file = fget(fd); | ||
| 338 | if (!file) | ||
| 339 | goto out; | ||
| 340 | 327 | ||
| 341 | ret = -EINVAL; | ||
| 342 | if (!file->f_op || !file->f_op->fsync) { | 328 | if (!file->f_op || !file->f_op->fsync) { |
| 343 | /* Why? We can still call filemap_fdatawrite */ | 329 | /* Why? We can still call filemap_fdatawrite */ |
| 344 | goto out_putf; | 330 | ret = -EINVAL; |
| 331 | goto out; | ||
| 345 | } | 332 | } |
| 346 | 333 | ||
| 347 | mapping = file->f_mapping; | ||
| 348 | |||
| 349 | current->flags |= PF_SYNCWRITE; | 334 | current->flags |= PF_SYNCWRITE; |
| 350 | ret = filemap_fdatawrite(mapping); | 335 | ret = filemap_fdatawrite(mapping); |
| 351 | 336 | ||
| 352 | /* | 337 | /* |
| 353 | * We need to protect against concurrent writers, | 338 | * We need to protect against concurrent writers, which could cause |
| 354 | * which could cause livelocks in fsync_buffers_list | 339 | * livelocks in fsync_buffers_list(). |
| 355 | */ | 340 | */ |
| 356 | mutex_lock(&mapping->host->i_mutex); | 341 | mutex_lock(&mapping->host->i_mutex); |
| 357 | err = file->f_op->fsync(file, file->f_dentry, datasync); | 342 | err = file->f_op->fsync(file, file->f_dentry, datasync); |
| @@ -362,21 +347,31 @@ static long do_fsync(unsigned int fd, int datasync) | |||
| 362 | if (!ret) | 347 | if (!ret) |
| 363 | ret = err; | 348 | ret = err; |
| 364 | current->flags &= ~PF_SYNCWRITE; | 349 | current->flags &= ~PF_SYNCWRITE; |
| 365 | |||
| 366 | out_putf: | ||
| 367 | fput(file); | ||
| 368 | out: | 350 | out: |
| 369 | return ret; | 351 | return ret; |
| 370 | } | 352 | } |
| 371 | 353 | ||
| 354 | static long __do_fsync(unsigned int fd, int datasync) | ||
| 355 | { | ||
| 356 | struct file *file; | ||
| 357 | int ret = -EBADF; | ||
| 358 | |||
| 359 | file = fget(fd); | ||
| 360 | if (file) { | ||
| 361 | ret = do_fsync(file, datasync); | ||
| 362 | fput(file); | ||
| 363 | } | ||
| 364 | return ret; | ||
| 365 | } | ||
| 366 | |||
| 372 | asmlinkage long sys_fsync(unsigned int fd) | 367 | asmlinkage long sys_fsync(unsigned int fd) |
| 373 | { | 368 | { |
| 374 | return do_fsync(fd, 0); | 369 | return __do_fsync(fd, 0); |
| 375 | } | 370 | } |
| 376 | 371 | ||
| 377 | asmlinkage long sys_fdatasync(unsigned int fd) | 372 | asmlinkage long sys_fdatasync(unsigned int fd) |
| 378 | { | 373 | { |
| 379 | return do_fsync(fd, 1); | 374 | return __do_fsync(fd, 1); |
| 380 | } | 375 | } |
| 381 | 376 | ||
| 382 | /* | 377 | /* |
| @@ -865,8 +860,8 @@ int __set_page_dirty_buffers(struct page *page) | |||
| 865 | } | 860 | } |
| 866 | write_unlock_irq(&mapping->tree_lock); | 861 | write_unlock_irq(&mapping->tree_lock); |
| 867 | __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); | 862 | __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); |
| 863 | return 1; | ||
| 868 | } | 864 | } |
| 869 | |||
| 870 | return 0; | 865 | return 0; |
| 871 | } | 866 | } |
| 872 | EXPORT_SYMBOL(__set_page_dirty_buffers); | 867 | EXPORT_SYMBOL(__set_page_dirty_buffers); |
| @@ -3051,66 +3046,6 @@ asmlinkage long sys_bdflush(int func, long data) | |||
| 3051 | } | 3046 | } |
| 3052 | 3047 | ||
| 3053 | /* | 3048 | /* |
| 3054 | * Migration function for pages with buffers. This function can only be used | ||
| 3055 | * if the underlying filesystem guarantees that no other references to "page" | ||
| 3056 | * exist. | ||
| 3057 | */ | ||
| 3058 | #ifdef CONFIG_MIGRATION | ||
| 3059 | int buffer_migrate_page(struct page *newpage, struct page *page) | ||
| 3060 | { | ||
| 3061 | struct address_space *mapping = page->mapping; | ||
| 3062 | struct buffer_head *bh, *head; | ||
| 3063 | |||
| 3064 | if (!mapping) | ||
| 3065 | return -EAGAIN; | ||
| 3066 | |||
| 3067 | if (!page_has_buffers(page)) | ||
| 3068 | return migrate_page(newpage, page); | ||
| 3069 | |||
| 3070 | head = page_buffers(page); | ||
| 3071 | |||
| 3072 | if (migrate_page_remove_references(newpage, page, 3)) | ||
| 3073 | return -EAGAIN; | ||
| 3074 | |||
| 3075 | bh = head; | ||
| 3076 | do { | ||
| 3077 | get_bh(bh); | ||
| 3078 | lock_buffer(bh); | ||
| 3079 | bh = bh->b_this_page; | ||
| 3080 | |||
| 3081 | } while (bh != head); | ||
| 3082 | |||
| 3083 | ClearPagePrivate(page); | ||
| 3084 | set_page_private(newpage, page_private(page)); | ||
| 3085 | set_page_private(page, 0); | ||
| 3086 | put_page(page); | ||
| 3087 | get_page(newpage); | ||
| 3088 | |||
| 3089 | bh = head; | ||
| 3090 | do { | ||
| 3091 | set_bh_page(bh, newpage, bh_offset(bh)); | ||
| 3092 | bh = bh->b_this_page; | ||
| 3093 | |||
| 3094 | } while (bh != head); | ||
| 3095 | |||
| 3096 | SetPagePrivate(newpage); | ||
| 3097 | |||
| 3098 | migrate_page_copy(newpage, page); | ||
| 3099 | |||
| 3100 | bh = head; | ||
| 3101 | do { | ||
| 3102 | unlock_buffer(bh); | ||
| 3103 | put_bh(bh); | ||
| 3104 | bh = bh->b_this_page; | ||
| 3105 | |||
| 3106 | } while (bh != head); | ||
| 3107 | |||
| 3108 | return 0; | ||
| 3109 | } | ||
| 3110 | EXPORT_SYMBOL(buffer_migrate_page); | ||
| 3111 | #endif | ||
| 3112 | |||
| 3113 | /* | ||
| 3114 | * Buffer-head allocation | 3049 | * Buffer-head allocation |
| 3115 | */ | 3050 | */ |
| 3116 | static kmem_cache_t *bh_cachep; | 3051 | static kmem_cache_t *bh_cachep; |
| @@ -3138,7 +3073,7 @@ static void recalc_bh_state(void) | |||
| 3138 | if (__get_cpu_var(bh_accounting).ratelimit++ < 4096) | 3073 | if (__get_cpu_var(bh_accounting).ratelimit++ < 4096) |
| 3139 | return; | 3074 | return; |
| 3140 | __get_cpu_var(bh_accounting).ratelimit = 0; | 3075 | __get_cpu_var(bh_accounting).ratelimit = 0; |
| 3141 | for_each_cpu(i) | 3076 | for_each_online_cpu(i) |
| 3142 | tot += per_cpu(bh_accounting, i).nr; | 3077 | tot += per_cpu(bh_accounting, i).nr; |
| 3143 | buffer_heads_over_limit = (tot > max_buffer_heads); | 3078 | buffer_heads_over_limit = (tot > max_buffer_heads); |
| 3144 | } | 3079 | } |
| @@ -3187,6 +3122,9 @@ static void buffer_exit_cpu(int cpu) | |||
| 3187 | brelse(b->bhs[i]); | 3122 | brelse(b->bhs[i]); |
| 3188 | b->bhs[i] = NULL; | 3123 | b->bhs[i] = NULL; |
| 3189 | } | 3124 | } |
| 3125 | get_cpu_var(bh_accounting).nr += per_cpu(bh_accounting, cpu).nr; | ||
| 3126 | per_cpu(bh_accounting, cpu).nr = 0; | ||
| 3127 | put_cpu_var(bh_accounting); | ||
| 3190 | } | 3128 | } |
| 3191 | 3129 | ||
| 3192 | static int buffer_cpu_notify(struct notifier_block *self, | 3130 | static int buffer_cpu_notify(struct notifier_block *self, |
| @@ -3203,8 +3141,11 @@ void __init buffer_init(void) | |||
| 3203 | int nrpages; | 3141 | int nrpages; |
| 3204 | 3142 | ||
| 3205 | bh_cachep = kmem_cache_create("buffer_head", | 3143 | bh_cachep = kmem_cache_create("buffer_head", |
| 3206 | sizeof(struct buffer_head), 0, | 3144 | sizeof(struct buffer_head), 0, |
| 3207 | SLAB_RECLAIM_ACCOUNT|SLAB_PANIC, init_buffer_head, NULL); | 3145 | (SLAB_RECLAIM_ACCOUNT|SLAB_PANIC| |
| 3146 | SLAB_MEM_SPREAD), | ||
| 3147 | init_buffer_head, | ||
| 3148 | NULL); | ||
| 3208 | 3149 | ||
| 3209 | /* | 3150 | /* |
| 3210 | * Limit the bh occupancy to 10% of ZONE_NORMAL | 3151 | * Limit the bh occupancy to 10% of ZONE_NORMAL |
