dect
/
linux-2.6
Archived
13
0
Fork 0

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 @@ out:
}
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,11 +968,17 @@ int pohmelfs_setattr_raw(struct inode *inode, struct iattr *attr)
goto err_out_exit;
}
err = inode_setattr(inode, attr);
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,
@ -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 @@ error:
* @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;
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
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,8 +548,6 @@ 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_free_bitmap(sb);
} else

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 @@ out_big:
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 @@ error:
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;
di = find_inode(s, inode->i_ino, &bh);
if (IS_ERR(di))
return;
}
inode->i_size = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
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 @@ out3:
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 (!err && ((attr->ia_valid & ATTR_MODE)))
if (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 @@ again:
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 @@ again:
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 @@ free:
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,
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;
return block_prepare_write(page, start, start + len, get_block);
}
*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;
}
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 @@ out:
* 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 @@ out_release:
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 */
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;
else
rc = 0;
}
full_path = build_path_from_dentry(direntry);
if (full_path == NULL) {
@ -1908,8 +1896,15 @@ 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;
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
@ -1917,9 +1912,8 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
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)))
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 */
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;
} else
rc = 0;
}
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,29 +39,9 @@ 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 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;
@ -86,17 +66,26 @@ static struct inode *get_cramfs_inode(struct super_block *sb,
init_special_inode(inode, inode->i_mode,
old_decode_dev(cramfs_inode->size));
}
unlock_new_inode(inode);
}
return inode;
}
static void cramfs_drop_inode(struct inode *inode)
static struct inode *get_cramfs_inode(struct super_block *sb,
struct cramfs_inode * cramfs_inode)
{
if (inode->i_ino == 1)
generic_delete_inode(inode);
else
generic_drop_inode(inode);
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);
}
}
return inode;
}
/*
@ -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 @@ restart:
*/
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));
if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
rc = simple_setsize(inode, ia->ia_size);
/*
* 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)) {
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);
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 @@ do_more:
error_return:
brelse(bitmap_bh);
release_blocks(sb, freed);
dquot_free_block(inode, freed);
dquot_free_block_nodirty(inode, freed);
}
/**
@ -1418,7 +1418,8 @@ allocated:
*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 @@ out:
/*
* 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 @@ out_unlock:
*/
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 @@ out:
*/
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);
}
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;
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);
ext2_free_inode (inode);
}
return;
no_delete:
clear_inode(inode); /* We must guarantee clearing of inode... */
invalidate_inode_buffers(inode);
end_writeback(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 @@ again:
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 @@ retry:
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 @@ retry:
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 @@ out_stop:
* 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 @@ again:
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 @@ retry:
*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 @@ retry:
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 @@ retry:
}
*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 @@ again:
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,7 +212,7 @@ 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,
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 @@ out:
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);
if (!inode->i_nlink) {
inode->i_size = 0;
fat_truncate_blocks(inode, 0);
clear_inode(inode);
}
static void fat_clear_inode(struct inode *inode)
{
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) {
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 @@ out:
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 @@ fail:
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);
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);
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 error;
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);
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 @@ out_unlock:
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 @@ fail:
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);
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 @@ out:
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 ((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;
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);
}
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:
dev_t rdev;
struct hostfs_stat st;
int err = stat_file(name, &st, -1);
if (err)
return err;
/* 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;
}
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)
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;
else if (err > 0) {
flush_dcache_page(page);
SetPageUptodate(page);
if (PageError(page)) ClearPageError(page);
err = 0;
__putname(path);
}
kunmap(page);
unlock_page(page);
return err;
if (err < 0) {
__putname(link);
link = ERR_PTR(err);
}
} else {
link = ERR_PTR(-ENOMEM);
}
static const struct address_space_operations hostfs_link_aops = {
.readpage = hostfs_link_readpage,
nd_set_link(nd, link);
return NULL;
}
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 ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
error = vmtruncate(inode, attr->ia_size);
if (error)
goto out_unlock;
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);
end_writeback(inode);
if (!inode->i_nlink) {
lock_kernel();
hpfs_remove_fnode(inode->i_sb, inode->i_ino);
unlock_kernel();
clear_inode(inode);
}
}

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,21 +431,22 @@ 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)))
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;
}
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,
gid_t gid, int mode, dev_t dev)
{
@ -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 @@ repeat:
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 @@ repeat:
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