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: (96 commits)
  no need for list_for_each_entry_safe()/resetting with superblock list
  Fix sget() race with failing mount
  vfs: don't hold s_umount over close_bdev_exclusive() call
  sysv: do not mark superblock dirty on remount
  sysv: do not mark superblock dirty on mount
  btrfs: remove junk sb_dirt change
  BFS: clean up the superblock usage
  AFFS: wait for sb synchronization when needed
  AFFS: clean up dirty flag usage
  cifs: truncate fallout
  mbcache: fix shrinker function return value
  mbcache: Remove unused features
  add f_flags to struct statfs(64)
  pass a struct path to vfs_statfs
  update VFS documentation for method changes.
  All filesystems that need invalidate_inode_buffers() are doing that explicitly
  convert remaining ->clear_inode() to ->evict_inode()
  Make ->drop_inode() just return whether inode needs to be dropped
  fs/inode.c:clear_inode() is gone
  fs/inode.c:evict() doesn't care about delete vs. non-delete paths now
  ...

Fix up trivial conflicts in fs/nilfs2/super.c
This commit is contained in:
Linus Torvalds 2010-08-10 11:26:52 -07:00
commit 5f248c9c25
205 changed files with 2594 additions and 2485 deletions

View File

@ -92,8 +92,8 @@ prototypes:
void (*destroy_inode)(struct inode *);
void (*dirty_inode) (struct inode *);
int (*write_inode) (struct inode *, int);
void (*drop_inode) (struct inode *);
void (*delete_inode) (struct inode *);
int (*drop_inode) (struct inode *);
void (*evict_inode) (struct inode *);
void (*put_super) (struct super_block *);
void (*write_super) (struct super_block *);
int (*sync_fs)(struct super_block *sb, int wait);
@ -101,14 +101,13 @@ prototypes:
int (*unfreeze_fs) (struct super_block *);
int (*statfs) (struct dentry *, struct kstatfs *);
int (*remount_fs) (struct super_block *, int *, char *);
void (*clear_inode) (struct inode *);
void (*umount_begin) (struct super_block *);
int (*show_options)(struct seq_file *, struct vfsmount *);
ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
locking rules:
All may block.
All may block [not true, see below]
None have BKL
s_umount
alloc_inode:
@ -116,22 +115,25 @@ destroy_inode:
dirty_inode: (must not sleep)
write_inode:
drop_inode: !!!inode_lock!!!
delete_inode:
evict_inode:
put_super: write
write_super: read
sync_fs: read
freeze_fs: read
unfreeze_fs: read
statfs: no
remount_fs: maybe (see below)
clear_inode:
statfs: maybe(read) (see below)
remount_fs: write
umount_begin: no
show_options: no (namespace_sem)
quota_read: no (see below)
quota_write: no (see below)
->remount_fs() will have the s_umount exclusive lock if it's already mounted.
When called from get_sb_single, it does NOT have the s_umount lock.
->statfs() has s_umount (shared) when called by ustat(2) (native or
compat), but that's an accident of bad API; s_umount is used to pin
the superblock down when we only have dev_t given us by userland to
identify the superblock. Everything else (statfs(), fstatfs(), etc.)
doesn't hold it when calling ->statfs() - superblock is pinned down
by resolving the pathname passed to syscall.
->quota_read() and ->quota_write() functions are both guaranteed to
be the only ones operating on the quota file by the quota code (via
dqio_sem) (unless an admin really wants to screw up something and

View File

@ -273,3 +273,48 @@ it's safe to remove it. If you don't need it, remove it.
deliberate; as soon as struct block_device * is propagated in a reasonable
way by that code fixing will become trivial; until then nothing can be
done.
[mandatory]
block truncatation on error exit from ->write_begin, and ->direct_IO
moved from generic methods (block_write_begin, cont_write_begin,
nobh_write_begin, blockdev_direct_IO*) to callers. Take a look at
ext2_write_failed and callers for an example.
[mandatory]
->truncate is going away. The whole truncate sequence needs to be
implemented in ->setattr, which is now mandatory for filesystems
implementing on-disk size changes. Start with a copy of the old inode_setattr
and vmtruncate, and the reorder the vmtruncate + foofs_vmtruncate sequence to
be in order of zeroing blocks using block_truncate_page or similar helpers,
size update and on finally on-disk truncation which should not fail.
inode_change_ok now includes the size checks for ATTR_SIZE and must be called
in the beginning of ->setattr unconditionally.
[mandatory]
->clear_inode() and ->delete_inode() are gone; ->evict_inode() should
be used instead. It gets called whenever the inode is evicted, whether it has
remaining links or not. Caller does *not* evict the pagecache or inode-associated
metadata buffers; getting rid of those is responsibility of method, as it had
been for ->delete_inode().
->drop_inode() returns int now; it's called on final iput() with inode_lock
held and it returns true if filesystems wants the inode to be dropped. As before,
generic_drop_inode() is still the default and it's been updated appropriately.
generic_delete_inode() is also alive and it consists simply of return 1. Note that
all actual eviction work is done by caller after ->drop_inode() returns.
clear_inode() is gone; use end_writeback() instead. As before, it must
be called exactly once on each call of ->evict_inode() (as it used to be for
each call of ->delete_inode()). Unlike before, if you are using inode-associated
metadata buffers (i.e. mark_buffer_dirty_inode()), it's your responsibility to
call invalidate_inode_buffers() before end_writeback().
No async writeback (and thus no calls of ->write_inode()) will happen
after end_writeback() returns, so actions that should not overlap with ->write_inode()
(e.g. freeing on-disk inode if i_nlink is 0) ought to be done after that call.
NOTE: checking i_nlink in the beginning of ->write_inode() and bailing out
if it's zero is not *and* *never* *had* *been* enough. Final unlink() and iput()
may happen while the inode is in the middle of ->write_inode(); e.g. if you blindly
free the on-disk inode, you may end up doing that while ->write_inode() is writing
to it.

View File

@ -234,11 +234,11 @@ linux_to_osf_statfs(struct kstatfs *linux_stat, struct osf_statfs __user *osf_st
}
static int
do_osf_statfs(struct dentry * dentry, struct osf_statfs __user *buffer,
do_osf_statfs(struct path *path, struct osf_statfs __user *buffer,
unsigned long bufsiz)
{
struct kstatfs linux_stat;
int error = vfs_statfs(dentry, &linux_stat);
int error = vfs_statfs(path, &linux_stat);
if (!error)
error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz);
return error;
@ -252,7 +252,7 @@ SYSCALL_DEFINE3(osf_statfs, char __user *, pathname,
retval = user_path(pathname, &path);
if (!retval) {
retval = do_osf_statfs(path.dentry, buffer, bufsiz);
retval = do_osf_statfs(&path buffer, bufsiz);
path_put(&path);
}
return retval;
@ -267,7 +267,7 @@ SYSCALL_DEFINE3(osf_fstatfs, unsigned long, fd,
retval = -EBADF;
file = fget(fd);
if (file) {
retval = do_osf_statfs(file->f_path.dentry, buffer, bufsiz);
retval = do_osf_statfs(&file->f_path, buffer, bufsiz);
fput(file);
}
return retval;

View File

@ -33,7 +33,8 @@ struct statfs {
/* Linux specials */
__kernel_fsid_t f_fsid;
long f_namelen;
long f_spare[6];
long f_flags;
long f_spare[5];
};
#if (_MIPS_SIM == _MIPS_SIM_ABI32) || (_MIPS_SIM == _MIPS_SIM_NABI32)
@ -53,7 +54,8 @@ struct statfs64 {
__u64 f_bavail;
__kernel_fsid_t f_fsid;
__u32 f_namelen;
__u32 f_spare[6];
__u32 f_flags;
__u32 f_spare[5];
};
#endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
@ -73,7 +75,8 @@ struct statfs64 { /* Same as struct statfs */
/* Linux specials */
__kernel_fsid_t f_fsid;
long f_namelen;
long f_spare[6];
long f_flags;
long f_spare[5];
};
struct compat_statfs64 {
@ -88,7 +91,8 @@ struct compat_statfs64 {
__u64 f_bavail;
__kernel_fsid_t f_fsid;
__u32 f_namelen;
__u32 f_spare[6];
__u32 f_flags;
__u32 f_spare[5];
};
#endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */

View File

@ -145,7 +145,7 @@ static int hpux_ustat(dev_t dev, struct hpux_ustat __user *ubuf)
s = user_get_super(dev);
if (s == NULL)
goto out;
err = vfs_statfs(s->s_root, &sbuf);
err = statfs_by_dentry(s->s_root, &sbuf);
drop_super(s);
if (err)
goto out;
@ -186,12 +186,12 @@ struct hpux_statfs {
int16_t f_pad;
};
static int vfs_statfs_hpux(struct dentry *dentry, struct hpux_statfs *buf)
static int do_statfs_hpux(struct path *path, struct hpux_statfs *buf)
{
struct kstatfs st;
int retval;
retval = vfs_statfs(dentry, &st);
retval = vfs_statfs(path, &st);
if (retval)
return retval;
@ -219,7 +219,7 @@ asmlinkage long hpux_statfs(const char __user *pathname,
error = user_path(pathname, &path);
if (!error) {
struct hpux_statfs tmp;
error = vfs_statfs_hpux(path.dentry, &tmp);
error = do_statfs_hpux(&path, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
path_put(&path);
@ -237,7 +237,7 @@ asmlinkage long hpux_fstatfs(unsigned int fd, struct hpux_statfs __user * buf)
file = fget(fd);
if (!file)
goto out;
error = vfs_statfs_hpux(file->f_path.dentry, &tmp);
error = do_statfs_hpux(&file->f_path, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
fput(file);

View File

@ -110,7 +110,9 @@ spufs_setattr(struct dentry *dentry, struct iattr *attr)
if ((attr->ia_valid & ATTR_SIZE) &&
(attr->ia_size != inode->i_size))
return -EINVAL;
return inode_setattr(inode, attr);
setattr_copy(inode, attr);
mark_inode_dirty(inode);
return 0;
}
@ -141,15 +143,14 @@ spufs_new_file(struct super_block *sb, struct dentry *dentry,
}
static void
spufs_delete_inode(struct inode *inode)
spufs_evict_inode(struct inode *inode)
{
struct spufs_inode_info *ei = SPUFS_I(inode);
end_writeback(inode);
if (ei->i_ctx)
put_spu_context(ei->i_ctx);
if (ei->i_gang)
put_spu_gang(ei->i_gang);
clear_inode(inode);
}
static void spufs_prune_dir(struct dentry *dir)
@ -777,8 +778,7 @@ spufs_fill_super(struct super_block *sb, void *data, int silent)
.alloc_inode = spufs_alloc_inode,
.destroy_inode = spufs_destroy_inode,
.statfs = simple_statfs,
.delete_inode = spufs_delete_inode,
.drop_inode = generic_delete_inode,
.evict_inode = spufs_evict_inode,
.show_options = generic_show_options,
};

View File

@ -117,10 +117,10 @@ static struct inode *hypfs_make_inode(struct super_block *sb, int mode)
return ret;
}
static void hypfs_drop_inode(struct inode *inode)
static void hypfs_evict_inode(struct inode *inode)
{
end_writeback(inode);
kfree(inode->i_private);
generic_delete_inode(inode);
}
static int hypfs_open(struct inode *inode, struct file *filp)
@ -460,7 +460,7 @@ static struct file_system_type hypfs_type = {
static const struct super_operations hypfs_s_ops = {
.statfs = simple_statfs,
.drop_inode = hypfs_drop_inode,
.evict_inode = hypfs_evict_inode,
.show_options = hypfs_show_options,
};

View File

@ -33,7 +33,8 @@ struct statfs {
__kernel_fsid_t f_fsid;
int f_namelen;
int f_frsize;
int f_spare[5];
int f_flags;
int f_spare[4];
};
struct statfs64 {
@ -47,7 +48,8 @@ struct statfs64 {
__kernel_fsid_t f_fsid;
int f_namelen;
int f_frsize;
int f_spare[5];
int f_flags;
int f_spare[4];
};
struct compat_statfs64 {
@ -61,7 +63,8 @@ struct compat_statfs64 {
__kernel_fsid_t f_fsid;
__u32 f_namelen;
__u32 f_frsize;
__u32 f_spare[5];
__u32 f_flags;
__u32 f_spare[4];
};
#endif /* __s390x__ */

View File

@ -161,6 +161,9 @@ extern int os_stat_filesystem(char *path, long *bsize_out,
long *spare_out);
extern int os_change_dir(char *dir);
extern int os_fchange_dir(int fd);
extern unsigned os_major(unsigned long long dev);
extern unsigned os_minor(unsigned long long dev);
extern unsigned long long os_makedev(unsigned major, unsigned minor);
/* start_up.c */
extern void os_early_checks(void);

View File

@ -58,6 +58,9 @@ EXPORT_SYMBOL(os_accept_connection);
EXPORT_SYMBOL(os_rcv_fd);
EXPORT_SYMBOL(run_helper);
EXPORT_SYMBOL(start_thread);
EXPORT_SYMBOL(os_major);
EXPORT_SYMBOL(os_minor);
EXPORT_SYMBOL(os_makedev);
EXPORT_SYMBOL(add_sigio_fd);
EXPORT_SYMBOL(ignore_sigio_fd);

View File

@ -561,3 +561,18 @@ int os_lock_file(int fd, int excl)
out:
return err;
}
unsigned os_major(unsigned long long dev)
{
return major(dev);
}
unsigned os_minor(unsigned long long dev)
{
return minor(dev);
}
unsigned long long os_makedev(unsigned major, unsigned minor)
{
return makedev(major, minor);
}

View File

@ -103,6 +103,10 @@ EXPORT_SYMBOL_PROTO(getuid);
EXPORT_SYMBOL_PROTO(fsync);
EXPORT_SYMBOL_PROTO(fdatasync);
EXPORT_SYMBOL_PROTO(lstat64);
EXPORT_SYMBOL_PROTO(fstat64);
EXPORT_SYMBOL_PROTO(mknod);
/* Export symbols used by GCC for the stack protector. */
extern void __stack_smash_handler(void *) __attribute__((weak));
EXPORT_SYMBOL(__stack_smash_handler);

View File

@ -968,12 +968,18 @@ int pohmelfs_setattr_raw(struct inode *inode, struct iattr *attr)
goto err_out_exit;
}
err = inode_setattr(inode, attr);
if (err) {
dprintk("%s: ino: %llu, failed to set the attributes.\n", __func__, POHMELFS_I(inode)->ino);
goto err_out_exit;
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
err = vmtruncate(inode, attr->ia_size);
if (err) {
dprintk("%s: ino: %llu, failed to set the attributes.\n", __func__, POHMELFS_I(inode)->ino);
goto err_out_exit;
}
}
setattr_copy(inode, attr);
mark_inode_dirty(inode);
dprintk("%s: ino: %llu, mode: %o -> %o, uid: %u -> %u, gid: %u -> %u, size: %llu -> %llu.\n",
__func__, POHMELFS_I(inode)->ino, inode->i_mode, attr->ia_mode,
inode->i_uid, attr->ia_uid, inode->i_gid, attr->ia_gid, inode->i_size, attr->ia_size);
@ -1217,7 +1223,7 @@ void pohmelfs_fill_inode(struct inode *inode, struct netfs_inode_info *info)
}
}
static void pohmelfs_drop_inode(struct inode *inode)
static int pohmelfs_drop_inode(struct inode *inode)
{
struct pohmelfs_sb *psb = POHMELFS_SB(inode->i_sb);
struct pohmelfs_inode *pi = POHMELFS_I(inode);
@ -1226,7 +1232,7 @@ static void pohmelfs_drop_inode(struct inode *inode)
list_del_init(&pi->inode_entry);
spin_unlock(&psb->ino_lock);
generic_drop_inode(inode);
return generic_drop_inode(inode);
}
static struct pohmelfs_inode *pohmelfs_get_inode_from_list(struct pohmelfs_sb *psb,

View File

@ -52,7 +52,7 @@ void v9fs_destroy_inode(struct inode *inode);
#endif
struct inode *v9fs_get_inode(struct super_block *sb, int mode);
void v9fs_clear_inode(struct inode *inode);
void v9fs_evict_inode(struct inode *inode);
ino_t v9fs_qid2ino(struct p9_qid *qid);
void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *);
void v9fs_stat2inode_dotl(struct p9_stat_dotl *, struct inode *);

View File

@ -430,8 +430,10 @@ v9fs_clone_walk(struct v9fs_session_info *v9ses, u32 fid, struct dentry *dentry)
* @inode: inode to release
*
*/
void v9fs_clear_inode(struct inode *inode)
void v9fs_evict_inode(struct inode *inode)
{
truncate_inode_pages(inode->i_mapping, 0);
end_writeback(inode);
filemap_fdatawrite(inode->i_mapping);
#ifdef CONFIG_9P_FSCACHE
@ -1209,10 +1211,19 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
}
retval = p9_client_wstat(fid, &wstat);
if (retval >= 0)
retval = inode_setattr(dentry->d_inode, iattr);
if (retval < 0)
return retval;
return retval;
if ((iattr->ia_valid & ATTR_SIZE) &&
iattr->ia_size != i_size_read(dentry->d_inode)) {
retval = vmtruncate(dentry->d_inode, iattr->ia_size);
if (retval)
return retval;
}
setattr_copy(dentry->d_inode, iattr);
mark_inode_dirty(dentry->d_inode);
return 0;
}
/**

View File

@ -266,7 +266,7 @@ static const struct super_operations v9fs_super_ops = {
.destroy_inode = v9fs_destroy_inode,
#endif
.statfs = simple_statfs,
.clear_inode = v9fs_clear_inode,
.evict_inode = v9fs_evict_inode,
.show_options = generic_show_options,
.umount_begin = v9fs_umount_begin,
};
@ -277,7 +277,7 @@ static const struct super_operations v9fs_super_ops_dotl = {
.destroy_inode = v9fs_destroy_inode,
#endif
.statfs = v9fs_statfs,
.clear_inode = v9fs_clear_inode,
.evict_inode = v9fs_evict_inode,
.show_options = generic_show_options,
.umount_begin = v9fs_umount_begin,
};

View File

@ -50,10 +50,19 @@ static int adfs_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
int ret;
*pagep = NULL;
return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
adfs_get_block,
&ADFS_I(mapping->host)->mmu_private);
if (unlikely(ret)) {
loff_t isize = mapping->host->i_size;
if (pos + len > isize)
vmtruncate(mapping->host, isize);
}
return ret;
}
static sector_t _adfs_bmap(struct address_space *mapping, sector_t block)
@ -324,10 +333,7 @@ adfs_notify_change(struct dentry *dentry, struct iattr *attr)
/* XXX: this is missing some actual on-disk truncation.. */
if (ia_valid & ATTR_SIZE)
error = simple_setsize(inode, attr->ia_size);
if (error)
goto out;
truncate_setsize(inode, attr->ia_size);
if (ia_valid & ATTR_MTIME) {
inode->i_mtime = attr->ia_mtime;

View File

@ -171,8 +171,7 @@ extern int affs_rename(struct inode *old_dir, struct dentry *old_dentry,
extern unsigned long affs_parent_ino(struct inode *dir);
extern struct inode *affs_new_inode(struct inode *dir);
extern int affs_notify_change(struct dentry *dentry, struct iattr *attr);
extern void affs_delete_inode(struct inode *inode);
extern void affs_clear_inode(struct inode *inode);
extern void affs_evict_inode(struct inode *inode);
extern struct inode *affs_iget(struct super_block *sb,
unsigned long ino);
extern int affs_write_inode(struct inode *inode,

View File

@ -406,10 +406,19 @@ static int affs_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
int ret;
*pagep = NULL;
return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
affs_get_block,
&AFFS_I(mapping->host)->mmu_private);
if (unlikely(ret)) {
loff_t isize = mapping->host->i_size;
if (pos + len > isize)
vmtruncate(mapping->host, isize);
}
return ret;
}
static sector_t _affs_bmap(struct address_space *mapping, sector_t block)

View File

@ -235,31 +235,36 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr)
goto out;
}
error = inode_setattr(inode, attr);
if (!error && (attr->ia_valid & ATTR_MODE))
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
error = vmtruncate(inode, attr->ia_size);
if (error)
return error;
}
setattr_copy(inode, attr);
mark_inode_dirty(inode);
if (attr->ia_valid & ATTR_MODE)
mode_to_prot(inode);
out:
return error;
}
void
affs_delete_inode(struct inode *inode)
{
pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
truncate_inode_pages(&inode->i_data, 0);
inode->i_size = 0;
affs_truncate(inode);
clear_inode(inode);
affs_free_block(inode->i_sb, inode->i_ino);
}
void
affs_clear_inode(struct inode *inode)
affs_evict_inode(struct inode *inode)
{
unsigned long cache_page;
pr_debug("AFFS: evict_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
truncate_inode_pages(&inode->i_data, 0);
pr_debug("AFFS: clear_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
if (!inode->i_nlink) {
inode->i_size = 0;
affs_truncate(inode);
}
invalidate_inode_buffers(inode);
end_writeback(inode);
affs_free_prealloc(inode);
cache_page = (unsigned long)AFFS_I(inode)->i_lc;
if (cache_page) {
@ -271,6 +276,9 @@ affs_clear_inode(struct inode *inode)
affs_brelse(AFFS_I(inode)->i_ext_bh);
AFFS_I(inode)->i_ext_last = ~1;
AFFS_I(inode)->i_ext_bh = NULL;
if (!inode->i_nlink)
affs_free_block(inode->i_sb, inode->i_ino);
}
struct inode *

View File

@ -26,7 +26,7 @@ static int affs_statfs(struct dentry *dentry, struct kstatfs *buf);
static int affs_remount (struct super_block *sb, int *flags, char *data);
static void
affs_commit_super(struct super_block *sb, int clean)
affs_commit_super(struct super_block *sb, int wait, int clean)
{
struct affs_sb_info *sbi = AFFS_SB(sb);
struct buffer_head *bh = sbi->s_root_bh;
@ -36,6 +36,8 @@ affs_commit_super(struct super_block *sb, int clean)
secs_to_datestamp(get_seconds(), &tail->disk_change);
affs_fix_checksum(sb, bh);
mark_buffer_dirty(bh);
if (wait)
sync_dirty_buffer(bh);
}
static void
@ -46,8 +48,8 @@ affs_put_super(struct super_block *sb)
lock_kernel();
if (!(sb->s_flags & MS_RDONLY))
affs_commit_super(sb, 1);
if (!(sb->s_flags & MS_RDONLY) && sb->s_dirt)
affs_commit_super(sb, 1, 1);
kfree(sbi->s_prefix);
affs_free_bitmap(sb);
@ -61,27 +63,20 @@ affs_put_super(struct super_block *sb)
static void
affs_write_super(struct super_block *sb)
{
int clean = 2;
lock_super(sb);
if (!(sb->s_flags & MS_RDONLY)) {
// if (sbi->s_bitmap[i].bm_bh) {
// if (buffer_dirty(sbi->s_bitmap[i].bm_bh)) {
// clean = 0;
affs_commit_super(sb, clean);
sb->s_dirt = !clean; /* redo until bitmap synced */
} else
sb->s_dirt = 0;
if (!(sb->s_flags & MS_RDONLY))
affs_commit_super(sb, 1, 2);
sb->s_dirt = 0;
unlock_super(sb);
pr_debug("AFFS: write_super() at %lu, clean=%d\n", get_seconds(), clean);
pr_debug("AFFS: write_super() at %lu, clean=2\n", get_seconds());
}
static int
affs_sync_fs(struct super_block *sb, int wait)
{
lock_super(sb);
affs_commit_super(sb, 2);
affs_commit_super(sb, wait, 2);
sb->s_dirt = 0;
unlock_super(sb);
return 0;
@ -140,8 +135,7 @@ static const struct super_operations affs_sops = {
.alloc_inode = affs_alloc_inode,
.destroy_inode = affs_destroy_inode,
.write_inode = affs_write_inode,
.delete_inode = affs_delete_inode,
.clear_inode = affs_clear_inode,
.evict_inode = affs_evict_inode,
.put_super = affs_put_super,
.write_super = affs_write_super,
.sync_fs = affs_sync_fs,
@ -554,9 +548,7 @@ affs_remount(struct super_block *sb, int *flags, char *data)
return 0;
}
if (*flags & MS_RDONLY) {
sb->s_dirt = 1;
while (sb->s_dirt)
affs_write_super(sb);
affs_write_super(sb);
affs_free_bitmap(sb);
} else
res = affs_init_bitmap(sb, flags);

View File

@ -316,7 +316,7 @@ int afs_getattr(struct vfsmount *mnt, struct dentry *dentry,
/*
* clear an AFS inode
*/
void afs_clear_inode(struct inode *inode)
void afs_evict_inode(struct inode *inode)
{
struct afs_permits *permits;
struct afs_vnode *vnode;
@ -335,6 +335,9 @@ void afs_clear_inode(struct inode *inode)
ASSERTCMP(inode->i_ino, ==, vnode->fid.vnode);
truncate_inode_pages(&inode->i_data, 0);
end_writeback(inode);
afs_give_up_callback(vnode);
if (vnode->server) {

View File

@ -565,7 +565,7 @@ extern void afs_zap_data(struct afs_vnode *);
extern int afs_validate(struct afs_vnode *, struct key *);
extern int afs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
extern int afs_setattr(struct dentry *, struct iattr *);
extern void afs_clear_inode(struct inode *);
extern void afs_evict_inode(struct inode *);
/*
* main.c

View File

@ -49,7 +49,7 @@ static const struct super_operations afs_super_ops = {
.statfs = afs_statfs,
.alloc_inode = afs_alloc_inode,
.destroy_inode = afs_destroy_inode,
.clear_inode = afs_clear_inode,
.evict_inode = afs_evict_inode,
.put_super = afs_put_super,
.show_options = generic_show_options,
};

View File

@ -14,35 +14,53 @@
#include <linux/fcntl.h>
#include <linux/security.h>
/* Taken over from the old code... */
/* POSIX UID/GID verification for setting inode attributes. */
/**
* inode_change_ok - check if attribute changes to an inode are allowed
* @inode: inode to check
* @attr: attributes to change
*
* Check if we are allowed to change the attributes contained in @attr
* in the given inode. This includes the normal unix access permission
* checks, as well as checks for rlimits and others.
*
* Should be called as the first thing in ->setattr implementations,
* possibly after taking additional locks.
*/
int inode_change_ok(const struct inode *inode, struct iattr *attr)
{
int retval = -EPERM;
unsigned int ia_valid = attr->ia_valid;
/*
* First check size constraints. These can't be overriden using
* ATTR_FORCE.
*/
if (ia_valid & ATTR_SIZE) {
int error = inode_newsize_ok(inode, attr->ia_size);
if (error)
return error;
}
/* If force is set do it anyway. */
if (ia_valid & ATTR_FORCE)
goto fine;
return 0;
/* Make sure a caller can chown. */
if ((ia_valid & ATTR_UID) &&
(current_fsuid() != inode->i_uid ||
attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN))
goto error;
return -EPERM;
/* Make sure caller can chgrp. */
if ((ia_valid & ATTR_GID) &&
(current_fsuid() != inode->i_uid ||
(!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) &&
!capable(CAP_CHOWN))
goto error;
return -EPERM;
/* Make sure a caller can chmod. */
if (ia_valid & ATTR_MODE) {
if (!is_owner_or_cap(inode))
goto error;
return -EPERM;
/* Also check the setgid bit! */
if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
inode->i_gid) && !capable(CAP_FSETID))
@ -52,12 +70,10 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)
/* Check for setting the inode time. */
if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) {
if (!is_owner_or_cap(inode))
goto error;
return -EPERM;
}
fine:
retval = 0;
error:
return retval;
return 0;
}
EXPORT_SYMBOL(inode_change_ok);
@ -105,21 +121,21 @@ int inode_newsize_ok(const struct inode *inode, loff_t offset)
EXPORT_SYMBOL(inode_newsize_ok);
/**
* generic_setattr - copy simple metadata updates into the generic inode
* setattr_copy - copy simple metadata updates into the generic inode
* @inode: the inode to be updated
* @attr: the new attributes
*
* generic_setattr must be called with i_mutex held.
* setattr_copy must be called with i_mutex held.
*
* generic_setattr updates the inode's metadata with that specified
* setattr_copy updates the inode's metadata with that specified
* in attr. Noticably missing is inode size update, which is more complex
* as it requires pagecache updates. See simple_setsize.
* as it requires pagecache updates.
*
* The inode is not marked as dirty after this operation. The rationale is
* that for "simple" filesystems, the struct inode is the inode storage.
* The caller is free to mark the inode dirty afterwards if needed.
*/
void generic_setattr(struct inode *inode, const struct iattr *attr)
void setattr_copy(struct inode *inode, const struct iattr *attr)
{
unsigned int ia_valid = attr->ia_valid;
@ -144,32 +160,7 @@ void generic_setattr(struct inode *inode, const struct iattr *attr)
inode->i_mode = mode;
}
}
EXPORT_SYMBOL(generic_setattr);
/*
* note this function is deprecated, the new truncate sequence should be
* used instead -- see eg. simple_setsize, generic_setattr.
*/
int inode_setattr(struct inode *inode, const struct iattr *attr)
{
unsigned int ia_valid = attr->ia_valid;
if (ia_valid & ATTR_SIZE &&
attr->ia_size != i_size_read(inode)) {
int error;
error = vmtruncate(inode, attr->ia_size);
if (error)
return error;
}
generic_setattr(inode, attr);
mark_inode_dirty(inode);
return 0;
}
EXPORT_SYMBOL(inode_setattr);
EXPORT_SYMBOL(setattr_copy);
int notify_change(struct dentry * dentry, struct iattr * attr)
{
@ -237,13 +228,10 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
if (ia_valid & ATTR_SIZE)
down_write(&dentry->d_inode->i_alloc_sem);
if (inode->i_op && inode->i_op->setattr) {
if (inode->i_op->setattr)
error = inode->i_op->setattr(dentry, attr);
} else {
error = inode_change_ok(inode, attr);
if (!error)
error = inode_setattr(inode, attr);
}
else
error = simple_setattr(dentry, attr);
if (ia_valid & ATTR_SIZE)
up_write(&dentry->d_inode->i_alloc_sem);

View File

@ -17,7 +17,6 @@ struct bfs_sb_info {
unsigned long si_lf_eblk;
unsigned long si_lasti;
unsigned long *si_imap;
struct buffer_head *si_sbh; /* buffer header w/superblock */
struct mutex bfs_lock;
};

View File

@ -70,7 +70,6 @@ static int bfs_get_block(struct inode *inode, sector_t block,
struct super_block *sb = inode->i_sb;
struct bfs_sb_info *info = BFS_SB(sb);
struct bfs_inode_info *bi = BFS_I(inode);
struct buffer_head *sbh = info->si_sbh;
phys = bi->i_sblock + block;
if (!create) {
@ -112,7 +111,6 @@ static int bfs_get_block(struct inode *inode, sector_t block,
info->si_freeb -= phys - bi->i_eblock;
info->si_lf_eblk = bi->i_eblock = phys;
mark_inode_dirty(inode);
mark_buffer_dirty(sbh);
err = 0;
goto out;
}
@ -147,7 +145,6 @@ static int bfs_get_block(struct inode *inode, sector_t block,
*/
info->si_freeb -= bi->i_eblock - bi->i_sblock + 1 - inode->i_blocks;
mark_inode_dirty(inode);
mark_buffer_dirty(sbh);
map_bh(bh_result, sb, phys);
out:
mutex_unlock(&info->bfs_lock);
@ -168,9 +165,17 @@ static int bfs_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
*pagep = NULL;
return block_write_begin(file, mapping, pos, len, flags,
pagep, fsdata, bfs_get_block);
int ret;
ret = block_write_begin(mapping, pos, len, flags, pagep,
bfs_get_block);
if (unlikely(ret)) {
loff_t isize = mapping->host->i_size;
if (pos + len > isize)
vmtruncate(mapping->host, isize);
}
return ret;
}
static sector_t bfs_bmap(struct address_space *mapping, sector_t block)

View File

@ -31,7 +31,6 @@ MODULE_LICENSE("GPL");
#define dprintf(x...)
#endif
static void bfs_write_super(struct super_block *s);
void dump_imap(const char *prefix, struct super_block *s);
struct inode *bfs_iget(struct super_block *sb, unsigned long ino)
@ -99,6 +98,24 @@ struct inode *bfs_iget(struct super_block *sb, unsigned long ino)
return ERR_PTR(-EIO);
}
static struct bfs_inode *find_inode(struct super_block *sb, u16 ino, struct buffer_head **p)
{
if ((ino < BFS_ROOT_INO) || (ino > BFS_SB(sb)->si_lasti)) {
printf("Bad inode number %s:%08x\n", sb->s_id, ino);
return ERR_PTR(-EIO);
}
ino -= BFS_ROOT_INO;
*p = sb_bread(sb, 1 + ino / BFS_INODES_PER_BLOCK);
if (!*p) {
printf("Unable to read inode %s:%08x\n", sb->s_id, ino);
return ERR_PTR(-EIO);
}
return (struct bfs_inode *)(*p)->b_data + ino % BFS_INODES_PER_BLOCK;
}
static int bfs_write_inode(struct inode *inode, struct writeback_control *wbc)
{
struct bfs_sb_info *info = BFS_SB(inode->i_sb);
@ -106,28 +123,15 @@ static int bfs_write_inode(struct inode *inode, struct writeback_control *wbc)
unsigned long i_sblock;
struct bfs_inode *di;
struct buffer_head *bh;
int block, off;
int err = 0;
dprintf("ino=%08x\n", ino);
if ((ino < BFS_ROOT_INO) || (ino > BFS_SB(inode->i_sb)->si_lasti)) {
printf("Bad inode number %s:%08x\n", inode->i_sb->s_id, ino);
return -EIO;
}
di = find_inode(inode->i_sb, ino, &bh);
if (IS_ERR(di))
return PTR_ERR(di);
mutex_lock(&info->bfs_lock);
block = (ino - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1;
bh = sb_bread(inode->i_sb, block);
if (!bh) {
printf("Unable to read inode %s:%08x\n",
inode->i_sb->s_id, ino);
mutex_unlock(&info->bfs_lock);
return -EIO;
}
off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;
di = (struct bfs_inode *)bh->b_data + off;
if (ino == BFS_ROOT_INO)
di->i_vtype = cpu_to_le32(BFS_VDIR);
@ -158,12 +162,11 @@ static int bfs_write_inode(struct inode *inode, struct writeback_control *wbc)
return err;
}
static void bfs_delete_inode(struct inode *inode)
static void bfs_evict_inode(struct inode *inode)
{
unsigned long ino = inode->i_ino;
struct bfs_inode *di;
struct buffer_head *bh;
int block, off;
struct super_block *s = inode->i_sb;
struct bfs_sb_info *info = BFS_SB(s);
struct bfs_inode_info *bi = BFS_I(inode);
@ -171,28 +174,19 @@ static void bfs_delete_inode(struct inode *inode)
dprintf("ino=%08lx\n", ino);
truncate_inode_pages(&inode->i_data, 0);
invalidate_inode_buffers(inode);
end_writeback(inode);
if ((ino < BFS_ROOT_INO) || (ino > info->si_lasti)) {
printf("invalid ino=%08lx\n", ino);
if (inode->i_nlink)
return;
}
inode->i_size = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
di = find_inode(s, inode->i_ino, &bh);
if (IS_ERR(di))
return;
mutex_lock(&info->bfs_lock);
mark_inode_dirty(inode);
block = (ino - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1;
bh = sb_bread(s, block);
if (!bh) {
printf("Unable to read inode %s:%08lx\n",
inode->i_sb->s_id, ino);
mutex_unlock(&info->bfs_lock);
return;
}
off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;
di = (struct bfs_inode *)bh->b_data + off;
memset((void *)di, 0, sizeof(struct bfs_inode));
/* clear on-disk inode */
memset(di, 0, sizeof(struct bfs_inode));
mark_buffer_dirty(bh);
brelse(bh);
@ -209,32 +203,9 @@ static void bfs_delete_inode(struct inode *inode)
* "last block of the last file" even if there is no
* real file there, saves us 1 gap.
*/
if (info->si_lf_eblk == bi->i_eblock) {
if (info->si_lf_eblk == bi->i_eblock)
info->si_lf_eblk = bi->i_sblock - 1;
mark_buffer_dirty(info->si_sbh);
}
mutex_unlock(&info->bfs_lock);
clear_inode(inode);
}
static int bfs_sync_fs(struct super_block *sb, int wait)
{
struct bfs_sb_info *info = BFS_SB(sb);
mutex_lock(&info->bfs_lock);
mark_buffer_dirty(info->si_sbh);
sb->s_dirt = 0;
mutex_unlock(&info->bfs_lock);
return 0;
}
static void bfs_write_super(struct super_block *sb)
{
if (!(sb->s_flags & MS_RDONLY))
bfs_sync_fs(sb, 1);
else
sb->s_dirt = 0;
}
static void bfs_put_super(struct super_block *s)
@ -246,10 +217,6 @@ static void bfs_put_super(struct super_block *s)
lock_kernel();
if (s->s_dirt)
bfs_write_super(s);
brelse(info->si_sbh);
mutex_destroy(&info->bfs_lock);
kfree(info->si_imap);
kfree(info);
@ -319,10 +286,8 @@ static const struct super_operations bfs_sops = {
.alloc_inode = bfs_alloc_inode,
.destroy_inode = bfs_destroy_inode,
.write_inode = bfs_write_inode,
.delete_inode = bfs_delete_inode,
.evict_inode = bfs_evict_inode,
.put_super = bfs_put_super,
.write_super = bfs_write_super,
.sync_fs = bfs_sync_fs,
.statfs = bfs_statfs,
};
@ -349,7 +314,7 @@ void dump_imap(const char *prefix, struct super_block *s)
static int bfs_fill_super(struct super_block *s, void *data, int silent)
{
struct buffer_head *bh;
struct buffer_head *bh, *sbh;
struct bfs_super_block *bfs_sb;
struct inode *inode;
unsigned i, imap_len;
@ -365,10 +330,10 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
sb_set_blocksize(s, BFS_BSIZE);
info->si_sbh = sb_bread(s, 0);
if (!info->si_sbh)
sbh = sb_bread(s, 0);
if (!sbh)
goto out;
bfs_sb = (struct bfs_super_block *)info->si_sbh->b_data;
bfs_sb = (struct bfs_super_block *)sbh->b_data;
if (le32_to_cpu(bfs_sb->s_magic) != BFS_MAGIC) {
if (!silent)
printf("No BFS filesystem on %s (magic=%08x)\n",
@ -472,10 +437,7 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
info->si_lf_eblk = eblock;
}
brelse(bh);
if (!(s->s_flags & MS_RDONLY)) {
mark_buffer_dirty(info->si_sbh);
s->s_dirt = 1;
}
brelse(sbh);
dump_imap("read_super", s);
return 0;
@ -485,7 +447,7 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
out2:
kfree(info->si_imap);
out1:
brelse(info->si_sbh);
brelse(sbh);
out:
mutex_destroy(&info->bfs_lock);
kfree(info);

View File

@ -502,8 +502,9 @@ static struct inode *bm_get_inode(struct super_block *sb, int mode)
return inode;
}
static void bm_clear_inode(struct inode *inode)
static void bm_evict_inode(struct inode *inode)
{
end_writeback(inode);
kfree(inode->i_private);
}
@ -685,7 +686,7 @@ static const struct file_operations bm_status_operations = {
static const struct super_operations s_ops = {
.statfs = simple_statfs,
.clear_inode = bm_clear_inode,
.evict_inode = bm_evict_inode,
};
static int bm_fill_super(struct super_block * sb, void * data, int silent)

View File

@ -172,9 +172,8 @@ blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
struct file *file = iocb->ki_filp;
struct inode *inode = file->f_mapping->host;
return blockdev_direct_IO_no_locking_newtrunc(rw, iocb, inode,
I_BDEV(inode), iov, offset, nr_segs,
blkdev_get_blocks, NULL);
return __blockdev_direct_IO(rw, iocb, inode, I_BDEV(inode), iov, offset,
nr_segs, blkdev_get_blocks, NULL, NULL, 0);
}
int __sync_blockdev(struct block_device *bdev, int wait)
@ -309,9 +308,8 @@ static int blkdev_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
*pagep = NULL;
return block_write_begin_newtrunc(file, mapping, pos, len, flags,
pagep, fsdata, blkdev_get_block);
return block_write_begin(mapping, pos, len, flags, pagep,
blkdev_get_block);
}
static int blkdev_write_end(struct file *file, struct address_space *mapping,
@ -428,10 +426,13 @@ static inline void __bd_forget(struct inode *inode)
inode->i_mapping = &inode->i_data;
}
static void bdev_clear_inode(struct inode *inode)
static void bdev_evict_inode(struct inode *inode)
{
struct block_device *bdev = &BDEV_I(inode)->bdev;
struct list_head *p;
truncate_inode_pages(&inode->i_data, 0);
invalidate_inode_buffers(inode); /* is it needed here? */
end_writeback(inode);
spin_lock(&bdev_lock);
while ( (p = bdev->bd_inodes.next) != &bdev->bd_inodes ) {
__bd_forget(list_entry(p, struct inode, i_devices));
@ -445,7 +446,7 @@ static const struct super_operations bdev_sops = {
.alloc_inode = bdev_alloc_inode,
.destroy_inode = bdev_destroy_inode,
.drop_inode = generic_delete_inode,
.clear_inode = bdev_clear_inode,
.evict_inode = bdev_evict_inode,
};
static int bd_get_sb(struct file_system_type *fs_type,

View File

@ -2389,13 +2389,13 @@ unsigned long btrfs_force_ra(struct address_space *mapping,
pgoff_t offset, pgoff_t last_index);
int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
int btrfs_readpage(struct file *file, struct page *page);
void btrfs_delete_inode(struct inode *inode);
void btrfs_evict_inode(struct inode *inode);
void btrfs_put_inode(struct inode *inode);
int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc);
void btrfs_dirty_inode(struct inode *inode);
struct inode *btrfs_alloc_inode(struct super_block *sb);
void btrfs_destroy_inode(struct inode *inode);
void btrfs_drop_inode(struct inode *inode);
int btrfs_drop_inode(struct inode *inode);
int btrfs_init_cachep(void);
void btrfs_destroy_cachep(void);
long btrfs_ioctl_trans_end(struct file *file);

View File

@ -2938,7 +2938,6 @@ int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
ret = btrfs_update_inode(trans, root, dir);
BUG_ON(ret);
dir->i_sb->s_dirt = 1;
btrfs_free_path(path);
return 0;
@ -3656,17 +3655,19 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
if (err)
return err;
}
attr->ia_valid &= ~ATTR_SIZE;
if (attr->ia_valid)
err = inode_setattr(inode, attr);
if (attr->ia_valid) {
setattr_copy(inode, attr);
mark_inode_dirty(inode);
if (attr->ia_valid & ATTR_MODE)
err = btrfs_acl_chmod(inode);
}
if (!err && ((attr->ia_valid & ATTR_MODE)))
err = btrfs_acl_chmod(inode);
return err;
}
void btrfs_delete_inode(struct inode *inode)
void btrfs_evict_inode(struct inode *inode)
{
struct btrfs_trans_handle *trans;
struct btrfs_root *root = BTRFS_I(inode)->root;
@ -3674,10 +3675,14 @@ void btrfs_delete_inode(struct inode *inode)
int ret;
truncate_inode_pages(&inode->i_data, 0);
if (inode->i_nlink && btrfs_root_refs(&root->root_item) != 0)
goto no_delete;
if (is_bad_inode(inode)) {
btrfs_orphan_del(NULL, inode);
goto no_delete;
}
/* do we really want it for ->i_nlink > 0 and zero btrfs_root_refs? */
btrfs_wait_ordered_range(inode, 0, (u64)-1);
if (root->fs_info->log_root_recovering) {
@ -3727,7 +3732,7 @@ void btrfs_delete_inode(struct inode *inode)
btrfs_end_transaction(trans, root);
btrfs_btree_balance_dirty(root, nr);
no_delete:
clear_inode(inode);
end_writeback(inode);
return;
}
@ -3858,7 +3863,7 @@ static void inode_tree_add(struct inode *inode)
p = &parent->rb_right;
else {
WARN_ON(!(entry->vfs_inode.i_state &
(I_WILL_FREE | I_FREEING | I_CLEAR)));
(I_WILL_FREE | I_FREEING)));
rb_erase(parent, &root->inode_tree);
RB_CLEAR_NODE(parent);
spin_unlock(&root->inode_lock);
@ -3937,7 +3942,7 @@ int btrfs_invalidate_inodes(struct btrfs_root *root)
if (atomic_read(&inode->i_count) > 1)
d_prune_aliases(inode);
/*
* btrfs_drop_inode will remove it from
* btrfs_drop_inode will have it removed from
* the inode cache when its usage count
* hits zero.
*/
@ -6331,13 +6336,14 @@ void btrfs_destroy_inode(struct inode *inode)
kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode));
}
void btrfs_drop_inode(struct inode *inode)
int btrfs_drop_inode(struct inode *inode)
{
struct btrfs_root *root = BTRFS_I(inode)->root;
if (inode->i_nlink > 0 && btrfs_root_refs(&root->root_item) == 0)
generic_delete_inode(inode);
if (btrfs_root_refs(&root->root_item) == 0)
return 1;
else
generic_drop_inode(inode);
return generic_drop_inode(inode);
}
static void init_once(void *foo)

View File

@ -797,7 +797,7 @@ static int btrfs_unfreeze(struct super_block *sb)
static const struct super_operations btrfs_super_ops = {
.drop_inode = btrfs_drop_inode,
.delete_inode = btrfs_delete_inode,
.evict_inode = btrfs_evict_inode,
.put_super = btrfs_put_super,
.sync_fs = btrfs_sync_fs,
.show_options = btrfs_show_options,

View File

@ -1833,9 +1833,10 @@ void page_zero_new_buffers(struct page *page, unsigned from, unsigned to)
}
EXPORT_SYMBOL(page_zero_new_buffers);
static int __block_prepare_write(struct inode *inode, struct page *page,
unsigned from, unsigned to, get_block_t *get_block)
int block_prepare_write(struct page *page, unsigned from, unsigned to,
get_block_t *get_block)
{
struct inode *inode = page->mapping->host;
unsigned block_start, block_end;
sector_t block;
int err = 0;
@ -1908,10 +1909,13 @@ static int __block_prepare_write(struct inode *inode, struct page *page,
if (!buffer_uptodate(*wait_bh))
err = -EIO;
}
if (unlikely(err))
if (unlikely(err)) {
page_zero_new_buffers(page, from, to);
ClearPageUptodate(page);
}
return err;
}
EXPORT_SYMBOL(block_prepare_write);
static int __block_commit_write(struct inode *inode, struct page *page,
unsigned from, unsigned to)
@ -1948,90 +1952,41 @@ static int __block_commit_write(struct inode *inode, struct page *page,
return 0;
}
/*
* Filesystems implementing the new truncate sequence should use the
* _newtrunc postfix variant which won't incorrectly call vmtruncate.
* The filesystem needs to handle block truncation upon failure.
*/
int block_write_begin_newtrunc(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata,
get_block_t *get_block)
int __block_write_begin(struct page *page, loff_t pos, unsigned len,
get_block_t *get_block)
{
struct inode *inode = mapping->host;
int status = 0;
struct page *page;
pgoff_t index;
unsigned start, end;
int ownpage = 0;
unsigned start = pos & (PAGE_CACHE_SIZE - 1);
index = pos >> PAGE_CACHE_SHIFT;
start = pos & (PAGE_CACHE_SIZE - 1);
end = start + len;
page = *pagep;
if (page == NULL) {
ownpage = 1;
page = grab_cache_page_write_begin(mapping, index, flags);
if (!page) {
status = -ENOMEM;
goto out;
}
*pagep = page;
} else
BUG_ON(!PageLocked(page));
status = __block_prepare_write(inode, page, start, end, get_block);
if (unlikely(status)) {
ClearPageUptodate(page);
if (ownpage) {
unlock_page(page);
page_cache_release(page);
*pagep = NULL;
}
}
out:
return status;
return block_prepare_write(page, start, start + len, get_block);
}
EXPORT_SYMBOL(block_write_begin_newtrunc);
EXPORT_SYMBOL(__block_write_begin);
/*
* block_write_begin takes care of the basic task of block allocation and
* bringing partial write blocks uptodate first.
*
* If *pagep is not NULL, then block_write_begin uses the locked page
* at *pagep rather than allocating its own. In this case, the page will
* not be unlocked or deallocated on failure.
* The filesystem needs to handle block truncation upon failure.
*/
int block_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata,
get_block_t *get_block)
int block_write_begin(struct address_space *mapping, loff_t pos, unsigned len,
unsigned flags, struct page **pagep, get_block_t *get_block)
{
int ret;
pgoff_t index = pos >> PAGE_CACHE_SHIFT;
struct page *page;
int status;
ret = block_write_begin_newtrunc(file, mapping, pos, len, flags,
pagep, fsdata, get_block);
page = grab_cache_page_write_begin(mapping, index, flags);
if (!page)
return -ENOMEM;
/*
* prepare_write() may have instantiated a few blocks
* outside i_size. Trim these off again. Don't need
* i_size_read because we hold i_mutex.
*
* Filesystems which pass down their own page also cannot
* call into vmtruncate here because it would lead to lock
* inversion problems (*pagep is locked). This is a further
* example of where the old truncate sequence is inadequate.
*/
if (unlikely(ret) && *pagep == NULL) {
loff_t isize = mapping->host->i_size;
if (pos + len > isize)
vmtruncate(mapping->host, isize);
status = __block_write_begin(page, pos, len, get_block);
if (unlikely(status)) {
unlock_page(page);
page_cache_release(page);
page = NULL;
}
return ret;
*pagep = page;
return status;
}
EXPORT_SYMBOL(block_write_begin);
@ -2351,7 +2306,7 @@ static int cont_expand_zero(struct file *file, struct address_space *mapping,
* For moronic filesystems that do not allow holes in file.
* We may have to extend the file.
*/
int cont_write_begin_newtrunc(struct file *file, struct address_space *mapping,
int cont_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata,
get_block_t *get_block, loff_t *bytes)
@ -2363,7 +2318,7 @@ int cont_write_begin_newtrunc(struct file *file, struct address_space *mapping,
err = cont_expand_zero(file, mapping, pos, bytes);
if (err)
goto out;
return err;
zerofrom = *bytes & ~PAGE_CACHE_MASK;
if (pos+len > *bytes && zerofrom & (blocksize-1)) {
@ -2371,44 +2326,10 @@ int cont_write_begin_newtrunc(struct file *file, struct address_space *mapping,
(*bytes)++;
}
*pagep = NULL;
err = block_write_begin_newtrunc(file, mapping, pos, len,
flags, pagep, fsdata, get_block);
out:
return err;
}
EXPORT_SYMBOL(cont_write_begin_newtrunc);
int cont_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata,
get_block_t *get_block, loff_t *bytes)
{
int ret;
ret = cont_write_begin_newtrunc(file, mapping, pos, len, flags,
pagep, fsdata, get_block, bytes);
if (unlikely(ret)) {
loff_t isize = mapping->host->i_size;
if (pos + len > isize)
vmtruncate(mapping->host, isize);
}
return ret;
return block_write_begin(mapping, pos, len, flags, pagep, get_block);
}
EXPORT_SYMBOL(cont_write_begin);
int block_prepare_write(struct page *page, unsigned from, unsigned to,
get_block_t *get_block)
{
struct inode *inode = page->mapping->host;
int err = __block_prepare_write(inode, page, from, to, get_block);
if (err)
ClearPageUptodate(page);
return err;
}
EXPORT_SYMBOL(block_prepare_write);
int block_commit_write(struct page *page, unsigned from, unsigned to)
{
struct inode *inode = page->mapping->host;
@ -2510,11 +2431,11 @@ static void attach_nobh_buffers(struct page *page, struct buffer_head *head)
}
/*
* Filesystems implementing the new truncate sequence should use the
* _newtrunc postfix variant which won't incorrectly call vmtruncate.
* On entry, the page is fully not uptodate.
* On exit the page is fully uptodate in the areas outside (from,to)
* The filesystem needs to handle block truncation upon failure.
*/
int nobh_write_begin_newtrunc(struct file *file, struct address_space *mapping,
int nobh_write_begin(struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata,
get_block_t *get_block)
@ -2547,8 +2468,8 @@ int nobh_write_begin_newtrunc(struct file *file, struct address_space *mapping,
unlock_page(page);
page_cache_release(page);
*pagep = NULL;
return block_write_begin_newtrunc(file, mapping, pos, len,
flags, pagep, fsdata, get_block);
return block_write_begin(mapping, pos, len, flags, pagep,
get_block);
}
if (PageMappedToDisk(page))
@ -2654,35 +2575,6 @@ int nobh_write_begin_newtrunc(struct file *file, struct address_space *mapping,
return ret;
}
EXPORT_SYMBOL(nobh_write_begin_newtrunc);
/*
* On entry, the page is fully not uptodate.
* On exit the page is fully uptodate in the areas outside (from,to)
*/
int nobh_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata,
get_block_t *get_block)
{
int ret;
ret = nobh_write_begin_newtrunc(file, mapping, pos, len, flags,
pagep, fsdata, get_block);
/*
* prepare_write() may have instantiated a few blocks
* outside i_size. Trim these off again. Don't need
* i_size_read because we hold i_mutex.
*/
if (unlikely(ret)) {
loff_t isize = mapping->host->i_size;
if (pos + len > isize)
vmtruncate(mapping->host, isize);
}
return ret;
}
EXPORT_SYMBOL(nobh_write_begin);
int nobh_write_end(struct file *file, struct address_space *mapping,

View File

@ -146,7 +146,7 @@ static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache)
goto error_unsupported;
/* get the cache size and blocksize */
ret = vfs_statfs(root, &stats);
ret = vfs_statfs(&path, &stats);
if (ret < 0)
goto error_unsupported;

View File

@ -683,6 +683,10 @@ int cachefiles_has_space(struct cachefiles_cache *cache,
unsigned fnr, unsigned bnr)
{
struct kstatfs stats;
struct path path = {
.mnt = cache->mnt,
.dentry = cache->mnt->mnt_root,
};
int ret;
//_enter("{%llu,%llu,%llu,%llu,%llu,%llu},%u,%u",
@ -697,7 +701,7 @@ int cachefiles_has_space(struct cachefiles_cache *cache,
/* find out how many pages of blockdev are available */
memset(&stats, 0, sizeof(stats));
ret = vfs_statfs(cache->mnt->mnt_root, &stats);
ret = vfs_statfs(&path, &stats);
if (ret < 0) {
if (ret == -EIO)
cachefiles_io_error(cache, "statfs failed");

View File

@ -329,8 +329,10 @@ cifs_destroy_inode(struct inode *inode)
}
static void
cifs_clear_inode(struct inode *inode)
cifs_evict_inode(struct inode *inode)
{
truncate_inode_pages(&inode->i_data, 0);
end_writeback(inode);
cifs_fscache_release_inode_cookie(inode);
}
@ -479,14 +481,13 @@ static int cifs_remount(struct super_block *sb, int *flags, char *data)
return 0;
}
void cifs_drop_inode(struct inode *inode)
static int cifs_drop_inode(struct inode *inode)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
return generic_drop_inode(inode);
return generic_delete_inode(inode);
/* no serverino => unconditional eviction */
return !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) ||
generic_drop_inode(inode);
}
static const struct super_operations cifs_super_ops = {
@ -495,7 +496,7 @@ static const struct super_operations cifs_super_ops = {
.alloc_inode = cifs_alloc_inode,
.destroy_inode = cifs_destroy_inode,
.drop_inode = cifs_drop_inode,
.clear_inode = cifs_clear_inode,
.evict_inode = cifs_evict_inode,
/* .delete_inode = cifs_delete_inode, */ /* Do not need above
function unless later we add lazy close of inodes or unless the
kernel forgets to call us with the same number of releases (closes)

View File

@ -1698,26 +1698,16 @@ static int cifs_truncate_page(struct address_space *mapping, loff_t from)
return rc;
}
static int cifs_vmtruncate(struct inode *inode, loff_t offset)
static void cifs_setsize(struct inode *inode, loff_t offset)
{
loff_t oldsize;
int err;
spin_lock(&inode->i_lock);
err = inode_newsize_ok(inode, offset);
if (err) {
spin_unlock(&inode->i_lock);
goto out;
}
oldsize = inode->i_size;
i_size_write(inode, offset);
spin_unlock(&inode->i_lock);
truncate_pagecache(inode, oldsize, offset);
if (inode->i_op->truncate)
inode->i_op->truncate(inode);
out:
return err;
}
static int
@ -1790,7 +1780,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
if (rc == 0) {
cifsInode->server_eof = attrs->ia_size;
rc = cifs_vmtruncate(inode, attrs->ia_size);
cifs_setsize(inode, attrs->ia_size);
cifs_truncate_page(inode->i_mapping, inode->i_size);
}
@ -1815,14 +1805,12 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
xid = GetXid();
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
/* check if we have permission to change attrs */
rc = inode_change_ok(inode, attrs);
if (rc < 0)
goto out;
else
rc = 0;
}
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
attrs->ia_valid |= ATTR_FORCE;
rc = inode_change_ok(inode, attrs);
if (rc < 0)
goto out;
full_path = build_path_from_dentry(direntry);
if (full_path == NULL) {
@ -1908,18 +1896,24 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
CIFS_MOUNT_MAP_SPECIAL_CHR);
}
if (!rc) {
rc = inode_setattr(inode, attrs);
if (rc)
goto out;
/* force revalidate when any of these times are set since some
of the fs types (eg ext3, fat) do not have fine enough
time granularity to match protocol, and we do not have a
a way (yet) to query the server fs's time granularity (and
whether it rounds times down).
*/
if (!rc && (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME)))
cifsInode->time = 0;
}
if ((attrs->ia_valid & ATTR_SIZE) &&
attrs->ia_size != i_size_read(inode))
truncate_setsize(inode, attrs->ia_size);
setattr_copy(inode, attrs);
mark_inode_dirty(inode);
/* force revalidate when any of these times are set since some
of the fs types (eg ext3, fat) do not have fine enough
time granularity to match protocol, and we do not have a
a way (yet) to query the server fs's time granularity (and
whether it rounds times down).
*/
if (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME))
cifsInode->time = 0;
out:
kfree(args);
kfree(full_path);
@ -1944,14 +1938,13 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
cFYI(1, "setattr on file %s attrs->iavalid 0x%x",
direntry->d_name.name, attrs->ia_valid);
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
/* check if we have permission to change attrs */
rc = inode_change_ok(inode, attrs);
if (rc < 0) {
FreeXid(xid);
return rc;
} else
rc = 0;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
attrs->ia_valid |= ATTR_FORCE;
rc = inode_change_ok(inode, attrs);
if (rc < 0) {
FreeXid(xid);
return rc;
}
full_path = build_path_from_dentry(direntry);
@ -2059,8 +2052,17 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
/* do not need local check to inode_check_ok since the server does
that */
if (!rc)
rc = inode_setattr(inode, attrs);
if (rc)
goto cifs_setattr_exit;
if ((attrs->ia_valid & ATTR_SIZE) &&
attrs->ia_size != i_size_read(inode))
truncate_setsize(inode, attrs->ia_size);
setattr_copy(inode, attrs);
mark_inode_dirty(inode);
return 0;
cifs_setattr_exit:
kfree(full_path);
FreeXid(xid);

View File

@ -35,7 +35,7 @@
#include "coda_int.h"
/* VFS super_block ops */
static void coda_clear_inode(struct inode *);
static void coda_evict_inode(struct inode *);
static void coda_put_super(struct super_block *);
static int coda_statfs(struct dentry *dentry, struct kstatfs *buf);
@ -93,7 +93,7 @@ static const struct super_operations coda_super_operations =
{
.alloc_inode = coda_alloc_inode,
.destroy_inode = coda_destroy_inode,
.clear_inode = coda_clear_inode,
.evict_inode = coda_evict_inode,
.put_super = coda_put_super,
.statfs = coda_statfs,
.remount_fs = coda_remount,
@ -224,8 +224,10 @@ static void coda_put_super(struct super_block *sb)
printk("Coda: Bye bye.\n");
}
static void coda_clear_inode(struct inode *inode)
static void coda_evict_inode(struct inode *inode)
{
truncate_inode_pages(&inode->i_data, 0);
end_writeback(inode);
coda_cache_clear_inode(inode);
}

View File

@ -267,7 +267,7 @@ asmlinkage long compat_sys_statfs(const char __user *pathname, struct compat_sta
error = user_path(pathname, &path);
if (!error) {
struct kstatfs tmp;
error = vfs_statfs(path.dentry, &tmp);
error = vfs_statfs(&path, &tmp);
if (!error)
error = put_compat_statfs(buf, &tmp);
path_put(&path);
@ -285,7 +285,7 @@ asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user
file = fget(fd);
if (!file)
goto out;
error = vfs_statfs(file->f_path.dentry, &tmp);
error = vfs_statfs(&file->f_path, &tmp);
if (!error)
error = put_compat_statfs(buf, &tmp);
fput(file);
@ -335,7 +335,7 @@ asmlinkage long compat_sys_statfs64(const char __user *pathname, compat_size_t s
error = user_path(pathname, &path);
if (!error) {
struct kstatfs tmp;
error = vfs_statfs(path.dentry, &tmp);
error = vfs_statfs(&path, &tmp);
if (!error)
error = put_compat_statfs64(buf, &tmp);
path_put(&path);
@ -356,7 +356,7 @@ asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct c
file = fget(fd);
if (!file)
goto out;
error = vfs_statfs(file->f_path.dentry, &tmp);
error = vfs_statfs(&file->f_path, &tmp);
if (!error)
error = put_compat_statfs64(buf, &tmp);
fput(file);
@ -379,7 +379,7 @@ asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *u)
sb = user_get_super(new_decode_dev(dev));
if (!sb)
return -EINVAL;
err = vfs_statfs(sb->s_root, &sbuf);
err = statfs_by_dentry(sb->s_root, &sbuf);
drop_super(sb);
if (err)
return err;

View File

@ -39,66 +39,55 @@ static DEFINE_MUTEX(read_mutex);
#define CRAMINO(x) (((x)->offset && (x)->size)?(x)->offset<<2:1)
#define OFFSET(x) ((x)->i_ino)
static int cramfs_iget5_test(struct inode *inode, void *opaque)
static void setup_inode(struct inode *inode, struct cramfs_inode * cramfs_inode)
{
struct cramfs_inode *cramfs_inode = opaque;
return inode->i_ino == CRAMINO(cramfs_inode) && inode->i_ino != 1;
}
static int cramfs_iget5_set(struct inode *inode, void *opaque)
{
struct cramfs_inode *cramfs_inode = opaque;
inode->i_ino = CRAMINO(cramfs_inode);
return 0;
static struct timespec zerotime;
inode->i_mode = cramfs_inode->mode;
inode->i_uid = cramfs_inode->uid;
inode->i_size = cramfs_inode->size;
inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1;
inode->i_gid = cramfs_inode->gid;
/* Struct copy intentional */
inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime;
/* inode->i_nlink is left 1 - arguably wrong for directories,
but it's the best we can do without reading the directory
contents. 1 yields the right result in GNU find, even
without -noleaf option. */
if (S_ISREG(inode->i_mode)) {
inode->i_fop = &generic_ro_fops;
inode->i_data.a_ops = &cramfs_aops;
} else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &cramfs_dir_inode_operations;
inode->i_fop = &cramfs_directory_operations;
} else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &page_symlink_inode_operations;
inode->i_data.a_ops = &cramfs_aops;
} else {
init_special_inode(inode, inode->i_mode,
old_decode_dev(cramfs_inode->size));
}
}
static struct inode *get_cramfs_inode(struct super_block *sb,
struct cramfs_inode * cramfs_inode)
{
struct inode *inode = iget5_locked(sb, CRAMINO(cramfs_inode),
cramfs_iget5_test, cramfs_iget5_set,
cramfs_inode);
static struct timespec zerotime;
if (inode && (inode->i_state & I_NEW)) {
inode->i_mode = cramfs_inode->mode;
inode->i_uid = cramfs_inode->uid;
inode->i_size = cramfs_inode->size;
inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1;
inode->i_gid = cramfs_inode->gid;
/* Struct copy intentional */
inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime;
/* inode->i_nlink is left 1 - arguably wrong for directories,
but it's the best we can do without reading the directory
contents. 1 yields the right result in GNU find, even
without -noleaf option. */
if (S_ISREG(inode->i_mode)) {
inode->i_fop = &generic_ro_fops;
inode->i_data.a_ops = &cramfs_aops;
} else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &cramfs_dir_inode_operations;
inode->i_fop = &cramfs_directory_operations;
} else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &page_symlink_inode_operations;
inode->i_data.a_ops = &cramfs_aops;
} else {
init_special_inode(inode, inode->i_mode,
old_decode_dev(cramfs_inode->size));
struct inode *inode;
if (CRAMINO(cramfs_inode) == 1) {
inode = new_inode(sb);
if (inode) {
inode->i_ino = 1;
setup_inode(inode, cramfs_inode);
}
} else {
inode = iget_locked(sb, CRAMINO(cramfs_inode));
if (inode) {
setup_inode(inode, cramfs_inode);
unlock_new_inode(inode);
}
unlock_new_inode(inode);
}
return inode;
}
static void cramfs_drop_inode(struct inode *inode)
{
if (inode->i_ino == 1)
generic_delete_inode(inode);
else
generic_drop_inode(inode);
}
/*
* We have our own block cache: don't fill up the buffer cache
* with the rom-image, because the way the filesystem is set
@ -542,7 +531,6 @@ static const struct super_operations cramfs_ops = {
.put_super = cramfs_put_super,
.remount_fs = cramfs_remount,
.statfs = cramfs_statfs,
.drop_inode = cramfs_drop_inode,
};
static int cramfs_get_sb(struct file_system_type *fs_type,

View File

@ -536,7 +536,7 @@ static void __shrink_dcache_sb(struct super_block *sb, int *count, int flags)
*/
static void prune_dcache(int count)
{
struct super_block *sb, *n;
struct super_block *sb, *p = NULL;
int w_count;
int unused = dentry_stat.nr_unused;
int prune_ratio;
@ -550,7 +550,7 @@ static void prune_dcache(int count)
else
prune_ratio = unused / count;
spin_lock(&sb_lock);
list_for_each_entry_safe(sb, n, &super_blocks, s_list) {
list_for_each_entry(sb, &super_blocks, s_list) {
if (list_empty(&sb->s_instances))
continue;
if (sb->s_nr_dentry_unused == 0)
@ -590,14 +590,16 @@ static void prune_dcache(int count)
up_read(&sb->s_umount);
}
spin_lock(&sb_lock);
/* lock was dropped, must reset next */
list_safe_reset_next(sb, n, s_list);
if (p)
__put_super(p);
count -= pruned;
__put_super(sb);
p = sb;
/* more work left to do? */
if (count <= 0)
break;
}
if (p)
__put_super(p);
spin_unlock(&sb_lock);
spin_unlock(&dcache_lock);
}
@ -2049,16 +2051,12 @@ char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen,
/*
* Write full pathname from the root of the filesystem into the buffer.
*/
char *dentry_path(struct dentry *dentry, char *buf, int buflen)
char *__dentry_path(struct dentry *dentry, char *buf, int buflen)
{
char *end = buf + buflen;
char *retval;
spin_lock(&dcache_lock);
prepend(&end, &buflen, "\0", 1);
if (d_unlinked(dentry) &&
(prepend(&end, &buflen, "//deleted", 9) != 0))
goto Elong;
if (buflen < 1)
goto Elong;
/* Get '/' right */
@ -2076,7 +2074,28 @@ char *dentry_path(struct dentry *dentry, char *buf, int buflen)
retval = end;
dentry = parent;
}
return retval;
Elong:
return ERR_PTR(-ENAMETOOLONG);
}
EXPORT_SYMBOL(__dentry_path);
char *dentry_path(struct dentry *dentry, char *buf, int buflen)
{
char *p = NULL;
char *retval;
spin_lock(&dcache_lock);
if (d_unlinked(dentry)) {
p = buf + buflen;
if (prepend(&p, &buflen, "//deleted", 10) != 0)
goto Elong;
buflen++;
}
retval = __dentry_path(dentry, buf, buflen);
spin_unlock(&dcache_lock);
if (!IS_ERR(retval) && p)
*p = '/'; /* restore '/' overriden with '\0' */
return retval;
Elong:
spin_unlock(&dcache_lock);

View File

@ -1136,8 +1136,27 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
return ret;
}
/*
* This is a library function for use by filesystem drivers.
*
* The locking rules are governed by the flags parameter:
* - if the flags value contains DIO_LOCKING we use a fancy locking
* scheme for dumb filesystems.
* For writes this function is called under i_mutex and returns with
* i_mutex held, for reads, i_mutex is not held on entry, but it is
* taken and dropped again before returning.
* For reads and writes i_alloc_sem is taken in shared mode and released
* on I/O completion (which may happen asynchronously after returning to
* the caller).
*
* - if the flags value does NOT contain DIO_LOCKING we don't use any
* internal locking but rather rely on the filesystem to synchronize
* direct I/O reads/writes versus each other and truncate.
* For reads and writes both i_mutex and i_alloc_sem are not held on
* entry and are never taken.
*/
ssize_t
__blockdev_direct_IO_newtrunc(int rw, struct kiocb *iocb, struct inode *inode,
__blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
struct block_device *bdev, const struct iovec *iov, loff_t offset,
unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
dio_submit_t submit_io, int flags)
@ -1233,57 +1252,4 @@ __blockdev_direct_IO_newtrunc(int rw, struct kiocb *iocb, struct inode *inode,
out:
return retval;
}
EXPORT_SYMBOL(__blockdev_direct_IO_newtrunc);
/*
* This is a library function for use by filesystem drivers.
*
* The locking rules are governed by the flags parameter:
* - if the flags value contains DIO_LOCKING we use a fancy locking
* scheme for dumb filesystems.
* For writes this function is called under i_mutex and returns with
* i_mutex held, for reads, i_mutex is not held on entry, but it is
* taken and dropped again before returning.
* For reads and writes i_alloc_sem is taken in shared mode and released
* on I/O completion (which may happen asynchronously after returning to
* the caller).
*
* - if the flags value does NOT contain DIO_LOCKING we don't use any
* internal locking but rather rely on the filesystem to synchronize
* direct I/O reads/writes versus each other and truncate.
* For reads and writes both i_mutex and i_alloc_sem are not held on
* entry and are never taken.
*/
ssize_t
__blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
struct block_device *bdev, const struct iovec *iov, loff_t offset,
unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
dio_submit_t submit_io, int flags)
{
ssize_t retval;
retval = __blockdev_direct_IO_newtrunc(rw, iocb, inode, bdev, iov,
offset, nr_segs, get_block, end_io, submit_io, flags);
/*
* In case of error extending write may have instantiated a few
* blocks outside i_size. Trim these off again for DIO_LOCKING.
* NOTE: DIO_NO_LOCK/DIO_OWN_LOCK callers have to handle this in
* their own manner. This is a further example of where the old
* truncate sequence is inadequate.
*
* NOTE: filesystems with their own locking have to handle this
* on their own.
*/
if (flags & DIO_LOCKING) {
if (unlikely((rw & WRITE) && retval < 0)) {
loff_t isize = i_size_read(inode);
loff_t end = offset + iov_length(iov, nr_segs);
if (end > isize)
vmtruncate(inode, isize);
}
}
return retval;
}
EXPORT_SYMBOL(__blockdev_direct_IO);

View File

@ -18,7 +18,7 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused)
spin_lock(&inode_lock);
list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW))
if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW))
continue;
if (inode->i_mapping->nrpages == 0)
continue;

View File

@ -804,10 +804,20 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
size_t num_zeros = (PAGE_CACHE_SIZE
- (ia->ia_size & ~PAGE_CACHE_MASK));
/*
* XXX(truncate) this should really happen at the begginning
* of ->setattr. But the code is too messy to that as part
* of a larger patch. ecryptfs is also totally missing out
* on the inode_change_ok check at the beginning of
* ->setattr while would include this.
*/
rc = inode_newsize_ok(inode, ia->ia_size);
if (rc)
goto out;
if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
rc = simple_setsize(inode, ia->ia_size);
if (rc)
goto out;
truncate_setsize(inode, ia->ia_size);
lower_ia->ia_size = ia->ia_size;
lower_ia->ia_valid |= ATTR_SIZE;
goto out;
@ -830,7 +840,7 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
goto out;
}
}
simple_setsize(inode, ia->ia_size);
truncate_setsize(inode, ia->ia_size);
rc = ecryptfs_write_inode_size_to_metadata(inode);
if (rc) {
printk(KERN_ERR "Problem with "

View File

@ -118,11 +118,15 @@ void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode)
*/
static int ecryptfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
return vfs_statfs(ecryptfs_dentry_to_lower(dentry), buf);
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
if (!lower_dentry->d_sb->s_op->statfs)
return -ENOSYS;
return lower_dentry->d_sb->s_op->statfs(lower_dentry, buf);
}
/**
* ecryptfs_clear_inode
* ecryptfs_evict_inode
* @inode - The ecryptfs inode
*
* Called by iput() when the inode reference count reached zero
@ -131,8 +135,10 @@ static int ecryptfs_statfs(struct dentry *dentry, struct kstatfs *buf)
* on the inode free list. We use this to drop out reference to the
* lower inode.
*/
static void ecryptfs_clear_inode(struct inode *inode)
static void ecryptfs_evict_inode(struct inode *inode)
{
truncate_inode_pages(&inode->i_data, 0);
end_writeback(inode);
iput(ecryptfs_inode_to_lower(inode));
}
@ -184,6 +190,6 @@ const struct super_operations ecryptfs_sops = {
.drop_inode = generic_delete_inode,
.statfs = ecryptfs_statfs,
.remount_fs = NULL,
.clear_inode = ecryptfs_clear_inode,
.evict_inode = ecryptfs_evict_inode,
.show_options = ecryptfs_show_options
};

View File

@ -256,7 +256,6 @@ static inline int exofs_oi_read(struct exofs_i_info *oi,
}
/* inode.c */
void exofs_truncate(struct inode *inode);
int exofs_setattr(struct dentry *, struct iattr *);
int exofs_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
@ -264,7 +263,7 @@ int exofs_write_begin(struct file *file, struct address_space *mapping,
extern struct inode *exofs_iget(struct super_block *, unsigned long);
struct inode *exofs_new_inode(struct inode *, int);
extern int exofs_write_inode(struct inode *, struct writeback_control *wbc);
extern void exofs_delete_inode(struct inode *);
extern void exofs_evict_inode(struct inode *);
/* dir.c: */
int exofs_add_link(struct dentry *, struct inode *);

View File

@ -86,6 +86,5 @@ const struct file_operations exofs_file_operations = {
};
const struct inode_operations exofs_file_inode_operations = {
.truncate = exofs_truncate,
.setattr = exofs_setattr,
};

View File

@ -697,6 +697,13 @@ static int exofs_writepage(struct page *page, struct writeback_control *wbc)
return write_exec(&pcol);
}
/* i_mutex held using inode->i_size directly */
static void _write_failed(struct inode *inode, loff_t to)
{
if (to > inode->i_size)
truncate_pagecache(inode, to, inode->i_size);
}
int exofs_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
@ -710,7 +717,7 @@ int exofs_write_begin(struct file *file, struct address_space *mapping,
fsdata);
if (ret) {
EXOFS_DBGMSG("simple_write_begin faild\n");
return ret;
goto out;
}
page = *pagep;
@ -725,6 +732,9 @@ int exofs_write_begin(struct file *file, struct address_space *mapping,
EXOFS_DBGMSG("__readpage_filler faild\n");
}
}
out:
if (unlikely(ret))
_write_failed(mapping->host, pos + len);
return ret;
}
@ -750,6 +760,10 @@ static int exofs_write_end(struct file *file, struct address_space *mapping,
int ret;
ret = simple_write_end(file, mapping,pos, len, copied, page, fsdata);
if (unlikely(ret))
_write_failed(inode, pos + len);
/* TODO: once simple_write_end marks inode dirty remove */
if (i_size != inode->i_size)
mark_inode_dirty(inode);
return ret;
@ -808,87 +822,55 @@ static inline int exofs_inode_is_fast_symlink(struct inode *inode)
return S_ISLNK(inode->i_mode) && (oi->i_data[0] != 0);
}
/*
* get_block_t - Fill in a buffer_head
* An OSD takes care of block allocation so we just fake an allocation by
* putting in the inode's sector_t in the buffer_head.
* TODO: What about the case of create==0 and @iblock does not exist in the
* object?
*/
static int exofs_get_block(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create)
{
map_bh(bh_result, inode->i_sb, iblock);
return 0;
}
const struct osd_attr g_attr_logical_length = ATTR_DEF(
OSD_APAGE_OBJECT_INFORMATION, OSD_ATTR_OI_LOGICAL_LENGTH, 8);
static int _do_truncate(struct inode *inode)
static int _do_truncate(struct inode *inode, loff_t newsize)
{
struct exofs_i_info *oi = exofs_i(inode);
loff_t isize = i_size_read(inode);
int ret;
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
nobh_truncate_page(inode->i_mapping, isize, exofs_get_block);
ret = exofs_oi_truncate(oi, (u64)newsize);
if (likely(!ret))
truncate_setsize(inode, newsize);
ret = exofs_oi_truncate(oi, (u64)isize);
EXOFS_DBGMSG("(0x%lx) size=0x%llx\n", inode->i_ino, isize);
EXOFS_DBGMSG("(0x%lx) size=0x%llx ret=>%d\n",
inode->i_ino, newsize, ret);
return ret;
}
/*
* Truncate a file to the specified size - all we have to do is set the size
* attribute. We make sure the object exists first.
*/
void exofs_truncate(struct inode *inode)
{
struct exofs_i_info *oi = exofs_i(inode);
int ret;
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
|| S_ISLNK(inode->i_mode)))
return;
if (exofs_inode_is_fast_symlink(inode))
return;
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
return;
/* if we are about to truncate an object, and it hasn't been
* created yet, wait
*/
if (unlikely(wait_obj_created(oi)))
goto fail;
ret = _do_truncate(inode);
if (ret)
goto fail;
out:
mark_inode_dirty(inode);
return;
fail:
make_bad_inode(inode);
goto out;
}
/*
* Set inode attributes - just call generic functions.
* Set inode attributes - update size attribute on OSD if needed,
* otherwise just call generic functions.
*/
int exofs_setattr(struct dentry *dentry, struct iattr *iattr)
{
struct inode *inode = dentry->d_inode;
int error;
error = inode_change_ok(inode, iattr);
if (error)
/* if we are about to modify an object, and it hasn't been
* created yet, wait
*/
error = wait_obj_created(exofs_i(inode));
if (unlikely(error))
return error;
error = inode_setattr(inode, iattr);
return error;
error = inode_change_ok(inode, iattr);
if (unlikely(error))
return error;
if ((iattr->ia_valid & ATTR_SIZE) &&
iattr->ia_size != i_size_read(inode)) {
error = _do_truncate(inode, iattr->ia_size);
if (unlikely(error))
return error;
}
setattr_copy(inode, iattr);
mark_inode_dirty(inode);
return 0;
}
static const struct osd_attr g_attr_inode_file_layout = ATTR_DEF(
@ -1325,7 +1307,7 @@ static void delete_done(struct exofs_io_state *ios, void *p)
* from the OSD here. We make sure the object was created before we try and
* delete it.
*/
void exofs_delete_inode(struct inode *inode)
void exofs_evict_inode(struct inode *inode)
{
struct exofs_i_info *oi = exofs_i(inode);
struct super_block *sb = inode->i_sb;
@ -1335,28 +1317,25 @@ void exofs_delete_inode(struct inode *inode)
truncate_inode_pages(&inode->i_data, 0);
if (is_bad_inode(inode))
/* TODO: should do better here */
if (inode->i_nlink || is_bad_inode(inode))
goto no_delete;
mark_inode_dirty(inode);
exofs_update_inode(inode, inode_needs_sync(inode));
inode->i_size = 0;
if (inode->i_blocks)
exofs_truncate(inode);
clear_inode(inode);
ret = exofs_get_io_state(&sbi->layout, &ios);
if (unlikely(ret)) {
EXOFS_ERR("%s: exofs_get_io_state failed\n", __func__);
return;
}
end_writeback(inode);
/* if we are deleting an obj that hasn't been created yet, wait */
if (!obj_created(oi)) {
BUG_ON(!obj_2bcreated(oi));
wait_event(oi->i_wq, obj_created(oi));
/* ignore the error attempt a remove anyway */
}
/* Now Remove the OSD objects */
ret = exofs_get_io_state(&sbi->layout, &ios);
if (unlikely(ret)) {
EXOFS_ERR("%s: exofs_get_io_state failed\n", __func__);
return;
}
ios->obj.id = exofs_oi_objno(oi);
@ -1374,5 +1353,5 @@ void exofs_delete_inode(struct inode *inode)
return;
no_delete:
clear_inode(inode);
end_writeback(inode);
}

View File

@ -743,7 +743,7 @@ static const struct super_operations exofs_sops = {
.alloc_inode = exofs_alloc_inode,
.destroy_inode = exofs_destroy_inode,
.write_inode = exofs_write_inode,
.delete_inode = exofs_delete_inode,
.evict_inode = exofs_evict_inode,
.put_super = exofs_put_super,
.write_super = exofs_write_super,
.sync_fs = exofs_sync_fs,

View File

@ -571,7 +571,7 @@ void ext2_free_blocks (struct inode * inode, unsigned long block,
error_return:
brelse(bitmap_bh);
release_blocks(sb, freed);
dquot_free_block(inode, freed);
dquot_free_block_nodirty(inode, freed);
}
/**
@ -1418,7 +1418,8 @@ ext2_fsblk_t ext2_new_blocks(struct inode *inode, ext2_fsblk_t goal,
*errp = 0;
brelse(bitmap_bh);
dquot_free_block(inode, *count-num);
dquot_free_block_nodirty(inode, *count-num);
mark_inode_dirty(inode);
*count = num;
return ret_block;
@ -1428,8 +1429,10 @@ ext2_fsblk_t ext2_new_blocks(struct inode *inode, ext2_fsblk_t goal,
/*
* Undo the block allocation
*/
if (!performed_allocation)
dquot_free_block(inode, *count);
if (!performed_allocation) {
dquot_free_block_nodirty(inode, *count);
mark_inode_dirty(inode);
}
brelse(bitmap_bh);
return 0;
}

View File

@ -448,6 +448,11 @@ ino_t ext2_inode_by_name(struct inode *dir, struct qstr *child)
return res;
}
static int ext2_prepare_chunk(struct page *page, loff_t pos, unsigned len)
{
return __block_write_begin(page, pos, len, ext2_get_block);
}
/* Releases the page */
void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,
struct page *page, struct inode *inode, int update_times)
@ -458,8 +463,7 @@ void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,
int err;
lock_page(page);
err = __ext2_write_begin(NULL, page->mapping, pos, len,
AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
err = ext2_prepare_chunk(page, pos, len);
BUG_ON(err);
de->inode = cpu_to_le32(inode->i_ino);
ext2_set_de_type(de, inode);
@ -542,8 +546,7 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode)
got_it:
pos = page_offset(page) +
(char*)de - (char*)page_address(page);
err = __ext2_write_begin(NULL, page->mapping, pos, rec_len, 0,
&page, NULL);
err = ext2_prepare_chunk(page, pos, rec_len);
if (err)
goto out_unlock;
if (de->inode) {
@ -576,8 +579,7 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode)
*/
int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page )
{
struct address_space *mapping = page->mapping;
struct inode *inode = mapping->host;
struct inode *inode = page->mapping->host;
char *kaddr = page_address(page);
unsigned from = ((char*)dir - kaddr) & ~(ext2_chunk_size(inode)-1);
unsigned to = ((char *)dir - kaddr) +
@ -601,8 +603,7 @@ int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page )
from = (char*)pde - (char*)page_address(page);
pos = page_offset(page) + from;
lock_page(page);
err = __ext2_write_begin(NULL, page->mapping, pos, to - from, 0,
&page, NULL);
err = ext2_prepare_chunk(page, pos, to - from);
BUG_ON(err);
if (pde)
pde->rec_len = ext2_rec_len_to_disk(to - from);
@ -621,8 +622,7 @@ int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page )
*/
int ext2_make_empty(struct inode *inode, struct inode *parent)
{
struct address_space *mapping = inode->i_mapping;
struct page *page = grab_cache_page(mapping, 0);
struct page *page = grab_cache_page(inode->i_mapping, 0);
unsigned chunk_size = ext2_chunk_size(inode);
struct ext2_dir_entry_2 * de;
int err;
@ -631,8 +631,7 @@ int ext2_make_empty(struct inode *inode, struct inode *parent)
if (!page)
return -ENOMEM;
err = __ext2_write_begin(NULL, page->mapping, 0, chunk_size, 0,
&page, NULL);
err = ext2_prepare_chunk(page, 0, chunk_size);
if (err) {
unlock_page(page);
goto fail;

View File

@ -119,7 +119,7 @@ extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
/* inode.c */
extern struct inode *ext2_iget (struct super_block *, unsigned long);
extern int ext2_write_inode (struct inode *, struct writeback_control *);
extern void ext2_delete_inode (struct inode *);
extern void ext2_evict_inode(struct inode *);
extern int ext2_sync_inode (struct inode *);
extern int ext2_get_block(struct inode *, sector_t, struct buffer_head *, int);
extern int ext2_setattr (struct dentry *, struct iattr *);
@ -127,9 +127,6 @@ extern void ext2_set_inode_flags(struct inode *inode);
extern void ext2_get_inode_flags(struct ext2_inode_info *);
extern int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
u64 start, u64 len);
int __ext2_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata);
/* ioctl.c */
extern long ext2_ioctl(struct file *, unsigned int, unsigned long);

View File

@ -118,19 +118,14 @@ void ext2_free_inode (struct inode * inode)
* Note: we must free any quota before locking the superblock,
* as writing the quota to disk may need the lock as well.
*/
if (!is_bad_inode(inode)) {
/* Quota is already initialized in iput() */
ext2_xattr_delete_inode(inode);
dquot_free_inode(inode);
dquot_drop(inode);
}
/* Quota is already initialized in iput() */
ext2_xattr_delete_inode(inode);
dquot_free_inode(inode);
dquot_drop(inode);
es = EXT2_SB(sb)->s_es;
is_directory = S_ISDIR(inode->i_mode);
/* Do this BEFORE marking the inode not in use or returning an error */
clear_inode (inode);
if (ino < EXT2_FIRST_INO(sb) ||
ino > le32_to_cpu(es->s_inodes_count)) {
ext2_error (sb, "ext2_free_inode",

View File

@ -69,26 +69,42 @@ static void ext2_write_failed(struct address_space *mapping, loff_t to)
/*
* Called at the last iput() if i_nlink is zero.
*/
void ext2_delete_inode (struct inode * inode)
void ext2_evict_inode(struct inode * inode)
{
if (!is_bad_inode(inode))
struct ext2_block_alloc_info *rsv;
int want_delete = 0;
if (!inode->i_nlink && !is_bad_inode(inode)) {
want_delete = 1;
dquot_initialize(inode);
} else {
dquot_drop(inode);
}
truncate_inode_pages(&inode->i_data, 0);
if (is_bad_inode(inode))
goto no_delete;
EXT2_I(inode)->i_dtime = get_seconds();
mark_inode_dirty(inode);
__ext2_write_inode(inode, inode_needs_sync(inode));
if (want_delete) {
/* set dtime */
EXT2_I(inode)->i_dtime = get_seconds();
mark_inode_dirty(inode);
__ext2_write_inode(inode, inode_needs_sync(inode));
/* truncate to 0 */
inode->i_size = 0;
if (inode->i_blocks)
ext2_truncate_blocks(inode, 0);
}
inode->i_size = 0;
if (inode->i_blocks)
ext2_truncate_blocks(inode, 0);
ext2_free_inode (inode);
invalidate_inode_buffers(inode);
end_writeback(inode);
return;
no_delete:
clear_inode(inode); /* We must guarantee clearing of inode... */
ext2_discard_reservation(inode);
rsv = EXT2_I(inode)->i_block_alloc_info;
EXT2_I(inode)->i_block_alloc_info = NULL;
if (unlikely(rsv))
kfree(rsv);
if (want_delete)
ext2_free_inode(inode);
}
typedef struct {
@ -423,6 +439,8 @@ static int ext2_alloc_blocks(struct inode *inode,
failed_out:
for (i = 0; i <index; i++)
ext2_free_blocks(inode, new_blocks[i], 1);
if (index)
mark_inode_dirty(inode);
return ret;
}
@ -765,14 +783,6 @@ ext2_readpages(struct file *file, struct address_space *mapping,
return mpage_readpages(mapping, pages, nr_pages, ext2_get_block);
}
int __ext2_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
return block_write_begin_newtrunc(file, mapping, pos, len, flags,
pagep, fsdata, ext2_get_block);
}
static int
ext2_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
@ -780,8 +790,8 @@ ext2_write_begin(struct file *file, struct address_space *mapping,
{
int ret;
*pagep = NULL;
ret = __ext2_write_begin(file, mapping, pos, len, flags, pagep, fsdata);
ret = block_write_begin(mapping, pos, len, flags, pagep,
ext2_get_block);
if (ret < 0)
ext2_write_failed(mapping, pos + len);
return ret;
@ -806,13 +816,8 @@ ext2_nobh_write_begin(struct file *file, struct address_space *mapping,
{
int ret;
/*
* Dir-in-pagecache still uses ext2_write_begin. Would have to rework
* directory handling code to pass around offsets rather than struct
* pages in order to make this work easily.
*/
ret = nobh_write_begin_newtrunc(file, mapping, pos, len, flags, pagep,
fsdata, ext2_get_block);
ret = nobh_write_begin(mapping, pos, len, flags, pagep, fsdata,
ext2_get_block);
if (ret < 0)
ext2_write_failed(mapping, pos + len);
return ret;
@ -838,7 +843,7 @@ ext2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
struct inode *inode = mapping->host;
ssize_t ret;
ret = blockdev_direct_IO_newtrunc(rw, iocb, inode, inode->i_sb->s_bdev,
ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev,
iov, offset, nr_segs, ext2_get_block, NULL);
if (ret < 0 && (rw & WRITE))
ext2_write_failed(mapping, offset + iov_length(iov, nr_segs));
@ -1006,8 +1011,8 @@ static inline void ext2_free_data(struct inode *inode, __le32 *p, __le32 *q)
else if (block_to_free == nr - count)
count++;
else {
mark_inode_dirty(inode);
ext2_free_blocks (inode, block_to_free, count);
mark_inode_dirty(inode);
free_this:
block_to_free = nr;
count = 1;
@ -1015,8 +1020,8 @@ static inline void ext2_free_data(struct inode *inode, __le32 *p, __le32 *q)
}
}
if (count > 0) {
mark_inode_dirty(inode);
ext2_free_blocks (inode, block_to_free, count);
mark_inode_dirty(inode);
}
}
@ -1169,15 +1174,10 @@ static void ext2_truncate_blocks(struct inode *inode, loff_t offset)
__ext2_truncate_blocks(inode, offset);
}
int ext2_setsize(struct inode *inode, loff_t newsize)
static int ext2_setsize(struct inode *inode, loff_t newsize)
{
loff_t oldsize;
int error;
error = inode_newsize_ok(inode, newsize);
if (error)
return error;
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)))
return -EINVAL;
@ -1197,10 +1197,7 @@ int ext2_setsize(struct inode *inode, loff_t newsize)
if (error)
return error;
oldsize = inode->i_size;
i_size_write(inode, newsize);
truncate_pagecache(inode, oldsize, newsize);
truncate_setsize(inode, newsize);
__ext2_truncate_blocks(inode, newsize);
inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
@ -1557,7 +1554,7 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
if (error)
return error;
}
generic_setattr(inode, iattr);
setattr_copy(inode, iattr);
if (iattr->ia_valid & ATTR_MODE)
error = ext2_acl_chmod(inode);
mark_inode_dirty(inode);

View File

@ -195,17 +195,6 @@ static void destroy_inodecache(void)
kmem_cache_destroy(ext2_inode_cachep);
}
static void ext2_clear_inode(struct inode *inode)
{
struct ext2_block_alloc_info *rsv = EXT2_I(inode)->i_block_alloc_info;
dquot_drop(inode);
ext2_discard_reservation(inode);
EXT2_I(inode)->i_block_alloc_info = NULL;
if (unlikely(rsv))
kfree(rsv);
}
static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs)
{
struct super_block *sb = vfs->mnt_sb;
@ -299,13 +288,12 @@ static const struct super_operations ext2_sops = {
.alloc_inode = ext2_alloc_inode,
.destroy_inode = ext2_destroy_inode,
.write_inode = ext2_write_inode,
.delete_inode = ext2_delete_inode,
.evict_inode = ext2_evict_inode,
.put_super = ext2_put_super,
.write_super = ext2_write_super,
.sync_fs = ext2_sync_fs,
.statfs = ext2_statfs,
.remount_fs = ext2_remount,
.clear_inode = ext2_clear_inode,
.show_options = ext2_show_options,
#ifdef CONFIG_QUOTA
.quota_read = ext2_quota_read,

View File

@ -674,6 +674,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
new_bh = sb_getblk(sb, block);
if (!new_bh) {
ext2_free_blocks(inode, block, 1);
mark_inode_dirty(inode);
error = -EIO;
goto cleanup;
}
@ -703,8 +704,10 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
* written (only some dirty data were not) so we just proceed
* as if nothing happened and cleanup the unused block */
if (error && error != -ENOSPC) {
if (new_bh && new_bh != old_bh)
dquot_free_block(inode, 1);
if (new_bh && new_bh != old_bh) {
dquot_free_block_nodirty(inode, 1);
mark_inode_dirty(inode);
}
goto cleanup;
}
} else
@ -727,6 +730,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
mb_cache_entry_free(ce);
ea_bdebug(old_bh, "freeing");
ext2_free_blocks(inode, old_bh->b_blocknr, 1);
mark_inode_dirty(inode);
/* We let our caller release old_bh, so we
* need to duplicate the buffer before. */
get_bh(old_bh);
@ -736,7 +740,8 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
le32_add_cpu(&HDR(old_bh)->h_refcount, -1);
if (ce)
mb_cache_entry_release(ce);
dquot_free_block(inode, 1);
dquot_free_block_nodirty(inode, 1);
mark_inode_dirty(inode);
mark_buffer_dirty(old_bh);
ea_bdebug(old_bh, "refcount now=%d",
le32_to_cpu(HDR(old_bh)->h_refcount));
@ -799,7 +804,7 @@ ext2_xattr_delete_inode(struct inode *inode)
mark_buffer_dirty(bh);
if (IS_SYNC(inode))
sync_dirty_buffer(bh);
dquot_free_block(inode, 1);
dquot_free_block_nodirty(inode, 1);
}
EXT2_I(inode)->i_file_acl = 0;
@ -838,7 +843,7 @@ ext2_xattr_cache_insert(struct buffer_head *bh)
ce = mb_cache_entry_alloc(ext2_xattr_cache, GFP_NOFS);
if (!ce)
return -ENOMEM;
error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, &hash);
error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, hash);
if (error) {
mb_cache_entry_free(ce);
if (error == -EBUSY) {
@ -912,8 +917,8 @@ ext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header)
return NULL; /* never share */
ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
again:
ce = mb_cache_entry_find_first(ext2_xattr_cache, 0,
inode->i_sb->s_bdev, hash);
ce = mb_cache_entry_find_first(ext2_xattr_cache, inode->i_sb->s_bdev,
hash);
while (ce) {
struct buffer_head *bh;
@ -945,7 +950,7 @@ ext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header)
unlock_buffer(bh);
brelse(bh);
}
ce = mb_cache_entry_find_next(ce, 0, inode->i_sb->s_bdev, hash);
ce = mb_cache_entry_find_next(ce, inode->i_sb->s_bdev, hash);
}
return NULL;
}
@ -1021,9 +1026,7 @@ static void ext2_xattr_rehash(struct ext2_xattr_header *header,
int __init
init_ext2_xattr(void)
{
ext2_xattr_cache = mb_cache_create("ext2_xattr", NULL,
sizeof(struct mb_cache_entry) +
sizeof(((struct mb_cache_entry *) 0)->e_indexes[0]), 1, 6);
ext2_xattr_cache = mb_cache_create("ext2_xattr", 6);
if (!ext2_xattr_cache)
return -ENOMEM;
return 0;

View File

@ -119,20 +119,8 @@ void ext3_free_inode (handle_t *handle, struct inode * inode)
ino = inode->i_ino;
ext3_debug ("freeing inode %lu\n", ino);
/*
* Note: we must free any quota before locking the superblock,
* as writing the quota to disk may need the lock as well.
*/
dquot_initialize(inode);
ext3_xattr_delete_inode(handle, inode);
dquot_free_inode(inode);
dquot_drop(inode);
is_directory = S_ISDIR(inode->i_mode);
/* Do this BEFORE marking the inode not in use or returning an error */
clear_inode (inode);
es = EXT3_SB(sb)->s_es;
if (ino < EXT3_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) {
ext3_error (sb, "ext3_free_inode",

View File

@ -190,18 +190,28 @@ static int truncate_restart_transaction(handle_t *handle, struct inode *inode)
}
/*
* Called at the last iput() if i_nlink is zero.
* Called at inode eviction from icache
*/
void ext3_delete_inode (struct inode * inode)
void ext3_evict_inode (struct inode *inode)
{
struct ext3_block_alloc_info *rsv;
handle_t *handle;
int want_delete = 0;
if (!is_bad_inode(inode))
if (!inode->i_nlink && !is_bad_inode(inode)) {
dquot_initialize(inode);
want_delete = 1;
}
truncate_inode_pages(&inode->i_data, 0);
if (is_bad_inode(inode))
ext3_discard_reservation(inode);
rsv = EXT3_I(inode)->i_block_alloc_info;
EXT3_I(inode)->i_block_alloc_info = NULL;
if (unlikely(rsv))
kfree(rsv);
if (!want_delete)
goto no_delete;
handle = start_transaction(inode);
@ -238,15 +248,22 @@ void ext3_delete_inode (struct inode * inode)
* having errors), but we can't free the inode if the mark_dirty
* fails.
*/
if (ext3_mark_inode_dirty(handle, inode))
/* If that failed, just do the required in-core inode clear. */
clear_inode(inode);
else
if (ext3_mark_inode_dirty(handle, inode)) {
/* If that failed, just dquot_drop() and be done with that */
dquot_drop(inode);
end_writeback(inode);
} else {
ext3_xattr_delete_inode(handle, inode);
dquot_free_inode(inode);
dquot_drop(inode);
end_writeback(inode);
ext3_free_inode(handle, inode);
}
ext3_journal_stop(handle);
return;
no_delete:
clear_inode(inode); /* We must guarantee clearing of inode... */
end_writeback(inode);
dquot_drop(inode);
}
typedef struct {
@ -1212,8 +1229,7 @@ static int ext3_write_begin(struct file *file, struct address_space *mapping,
ret = PTR_ERR(handle);
goto out;
}
ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
ext3_get_block);
ret = __block_write_begin(page, pos, len, ext3_get_block);
if (ret)
goto write_begin_failed;
@ -1798,6 +1814,17 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb,
ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
offset, nr_segs,
ext3_get_block, NULL);
/*
* In case of error extending write may have instantiated a few
* blocks outside i_size. Trim these off again.
*/
if (unlikely((rw & WRITE) && ret < 0)) {
loff_t isize = i_size_read(inode);
loff_t end = offset + iov_length(iov, nr_segs);
if (end > isize)
vmtruncate(inode, isize);
}
if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
goto retry;
@ -2560,7 +2587,7 @@ void ext3_truncate(struct inode *inode)
* If this was a simple ftruncate(), and the file will remain alive
* then we need to clear up the orphan record which we created above.
* However, if this was a real unlink then we were called by
* ext3_delete_inode(), and we allow that function to clean up the
* ext3_evict_inode(), and we allow that function to clean up the
* orphan info for us.
*/
if (inode->i_nlink)
@ -3204,9 +3231,17 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr)
ext3_journal_stop(handle);
}
rc = inode_setattr(inode, attr);
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
rc = vmtruncate(inode, attr->ia_size);
if (rc)
goto err_out;
}
if (!rc && (ia_valid & ATTR_MODE))
setattr_copy(inode, attr);
mark_inode_dirty(inode);
if (ia_valid & ATTR_MODE)
rc = ext3_acl_chmod(inode);
err_out:

View File

@ -527,17 +527,6 @@ static void destroy_inodecache(void)
kmem_cache_destroy(ext3_inode_cachep);
}
static void ext3_clear_inode(struct inode *inode)
{
struct ext3_block_alloc_info *rsv = EXT3_I(inode)->i_block_alloc_info;
dquot_drop(inode);
ext3_discard_reservation(inode);
EXT3_I(inode)->i_block_alloc_info = NULL;
if (unlikely(rsv))
kfree(rsv);
}
static inline void ext3_show_quota_options(struct seq_file *seq, struct super_block *sb)
{
#if defined(CONFIG_QUOTA)
@ -780,14 +769,13 @@ static const struct super_operations ext3_sops = {
.destroy_inode = ext3_destroy_inode,
.write_inode = ext3_write_inode,
.dirty_inode = ext3_dirty_inode,
.delete_inode = ext3_delete_inode,
.evict_inode = ext3_evict_inode,
.put_super = ext3_put_super,
.sync_fs = ext3_sync_fs,
.freeze_fs = ext3_freeze,
.unfreeze_fs = ext3_unfreeze,
.statfs = ext3_statfs,
.remount_fs = ext3_remount,
.clear_inode = ext3_clear_inode,
.show_options = ext3_show_options,
#ifdef CONFIG_QUOTA
.quota_read = ext3_quota_read,

View File

@ -1139,7 +1139,7 @@ ext3_xattr_cache_insert(struct buffer_head *bh)
ea_bdebug(bh, "out of memory");
return;
}
error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, &hash);
error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, hash);
if (error) {
mb_cache_entry_free(ce);
if (error == -EBUSY) {
@ -1211,8 +1211,8 @@ ext3_xattr_cache_find(struct inode *inode, struct ext3_xattr_header *header,
return NULL; /* never share */
ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
again:
ce = mb_cache_entry_find_first(ext3_xattr_cache, 0,
inode->i_sb->s_bdev, hash);
ce = mb_cache_entry_find_first(ext3_xattr_cache, inode->i_sb->s_bdev,
hash);
while (ce) {
struct buffer_head *bh;
@ -1237,7 +1237,7 @@ ext3_xattr_cache_find(struct inode *inode, struct ext3_xattr_header *header,
return bh;
}
brelse(bh);
ce = mb_cache_entry_find_next(ce, 0, inode->i_sb->s_bdev, hash);
ce = mb_cache_entry_find_next(ce, inode->i_sb->s_bdev, hash);
}
return NULL;
}
@ -1313,9 +1313,7 @@ static void ext3_xattr_rehash(struct ext3_xattr_header *header,
int __init
init_ext3_xattr(void)
{
ext3_xattr_cache = mb_cache_create("ext3_xattr", NULL,
sizeof(struct mb_cache_entry) +
sizeof(((struct mb_cache_entry *) 0)->e_indexes[0]), 1, 6);
ext3_xattr_cache = mb_cache_create("ext3_xattr", 6);
if (!ext3_xattr_cache)
return -ENOMEM;
return 0;

View File

@ -1643,7 +1643,8 @@ extern int ext4_write_inode(struct inode *, struct writeback_control *);
extern int ext4_setattr(struct dentry *, struct iattr *);
extern int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat);
extern void ext4_delete_inode(struct inode *);
extern void ext4_evict_inode(struct inode *);
extern void ext4_clear_inode(struct inode *);
extern int ext4_sync_inode(handle_t *, struct inode *);
extern void ext4_dirty_inode(struct inode *);
extern int ext4_change_inode_journal_flag(struct inode *, int);

View File

@ -222,7 +222,7 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
is_directory = S_ISDIR(inode->i_mode);
/* Do this BEFORE marking the inode not in use or returning an error */
clear_inode(inode);
ext4_clear_inode(inode);
es = EXT4_SB(sb)->s_es;
if (ino < EXT4_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) {

View File

@ -167,11 +167,16 @@ int ext4_truncate_restart_trans(handle_t *handle, struct inode *inode,
/*
* Called at the last iput() if i_nlink is zero.
*/
void ext4_delete_inode(struct inode *inode)
void ext4_evict_inode(struct inode *inode)
{
handle_t *handle;
int err;
if (inode->i_nlink) {
truncate_inode_pages(&inode->i_data, 0);
goto no_delete;
}
if (!is_bad_inode(inode))
dquot_initialize(inode);
@ -246,13 +251,13 @@ void ext4_delete_inode(struct inode *inode)
*/
if (ext4_mark_inode_dirty(handle, inode))
/* If that failed, just do the required in-core inode clear. */
clear_inode(inode);
ext4_clear_inode(inode);
else
ext4_free_inode(handle, inode);
ext4_journal_stop(handle);
return;
no_delete:
clear_inode(inode); /* We must guarantee clearing of inode... */
ext4_clear_inode(inode); /* We must guarantee clearing of inode... */
}
typedef struct {
@ -1602,11 +1607,9 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping,
*pagep = page;
if (ext4_should_dioread_nolock(inode))
ret = block_write_begin(file, mapping, pos, len, flags, pagep,
fsdata, ext4_get_block_write);
ret = __block_write_begin(page, pos, len, ext4_get_block_write);
else
ret = block_write_begin(file, mapping, pos, len, flags, pagep,
fsdata, ext4_get_block);
ret = __block_write_begin(page, pos, len, ext4_get_block);
if (!ret && ext4_should_journal_data(inode)) {
ret = walk_page_buffers(handle, page_buffers(page),
@ -1617,7 +1620,7 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping,
unlock_page(page);
page_cache_release(page);
/*
* block_write_begin may have instantiated a few blocks
* __block_write_begin may have instantiated a few blocks
* outside i_size. Trim these off again. Don't need
* i_size_read because we hold i_mutex.
*
@ -3205,8 +3208,7 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
}
*pagep = page;
ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
ext4_da_get_block_prep);
ret = __block_write_begin(page, pos, len, ext4_da_get_block_prep);
if (ret < 0) {
unlock_page(page);
ext4_journal_stop(handle);
@ -3565,15 +3567,24 @@ static ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb,
retry:
if (rw == READ && ext4_should_dioread_nolock(inode))
ret = blockdev_direct_IO_no_locking(rw, iocb, inode,
ret = __blockdev_direct_IO(rw, iocb, inode,
inode->i_sb->s_bdev, iov,
offset, nr_segs,
ext4_get_block, NULL);
else
ext4_get_block, NULL, NULL, 0);
else {
ret = blockdev_direct_IO(rw, iocb, inode,
inode->i_sb->s_bdev, iov,
offset, nr_segs,
ext4_get_block, NULL);
if (unlikely((rw & WRITE) && ret < 0)) {
loff_t isize = i_size_read(inode);
loff_t end = offset + iov_length(iov, nr_segs);
if (end > isize)
vmtruncate(inode, isize);
}
}
if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
goto retry;
@ -5536,11 +5547,19 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
ext4_truncate(inode);
}
rc = inode_setattr(inode, attr);
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode))
rc = vmtruncate(inode, attr->ia_size);
/* If inode_setattr's call to ext4_truncate failed to get a
* transaction handle at all, we need to clean up the in-core
* orphan list manually. */
if (!rc) {
setattr_copy(inode, attr);
mark_inode_dirty(inode);
}
/*
* If the call to ext4_truncate failed to get a transaction handle at
* all, we need to clean up the in-core orphan list manually.
*/
if (inode->i_nlink)
ext4_orphan_del(NULL, inode);

View File

@ -868,8 +868,10 @@ static void destroy_inodecache(void)
kmem_cache_destroy(ext4_inode_cachep);
}
static void ext4_clear_inode(struct inode *inode)
void ext4_clear_inode(struct inode *inode)
{
invalidate_inode_buffers(inode);
end_writeback(inode);
dquot_drop(inode);
ext4_discard_preallocations(inode);
if (EXT4_JOURNAL(inode))
@ -1158,14 +1160,13 @@ static const struct super_operations ext4_sops = {
.destroy_inode = ext4_destroy_inode,
.write_inode = ext4_write_inode,
.dirty_inode = ext4_dirty_inode,
.delete_inode = ext4_delete_inode,
.evict_inode = ext4_evict_inode,
.put_super = ext4_put_super,
.sync_fs = ext4_sync_fs,
.freeze_fs = ext4_freeze,
.unfreeze_fs = ext4_unfreeze,
.statfs = ext4_statfs,
.remount_fs = ext4_remount,
.clear_inode = ext4_clear_inode,
.show_options = ext4_show_options,
#ifdef CONFIG_QUOTA
.quota_read = ext4_quota_read,
@ -1179,12 +1180,11 @@ static const struct super_operations ext4_nojournal_sops = {
.destroy_inode = ext4_destroy_inode,
.write_inode = ext4_write_inode,
.dirty_inode = ext4_dirty_inode,
.delete_inode = ext4_delete_inode,
.evict_inode = ext4_evict_inode,
.write_super = ext4_write_super,
.put_super = ext4_put_super,
.statfs = ext4_statfs,
.remount_fs = ext4_remount,
.clear_inode = ext4_clear_inode,
.show_options = ext4_show_options,
#ifdef CONFIG_QUOTA
.quota_read = ext4_quota_read,

View File

@ -1417,7 +1417,7 @@ ext4_xattr_cache_insert(struct buffer_head *bh)
ea_bdebug(bh, "out of memory");
return;
}
error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, &hash);
error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, hash);
if (error) {
mb_cache_entry_free(ce);
if (error == -EBUSY) {
@ -1489,8 +1489,8 @@ ext4_xattr_cache_find(struct inode *inode, struct ext4_xattr_header *header,
return NULL; /* never share */
ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
again:
ce = mb_cache_entry_find_first(ext4_xattr_cache, 0,
inode->i_sb->s_bdev, hash);
ce = mb_cache_entry_find_first(ext4_xattr_cache, inode->i_sb->s_bdev,
hash);
while (ce) {
struct buffer_head *bh;
@ -1514,7 +1514,7 @@ ext4_xattr_cache_find(struct inode *inode, struct ext4_xattr_header *header,
return bh;
}
brelse(bh);
ce = mb_cache_entry_find_next(ce, 0, inode->i_sb->s_bdev, hash);
ce = mb_cache_entry_find_next(ce, inode->i_sb->s_bdev, hash);
}
return NULL;
}
@ -1590,9 +1590,7 @@ static void ext4_xattr_rehash(struct ext4_xattr_header *header,
int __init
init_ext4_xattr(void)
{
ext4_xattr_cache = mb_cache_create("ext4_xattr", NULL,
sizeof(struct mb_cache_entry) +
sizeof(((struct mb_cache_entry *) 0)->e_indexes[0]), 1, 6);
ext4_xattr_cache = mb_cache_create("ext4_xattr", 6);
if (!ext4_xattr_cache)
return -ENOMEM;
return 0;

View File

@ -306,7 +306,6 @@ extern long fat_generic_ioctl(struct file *filp, unsigned int cmd,
extern const struct file_operations fat_file_operations;
extern const struct inode_operations fat_file_inode_operations;
extern int fat_setattr(struct dentry * dentry, struct iattr * attr);
extern int fat_setsize(struct inode *inode, loff_t offset);
extern void fat_truncate_blocks(struct inode *inode, loff_t offset);
extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat);

View File

@ -364,18 +364,6 @@ static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode)
return 0;
}
int fat_setsize(struct inode *inode, loff_t offset)
{
int error;
error = simple_setsize(inode, offset);
if (error)
return error;
fat_truncate_blocks(inode, offset);
return error;
}
#define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)
/* valid file mode bits */
#define FAT_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXUGO)
@ -387,21 +375,6 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
unsigned int ia_valid;
int error;
/*
* Expand the file. Since inode_setattr() updates ->i_size
* before calling the ->truncate(), but FAT needs to fill the
* hole before it. XXX: this is no longer true with new truncate
* sequence.
*/
if (attr->ia_valid & ATTR_SIZE) {
if (attr->ia_size > inode->i_size) {
error = fat_cont_expand(inode, attr->ia_size);
if (error || attr->ia_valid == ATTR_SIZE)
goto out;
attr->ia_valid &= ~ATTR_SIZE;
}
}
/* Check for setting the inode time. */
ia_valid = attr->ia_valid;
if (ia_valid & TIMES_SET_FLAGS) {
@ -417,6 +390,21 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
goto out;
}
/*
* Expand the file. Since inode_setattr() updates ->i_size
* before calling the ->truncate(), but FAT needs to fill the
* hole before it. XXX: this is no longer true with new truncate
* sequence.
*/
if (attr->ia_valid & ATTR_SIZE) {
if (attr->ia_size > inode->i_size) {
error = fat_cont_expand(inode, attr->ia_size);
if (error || attr->ia_valid == ATTR_SIZE)
goto out;
attr->ia_valid &= ~ATTR_SIZE;
}
}
if (((attr->ia_valid & ATTR_UID) &&
(attr->ia_uid != sbi->options.fs_uid)) ||
((attr->ia_valid & ATTR_GID) &&
@ -441,12 +429,11 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
}
if (attr->ia_valid & ATTR_SIZE) {
error = fat_setsize(inode, attr->ia_size);
if (error)
goto out;
truncate_setsize(inode, attr->ia_size);
fat_truncate_blocks(inode, attr->ia_size);
}
generic_setattr(inode, attr);
setattr_copy(inode, attr);
mark_inode_dirty(inode);
out:
return error;

View File

@ -159,7 +159,7 @@ static int fat_write_begin(struct file *file, struct address_space *mapping,
int err;
*pagep = NULL;
err = cont_write_begin_newtrunc(file, mapping, pos, len, flags,
err = cont_write_begin(file, mapping, pos, len, flags,
pagep, fsdata, fat_get_block,
&MSDOS_I(mapping->host)->mmu_private);
if (err < 0)
@ -212,8 +212,8 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,
* FAT need to use the DIO_LOCKING for avoiding the race
* condition of fat_get_block() and ->truncate().
*/
ret = blockdev_direct_IO_newtrunc(rw, iocb, inode, inode->i_sb->s_bdev,
iov, offset, nr_segs, fat_get_block, NULL);
ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev,
iov, offset, nr_segs, fat_get_block, NULL);
if (ret < 0 && (rw & WRITE))
fat_write_failed(mapping, offset + iov_length(iov, nr_segs));
@ -263,7 +263,7 @@ static const struct address_space_operations fat_aops = {
* check if the location is still valid and retry if it
* isn't. Otherwise we do changes.
* 5. Spinlock is used to protect hash/unhash/location check/lookup
* 6. fat_clear_inode() unhashes the F-d-c entry.
* 6. fat_evict_inode() unhashes the F-d-c entry.
* 7. lookup() and readdir() do igrab() if they find a F-d-c entry
* and consider negative result as cache miss.
*/
@ -448,16 +448,15 @@ struct inode *fat_build_inode(struct super_block *sb,
EXPORT_SYMBOL_GPL(fat_build_inode);
static void fat_delete_inode(struct inode *inode)
static void fat_evict_inode(struct inode *inode)
{
truncate_inode_pages(&inode->i_data, 0);
inode->i_size = 0;
fat_truncate_blocks(inode, 0);
clear_inode(inode);
}
static void fat_clear_inode(struct inode *inode)
{
if (!inode->i_nlink) {
inode->i_size = 0;
fat_truncate_blocks(inode, 0);
}
invalidate_inode_buffers(inode);
end_writeback(inode);
fat_cache_inval_inode(inode);
fat_detach(inode);
}
@ -674,12 +673,11 @@ static const struct super_operations fat_sops = {
.alloc_inode = fat_alloc_inode,
.destroy_inode = fat_destroy_inode,
.write_inode = fat_write_inode,
.delete_inode = fat_delete_inode,
.evict_inode = fat_evict_inode,
.put_super = fat_put_super,
.write_super = fat_write_super,
.sync_fs = fat_sync_fs,
.statfs = fat_statfs,
.clear_inode = fat_clear_inode,
.remount_fs = fat_remount,
.show_options = fat_show_options,

View File

@ -63,7 +63,7 @@ extern void vxfs_put_fake_inode(struct inode *);
extern struct vxfs_inode_info * vxfs_blkiget(struct super_block *, u_long, ino_t);
extern struct vxfs_inode_info * vxfs_stiget(struct super_block *, ino_t);
extern struct inode * vxfs_iget(struct super_block *, ino_t);
extern void vxfs_clear_inode(struct inode *);
extern void vxfs_evict_inode(struct inode *);
/* vxfs_lookup.c */
extern const struct inode_operations vxfs_dir_inode_ops;

View File

@ -337,15 +337,17 @@ vxfs_iget(struct super_block *sbp, ino_t ino)
}
/**
* vxfs_clear_inode - remove inode from main memory
* vxfs_evict_inode - remove inode from main memory
* @ip: inode to discard.
*
* Description:
* vxfs_clear_inode() is called on the final iput and frees the private
* vxfs_evict_inode() is called on the final iput and frees the private
* inode area.
*/
void
vxfs_clear_inode(struct inode *ip)
vxfs_evict_inode(struct inode *ip)
{
truncate_inode_pages(&ip->i_data, 0);
end_writeback(ip);
kmem_cache_free(vxfs_inode_cachep, ip->i_private);
}

View File

@ -61,7 +61,7 @@ static int vxfs_statfs(struct dentry *, struct kstatfs *);
static int vxfs_remount(struct super_block *, int *, char *);
static const struct super_operations vxfs_super_ops = {
.clear_inode = vxfs_clear_inode,
.evict_inode = vxfs_evict_inode,
.put_super = vxfs_put_super,
.statfs = vxfs_statfs,
.remount_fs = vxfs_remount,

View File

@ -352,7 +352,7 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
spin_lock(&inode_lock);
inode->i_state &= ~I_SYNC;
if (!(inode->i_state & (I_FREEING | I_CLEAR))) {
if (!(inode->i_state & I_FREEING)) {
if ((inode->i_state & I_DIRTY_PAGES) && wbc->for_kupdate) {
/*
* More pages get dirtied by a fast dirtier.
@ -499,7 +499,7 @@ static int writeback_sb_inodes(struct super_block *sb, struct bdi_writeback *wb,
if (inode_dirtied_after(inode, wbc->wb_start))
return 1;
BUG_ON(inode->i_state & (I_FREEING | I_CLEAR));
BUG_ON(inode->i_state & I_FREEING);
__iget(inode);
pages_skipped = wbc->pages_skipped;
writeback_single_inode(inode, wbc);
@ -936,7 +936,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
if (hlist_unhashed(&inode->i_hash))
goto out;
}
if (inode->i_state & (I_FREEING|I_CLEAR))
if (inode->i_state & I_FREEING)
goto out;
/*
@ -1002,7 +1002,7 @@ static void wait_sb_inodes(struct super_block *sb)
list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
struct address_space *mapping;
if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW))
if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW))
continue;
mapping = inode->i_mapping;
if (mapping->nrpages == 0)

View File

@ -1270,21 +1270,18 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
if (!fuse_allow_task(fc, current))
return -EACCES;
if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
err = inode_change_ok(inode, attr);
if (err)
return err;
}
if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
attr->ia_valid |= ATTR_FORCE;
err = inode_change_ok(inode, attr);
if (err)
return err;
if ((attr->ia_valid & ATTR_OPEN) && fc->atomic_o_trunc)
return 0;
if (attr->ia_valid & ATTR_SIZE) {
err = inode_newsize_ok(inode, attr->ia_size);
if (err)
return err;
if (attr->ia_valid & ATTR_SIZE)
is_truncate = true;
}
req = fuse_get_req(fc);
if (IS_ERR(req))

View File

@ -122,8 +122,10 @@ void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
fuse_request_send_noreply(fc, req);
}
static void fuse_clear_inode(struct inode *inode)
static void fuse_evict_inode(struct inode *inode)
{
truncate_inode_pages(&inode->i_data, 0);
end_writeback(inode);
if (inode->i_sb->s_flags & MS_ACTIVE) {
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_inode *fi = get_fuse_inode(inode);
@ -736,7 +738,7 @@ static const struct export_operations fuse_export_operations = {
static const struct super_operations fuse_super_operations = {
.alloc_inode = fuse_alloc_inode,
.destroy_inode = fuse_destroy_inode,
.clear_inode = fuse_clear_inode,
.evict_inode = fuse_evict_inode,
.drop_inode = generic_delete_inode,
.remount_fs = fuse_remount_fs,
.put_super = fuse_put_super,

View File

@ -697,12 +697,12 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
page_cache_release(page);
/*
* XXX(hch): the call below should probably be replaced with
* XXX(truncate): the call below should probably be replaced with
* a call to the gfs2-specific truncate blocks helper to actually
* release disk blocks..
*/
if (pos + len > ip->i_inode.i_size)
simple_setsize(&ip->i_inode, ip->i_inode.i_size);
truncate_setsize(&ip->i_inode, ip->i_inode.i_size);
out_endtrans:
gfs2_trans_end(sdp);
out_trans_fail:
@ -1042,9 +1042,9 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
if (rv != 1)
goto out; /* dio not valid, fall back to buffered i/o */
rv = blockdev_direct_IO_no_locking(rw, iocb, inode, inode->i_sb->s_bdev,
iov, offset, nr_segs,
gfs2_get_block_direct, NULL);
rv = __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
offset, nr_segs, gfs2_get_block_direct,
NULL, NULL, 0);
out:
gfs2_glock_dq_m(1, &gh);
gfs2_holder_uninit(&gh);

View File

@ -84,7 +84,7 @@ static int iget_skip_test(struct inode *inode, void *opaque)
struct gfs2_skip_data *data = opaque;
if (ip->i_no_addr == data->no_addr) {
if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)){
if (inode->i_state & (I_FREEING|I_WILL_FREE)){
data->skipped = 1;
return 0;
}
@ -991,18 +991,29 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
{
struct inode *inode = &ip->i_inode;
struct buffer_head *dibh;
int error;
error = gfs2_meta_inode_buffer(ip, &dibh);
if (!error) {
error = inode_setattr(&ip->i_inode, attr);
gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error);
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
if (error)
return error;
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
error = vmtruncate(inode, attr->ia_size);
if (error)
return error;
}
return error;
setattr_copy(inode, attr);
mark_inode_dirty(inode);
gfs2_assert_warn(GFS2_SB(inode), !error);
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
return 0;
}
/**

View File

@ -1072,7 +1072,7 @@ int gfs2_permission(struct inode *inode, int mask)
}
/*
* XXX: should be changed to have proper ordering by opencoding simple_setsize
* XXX(truncate): the truncate_setsize calls should be moved to the end.
*/
static int setattr_size(struct inode *inode, struct iattr *attr)
{
@ -1084,10 +1084,8 @@ static int setattr_size(struct inode *inode, struct iattr *attr)
error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
if (error)
return error;
error = simple_setsize(inode, attr->ia_size);
truncate_setsize(inode, attr->ia_size);
gfs2_trans_end(sdp);
if (error)
return error;
}
error = gfs2_truncatei(ip, attr->ia_size);
@ -1136,8 +1134,16 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
if (error)
goto out_end_trans;
error = inode_setattr(inode, attr);
gfs2_assert_warn(sdp, !error);
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
int error;
error = vmtruncate(inode, attr->ia_size);
gfs2_assert_warn(sdp, !error);
}
setattr_copy(inode, attr);
mark_inode_dirty(inode);
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);

View File

@ -1188,7 +1188,7 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
* node for later deallocation.
*/
static void gfs2_drop_inode(struct inode *inode)
static int gfs2_drop_inode(struct inode *inode)
{
struct gfs2_inode *ip = GFS2_I(inode);
@ -1197,26 +1197,7 @@ static void gfs2_drop_inode(struct inode *inode)
if (gl && test_bit(GLF_DEMOTE, &gl->gl_flags))
clear_nlink(inode);
}
generic_drop_inode(inode);
}
/**
* gfs2_clear_inode - Deallocate an inode when VFS is done with it
* @inode: The VFS inode
*
*/
static void gfs2_clear_inode(struct inode *inode)
{
struct gfs2_inode *ip = GFS2_I(inode);
ip->i_gl->gl_object = NULL;
gfs2_glock_put(ip->i_gl);
ip->i_gl = NULL;
if (ip->i_iopen_gh.gh_gl) {
ip->i_iopen_gh.gh_gl->gl_object = NULL;
gfs2_glock_dq_uninit(&ip->i_iopen_gh);
}
return generic_drop_inode(inode);
}
static int is_ancestor(const struct dentry *d1, const struct dentry *d2)
@ -1344,13 +1325,16 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
* is safe, just less efficient.
*/
static void gfs2_delete_inode(struct inode *inode)
static void gfs2_evict_inode(struct inode *inode)
{
struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_holder gh;
int error;
if (inode->i_nlink)
goto out;
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
if (unlikely(error)) {
gfs2_glock_dq_uninit(&ip->i_iopen_gh);
@ -1404,10 +1388,18 @@ static void gfs2_delete_inode(struct inode *inode)
gfs2_holder_uninit(&ip->i_iopen_gh);
gfs2_glock_dq_uninit(&gh);
if (error && error != GLR_TRYFAILED && error != -EROFS)
fs_warn(sdp, "gfs2_delete_inode: %d\n", error);
fs_warn(sdp, "gfs2_evict_inode: %d\n", error);
out:
truncate_inode_pages(&inode->i_data, 0);
clear_inode(inode);
end_writeback(inode);
ip->i_gl->gl_object = NULL;
gfs2_glock_put(ip->i_gl);
ip->i_gl = NULL;
if (ip->i_iopen_gh.gh_gl) {
ip->i_iopen_gh.gh_gl->gl_object = NULL;
gfs2_glock_dq_uninit(&ip->i_iopen_gh);
}
}
static struct inode *gfs2_alloc_inode(struct super_block *sb)
@ -1431,14 +1423,13 @@ const struct super_operations gfs2_super_ops = {
.alloc_inode = gfs2_alloc_inode,
.destroy_inode = gfs2_destroy_inode,
.write_inode = gfs2_write_inode,
.delete_inode = gfs2_delete_inode,
.evict_inode = gfs2_evict_inode,
.put_super = gfs2_put_super,
.sync_fs = gfs2_sync_fs,
.freeze_fs = gfs2_freeze,
.unfreeze_fs = gfs2_unfreeze,
.statfs = gfs2_statfs,
.remount_fs = gfs2_remount_fs,
.clear_inode = gfs2_clear_inode,
.drop_inode = gfs2_drop_inode,
.show_options = gfs2_show_options,
};

View File

@ -1296,6 +1296,7 @@ static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip,
int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data)
{
struct inode *inode = &ip->i_inode;
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_ea_location el;
struct buffer_head *dibh;
@ -1321,14 +1322,25 @@ int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data)
return error;
error = gfs2_meta_inode_buffer(ip, &dibh);
if (!error) {
error = inode_setattr(&ip->i_inode, attr);
gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error);
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
if (error)
goto out_trans_end;
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
int error;
error = vmtruncate(inode, attr->ia_size);
gfs2_assert_warn(GFS2_SB(inode), !error);
}
setattr_copy(inode, attr);
mark_inode_dirty(inode);
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
out_trans_end:
gfs2_trans_end(sdp);
return error;
}

View File

@ -193,7 +193,7 @@ extern int hfs_inode_setattr(struct dentry *, struct iattr *);
extern void hfs_inode_read_fork(struct inode *inode, struct hfs_extent *ext,
__be32 log_size, __be32 phys_size, u32 clump_size);
extern struct inode *hfs_iget(struct super_block *, struct hfs_cat_key *, hfs_cat_rec *);
extern void hfs_clear_inode(struct inode *);
extern void hfs_evict_inode(struct inode *);
extern void hfs_delete_inode(struct inode *);
/* attr.c */

View File

@ -39,10 +39,19 @@ static int hfs_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
int ret;
*pagep = NULL;
return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
hfs_get_block,
&HFS_I(mapping->host)->phys_size);
if (unlikely(ret)) {
loff_t isize = mapping->host->i_size;
if (pos + len > isize)
vmtruncate(mapping->host, isize);
}
return ret;
}
static sector_t hfs_bmap(struct address_space *mapping, sector_t block)
@ -112,9 +121,24 @@ static ssize_t hfs_direct_IO(int rw, struct kiocb *iocb,
{
struct file *file = iocb->ki_filp;
struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host;
ssize_t ret;
return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
offset, nr_segs, hfs_get_block, NULL);
/*
* In case of error extending write may have instantiated a few
* blocks outside i_size. Trim these off again.
*/
if (unlikely((rw & WRITE) && ret < 0)) {
loff_t isize = i_size_read(inode);
loff_t end = offset + iov_length(iov, nr_segs);
if (end > isize)
vmtruncate(inode, isize);
}
return ret;
}
static int hfs_writepages(struct address_space *mapping,
@ -507,8 +531,10 @@ static struct dentry *hfs_file_lookup(struct inode *dir, struct dentry *dentry,
return NULL;
}
void hfs_clear_inode(struct inode *inode)
void hfs_evict_inode(struct inode *inode)
{
truncate_inode_pages(&inode->i_data, 0);
end_writeback(inode);
if (HFS_IS_RSRC(inode) && HFS_I(inode)->rsrc_inode) {
HFS_I(HFS_I(inode)->rsrc_inode)->rsrc_inode = NULL;
iput(HFS_I(inode)->rsrc_inode);
@ -588,13 +614,43 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr)
attr->ia_mode = inode->i_mode & ~S_IWUGO;
attr->ia_mode &= S_ISDIR(inode->i_mode) ? ~hsb->s_dir_umask: ~hsb->s_file_umask;
}
error = inode_setattr(inode, attr);
if (error)
return error;
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
error = vmtruncate(inode, attr->ia_size);
if (error)
return error;
}
setattr_copy(inode, attr);
mark_inode_dirty(inode);
return 0;
}
static int hfs_file_fsync(struct file *filp, int datasync)
{
struct inode *inode = filp->f_mapping->host;
struct super_block * sb;
int ret, err;
/* sync the inode to buffers */
ret = write_inode_now(inode, 0);
/* sync the superblock to buffers */
sb = inode->i_sb;
if (sb->s_dirt) {
lock_super(sb);
sb->s_dirt = 0;
if (!(sb->s_flags & MS_RDONLY))
hfs_mdb_commit(sb);
unlock_super(sb);
}
/* .. finally sync the buffers to disk */
err = sync_blockdev(sb->s_bdev);
if (!ret)
ret = err;
return ret;
}
static const struct file_operations hfs_file_operations = {
.llseek = generic_file_llseek,
@ -604,7 +660,7 @@ static const struct file_operations hfs_file_operations = {
.aio_write = generic_file_aio_write,
.mmap = generic_file_mmap,
.splice_read = generic_file_splice_read,
.fsync = file_fsync,
.fsync = hfs_file_fsync,
.open = hfs_file_open,
.release = hfs_file_release,
};

View File

@ -181,7 +181,7 @@ static const struct super_operations hfs_super_operations = {
.alloc_inode = hfs_alloc_inode,
.destroy_inode = hfs_destroy_inode,
.write_inode = hfs_write_inode,
.clear_inode = hfs_clear_inode,
.evict_inode = hfs_evict_inode,
.put_super = hfs_put_super,
.write_super = hfs_write_super,
.sync_fs = hfs_sync_fs,

View File

@ -351,6 +351,7 @@ int hfsplus_show_options(struct seq_file *, struct vfsmount *);
/* super.c */
struct inode *hfsplus_iget(struct super_block *, unsigned long);
int hfsplus_sync_fs(struct super_block *sb, int wait);
/* tables.c */
extern u16 hfsplus_case_fold_table[];

View File

@ -31,10 +31,19 @@ static int hfsplus_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
int ret;
*pagep = NULL;
return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
hfsplus_get_block,
&HFSPLUS_I(mapping->host).phys_size);
if (unlikely(ret)) {
loff_t isize = mapping->host->i_size;
if (pos + len > isize)
vmtruncate(mapping->host, isize);
}
return ret;
}
static sector_t hfsplus_bmap(struct address_space *mapping, sector_t block)
@ -105,9 +114,24 @@ static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb,
{
struct file *file = iocb->ki_filp;
struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host;
ssize_t ret;
return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
offset, nr_segs, hfsplus_get_block, NULL);
/*
* In case of error extending write may have instantiated a few
* blocks outside i_size. Trim these off again.
*/
if (unlikely((rw & WRITE) && ret < 0)) {
loff_t isize = i_size_read(inode);
loff_t end = offset + iov_length(iov, nr_segs);
if (end > isize)
vmtruncate(inode, isize);
}
return ret;
}
static int hfsplus_writepages(struct address_space *mapping,
@ -266,9 +290,56 @@ static int hfsplus_file_release(struct inode *inode, struct file *file)
return 0;
}
static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr)
{
struct inode *inode = dentry->d_inode;
int error;
error = inode_change_ok(inode, attr);
if (error)
return error;
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
error = vmtruncate(inode, attr->ia_size);
if (error)
return error;
}
setattr_copy(inode, attr);
mark_inode_dirty(inode);
return 0;
}
static int hfsplus_file_fsync(struct file *filp, int datasync)
{
struct inode *inode = filp->f_mapping->host;
struct super_block * sb;
int ret, err;
/* sync the inode to buffers */
ret = write_inode_now(inode, 0);
/* sync the superblock to buffers */
sb = inode->i_sb;
if (sb->s_dirt) {
if (!(sb->s_flags & MS_RDONLY))
hfsplus_sync_fs(sb, 1);
else
sb->s_dirt = 0;
}
/* .. finally sync the buffers to disk */
err = sync_blockdev(sb->s_bdev);
if (!ret)
ret = err;
return ret;
}
static const struct inode_operations hfsplus_file_inode_operations = {
.lookup = hfsplus_file_lookup,
.truncate = hfsplus_file_truncate,
.setattr = hfsplus_setattr,
.setxattr = hfsplus_setxattr,
.getxattr = hfsplus_getxattr,
.listxattr = hfsplus_listxattr,
@ -282,7 +353,7 @@ static const struct file_operations hfsplus_file_operations = {
.aio_write = generic_file_aio_write,
.mmap = generic_file_mmap,
.splice_read = generic_file_splice_read,
.fsync = file_fsync,
.fsync = hfsplus_file_fsync,
.open = hfsplus_file_open,
.release = hfsplus_file_release,
.unlocked_ioctl = hfsplus_ioctl,

View File

@ -145,16 +145,18 @@ static int hfsplus_write_inode(struct inode *inode,
return ret;
}
static void hfsplus_clear_inode(struct inode *inode)
static void hfsplus_evict_inode(struct inode *inode)
{
dprint(DBG_INODE, "hfsplus_clear_inode: %lu\n", inode->i_ino);
dprint(DBG_INODE, "hfsplus_evict_inode: %lu\n", inode->i_ino);
truncate_inode_pages(&inode->i_data, 0);
end_writeback(inode);
if (HFSPLUS_IS_RSRC(inode)) {
HFSPLUS_I(HFSPLUS_I(inode).rsrc_inode).rsrc_inode = NULL;
iput(HFSPLUS_I(inode).rsrc_inode);
}
}
static int hfsplus_sync_fs(struct super_block *sb, int wait)
int hfsplus_sync_fs(struct super_block *sb, int wait)
{
struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr;
@ -293,7 +295,7 @@ static const struct super_operations hfsplus_sops = {
.alloc_inode = hfsplus_alloc_inode,
.destroy_inode = hfsplus_destroy_inode,
.write_inode = hfsplus_write_inode,
.clear_inode = hfsplus_clear_inode,
.evict_inode = hfsplus_evict_inode,
.put_super = hfsplus_put_super,
.write_super = hfsplus_write_super,
.sync_fs = hfsplus_sync_fs,

View File

@ -53,18 +53,28 @@ struct hostfs_iattr {
struct timespec ia_ctime;
};
extern int stat_file(const char *path, unsigned long long *inode_out,
int *mode_out, int *nlink_out, int *uid_out, int *gid_out,
unsigned long long *size_out, struct timespec *atime_out,
struct timespec *mtime_out, struct timespec *ctime_out,
int *blksize_out, unsigned long long *blocks_out, int fd);
struct hostfs_stat {
unsigned long long ino;
unsigned int mode;
unsigned int nlink;
unsigned int uid;
unsigned int gid;
unsigned long long size;
struct timespec atime, mtime, ctime;
unsigned int blksize;
unsigned long long blocks;
unsigned int maj;
unsigned int min;
};
extern int stat_file(const char *path, struct hostfs_stat *p, int fd);
extern int access_file(char *path, int r, int w, int x);
extern int open_file(char *path, int r, int w, int append);
extern int file_type(const char *path, int *maj, int *min);
extern void *open_dir(char *path, int *err_out);
extern char *read_dir(void *stream, unsigned long long *pos,
unsigned long long *ino_out, int *len_out);
extern void close_file(void *stream);
extern int replace_file(int oldfd, int fd);
extern void close_dir(void *stream);
extern int read_file(int fd, unsigned long long *offset, char *buf, int len);
extern int write_file(int fd, unsigned long long *offset, const char *buf,

View File

@ -14,12 +14,12 @@
#include <linux/slab.h>
#include <linux/seq_file.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include "hostfs.h"
#include "init.h"
#include "kern.h"
struct hostfs_inode_info {
char *host_filename;
int fd;
fmode_t mode;
struct inode vfs_inode;
@ -49,7 +49,7 @@ static int append = 0;
static const struct inode_operations hostfs_iops;
static const struct inode_operations hostfs_dir_iops;
static const struct address_space_operations hostfs_link_aops;
static const struct inode_operations hostfs_link_iops;
#ifndef MODULE
static int __init hostfs_args(char *options, int *add)
@ -90,71 +90,58 @@ __uml_setup("hostfs=", hostfs_args,
);
#endif
static char *dentry_name(struct dentry *dentry, int extra)
static char *__dentry_name(struct dentry *dentry, char *name)
{
struct dentry *parent;
char *root, *name;
int len;
char *p = __dentry_path(dentry, name, PATH_MAX);
char *root;
size_t len;
len = 0;
parent = dentry;
while (parent->d_parent != parent) {
len += parent->d_name.len + 1;
parent = parent->d_parent;
}
spin_unlock(&dcache_lock);
root = HOSTFS_I(parent->d_inode)->host_filename;
len += strlen(root);
name = kmalloc(len + extra + 1, GFP_KERNEL);
if (name == NULL)
root = dentry->d_sb->s_fs_info;
len = strlen(root);
if (IS_ERR(p)) {
__putname(name);
return NULL;
name[len] = '\0';
parent = dentry;
while (parent->d_parent != parent) {
len -= parent->d_name.len + 1;
name[len] = '/';
strncpy(&name[len + 1], parent->d_name.name,
parent->d_name.len);
parent = parent->d_parent;
}
strncpy(name, root, strlen(root));
strncpy(name, root, PATH_MAX);
if (len > p - name) {
__putname(name);
return NULL;
}
if (p > name + len) {
char *s = name + len;
while ((*s++ = *p++) != '\0')
;
}
return name;
}
static char *inode_name(struct inode *ino, int extra)
static char *dentry_name(struct dentry *dentry)
{
struct dentry *dentry;
char *name = __getname();
if (!name)
return NULL;
dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
return dentry_name(dentry, extra);
spin_lock(&dcache_lock);
return __dentry_name(dentry, name); /* will unlock */
}
static int read_name(struct inode *ino, char *name)
static char *inode_name(struct inode *ino)
{
/*
* The non-int inode fields are copied into ints by stat_file and
* then copied into the inode because passing the actual pointers
* in and having them treated as int * breaks on big-endian machines
*/
int err;
int i_mode, i_nlink, i_blksize;
unsigned long long i_size;
unsigned long long i_ino;
unsigned long long i_blocks;
struct dentry *dentry;
char *name = __getname();
if (!name)
return NULL;
err = stat_file(name, &i_ino, &i_mode, &i_nlink, &ino->i_uid,
&ino->i_gid, &i_size, &ino->i_atime, &ino->i_mtime,
&ino->i_ctime, &i_blksize, &i_blocks, -1);
if (err)
return err;
ino->i_ino = i_ino;
ino->i_mode = i_mode;
ino->i_nlink = i_nlink;
ino->i_size = i_size;
ino->i_blocks = i_blocks;
return 0;
spin_lock(&dcache_lock);
if (list_empty(&ino->i_dentry)) {
spin_unlock(&dcache_lock);
__putname(name);
return NULL;
}
dentry = list_first_entry(&ino->i_dentry, struct dentry, d_alias);
return __dentry_name(dentry, name); /* will unlock */
}
static char *follow_link(char *link)
@ -205,53 +192,11 @@ static char *follow_link(char *link)
return ERR_PTR(n);
}
static int hostfs_read_inode(struct inode *ino)
{
char *name;
int err = 0;
/*
* Unfortunately, we are called from iget() when we don't have a dentry
* allocated yet.
*/
if (list_empty(&ino->i_dentry))
goto out;
err = -ENOMEM;
name = inode_name(ino, 0);
if (name == NULL)
goto out;
if (file_type(name, NULL, NULL) == OS_TYPE_SYMLINK) {
name = follow_link(name);
if (IS_ERR(name)) {
err = PTR_ERR(name);
goto out;
}
}
err = read_name(ino, name);
kfree(name);
out:
return err;
}
static struct inode *hostfs_iget(struct super_block *sb)
{
struct inode *inode;
long ret;
inode = iget_locked(sb, 0);
struct inode *inode = new_inode(sb);
if (!inode)
return ERR_PTR(-ENOMEM);
if (inode->i_state & I_NEW) {
ret = hostfs_read_inode(inode);
if (ret < 0) {
iget_failed(inode);
return ERR_PTR(ret);
}
unlock_new_inode(inode);
}
return inode;
}
@ -269,7 +214,7 @@ int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
long long f_files;
long long f_ffree;
err = do_statfs(HOSTFS_I(dentry->d_sb->s_root->d_inode)->host_filename,
err = do_statfs(dentry->d_sb->s_fs_info,
&sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
&f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
&sf->f_namelen, sf->f_spare);
@ -288,47 +233,32 @@ static struct inode *hostfs_alloc_inode(struct super_block *sb)
{
struct hostfs_inode_info *hi;
hi = kmalloc(sizeof(*hi), GFP_KERNEL);
hi = kzalloc(sizeof(*hi), GFP_KERNEL);
if (hi == NULL)
return NULL;
*hi = ((struct hostfs_inode_info) { .host_filename = NULL,
.fd = -1,
.mode = 0 });
hi->fd = -1;
inode_init_once(&hi->vfs_inode);
return &hi->vfs_inode;
}
static void hostfs_delete_inode(struct inode *inode)
static void hostfs_evict_inode(struct inode *inode)
{
truncate_inode_pages(&inode->i_data, 0);
end_writeback(inode);
if (HOSTFS_I(inode)->fd != -1) {
close_file(&HOSTFS_I(inode)->fd);
HOSTFS_I(inode)->fd = -1;
}
clear_inode(inode);
}
static void hostfs_destroy_inode(struct inode *inode)
{
kfree(HOSTFS_I(inode)->host_filename);
/*
* XXX: This should not happen, probably. The check is here for
* additional safety.
*/
if (HOSTFS_I(inode)->fd != -1) {
close_file(&HOSTFS_I(inode)->fd);
printk(KERN_DEBUG "Closing host fd in .destroy_inode\n");
}
kfree(HOSTFS_I(inode));
}
static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
{
struct inode *root = vfs->mnt_sb->s_root->d_inode;
const char *root_path = HOSTFS_I(root)->host_filename;
const char *root_path = vfs->mnt_sb->s_fs_info;
size_t offset = strlen(root_ino) + 1;
if (strlen(root_path) > offset)
@ -339,9 +269,8 @@ static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
static const struct super_operations hostfs_sbops = {
.alloc_inode = hostfs_alloc_inode,
.drop_inode = generic_delete_inode,
.delete_inode = hostfs_delete_inode,
.destroy_inode = hostfs_destroy_inode,
.evict_inode = hostfs_evict_inode,
.statfs = hostfs_statfs,
.show_options = hostfs_show_options,
};
@ -353,11 +282,11 @@ int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
unsigned long long next, ino;
int error, len;
name = dentry_name(file->f_path.dentry, 0);
name = dentry_name(file->f_path.dentry);
if (name == NULL)
return -ENOMEM;
dir = open_dir(name, &error);
kfree(name);
__putname(name);
if (dir == NULL)
return -error;
next = file->f_pos;
@ -373,40 +302,59 @@ int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
int hostfs_file_open(struct inode *ino, struct file *file)
{
static DEFINE_MUTEX(open_mutex);
char *name;
fmode_t mode = 0;
int err;
int r = 0, w = 0, fd;
mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
if ((mode & HOSTFS_I(ino)->mode) == mode)
return 0;
/*
* The file may already have been opened, but with the wrong access,
* so this resets things and reopens the file with the new access.
*/
if (HOSTFS_I(ino)->fd != -1) {
close_file(&HOSTFS_I(ino)->fd);
HOSTFS_I(ino)->fd = -1;
}
mode |= HOSTFS_I(ino)->mode;
HOSTFS_I(ino)->mode |= mode;
if (HOSTFS_I(ino)->mode & FMODE_READ)
retry:
if (mode & FMODE_READ)
r = 1;
if (HOSTFS_I(ino)->mode & FMODE_WRITE)
if (mode & FMODE_WRITE)
w = 1;
if (w)
r = 1;
name = dentry_name(file->f_path.dentry, 0);
name = dentry_name(file->f_path.dentry);
if (name == NULL)
return -ENOMEM;
fd = open_file(name, r, w, append);
kfree(name);
__putname(name);
if (fd < 0)
return fd;
FILE_HOSTFS_I(file)->fd = fd;
mutex_lock(&open_mutex);
/* somebody else had handled it first? */
if ((mode & HOSTFS_I(ino)->mode) == mode) {
mutex_unlock(&open_mutex);
return 0;
}
if ((mode | HOSTFS_I(ino)->mode) != mode) {
mode |= HOSTFS_I(ino)->mode;
mutex_unlock(&open_mutex);
close_file(&fd);
goto retry;
}
if (HOSTFS_I(ino)->fd == -1) {
HOSTFS_I(ino)->fd = fd;
} else {
err = replace_file(fd, HOSTFS_I(ino)->fd);
close_file(&fd);
if (err < 0) {
mutex_unlock(&open_mutex);
return err;
}
}
HOSTFS_I(ino)->mode = mode;
mutex_unlock(&open_mutex);
return 0;
}
@ -544,54 +492,50 @@ static const struct address_space_operations hostfs_aops = {
.write_end = hostfs_write_end,
};
static int init_inode(struct inode *inode, struct dentry *dentry)
static int read_name(struct inode *ino, char *name)
{
char *name;
int type, err = -ENOMEM;
int maj, min;
dev_t rdev = 0;
dev_t rdev;
struct hostfs_stat st;
int err = stat_file(name, &st, -1);
if (err)
return err;
if (dentry) {
name = dentry_name(dentry, 0);
if (name == NULL)
goto out;
type = file_type(name, &maj, &min);
/* Reencode maj and min with the kernel encoding.*/
rdev = MKDEV(maj, min);
kfree(name);
/* Reencode maj and min with the kernel encoding.*/
rdev = MKDEV(st.maj, st.min);
switch (st.mode & S_IFMT) {
case S_IFLNK:
ino->i_op = &hostfs_link_iops;
break;
case S_IFDIR:
ino->i_op = &hostfs_dir_iops;
ino->i_fop = &hostfs_dir_fops;
break;
case S_IFCHR:
case S_IFBLK:
case S_IFIFO:
case S_IFSOCK:
init_special_inode(ino, st.mode & S_IFMT, rdev);
ino->i_op = &hostfs_iops;
break;
default:
ino->i_op = &hostfs_iops;
ino->i_fop = &hostfs_file_fops;
ino->i_mapping->a_ops = &hostfs_aops;
}
else type = OS_TYPE_DIR;
err = 0;
if (type == OS_TYPE_SYMLINK)
inode->i_op = &page_symlink_inode_operations;
else if (type == OS_TYPE_DIR)
inode->i_op = &hostfs_dir_iops;
else inode->i_op = &hostfs_iops;
if (type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops;
else inode->i_fop = &hostfs_file_fops;
if (type == OS_TYPE_SYMLINK)
inode->i_mapping->a_ops = &hostfs_link_aops;
else inode->i_mapping->a_ops = &hostfs_aops;
switch (type) {
case OS_TYPE_CHARDEV:
init_special_inode(inode, S_IFCHR, rdev);
break;
case OS_TYPE_BLOCKDEV:
init_special_inode(inode, S_IFBLK, rdev);
break;
case OS_TYPE_FIFO:
init_special_inode(inode, S_IFIFO, 0);
break;
case OS_TYPE_SOCK:
init_special_inode(inode, S_IFSOCK, 0);
break;
}
out:
return err;
ino->i_ino = st.ino;
ino->i_mode = st.mode;
ino->i_nlink = st.nlink;
ino->i_uid = st.uid;
ino->i_gid = st.gid;
ino->i_atime = st.atime;
ino->i_mtime = st.mtime;
ino->i_ctime = st.ctime;
ino->i_size = st.size;
ino->i_blocks = st.blocks;
return 0;
}
int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
@ -607,12 +551,8 @@ int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
goto out;
}
error = init_inode(inode, dentry);
if (error)
goto out_put;
error = -ENOMEM;
name = dentry_name(dentry, 0);
name = dentry_name(dentry);
if (name == NULL)
goto out_put;
@ -622,9 +562,10 @@ int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
if (fd < 0)
error = fd;
else error = read_name(inode, name);
else
error = read_name(inode, name);
kfree(name);
__putname(name);
if (error)
goto out_put;
@ -652,17 +593,14 @@ struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
goto out;
}
err = init_inode(inode, dentry);
if (err)
goto out_put;
err = -ENOMEM;
name = dentry_name(dentry, 0);
name = dentry_name(dentry);
if (name == NULL)
goto out_put;
err = read_name(inode, name);
kfree(name);
__putname(name);
if (err == -ENOENT) {
iput(inode);
inode = NULL;
@ -680,36 +618,21 @@ struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
return ERR_PTR(err);
}
static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
{
char *file;
int len;
file = inode_name(ino, dentry->d_name.len + 1);
if (file == NULL)
return NULL;
strcat(file, "/");
len = strlen(file);
strncat(file, dentry->d_name.name, dentry->d_name.len);
file[len + dentry->d_name.len] = '\0';
return file;
}
int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
{
char *from_name, *to_name;
int err;
if ((from_name = inode_dentry_name(ino, from)) == NULL)
if ((from_name = dentry_name(from)) == NULL)
return -ENOMEM;
to_name = dentry_name(to, 0);
to_name = dentry_name(to);
if (to_name == NULL) {
kfree(from_name);
__putname(from_name);
return -ENOMEM;
}
err = link_file(to_name, from_name);
kfree(from_name);
kfree(to_name);
__putname(from_name);
__putname(to_name);
return err;
}
@ -718,13 +641,14 @@ int hostfs_unlink(struct inode *ino, struct dentry *dentry)
char *file;
int err;
if ((file = inode_dentry_name(ino, dentry)) == NULL)
return -ENOMEM;
if (append)
return -EPERM;
if ((file = dentry_name(dentry)) == NULL)
return -ENOMEM;
err = unlink_file(file);
kfree(file);
__putname(file);
return err;
}
@ -733,10 +657,10 @@ int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
char *file;
int err;
if ((file = inode_dentry_name(ino, dentry)) == NULL)
if ((file = dentry_name(dentry)) == NULL)
return -ENOMEM;
err = make_symlink(file, to);
kfree(file);
__putname(file);
return err;
}
@ -745,10 +669,10 @@ int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
char *file;
int err;
if ((file = inode_dentry_name(ino, dentry)) == NULL)
if ((file = dentry_name(dentry)) == NULL)
return -ENOMEM;
err = do_mkdir(file, mode);
kfree(file);
__putname(file);
return err;
}
@ -757,10 +681,10 @@ int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
char *file;
int err;
if ((file = inode_dentry_name(ino, dentry)) == NULL)
if ((file = dentry_name(dentry)) == NULL)
return -ENOMEM;
err = do_rmdir(file);
kfree(file);
__putname(file);
return err;
}
@ -776,22 +700,20 @@ int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
goto out;
}
err = init_inode(inode, dentry);
if (err)
goto out_put;
err = -ENOMEM;
name = dentry_name(dentry, 0);
name = dentry_name(dentry);
if (name == NULL)
goto out_put;
init_special_inode(inode, mode, dev);
err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
if (err)
if (!err)
goto out_free;
err = read_name(inode, name);
kfree(name);
__putname(name);
if (err)
goto out_put;
if (err)
goto out_put;
@ -799,7 +721,7 @@ int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
return 0;
out_free:
kfree(name);
__putname(name);
out_put:
iput(inode);
out:
@ -812,15 +734,15 @@ int hostfs_rename(struct inode *from_ino, struct dentry *from,
char *from_name, *to_name;
int err;
if ((from_name = inode_dentry_name(from_ino, from)) == NULL)
if ((from_name = dentry_name(from)) == NULL)
return -ENOMEM;
if ((to_name = inode_dentry_name(to_ino, to)) == NULL) {
kfree(from_name);
if ((to_name = dentry_name(to)) == NULL) {
__putname(from_name);
return -ENOMEM;
}
err = rename_file(from_name, to_name);
kfree(from_name);
kfree(to_name);
__putname(from_name);
__putname(to_name);
return err;
}
@ -832,7 +754,7 @@ int hostfs_permission(struct inode *ino, int desired)
if (desired & MAY_READ) r = 1;
if (desired & MAY_WRITE) w = 1;
if (desired & MAY_EXEC) x = 1;
name = inode_name(ino, 0);
name = inode_name(ino);
if (name == NULL)
return -ENOMEM;
@ -841,7 +763,7 @@ int hostfs_permission(struct inode *ino, int desired)
err = 0;
else
err = access_file(name, r, w, x);
kfree(name);
__putname(name);
if (!err)
err = generic_permission(ino, desired, NULL);
return err;
@ -849,13 +771,14 @@ int hostfs_permission(struct inode *ino, int desired)
int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
{
struct inode *inode = dentry->d_inode;
struct hostfs_iattr attrs;
char *name;
int err;
int fd = HOSTFS_I(dentry->d_inode)->fd;
int fd = HOSTFS_I(inode)->fd;
err = inode_change_ok(dentry->d_inode, attr);
err = inode_change_ok(inode, attr);
if (err)
return err;
@ -897,15 +820,26 @@ int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
if (attr->ia_valid & ATTR_MTIME_SET) {
attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
}
name = dentry_name(dentry, 0);
name = dentry_name(dentry);
if (name == NULL)
return -ENOMEM;
err = set_attr(name, &attrs, fd);
kfree(name);
__putname(name);
if (err)
return err;
return inode_setattr(dentry->d_inode, attr);
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
int error;
error = vmtruncate(inode, attr->ia_size);
if (err)
return err;
}
setattr_copy(inode, attr);
mark_inode_dirty(inode);
return 0;
}
static const struct inode_operations hostfs_iops = {
@ -935,32 +869,41 @@ static const struct inode_operations hostfs_dir_iops = {
.setattr = hostfs_setattr,
};
int hostfs_link_readpage(struct file *file, struct page *page)
static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
char *buffer, *name;
int err;
buffer = kmap(page);
name = inode_name(page->mapping->host, 0);
if (name == NULL)
return -ENOMEM;
err = hostfs_do_readlink(name, buffer, PAGE_CACHE_SIZE);
kfree(name);
if (err == PAGE_CACHE_SIZE)
err = -E2BIG;
else if (err > 0) {
flush_dcache_page(page);
SetPageUptodate(page);
if (PageError(page)) ClearPageError(page);
err = 0;
char *link = __getname();
if (link) {
char *path = dentry_name(dentry);
int err = -ENOMEM;
if (path) {
int err = hostfs_do_readlink(path, link, PATH_MAX);
if (err == PATH_MAX)
err = -E2BIG;
__putname(path);
}
if (err < 0) {
__putname(link);
link = ERR_PTR(err);
}
} else {
link = ERR_PTR(-ENOMEM);
}
kunmap(page);
unlock_page(page);
return err;
nd_set_link(nd, link);
return NULL;
}
static const struct address_space_operations hostfs_link_aops = {
.readpage = hostfs_link_readpage,
static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
{
char *s = nd_get_link(nd);
if (!IS_ERR(s))
__putname(s);
}
static const struct inode_operations hostfs_link_iops = {
.readlink = generic_readlink,
.follow_link = hostfs_follow_link,
.put_link = hostfs_put_link,
};
static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
@ -980,49 +923,41 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
req_root = "";
err = -ENOMEM;
host_root_path = kmalloc(strlen(root_ino) + 1
+ strlen(req_root) + 1, GFP_KERNEL);
sb->s_fs_info = host_root_path =
kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
if (host_root_path == NULL)
goto out;
sprintf(host_root_path, "%s/%s", root_ino, req_root);
root_inode = hostfs_iget(sb);
if (IS_ERR(root_inode)) {
err = PTR_ERR(root_inode);
goto out_free;
}
root_inode = new_inode(sb);
if (!root_inode)
goto out;
err = init_inode(root_inode, NULL);
err = read_name(root_inode, host_root_path);
if (err)
goto out_put;
HOSTFS_I(root_inode)->host_filename = host_root_path;
/*
* Avoid that in the error path, iput(root_inode) frees again
* host_root_path through hostfs_destroy_inode!
*/
host_root_path = NULL;
if (S_ISLNK(root_inode->i_mode)) {
char *name = follow_link(host_root_path);
if (IS_ERR(name))
err = PTR_ERR(name);
else
err = read_name(root_inode, name);
kfree(name);
if (err)
goto out_put;
}
err = -ENOMEM;
sb->s_root = d_alloc_root(root_inode);
if (sb->s_root == NULL)
goto out_put;
err = hostfs_read_inode(root_inode);
if (err) {
/* No iput in this case because the dput does that for us */
dput(sb->s_root);
sb->s_root = NULL;
goto out;
}
return 0;
out_put:
iput(root_inode);
out_free:
kfree(host_root_path);
out:
return err;
}
@ -1034,11 +969,17 @@ static int hostfs_read_sb(struct file_system_type *type,
return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt);
}
static void hostfs_kill_sb(struct super_block *s)
{
kill_anon_super(s);
kfree(s->s_fs_info);
}
static struct file_system_type hostfs_type = {
.owner = THIS_MODULE,
.name = "hostfs",
.get_sb = hostfs_read_sb,
.kill_sb = kill_anon_super,
.kill_sb = hostfs_kill_sb,
.fs_flags = 0,
};

View File

@ -19,11 +19,27 @@
#include "user.h"
#include <utime.h>
int stat_file(const char *path, unsigned long long *inode_out, int *mode_out,
int *nlink_out, int *uid_out, int *gid_out,
unsigned long long *size_out, struct timespec *atime_out,
struct timespec *mtime_out, struct timespec *ctime_out,
int *blksize_out, unsigned long long *blocks_out, int fd)
static void stat64_to_hostfs(const struct stat64 *buf, struct hostfs_stat *p)
{
p->ino = buf->st_ino;
p->mode = buf->st_mode;
p->nlink = buf->st_nlink;
p->uid = buf->st_uid;
p->gid = buf->st_gid;
p->size = buf->st_size;
p->atime.tv_sec = buf->st_atime;
p->atime.tv_nsec = 0;
p->ctime.tv_sec = buf->st_ctime;
p->ctime.tv_nsec = 0;
p->mtime.tv_sec = buf->st_mtime;
p->mtime.tv_nsec = 0;
p->blksize = buf->st_blksize;
p->blocks = buf->st_blocks;
p->maj = os_major(buf->st_rdev);
p->min = os_minor(buf->st_rdev);
}
int stat_file(const char *path, struct hostfs_stat *p, int fd)
{
struct stat64 buf;
@ -33,68 +49,10 @@ int stat_file(const char *path, unsigned long long *inode_out, int *mode_out,
} else if (lstat64(path, &buf) < 0) {
return -errno;
}
if (inode_out != NULL)
*inode_out = buf.st_ino;
if (mode_out != NULL)
*mode_out = buf.st_mode;
if (nlink_out != NULL)
*nlink_out = buf.st_nlink;
if (uid_out != NULL)
*uid_out = buf.st_uid;
if (gid_out != NULL)
*gid_out = buf.st_gid;
if (size_out != NULL)
*size_out = buf.st_size;
if (atime_out != NULL) {
atime_out->tv_sec = buf.st_atime;
atime_out->tv_nsec = 0;
}
if (mtime_out != NULL) {
mtime_out->tv_sec = buf.st_mtime;
mtime_out->tv_nsec = 0;
}
if (ctime_out != NULL) {
ctime_out->tv_sec = buf.st_ctime;
ctime_out->tv_nsec = 0;
}
if (blksize_out != NULL)
*blksize_out = buf.st_blksize;
if (blocks_out != NULL)
*blocks_out = buf.st_blocks;
stat64_to_hostfs(&buf, p);
return 0;
}
int file_type(const char *path, int *maj, int *min)
{
struct stat64 buf;
if (lstat64(path, &buf) < 0)
return -errno;
/*
* We cannot pass rdev as is because glibc and the kernel disagree
* about its definition.
*/
if (maj != NULL)
*maj = major(buf.st_rdev);
if (min != NULL)
*min = minor(buf.st_rdev);
if (S_ISDIR(buf.st_mode))
return OS_TYPE_DIR;
else if (S_ISLNK(buf.st_mode))
return OS_TYPE_SYMLINK;
else if (S_ISCHR(buf.st_mode))
return OS_TYPE_CHARDEV;
else if (S_ISBLK(buf.st_mode))
return OS_TYPE_BLOCKDEV;
else if (S_ISFIFO(buf.st_mode))
return OS_TYPE_FIFO;
else if (S_ISSOCK(buf.st_mode))
return OS_TYPE_SOCK;
else return OS_TYPE_FILE;
}
int access_file(char *path, int r, int w, int x)
{
int mode = 0;
@ -202,6 +160,11 @@ int fsync_file(int fd, int datasync)
return 0;
}
int replace_file(int oldfd, int fd)
{
return dup2(oldfd, fd);
}
void close_file(void *stream)
{
close(*((int *) stream));
@ -235,8 +198,8 @@ int file_create(char *name, int ur, int uw, int ux, int gr,
int set_attr(const char *file, struct hostfs_iattr *attrs, int fd)
{
struct hostfs_stat st;
struct timeval times[2];
struct timespec atime_ts, mtime_ts;
int err, ma;
if (attrs->ia_valid & HOSTFS_ATTR_MODE) {
@ -279,15 +242,14 @@ int set_attr(const char *file, struct hostfs_iattr *attrs, int fd)
*/
ma = (HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET);
if (attrs->ia_valid & ma) {
err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL,
&atime_ts, &mtime_ts, NULL, NULL, NULL, fd);
err = stat_file(file, &st, fd);
if (err != 0)
return err;
times[0].tv_sec = atime_ts.tv_sec;
times[0].tv_usec = atime_ts.tv_nsec / 1000;
times[1].tv_sec = mtime_ts.tv_sec;
times[1].tv_usec = mtime_ts.tv_nsec / 1000;
times[0].tv_sec = st.atime.tv_sec;
times[0].tv_usec = st.atime.tv_nsec / 1000;
times[1].tv_sec = st.mtime.tv_sec;
times[1].tv_usec = st.mtime.tv_nsec / 1000;
if (attrs->ia_valid & HOSTFS_ATTR_ATIME_SET) {
times[0].tv_sec = attrs->ia_atime.tv_sec;
@ -308,9 +270,9 @@ int set_attr(const char *file, struct hostfs_iattr *attrs, int fd)
/* Note: ctime is not handled */
if (attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)) {
err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL,
&attrs->ia_atime, &attrs->ia_mtime, NULL,
NULL, NULL, fd);
err = stat_file(file, &st, fd);
attrs->ia_atime = st.atime;
attrs->ia_mtime = st.mtime;
if (err != 0)
return err;
}
@ -361,7 +323,7 @@ int do_mknod(const char *file, int mode, unsigned int major, unsigned int minor)
{
int err;
err = mknod(file, mode, makedev(major, minor));
err = mknod(file, mode, os_makedev(major, minor));
if (err)
return -errno;
return 0;

View File

@ -97,10 +97,19 @@ static int hpfs_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
int ret;
*pagep = NULL;
return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
hpfs_get_block,
&hpfs_i(mapping->host)->mmu_private);
if (unlikely(ret)) {
loff_t isize = mapping->host->i_size;
if (pos + len > isize)
vmtruncate(mapping->host, isize);
}
return ret;
}
static sector_t _hpfs_bmap(struct address_space *mapping, sector_t block)

View File

@ -281,7 +281,7 @@ void hpfs_write_inode(struct inode *);
void hpfs_write_inode_nolock(struct inode *);
int hpfs_setattr(struct dentry *, struct iattr *);
void hpfs_write_if_changed(struct inode *);
void hpfs_delete_inode(struct inode *);
void hpfs_evict_inode(struct inode *);
/* map.c */

View File

@ -277,9 +277,15 @@ int hpfs_setattr(struct dentry *dentry, struct iattr *attr)
if (error)
goto out_unlock;
error = inode_setattr(inode, attr);
if (error)
goto out_unlock;
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
error = vmtruncate(inode, attr->ia_size);
if (error)
return error;
}
setattr_copy(inode, attr);
mark_inode_dirty(inode);
hpfs_write_inode(inode);
@ -296,11 +302,13 @@ void hpfs_write_if_changed(struct inode *inode)
hpfs_write_inode(inode);
}
void hpfs_delete_inode(struct inode *inode)
void hpfs_evict_inode(struct inode *inode)
{
truncate_inode_pages(&inode->i_data, 0);
lock_kernel();
hpfs_remove_fnode(inode->i_sb, inode->i_ino);
unlock_kernel();
clear_inode(inode);
end_writeback(inode);
if (!inode->i_nlink) {
lock_kernel();
hpfs_remove_fnode(inode->i_sb, inode->i_ino);
unlock_kernel();
}
}

View File

@ -450,7 +450,7 @@ static const struct super_operations hpfs_sops =
{
.alloc_inode = hpfs_alloc_inode,
.destroy_inode = hpfs_destroy_inode,
.delete_inode = hpfs_delete_inode,
.evict_inode = hpfs_evict_inode,
.put_super = hpfs_put_super,
.statfs = hpfs_statfs,
.remount_fs = hpfs_remount_fs,

View File

@ -15,6 +15,7 @@
#include <linux/slab.h>
#include <linux/statfs.h>
#include <linux/types.h>
#include <linux/pid_namespace.h>
#include <asm/uaccess.h>
#include "os.h"
@ -623,12 +624,11 @@ static struct inode *hppfs_alloc_inode(struct super_block *sb)
return &hi->vfs_inode;
}
void hppfs_delete_inode(struct inode *ino)
void hppfs_evict_inode(struct inode *ino)
{
end_writeback(ino);
dput(HPPFS_I(ino)->proc_dentry);
mntput(ino->i_sb->s_fs_info);
clear_inode(ino);
}
static void hppfs_destroy_inode(struct inode *inode)
@ -639,7 +639,7 @@ static void hppfs_destroy_inode(struct inode *inode)
static const struct super_operations hppfs_sbops = {
.alloc_inode = hppfs_alloc_inode,
.destroy_inode = hppfs_destroy_inode,
.delete_inode = hppfs_delete_inode,
.evict_inode = hppfs_evict_inode,
.statfs = hppfs_statfs,
};

View File

@ -371,27 +371,10 @@ static void truncate_hugepages(struct inode *inode, loff_t lstart)
hugetlb_unreserve_pages(inode, start, freed);
}
static void hugetlbfs_delete_inode(struct inode *inode)
static void hugetlbfs_evict_inode(struct inode *inode)
{
truncate_hugepages(inode, 0);
clear_inode(inode);
}
static void hugetlbfs_forget_inode(struct inode *inode) __releases(inode_lock)
{
if (generic_detach_inode(inode)) {
truncate_hugepages(inode, 0);
clear_inode(inode);
destroy_inode(inode);
}
}
static void hugetlbfs_drop_inode(struct inode *inode)
{
if (!inode->i_nlink)
generic_delete_inode(inode);
else
hugetlbfs_forget_inode(inode);
end_writeback(inode);
}
static inline void
@ -448,19 +431,20 @@ static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr)
error = inode_change_ok(inode, attr);
if (error)
goto out;
return error;
if (ia_valid & ATTR_SIZE) {
error = -EINVAL;
if (!(attr->ia_size & ~huge_page_mask(h)))
error = hugetlb_vmtruncate(inode, attr->ia_size);
if (attr->ia_size & ~huge_page_mask(h))
return -EINVAL;
error = hugetlb_vmtruncate(inode, attr->ia_size);
if (error)
goto out;
attr->ia_valid &= ~ATTR_SIZE;
return error;
}
error = inode_setattr(inode, attr);
out:
return error;
setattr_copy(inode, attr);
mark_inode_dirty(inode);
return 0;
}
static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid,
@ -712,9 +696,8 @@ static const struct inode_operations hugetlbfs_inode_operations = {
static const struct super_operations hugetlbfs_ops = {
.alloc_inode = hugetlbfs_alloc_inode,
.destroy_inode = hugetlbfs_destroy_inode,
.evict_inode = hugetlbfs_evict_inode,
.statfs = hugetlbfs_statfs,
.delete_inode = hugetlbfs_delete_inode,
.drop_inode = hugetlbfs_drop_inode,
.put_super = hugetlbfs_put_super,
.show_options = generic_show_options,
};

View File

@ -294,32 +294,34 @@ void __iget(struct inode *inode)
inodes_stat.nr_unused--;
}
/**
* clear_inode - clear an inode
* @inode: inode to clear
*
* This is called by the filesystem to tell us
* that the inode is no longer useful. We just
* terminate it with extreme prejudice.
*/
void clear_inode(struct inode *inode)
void end_writeback(struct inode *inode)
{
might_sleep();
invalidate_inode_buffers(inode);
BUG_ON(inode->i_data.nrpages);
BUG_ON(!list_empty(&inode->i_data.private_list));
BUG_ON(!(inode->i_state & I_FREEING));
BUG_ON(inode->i_state & I_CLEAR);
inode_sync_wait(inode);
if (inode->i_sb->s_op->clear_inode)
inode->i_sb->s_op->clear_inode(inode);
inode->i_state = I_FREEING | I_CLEAR;
}
EXPORT_SYMBOL(end_writeback);
static void evict(struct inode *inode)
{
const struct super_operations *op = inode->i_sb->s_op;
if (op->evict_inode) {
op->evict_inode(inode);
} else {
if (inode->i_data.nrpages)
truncate_inode_pages(&inode->i_data, 0);
end_writeback(inode);
}
if (S_ISBLK(inode->i_mode) && inode->i_bdev)
bd_forget(inode);
if (S_ISCHR(inode->i_mode) && inode->i_cdev)
cd_forget(inode);
inode->i_state = I_CLEAR;
}
EXPORT_SYMBOL(clear_inode);
/*
* dispose_list - dispose of the contents of a local list
@ -338,9 +340,7 @@ static void dispose_list(struct list_head *head)
inode = list_first_entry(head, struct inode, i_list);
list_del(&inode->i_list);
if (inode->i_data.nrpages)
truncate_inode_pages(&inode->i_data, 0);
clear_inode(inode);
evict(inode);
spin_lock(&inode_lock);
hlist_del_init(&inode->i_hash);
@ -553,7 +553,7 @@ static struct inode *find_inode(struct super_block *sb,
continue;
if (!test(inode, data))
continue;
if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)) {
if (inode->i_state & (I_FREEING|I_WILL_FREE)) {
__wait_on_freeing_inode(inode);
goto repeat;
}
@ -578,7 +578,7 @@ static struct inode *find_inode_fast(struct super_block *sb,
continue;
if (inode->i_sb != sb)
continue;
if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)) {
if (inode->i_state & (I_FREEING|I_WILL_FREE)) {
__wait_on_freeing_inode(inode);
goto repeat;
}
@ -840,7 +840,7 @@ EXPORT_SYMBOL(iunique);
struct inode *igrab(struct inode *inode)
{
spin_lock(&inode_lock);
if (!(inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)))
if (!(inode->i_state & (I_FREEING|I_WILL_FREE)))
__iget(inode);
else
/*
@ -1089,7 +1089,7 @@ int insert_inode_locked(struct inode *inode)
continue;
if (old->i_sb != sb)
continue;
if (old->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE))
if (old->i_state & (I_FREEING|I_WILL_FREE))
continue;
break;
}
@ -1128,7 +1128,7 @@ int insert_inode_locked4(struct inode *inode, unsigned long hashval,
continue;
if (!test(old, data))
continue;
if (old->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE))
if (old->i_state & (I_FREEING|I_WILL_FREE))
continue;
break;
}
@ -1180,69 +1180,51 @@ void remove_inode_hash(struct inode *inode)
}
EXPORT_SYMBOL(remove_inode_hash);
/*
* Tell the filesystem that this inode is no longer of any interest and should
* be completely destroyed.
*
* We leave the inode in the inode hash table until *after* the filesystem's
* ->delete_inode completes. This ensures that an iget (such as nfsd might
* instigate) will always find up-to-date information either in the hash or on
* disk.
*
* I_FREEING is set so that no-one will take a new reference to the inode while
* it is being deleted.
*/
void generic_delete_inode(struct inode *inode)
int generic_delete_inode(struct inode *inode)
{
const struct super_operations *op = inode->i_sb->s_op;
list_del_init(&inode->i_list);
list_del_init(&inode->i_sb_list);
WARN_ON(inode->i_state & I_NEW);
inode->i_state |= I_FREEING;
inodes_stat.nr_inodes--;
spin_unlock(&inode_lock);
if (op->delete_inode) {
void (*delete)(struct inode *) = op->delete_inode;
/* Filesystems implementing their own
* s_op->delete_inode are required to call
* truncate_inode_pages and clear_inode()
* internally */
delete(inode);
} else {
truncate_inode_pages(&inode->i_data, 0);
clear_inode(inode);
}
spin_lock(&inode_lock);
hlist_del_init(&inode->i_hash);
spin_unlock(&inode_lock);
wake_up_inode(inode);
BUG_ON(inode->i_state != I_CLEAR);
destroy_inode(inode);
return 1;
}
EXPORT_SYMBOL(generic_delete_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.
/*
* Normal UNIX filesystem behaviour: delete the
* inode when the usage count drops to zero, and
* i_nlink is zero.
*/
int generic_detach_inode(struct inode *inode)
int generic_drop_inode(struct inode *inode)
{
return !inode->i_nlink || hlist_unhashed(&inode->i_hash);
}
EXPORT_SYMBOL_GPL(generic_drop_inode);
/*
* Called when we're dropping the last reference
* to an inode.
*
* Call the FS "drop_inode()" function, defaulting to
* the legacy UNIX filesystem behaviour. If it tells
* us to evict inode, do so. Otherwise, retain inode
* in cache if fs is alive, sync and evict if fs is
* shutting down.
*/
static void iput_final(struct inode *inode)
{
struct super_block *sb = inode->i_sb;
const struct super_operations *op = inode->i_sb->s_op;
int drop;
if (!hlist_unhashed(&inode->i_hash)) {
if (op && op->drop_inode)
drop = op->drop_inode(inode);
else
drop = generic_drop_inode(inode);
if (!drop) {
if (!(inode->i_state & (I_DIRTY|I_SYNC)))
list_move(&inode->i_list, &inode_unused);
inodes_stat.nr_unused++;
if (sb->s_flags & MS_ACTIVE) {
spin_unlock(&inode_lock);
return 0;
return;
}
WARN_ON(inode->i_state & I_NEW);
inode->i_state |= I_WILL_FREE;
@ -1260,56 +1242,15 @@ int generic_detach_inode(struct inode *inode)
inode->i_state |= I_FREEING;
inodes_stat.nr_inodes--;
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)
truncate_inode_pages(&inode->i_data, 0);
clear_inode(inode);
evict(inode);
spin_lock(&inode_lock);
hlist_del_init(&inode->i_hash);
spin_unlock(&inode_lock);
wake_up_inode(inode);
BUG_ON(inode->i_state != (I_FREEING | I_CLEAR));
destroy_inode(inode);
}
/*
* Normal UNIX filesystem behaviour: delete the
* inode when the usage count drops to zero, and
* i_nlink is zero.
*/
void generic_drop_inode(struct inode *inode)
{
if (!inode->i_nlink)
generic_delete_inode(inode);
else
generic_forget_inode(inode);
}
EXPORT_SYMBOL_GPL(generic_drop_inode);
/*
* Called when we're dropping the last reference
* to an inode.
*
* Call the FS "drop()" function, defaulting to
* the legacy UNIX filesystem behaviour..
*
* NOTE! NOTE! NOTE! We're called with the inode lock
* held, and the drop function is supposed to release
* the lock!
*/
static inline void iput_final(struct inode *inode)
{
const struct super_operations *op = inode->i_sb->s_op;
void (*drop)(struct inode *) = generic_drop_inode;
if (op && op->drop_inode)
drop = op->drop_inode;
drop(inode);
}
/**
* iput - put an inode
* @inode: inode to put
@ -1322,7 +1263,7 @@ static inline void iput_final(struct inode *inode)
void iput(struct inode *inode)
{
if (inode) {
BUG_ON(inode->i_state == I_CLEAR);
BUG_ON(inode->i_state & I_CLEAR);
if (atomic_dec_and_lock(&inode->i_count, &inode_lock))
iput_final(inode);

View File

@ -232,9 +232,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
return 0;
fail:
make_bad_inode(inode);
unlock_new_inode(inode);
iput(inode);
iget_failed(inode);
jffs2_free_raw_inode(ri);
return ret;
}
@ -454,9 +452,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
return 0;
fail:
make_bad_inode(inode);
unlock_new_inode(inode);
iput(inode);
iget_failed(inode);
return ret;
}
@ -601,9 +597,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
return 0;
fail:
make_bad_inode(inode);
unlock_new_inode(inode);
iput(inode);
iget_failed(inode);
return ret;
}
@ -778,9 +772,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
return 0;
fail:
make_bad_inode(inode);
unlock_new_inode(inode);
iput(inode);
iget_failed(inode);
return ret;
}

View File

@ -169,13 +169,13 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
mutex_unlock(&f->sem);
jffs2_complete_reservation(c);
/* We have to do the simple_setsize() without f->sem held, since
/* We have to do the truncate_setsize() without f->sem held, since
some pages may be locked and waiting for it in readpage().
We are protected from a simultaneous write() extending i_size
back past iattr->ia_size, because do_truncate() holds the
generic inode semaphore. */
if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) {
simple_setsize(inode, iattr->ia_size);
truncate_setsize(inode, iattr->ia_size);
inode->i_blocks = (inode->i_size + 511) >> 9;
}
@ -225,7 +225,7 @@ int jffs2_statfs(struct dentry *dentry, struct kstatfs *buf)
}
void jffs2_clear_inode (struct inode *inode)
void jffs2_evict_inode (struct inode *inode)
{
/* We can forget about this inode for now - drop all
* the nodelists associated with it, etc.
@ -233,7 +233,9 @@ void jffs2_clear_inode (struct inode *inode)
struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
D1(printk(KERN_DEBUG "jffs2_evict_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
truncate_inode_pages(&inode->i_data, 0);
end_writeback(inode);
jffs2_do_clear_inode(c, f);
}

View File

@ -171,7 +171,7 @@ extern const struct inode_operations jffs2_symlink_inode_operations;
int jffs2_setattr (struct dentry *, struct iattr *);
int jffs2_do_setattr (struct inode *, struct iattr *);
struct inode *jffs2_iget(struct super_block *, unsigned long);
void jffs2_clear_inode (struct inode *);
void jffs2_evict_inode (struct inode *);
void jffs2_dirty_inode(struct inode *inode);
struct inode *jffs2_new_inode (struct inode *dir_i, int mode,
struct jffs2_raw_inode *ri);

View File

@ -135,7 +135,7 @@ static const struct super_operations jffs2_super_operations =
.write_super = jffs2_write_super,
.statfs = jffs2_statfs,
.remount_fs = jffs2_remount_fs,
.clear_inode = jffs2_clear_inode,
.evict_inode = jffs2_evict_inode,
.dirty_inode = jffs2_dirty_inode,
.sync_fs = jffs2_sync_fs,
};

Some files were not shown because too many files have changed in this diff Show More