Commit 6c5daf01 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6:
  truncate: use new helpers
  truncate: new helpers
  fs: fix overflow in sys_mount() for in-kernel calls
  fs: Make unload_nls() NULL pointer safe
  freeze_bdev: grab active reference to frozen superblocks
  freeze_bdev: kill bd_mount_sem
  exofs: remove BKL from super operations
  fs/romfs: correct error-handling code
  vfs: seq_file: add helpers for data filling
  vfs: remove redundant position check in do_sendfile
  vfs: change sb->s_maxbytes to a loff_t
  vfs: explicitly cast s_maxbytes in fiemap_check_ranges
  libfs: return error code on failed attr set
  seq_file: return a negative error code when seq_path_root() fails.
  vfs: optimize touch_time() too
  vfs: optimization for touch_atime()
  vfs: split generic_forget_inode() so that hugetlbfs does not have to copy it
  fs/inode.c: add dev-id and inode number for debugging in init_special_inode()
  libfs: make simple_read_from_buffer conventional
parents 6d39b27f c08d3b0e
...@@ -80,7 +80,7 @@ Note: PTL can also be used to guarantee that no new clones using the ...@@ -80,7 +80,7 @@ Note: PTL can also be used to guarantee that no new clones using the
mm start up ... this is a loose form of stability on mm_users. For mm start up ... this is a loose form of stability on mm_users. For
example, it is used in copy_mm to protect against a racing tlb_gather_mmu example, it is used in copy_mm to protect against a racing tlb_gather_mmu
single address space optimization, so that the zap_page_range (from single address space optimization, so that the zap_page_range (from
vmtruncate) does not lose sending ipi's to cloned threads that might truncate) does not lose sending ipi's to cloned threads that might
be spawned underneath it and go to user mode to drag in pte's into tlbs. be spawned underneath it and go to user mode to drag in pte's into tlbs.
swap_lock swap_lock
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
/* Taken over from the old code... */ /* Taken over from the old code... */
/* POSIX UID/GID verification for setting inode attributes. */ /* POSIX UID/GID verification for setting inode attributes. */
int inode_change_ok(struct inode *inode, struct iattr *attr) int inode_change_ok(const struct inode *inode, struct iattr *attr)
{ {
int retval = -EPERM; int retval = -EPERM;
unsigned int ia_valid = attr->ia_valid; unsigned int ia_valid = attr->ia_valid;
...@@ -60,9 +60,51 @@ int inode_change_ok(struct inode *inode, struct iattr *attr) ...@@ -60,9 +60,51 @@ int inode_change_ok(struct inode *inode, struct iattr *attr)
error: error:
return retval; return retval;
} }
EXPORT_SYMBOL(inode_change_ok); EXPORT_SYMBOL(inode_change_ok);
/**
* inode_newsize_ok - may this inode be truncated to a given size
* @inode: the inode to be truncated
* @offset: the new size to assign to the inode
* @Returns: 0 on success, -ve errno on failure
*
* inode_newsize_ok will check filesystem limits and ulimits to check that the
* new inode size is within limits. inode_newsize_ok will also send SIGXFSZ
* when necessary. Caller must not proceed with inode size change if failure is
* returned. @inode must be a file (not directory), with appropriate
* permissions to allow truncate (inode_newsize_ok does NOT check these
* conditions).
*
* inode_newsize_ok must be called with i_mutex held.
*/
int inode_newsize_ok(const struct inode *inode, loff_t offset)
{
if (inode->i_size < offset) {
unsigned long limit;
limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
if (limit != RLIM_INFINITY && offset > limit)
goto out_sig;
if (offset > inode->i_sb->s_maxbytes)
goto out_big;
} else {
/*
* truncation of in-use swapfiles is disallowed - it would
* cause subsequent swapout to scribble on the now-freed
* blocks.
*/
if (IS_SWAPFILE(inode))
return -ETXTBSY;
}
return 0;
out_sig:
send_sig(SIGXFSZ, current, 0);
out_big:
return -EFBIG;
}
EXPORT_SYMBOL(inode_newsize_ok);
int inode_setattr(struct inode * inode, struct iattr * attr) int inode_setattr(struct inode * inode, struct iattr * attr)
{ {
unsigned int ia_valid = attr->ia_valid; unsigned int ia_valid = attr->ia_valid;
......
...@@ -737,12 +737,7 @@ befs_put_super(struct super_block *sb) ...@@ -737,12 +737,7 @@ befs_put_super(struct super_block *sb)
{ {
kfree(BEFS_SB(sb)->mount_opts.iocharset); kfree(BEFS_SB(sb)->mount_opts.iocharset);
BEFS_SB(sb)->mount_opts.iocharset = NULL; BEFS_SB(sb)->mount_opts.iocharset = NULL;
unload_nls(BEFS_SB(sb)->nls);
if (BEFS_SB(sb)->nls) {
unload_nls(BEFS_SB(sb)->nls);
BEFS_SB(sb)->nls = NULL;
}
kfree(sb->s_fs_info); kfree(sb->s_fs_info);
sb->s_fs_info = NULL; sb->s_fs_info = NULL;
} }
......
...@@ -216,8 +216,6 @@ EXPORT_SYMBOL(fsync_bdev); ...@@ -216,8 +216,6 @@ EXPORT_SYMBOL(fsync_bdev);
* freeze_bdev -- lock a filesystem and force it into a consistent state * freeze_bdev -- lock a filesystem and force it into a consistent state
* @bdev: blockdevice to lock * @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 * 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. * on it to make sure nobody unmounts until the snapshot creation is done.
* The reference counter (bd_fsfreeze_count) guarantees that only the last * The reference counter (bd_fsfreeze_count) guarantees that only the last
...@@ -232,46 +230,55 @@ struct super_block *freeze_bdev(struct block_device *bdev) ...@@ -232,46 +230,55 @@ struct super_block *freeze_bdev(struct block_device *bdev)
int error = 0; int error = 0;
mutex_lock(&bdev->bd_fsfreeze_mutex); mutex_lock(&bdev->bd_fsfreeze_mutex);
if (bdev->bd_fsfreeze_count > 0) { if (++bdev->bd_fsfreeze_count > 1) {
bdev->bd_fsfreeze_count++; /*
* We don't even need to grab a reference - the first call
* to freeze_bdev grab an active reference and only the last
* thaw_bdev drops it.
*/
sb = get_super(bdev); sb = get_super(bdev);
drop_super(sb);
mutex_unlock(&bdev->bd_fsfreeze_mutex); mutex_unlock(&bdev->bd_fsfreeze_mutex);
return sb; return sb;
} }
bdev->bd_fsfreeze_count++;
sb = get_active_super(bdev);
down(&bdev->bd_mount_sem); if (!sb)
sb = get_super(bdev); goto out;
if (sb && !(sb->s_flags & MS_RDONLY)) { if (sb->s_flags & MS_RDONLY) {
sb->s_frozen = SB_FREEZE_WRITE; deactivate_locked_super(sb);
smp_wmb(); mutex_unlock(&bdev->bd_fsfreeze_mutex);
return sb;
sync_filesystem(sb); }
sb->s_frozen = SB_FREEZE_TRANS; sb->s_frozen = SB_FREEZE_WRITE;
smp_wmb(); smp_wmb();
sync_blockdev(sb->s_bdev); sync_filesystem(sb);
if (sb->s_op->freeze_fs) { sb->s_frozen = SB_FREEZE_TRANS;
error = sb->s_op->freeze_fs(sb); smp_wmb();
if (error) {
printk(KERN_ERR sync_blockdev(sb->s_bdev);
"VFS:Filesystem freeze failed\n");
sb->s_frozen = SB_UNFROZEN; if (sb->s_op->freeze_fs) {
drop_super(sb); error = sb->s_op->freeze_fs(sb);
up(&bdev->bd_mount_sem); if (error) {
bdev->bd_fsfreeze_count--; printk(KERN_ERR
mutex_unlock(&bdev->bd_fsfreeze_mutex); "VFS:Filesystem freeze failed\n");
return ERR_PTR(error); sb->s_frozen = SB_UNFROZEN;
} deactivate_locked_super(sb);
bdev->bd_fsfreeze_count--;
mutex_unlock(&bdev->bd_fsfreeze_mutex);
return ERR_PTR(error);
} }
} }
up_write(&sb->s_umount);
out:
sync_blockdev(bdev); sync_blockdev(bdev);
mutex_unlock(&bdev->bd_fsfreeze_mutex); mutex_unlock(&bdev->bd_fsfreeze_mutex);
return sb; /* thaw_bdev releases s->s_umount */
return sb; /* thaw_bdev releases s->s_umount and bd_mount_sem */
} }
EXPORT_SYMBOL(freeze_bdev); EXPORT_SYMBOL(freeze_bdev);
...@@ -284,44 +291,44 @@ EXPORT_SYMBOL(freeze_bdev); ...@@ -284,44 +291,44 @@ EXPORT_SYMBOL(freeze_bdev);
*/ */
int thaw_bdev(struct block_device *bdev, struct super_block *sb) int thaw_bdev(struct block_device *bdev, struct super_block *sb)
{ {
int error = 0; int error = -EINVAL;
mutex_lock(&bdev->bd_fsfreeze_mutex); mutex_lock(&bdev->bd_fsfreeze_mutex);
if (!bdev->bd_fsfreeze_count) { if (!bdev->bd_fsfreeze_count)
mutex_unlock(&bdev->bd_fsfreeze_mutex); goto out_unlock;
return -EINVAL;
} error = 0;
if (--bdev->bd_fsfreeze_count > 0)
bdev->bd_fsfreeze_count--; goto out_unlock;
if (bdev->bd_fsfreeze_count > 0) {
if (sb) if (!sb)
drop_super(sb); goto out_unlock;
mutex_unlock(&bdev->bd_fsfreeze_mutex);
return 0; BUG_ON(sb->s_bdev != bdev);
} down_write(&sb->s_umount);
if (sb->s_flags & MS_RDONLY)
if (sb) { goto out_deactivate;
BUG_ON(sb->s_bdev != bdev);
if (!(sb->s_flags & MS_RDONLY)) { if (sb->s_op->unfreeze_fs) {
if (sb->s_op->unfreeze_fs) { error = sb->s_op->unfreeze_fs(sb);
error = sb->s_op->unfreeze_fs(sb); if (error) {
if (error) { printk(KERN_ERR
printk(KERN_ERR "VFS:Filesystem thaw failed\n");
"VFS:Filesystem thaw failed\n"); sb->s_frozen = SB_FREEZE_TRANS;
sb->s_frozen = SB_FREEZE_TRANS; bdev->bd_fsfreeze_count++;
bdev->bd_fsfreeze_count++; mutex_unlock(&bdev->bd_fsfreeze_mutex);
mutex_unlock(&bdev->bd_fsfreeze_mutex); return error;
return error;
}
}
sb->s_frozen = SB_UNFROZEN;
smp_wmb();
wake_up(&sb->s_wait_unfrozen);
} }
drop_super(sb);
} }
up(&bdev->bd_mount_sem); sb->s_frozen = SB_UNFROZEN;
smp_wmb();
wake_up(&sb->s_wait_unfrozen);
out_deactivate:
if (sb)
deactivate_locked_super(sb);
out_unlock:
mutex_unlock(&bdev->bd_fsfreeze_mutex); mutex_unlock(&bdev->bd_fsfreeze_mutex);
return 0; return 0;
} }
...@@ -430,7 +437,6 @@ static void init_once(void *foo) ...@@ -430,7 +437,6 @@ static void init_once(void *foo)
memset(bdev, 0, sizeof(*bdev)); memset(bdev, 0, sizeof(*bdev));
mutex_init(&bdev->bd_mutex); mutex_init(&bdev->bd_mutex);
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);
#ifdef CONFIG_SYSFS #ifdef CONFIG_SYSFS
......
...@@ -2239,16 +2239,10 @@ int generic_cont_expand_simple(struct inode *inode, loff_t size) ...@@ -2239,16 +2239,10 @@ int generic_cont_expand_simple(struct inode *inode, loff_t size)
struct address_space *mapping = inode->i_mapping; struct address_space *mapping = inode->i_mapping;
struct page *page; struct page *page;
void *fsdata; void *fsdata;
unsigned long limit;
int err; int err;
err = -EFBIG; err = inode_newsize_ok(inode, size);
limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; if (err)
if (limit != RLIM_INFINITY && size > (loff_t)limit) {
send_sig(SIGXFSZ, current, 0);
goto out;
}
if (size > inode->i_sb->s_maxbytes)
goto out; goto out;
err = pagecache_write_begin(NULL, mapping, size, 0, err = pagecache_write_begin(NULL, mapping, size, 0,
......
...@@ -185,8 +185,7 @@ cifs_read_super(struct super_block *sb, void *data, ...@@ -185,8 +185,7 @@ cifs_read_super(struct super_block *sb, void *data,
cifs_sb->mountdata = NULL; cifs_sb->mountdata = NULL;
} }
#endif #endif
if (cifs_sb->local_nls) unload_nls(cifs_sb->local_nls);
unload_nls(cifs_sb->local_nls);
kfree(cifs_sb); kfree(cifs_sb);
} }
return rc; return rc;
......
...@@ -1557,57 +1557,24 @@ static int cifs_truncate_page(struct address_space *mapping, loff_t from) ...@@ -1557,57 +1557,24 @@ static int cifs_truncate_page(struct address_space *mapping, loff_t from)
static int cifs_vmtruncate(struct inode *inode, loff_t offset) static int cifs_vmtruncate(struct inode *inode, loff_t offset)
{ {
struct address_space *mapping = inode->i_mapping; loff_t oldsize;
unsigned long limit; int err;
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
if (inode->i_size < offset) err = inode_newsize_ok(inode, offset);
goto do_expand; if (err) {
/*
* truncation of in-use swapfiles is disallowed - it would cause
* subsequent swapout to scribble on the now-freed blocks.
*/
if (IS_SWAPFILE(inode)) {
spin_unlock(&inode->i_lock);
goto out_busy;
}
i_size_write(inode, offset);
spin_unlock(&inode->i_lock);
/*
* unmap_mapping_range is called twice, first simply for efficiency
* so that truncate_inode_pages does fewer single-page unmaps. However
* after this first call, and before truncate_inode_pages finishes,
* it is possible for private pages to be COWed, which remain after
* truncate_inode_pages finishes, hence the second unmap_mapping_range
* call must be made for correctness.
*/
unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
truncate_inode_pages(mapping, offset);
unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
goto out_truncate;
do_expand:
limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
if (limit != RLIM_INFINITY && offset > limit) {
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
goto out_sig; goto out;
}
if (offset > inode->i_sb->s_maxbytes) {
spin_unlock(&inode->i_lock);
goto out_big;
} }
oldsize = inode->i_size;
i_size_write(inode, offset); i_size_write(inode, offset);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
out_truncate: truncate_pagecache(inode, oldsize, offset);
if (inode->i_op->truncate) if (inode->i_op->truncate)
inode->i_op->truncate(inode); inode->i_op->truncate(inode);
return 0; out:
out_sig: return err;
send_sig(SIGXFSZ, current, 0);
out_big:
return -EFBIG;
out_busy:
return -ETXTBSY;
} }
static int static int
......
...@@ -768,13 +768,13 @@ asmlinkage long compat_sys_mount(char __user * dev_name, char __user * dir_name, ...@@ -768,13 +768,13 @@ asmlinkage long compat_sys_mount(char __user * dev_name, char __user * dir_name,
char __user * type, unsigned long flags, char __user * type, unsigned long flags,
void __user * data) void __user * data)
{ {
unsigned long type_page; char *kernel_type;
unsigned long data_page; unsigned long data_page;
unsigned long dev_page; char *kernel_dev;
char *dir_page; char *dir_page;
int retval; int retval;
retval = copy_mount_options (type, &type_page); retval = copy_mount_string(type, &kernel_type);
if (retval < 0) if (retval < 0)
goto out; goto out;
...@@ -783,38 +783,38 @@ asmlinkage long compat_sys_mount(char __user * dev_name, char __user * dir_name, ...@@ -783,38 +783,38 @@ asmlinkage long compat_sys_mount(char __user * dev_name, char __user * dir_name,
if (IS_ERR(dir_page)) if (IS_ERR(dir_page))
goto out1; goto out1;
retval = copy_mount_options (dev_name, &dev_page); retval = copy_mount_string(dev_name, &kernel_dev);
if (retval < 0) if (retval < 0)
goto out2; goto out2;
retval = copy_mount_options (data, &data_page); retval = copy_mount_options(data, &data_page);
if (retval < 0) if (retval < 0)
goto out3; goto out3;
retval = -EINVAL; retval = -EINVAL;
if (type_page && data_page) { if (kernel_type && data_page) {
if (!strcmp((char *)type_page, SMBFS_NAME)) { if (!strcmp(kernel_type, SMBFS_NAME)) {
do_smb_super_data_conv((void *)data_page); do_smb_super_data_conv((void *)data_page);
} else if (!strcmp((char *)type_page, NCPFS_NAME)) { } else if (!strcmp(kernel_type, NCPFS_NAME)) {
do_ncp_super_data_conv((void *)data_page); do_ncp_super_data_conv((void *)data_page);
} else if (!strcmp((char *)type_page, NFS4_NAME)) { } else if (!strcmp(kernel_type, NFS4_NAME)) {
if (do_nfs4_super_data_conv((void *) data_page)) if (do_nfs4_super_data_conv((void *) data_page))
goto out4; goto out4;
} }
} }
retval = do_mount((char*)dev_page, dir_page, (char*)type_page, retval = do_mount(kernel_dev, dir_page, kernel_type,
flags, (void*)data_page); flags, (void*)data_page);
out4: out4:
free_page(data_page); free_page(data_page);
out3: out3:
free_page(dev_page); kfree(kernel_dev);
out2: out2:
putname(dir_page); putname(dir_page);
out1: out1:
free_page(type_page); kfree(kernel_type);
out: out:
return retval; return retval;
} }
......
...@@ -214,7 +214,6 @@ int exofs_sync_fs(struct super_block *sb, int wait) ...@@ -214,7 +214,6 @@ int exofs_sync_fs(struct super_block *sb, int wait)
} }
lock_super(sb); lock_super(sb);
lock_kernel();
sbi = sb->s_fs_info; sbi = sb->s_fs_info;
fscb->s_nextid = cpu_to_le64(sbi->s_nextid); fscb->s_nextid = cpu_to_le64(sbi->s_nextid);
fscb->s_numfiles = cpu_to_le32(sbi->s_numfiles); fscb->s_numfiles = cpu_to_le32(sbi->s_numfiles);
...@@ -245,7 +244,6 @@ int exofs_sync_fs(struct super_block *sb, int wait) ...@@ -245,7 +244,6 @@ int exofs_sync_fs(struct super_block *sb, int wait)
out: out:
if (or) if (or)
osd_end_request(or); osd_end_request(or);
unlock_kernel();
unlock_super(sb); unlock_super(sb);
kfree(fscb); kfree(fscb);
return ret; return ret;
...@@ -268,8 +266,6 @@ static void exofs_put_super(struct super_block *sb) ...@@ -268,8 +266,6 @@ static void exofs_put_super(struct super_block *sb)
int num_pend; int num_pend;
struct exofs_sb_info *sbi = sb->s_fs_info; struct exofs_sb_info *sbi = sb->s_fs_info;
lock_kernel();
if (sb->s_dirt) if (sb->s_dirt)
exofs_write_super(sb); exofs_write_super(sb);
...@@ -286,8 +282,6 @@ static void exofs_put_super(struct super_block *sb) ...@@ -286,8 +282,6 @@ static void exofs_put_super(struct super_block *sb)
osduld_put_device(sbi->s_dev); osduld_put_device(sbi->s_dev);
kfree(sb->s_fs_info); kfree(sb->s_fs_info);
sb->s_fs_info = NULL; sb->s_fs_info = NULL;
unlock_kernel();
} }
/* /*
......
...@@ -470,19 +470,11 @@ static void fat_put_super(struct super_block *sb) ...@@ -470,19 +470,11 @@ static void fat_put_super(struct super_block *sb)
iput(sbi->fat_inode); iput(sbi->fat_inode);
if (sbi->nls_disk) { unload_nls(sbi->nls_disk);
unload_nls(sbi->nls_disk); unload_nls(sbi->nls_io);
sbi->nls_disk = NULL;
sbi->options.codepage = fat_default_codepage; if (sbi->options.iocharset != fat_default_iocharset)
}
if (sbi->nls_io) {
unload_nls(sbi->nls_io);
sbi->nls_io = NULL;
}
if (sbi->options.iocharset != fat_default_iocharset) {
kfree(sbi->options.iocharset); kfree(sbi->options.iocharset);
sbi->options.iocharset = fat_default_iocharset;
}
sb->s_fs_info = NULL; sb->s_fs_info = NULL;
kfree(sbi); kfree(sbi);
......
...@@ -1276,14 +1276,9 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr, ...@@ -1276,14 +1276,9 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
return 0; return 0;
if (attr->ia_valid & ATTR_SIZE) { if (attr->ia_valid & ATTR_SIZE) {
unsigned long limit; err = inode_newsize_ok(inode, attr->ia_size);
if (IS_SWAPFILE(inode)) if (err)
return -ETXTBSY; return err;
limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
send_sig(SIGXFSZ, current, 0);
return -EFBIG;
}
is_truncate = true; is_truncate = true;
} }
...@@ -1350,8 +1345,7 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr, ...@@ -1350,8 +1345,7 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
* FUSE_NOWRITE, otherwise fuse_launder_page() would deadlock. * FUSE_NOWRITE, otherwise fuse_launder_page() would deadlock.
*/ */
if (S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) { if (S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) {
if (outarg.attr.size < oldsize) truncate_pagecache(inode, oldsize, outarg.attr.size);
fuse_truncate(inode->i_mapping, outarg.attr.size);
invalidate_inode_pages2(inode->i_mapping); invalidate_inode_pages2(inode->i_mapping);
} }
......
...@@ -606,8 +606,6 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, ...@@ -606,8 +606,6 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
u64 attr_valid); u64 attr_valid);
void fuse_truncate(struct address_space *mapping, loff_t offset);
/** /**
* Initialize the client device * Initialize the client device
*/ */
......
...@@ -140,14 +140,6 @@ static int fuse_remount_fs(struct super_block *sb, int *flags, char *data) ...@@ -140,14 +140,6 @@ static int fuse_remount_fs(struct super_block *sb, int *flags, char *data)
return 0; return 0;
} }
void fuse_truncate(struct address_space *mapping, loff_t offset)
{
/* See vmtruncate() */
unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
truncate_inode_pages(mapping, offset);
unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
}
void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
u64 attr_valid) u64 attr_valid)
{ {
...@@ -205,8 +197,7 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, ...@@ -205,8 +197,7 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
spin_unlock(&fc->lock); spin_unlock(&fc->lock);
if (S_ISREG(inode->i_mode) && oldsize != attr->size) { if (S_ISREG(inode->i_mode) && oldsize != attr->size) {
if (attr->size < oldsize) truncate_pagecache(inode, oldsize, attr->size);
fuse_truncate(inode->i_mapping, attr->size);
invalidate_inode_pages2(inode->i_mapping); invalidate_inode_pages2(inode->i_mapping);
} }
} }
......
...@@ -344,10 +344,8 @@ void hfs_mdb_put(struct super_block *sb) ...@@ -344,10 +344,8 @@ void hfs_mdb_put(struct super_block *sb)
brelse(HFS_SB(sb)->mdb_bh); brelse(HFS_SB(sb)->mdb_bh);
brelse(HFS_SB(sb)->alt_mdb_bh); brelse(HFS_SB(sb)->alt_mdb_bh);
if (HFS_SB(sb)->nls_io) unload_nls(HFS_SB(sb)->nls_io);
unload_nls(HFS_SB(sb)->nls_io); unload_nls(HFS_SB(sb)->nls_disk);
if (HFS_SB(sb)->nls_disk)
unload_nls(HFS_SB(sb)->nls_disk);
free_pages((unsigned long)HFS_SB(sb)->bitmap, PAGE_SIZE < 8192 ? 1 : 0); free_pages((unsigned long)HFS_SB(sb)->bitmap, PAGE_SIZE < 8192 ? 1 : 0);
kfree(HFS_SB(sb)); kfree(HFS_SB(sb));
......
...@@ -229,8 +229,7 @@ static void hfsplus_put_super(struct super_block *sb) ...@@ -229,8 +229,7 @@ static void hfsplus_put_super(struct super_block *sb)
iput(HFSPLUS_SB(sb).alloc_file); iput(HFSPLUS_SB(sb).alloc_file);
iput(HFSPLUS_SB(sb).hidden_dir); iput(HFSPLUS_SB(sb).hidden_dir);
brelse(HFSPLUS_SB(sb).s_vhbh); brelse(HFSPLUS_SB(sb).s_vhbh);
if (HFSPLUS_SB(sb).nls) unload_nls(HFSPLUS_SB(sb).nls);
unload_nls(HFSPLUS_SB(sb).nls);
kfree(sb->s_fs_info); kfree(sb->s_fs_info);
sb->s_fs_info = NULL; sb->s_fs_info = NULL;
...@@ -464,8 +463,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) ...@@ -464,8 +463,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
cleanup: cleanup:
hfsplus_put_super(sb); hfsplus_put_super(sb);
if (nls) unload_nls(nls);
unload_nls(nls);
return err; return err;
} }
......
...@@ -380,36 +380,11 @@ static void hugetlbfs_delete_inode(struct inode *inode) ...@@ -380,36 +380,11 @@ static void hugetlbfs_delete_inode(struct inode *inode)
static void hugetlbfs_forget_inode(struct inode *inode) __releases(inode_lock) static void hugetlbfs_forget_inode(struct inode *inode) __releases(inode_lock)
{ {
struct super_block *sb = inode->i_sb; if (generic_detach_inode(inode)) {
truncate_hugepages(inode, 0);
if (!hlist_unhashed(&inode->i_hash)) { clear_inode(inode);
if (!(inode->i_state & (I_DIRTY|I_SYNC))) destroy_inode(inode);
list_move(&inode->i_list, &inode_unused);
inodes_stat.nr_unused++;
if (!sb || (sb->s_flags & MS_ACTIVE)) {
spin_unlock(&inode_lock);
return;
}
inode->i_state |= I_WILL_FREE;
spin_unlock(&inode_lock);
/*
* write_inode_now is a noop as we set BDI_CAP_NO_WRITEBACK
* in our backing_dev_info.
*/
write_inode_now(inode, 1);
spin_lock(&inode_lock);
inode->i_state &= ~I_WILL_FREE;
inodes_stat.nr_unused--;
hlist_del_init(&inode->i_hash);
} }
list_del_init(&inode->i_list);
list_del_init(&inode->i_sb_list);
inode->i_state |= I_FREEING;
inodes_stat.nr_inodes--;
spin_unlock(&inode_lock);
truncate_hugepages(inode, 0);
clear_inode(inode);
destroy_inode(inode);
} }
static void hugetlbfs_drop_inode(struct inode *inode) static void hugetlbfs_drop_inode(struct inode *inode)
......
...@@ -1241,7 +1241,16 @@ void generic_delete_inode(struct inode *inode) ...@@ -1241,7 +1241,16 @@ void generic_delete_inode(struct inode *inode)
} }
EXPORT_SYMBOL(generic_delete_inode); EXPORT_SYMBOL(generic_delete_inode);
static void generic_forget_inode(struct inode *inode) /**
* generic_detach_inode - remove inode from inode lists
* @inode: inode to remove
*
* Remove inode from inode lists, write it if it's dirty. This is just an
* internal VFS helper exported for hugetlbfs. Do not use!
*
* Returns 1 if inode should be completely destroyed.
*/
int generic_detach_inode(struct inode *inode)
{ {
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
...@@ -1251,7 +1260,7 @@ static void generic_forget_inode(struct inode *inode) ...@@ -1251,7 +1260,7 @@ static void generic_forget_inode(struct inode *inode)
inodes_stat.nr_unused++; inodes_stat.nr_unused++;
if (sb->s_flags & MS_ACTIVE) { if (sb->s_flags & MS_ACTIVE) {
spin_unlock(&inode_lock); spin_unlock(&inode_lock);
return; return 0;
} }
WARN_ON(inode->i_state & I_NEW); WARN_ON(inode->i_state & I_NEW);
inode->i_state |= I_WILL_FREE; inode->i_state |= I_WILL_FREE;
...@@ -1269,6 +1278,14 @@ static void generic_forget_inode(struct inode *inode) ...@@ -1269,6 +1278,14 @@ static void generic_forget_inode(struct inode *inode)
inode->i_state |= I_FREEING; inode->i_state |= I_FREEING;
inodes_stat.nr_inodes--; inodes_stat.nr_inodes--;
spin_unlock(&inode_lock); spin_unlock(&inode_lock);
return 1;
}
EXPORT_SYMBOL_GPL(generic_detach_inode);
static void generic_forget_inode(struct inode *inode)
{
if (!generic_detach_inode(inode))
return;
if (inode->i_data.nrpages) if (inode->i_data.nrpages)
truncate_inode_pages(&inode->i_data, 0); truncate_inode_pages(&inode->i_data, 0);
clear_inode(inode); clear_inode(inode);
...@@ -1399,31 +1416,31 @@ void touch_atime(struct vfsmount *mnt, struct dentry *dentry) ...@@ -1399,31 +1416,31 @@ void touch_atime(struct vfsmount *mnt, struct dentry *dentry)
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
struct timespec now; struct timespec now;
if (mnt_want_write(mnt))
return;
if (inode->i_flags & S_NOATIME) if (inode->i_flags & S_NOATIME)
goto out; return;
if (IS_NOATIME(inode)) if (IS_NOATIME(inode))
goto out; return;
if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode)) if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode))
goto out; return;
if (mnt->mnt_flags & MNT_NOATIME) if (mnt->mnt_flags & MNT_NOATIME)
goto out; return;
if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)) if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))
goto out; return;
now = current_fs_time(inode->i_sb); now = current_fs_time(inode->i_sb);
if (!relatime_need_update(mnt, inode, now)) if (!relatime_need_update(mnt, inode, now))
goto out; return;
if (timespec_equal(&inode->i_atime, &now)) if (timespec_equal(&inode->i_atime, &now))
goto out; return;
if (mnt_want_write(mnt))
return;
inode->i_atime = now; inode->i_atime = now;
mark_inode_dirty_sync(inode); mark_inode_dirty_sync(inode);
out:
mnt_drop_write(mnt); mnt_drop_write(mnt);
} }
EXPORT_SYMBOL(touch_atime); EXPORT_SYMBOL(touch_atime);
...@@ -1444,34 +1461,37 @@ void file_update_time(struct file *file) ...@@ -1444,34 +1461,37 @@ void file_update_time(struct file *file)
{ {
struct inode *inode = file->f_path.dentry->d_inode; struct inode *inode = file->f_path.dentry->d_inode;
struct timespec now; struct timespec now;
int sync_it = 0; enum { S_MTIME = 1, S_CTIME = 2, S_VERSION = 4 } sync_it = 0;
int err;
/* First try to exhaust all avenues to not sync */
if (IS_NOCMTIME(inode)) if (IS_NOCMTIME(inode))
return; return;
err = mnt_want_write_file(file);
if (err)
return;
now = current_fs_time(inode->i_sb); now = current_fs_time(inode->i_sb);
if (!timespec_equal(&inode->i_mtime, &now)) { if (!timespec_equal(&inode->i_mtime, &now))
inode->i_mtime = now; sync_it = S_MTIME;
sync_it = 1;
}
if (!timespec_equal(&inode->i_ctime, &now)) { if (!timespec_equal(&inode->i_ctime, &now))
inode->i_ctime = now; sync_it |= S_CTIME;
sync_it = 1;
}
if (IS_I_VERSION(inode)) { if (IS_I_VERSION(inode))
inode_inc_iversion(inode); sync_it |= S_VERSION;
sync_it = 1;
} if (!sync_it)
return;
if (sync_it) /* Finally allowed to write? Takes lock. */
mark_inode_dirty_sync(inode); if (mnt_want_write_file(file))
return;
/* Only change inode inside the lock region */
if (sync_it & S_VERSION)
inode_inc_iversion(inode);
if (sync_it & S_CTIME)
inode->i_ctime = now;
if (sync_it & S_MTIME)
inode->i_mtime = now;
mark_inode_dirty_sync(inode);
mnt_drop_write(file->f_path.mnt); mnt_drop_write(file->f_path.mnt);
} }
EXPORT_SYMBOL(file_update_time); EXPORT_SYMBOL(file_update_time);
...@@ -1599,7 +1619,8 @@ void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev) ...@@ -1599,7 +1619,8 @@ void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
else if (S_ISSOCK(mode)) else if (S_ISSOCK(mode))
inode->i_fop = &bad_sock_fops; inode->i_fop = &bad_sock_fops;
else else
printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o)\n", printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for"
mode); " inode %s:%lu\n", mode, inode->i_sb->s_id,
inode->i_ino);
} }
EXPORT_SYMBOL(init_special_inode); EXPORT_SYMBOL(init_special_inode);
...@@ -57,6 +57,7 @@ extern int check_unsafe_exec(struct linux_binprm *); ...@@ -57,6 +57,7 @@ extern int check_unsafe_exec(struct linux_binprm *);
* namespace.c * namespace.c
*/ */
extern int copy_mount_options(const void __user *, unsigned long *); extern int copy_mount_options(const void __user *, unsigned long *);
extern int copy_mount_string(const void __user *, char **);
extern void free_vfsmnt(struct vfsmount *); extern void free_vfsmnt(struct vfsmount *);
extern struct vfsmount *alloc_vfsmnt(const char *); extern struct vfsmount *alloc_vfsmnt(const char *);
......
...@@ -162,20 +162,21 @@ EXPORT_SYMBOL(fiemap_check_flags); ...@@ -162,20 +162,21 @@ EXPORT_SYMBOL(fiemap_check_flags);
static int fiemap_check_ranges(struct super_block *sb, static int fiemap_check_ranges(struct super_block *sb,
u64 start, u64 len, u64 *new_len) u64 start, u64 len, u64 *new_len)
{ {
u64 maxbytes = (u64) sb->s_maxbytes;
*new_len = len; *new_len = len;
if (len == 0) if (len == 0)
return -EINVAL; return -EINVAL;
if (start > sb->s_maxbytes) if (start > maxbytes)
return -EFBIG; return -EFBIG;
/* /*
* Shrink request scope to what the fs can actually handle. * Shrink request scope to what the fs can actually handle.
*/ */
if ((len > sb->s_maxbytes) || if (len > maxbytes || (maxbytes - len) < start)
(sb->s_maxbytes - len) < start) *new_len = maxbytes - start;
*new_len = sb->s_maxbytes - start;
return 0; return 0;
} }
......
...@@ -46,10 +46,7 @@ static void isofs_put_super(struct super_block *sb) ...@@ -46,10 +46,7 @@ static void isofs_put_super(struct super_block *sb)
#ifdef CONFIG_JOLIET #ifdef CONFIG_JOLIET
lock_kernel(); lock_kernel();
if (sbi->s_nls_iocharset) { unload_nls(sbi->s_nls_iocharset);
unload_nls(sbi->s_nls_iocharset);
sbi->s_nls_iocharset = NULL;
}
unlock_kernel(); unlock_kernel();
#endif #endif
...@@ -912,8 +909,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) ...@@ -912,8 +909,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
printk(KERN_WARNING "%s: get root inode failed\n", __func__); printk(KERN_WARNING "%s: get root inode failed\n", __func__);
out_no_inode: out_no_inode:
#ifdef CONFIG_JOLIET #ifdef CONFIG_JOLIET
if (sbi->s_nls_iocharset) unload_nls(sbi->s_nls_iocharset);
unload_nls(sbi->s_nls_iocharset);
#endif #endif
goto out_freesbi; goto out_freesbi;
out_no_read: out_no_read:
......
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