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:
commit
5f248c9c25
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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__ */
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -968,12 +968,18 @@ int pohmelfs_setattr_raw(struct inode *inode, struct iattr *attr)
|
||||
goto err_out_exit;
|
||||
}
|
||||
|
||||
err = inode_setattr(inode, attr);
|
||||
if (err) {
|
||||
dprintk("%s: ino: %llu, failed to set the attributes.\n", __func__, POHMELFS_I(inode)->ino);
|
||||
goto err_out_exit;
|
||||
if ((attr->ia_valid & ATTR_SIZE) &&
|
||||
attr->ia_size != i_size_read(inode)) {
|
||||
err = vmtruncate(inode, attr->ia_size);
|
||||
if (err) {
|
||||
dprintk("%s: ino: %llu, failed to set the attributes.\n", __func__, POHMELFS_I(inode)->ino);
|
||||
goto err_out_exit;
|
||||
}
|
||||
}
|
||||
|
||||
setattr_copy(inode, attr);
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
dprintk("%s: ino: %llu, mode: %o -> %o, uid: %u -> %u, gid: %u -> %u, size: %llu -> %llu.\n",
|
||||
__func__, POHMELFS_I(inode)->ino, inode->i_mode, attr->ia_mode,
|
||||
inode->i_uid, attr->ia_uid, inode->i_gid, attr->ia_gid, inode->i_size, attr->ia_size);
|
||||
@ -1217,7 +1223,7 @@ void pohmelfs_fill_inode(struct inode *inode, struct netfs_inode_info *info)
|
||||
}
|
||||
}
|
||||
|
||||
static void pohmelfs_drop_inode(struct inode *inode)
|
||||
static int pohmelfs_drop_inode(struct inode *inode)
|
||||
{
|
||||
struct pohmelfs_sb *psb = POHMELFS_SB(inode->i_sb);
|
||||
struct pohmelfs_inode *pi = POHMELFS_I(inode);
|
||||
@ -1226,7 +1232,7 @@ static void pohmelfs_drop_inode(struct inode *inode)
|
||||
list_del_init(&pi->inode_entry);
|
||||
spin_unlock(&psb->ino_lock);
|
||||
|
||||
generic_drop_inode(inode);
|
||||
return generic_drop_inode(inode);
|
||||
}
|
||||
|
||||
static struct pohmelfs_inode *pohmelfs_get_inode_from_list(struct pohmelfs_sb *psb,
|
||||
|
@ -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 *);
|
||||
|
@ -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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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 *
|
||||
|
@ -26,7 +26,7 @@ static int affs_statfs(struct dentry *dentry, struct kstatfs *buf);
|
||||
static int affs_remount (struct super_block *sb, int *flags, char *data);
|
||||
|
||||
static void
|
||||
affs_commit_super(struct super_block *sb, int clean)
|
||||
affs_commit_super(struct super_block *sb, int wait, int clean)
|
||||
{
|
||||
struct affs_sb_info *sbi = AFFS_SB(sb);
|
||||
struct buffer_head *bh = sbi->s_root_bh;
|
||||
@ -36,6 +36,8 @@ affs_commit_super(struct super_block *sb, int clean)
|
||||
secs_to_datestamp(get_seconds(), &tail->disk_change);
|
||||
affs_fix_checksum(sb, bh);
|
||||
mark_buffer_dirty(bh);
|
||||
if (wait)
|
||||
sync_dirty_buffer(bh);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -46,8 +48,8 @@ affs_put_super(struct super_block *sb)
|
||||
|
||||
lock_kernel();
|
||||
|
||||
if (!(sb->s_flags & MS_RDONLY))
|
||||
affs_commit_super(sb, 1);
|
||||
if (!(sb->s_flags & MS_RDONLY) && sb->s_dirt)
|
||||
affs_commit_super(sb, 1, 1);
|
||||
|
||||
kfree(sbi->s_prefix);
|
||||
affs_free_bitmap(sb);
|
||||
@ -61,27 +63,20 @@ affs_put_super(struct super_block *sb)
|
||||
static void
|
||||
affs_write_super(struct super_block *sb)
|
||||
{
|
||||
int clean = 2;
|
||||
|
||||
lock_super(sb);
|
||||
if (!(sb->s_flags & MS_RDONLY)) {
|
||||
// if (sbi->s_bitmap[i].bm_bh) {
|
||||
// if (buffer_dirty(sbi->s_bitmap[i].bm_bh)) {
|
||||
// clean = 0;
|
||||
affs_commit_super(sb, clean);
|
||||
sb->s_dirt = !clean; /* redo until bitmap synced */
|
||||
} else
|
||||
sb->s_dirt = 0;
|
||||
if (!(sb->s_flags & MS_RDONLY))
|
||||
affs_commit_super(sb, 1, 2);
|
||||
sb->s_dirt = 0;
|
||||
unlock_super(sb);
|
||||
|
||||
pr_debug("AFFS: write_super() at %lu, clean=%d\n", get_seconds(), clean);
|
||||
pr_debug("AFFS: write_super() at %lu, clean=2\n", get_seconds());
|
||||
}
|
||||
|
||||
static int
|
||||
affs_sync_fs(struct super_block *sb, int wait)
|
||||
{
|
||||
lock_super(sb);
|
||||
affs_commit_super(sb, 2);
|
||||
affs_commit_super(sb, wait, 2);
|
||||
sb->s_dirt = 0;
|
||||
unlock_super(sb);
|
||||
return 0;
|
||||
@ -140,8 +135,7 @@ static const struct super_operations affs_sops = {
|
||||
.alloc_inode = affs_alloc_inode,
|
||||
.destroy_inode = affs_destroy_inode,
|
||||
.write_inode = affs_write_inode,
|
||||
.delete_inode = affs_delete_inode,
|
||||
.clear_inode = affs_clear_inode,
|
||||
.evict_inode = affs_evict_inode,
|
||||
.put_super = affs_put_super,
|
||||
.write_super = affs_write_super,
|
||||
.sync_fs = affs_sync_fs,
|
||||
@ -554,9 +548,7 @@ affs_remount(struct super_block *sb, int *flags, char *data)
|
||||
return 0;
|
||||
}
|
||||
if (*flags & MS_RDONLY) {
|
||||
sb->s_dirt = 1;
|
||||
while (sb->s_dirt)
|
||||
affs_write_super(sb);
|
||||
affs_write_super(sb);
|
||||
affs_free_bitmap(sb);
|
||||
} else
|
||||
res = affs_init_bitmap(sb, flags);
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
};
|
||||
|
88
fs/attr.c
88
fs/attr.c
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
|
118
fs/bfs/inode.c
118
fs/bfs/inode.c
@ -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;
|
||||
}
|
||||
|
||||
inode->i_size = 0;
|
||||
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
|
||||
|
||||
di = find_inode(s, inode->i_ino, &bh);
|
||||
if (IS_ERR(di))
|
||||
return;
|
||||
|
||||
mutex_lock(&info->bfs_lock);
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
block = (ino - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1;
|
||||
bh = sb_bread(s, block);
|
||||
if (!bh) {
|
||||
printf("Unable to read inode %s:%08lx\n",
|
||||
inode->i_sb->s_id, ino);
|
||||
mutex_unlock(&info->bfs_lock);
|
||||
return;
|
||||
}
|
||||
off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;
|
||||
di = (struct bfs_inode *)bh->b_data + off;
|
||||
memset((void *)di, 0, sizeof(struct bfs_inode));
|
||||
/* clear on-disk inode */
|
||||
memset(di, 0, sizeof(struct bfs_inode));
|
||||
mark_buffer_dirty(bh);
|
||||
brelse(bh);
|
||||
|
||||
@ -209,32 +203,9 @@ static void bfs_delete_inode(struct inode *inode)
|
||||
* "last block of the last file" even if there is no
|
||||
* real file there, saves us 1 gap.
|
||||
*/
|
||||
if (info->si_lf_eblk == bi->i_eblock) {
|
||||
if (info->si_lf_eblk == bi->i_eblock)
|
||||
info->si_lf_eblk = bi->i_sblock - 1;
|
||||
mark_buffer_dirty(info->si_sbh);
|
||||
}
|
||||
mutex_unlock(&info->bfs_lock);
|
||||
clear_inode(inode);
|
||||
}
|
||||
|
||||
static int bfs_sync_fs(struct super_block *sb, int wait)
|
||||
{
|
||||
struct bfs_sb_info *info = BFS_SB(sb);
|
||||
|
||||
mutex_lock(&info->bfs_lock);
|
||||
mark_buffer_dirty(info->si_sbh);
|
||||
sb->s_dirt = 0;
|
||||
mutex_unlock(&info->bfs_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bfs_write_super(struct super_block *sb)
|
||||
{
|
||||
if (!(sb->s_flags & MS_RDONLY))
|
||||
bfs_sync_fs(sb, 1);
|
||||
else
|
||||
sb->s_dirt = 0;
|
||||
}
|
||||
|
||||
static void bfs_put_super(struct super_block *s)
|
||||
@ -246,10 +217,6 @@ static void bfs_put_super(struct super_block *s)
|
||||
|
||||
lock_kernel();
|
||||
|
||||
if (s->s_dirt)
|
||||
bfs_write_super(s);
|
||||
|
||||
brelse(info->si_sbh);
|
||||
mutex_destroy(&info->bfs_lock);
|
||||
kfree(info->si_imap);
|
||||
kfree(info);
|
||||
@ -319,10 +286,8 @@ static const struct super_operations bfs_sops = {
|
||||
.alloc_inode = bfs_alloc_inode,
|
||||
.destroy_inode = bfs_destroy_inode,
|
||||
.write_inode = bfs_write_inode,
|
||||
.delete_inode = bfs_delete_inode,
|
||||
.evict_inode = bfs_evict_inode,
|
||||
.put_super = bfs_put_super,
|
||||
.write_super = bfs_write_super,
|
||||
.sync_fs = bfs_sync_fs,
|
||||
.statfs = bfs_statfs,
|
||||
};
|
||||
|
||||
@ -349,7 +314,7 @@ void dump_imap(const char *prefix, struct super_block *s)
|
||||
|
||||
static int bfs_fill_super(struct super_block *s, void *data, int silent)
|
||||
{
|
||||
struct buffer_head *bh;
|
||||
struct buffer_head *bh, *sbh;
|
||||
struct bfs_super_block *bfs_sb;
|
||||
struct inode *inode;
|
||||
unsigned i, imap_len;
|
||||
@ -365,10 +330,10 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
|
||||
|
||||
sb_set_blocksize(s, BFS_BSIZE);
|
||||
|
||||
info->si_sbh = sb_bread(s, 0);
|
||||
if (!info->si_sbh)
|
||||
sbh = sb_bread(s, 0);
|
||||
if (!sbh)
|
||||
goto out;
|
||||
bfs_sb = (struct bfs_super_block *)info->si_sbh->b_data;
|
||||
bfs_sb = (struct bfs_super_block *)sbh->b_data;
|
||||
if (le32_to_cpu(bfs_sb->s_magic) != BFS_MAGIC) {
|
||||
if (!silent)
|
||||
printf("No BFS filesystem on %s (magic=%08x)\n",
|
||||
@ -472,10 +437,7 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
|
||||
info->si_lf_eblk = eblock;
|
||||
}
|
||||
brelse(bh);
|
||||
if (!(s->s_flags & MS_RDONLY)) {
|
||||
mark_buffer_dirty(info->si_sbh);
|
||||
s->s_dirt = 1;
|
||||
}
|
||||
brelse(sbh);
|
||||
dump_imap("read_super", s);
|
||||
return 0;
|
||||
|
||||
@ -485,7 +447,7 @@ out3:
|
||||
out2:
|
||||
kfree(info->si_imap);
|
||||
out1:
|
||||
brelse(info->si_sbh);
|
||||
brelse(sbh);
|
||||
out:
|
||||
mutex_destroy(&info->bfs_lock);
|
||||
kfree(info);
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -2938,7 +2938,6 @@ int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
|
||||
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
|
||||
ret = btrfs_update_inode(trans, root, dir);
|
||||
BUG_ON(ret);
|
||||
dir->i_sb->s_dirt = 1;
|
||||
|
||||
btrfs_free_path(path);
|
||||
return 0;
|
||||
@ -3656,17 +3655,19 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
attr->ia_valid &= ~ATTR_SIZE;
|
||||
|
||||
if (attr->ia_valid)
|
||||
err = inode_setattr(inode, attr);
|
||||
if (attr->ia_valid) {
|
||||
setattr_copy(inode, attr);
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
if (attr->ia_valid & ATTR_MODE)
|
||||
err = btrfs_acl_chmod(inode);
|
||||
}
|
||||
|
||||
if (!err && ((attr->ia_valid & ATTR_MODE)))
|
||||
err = btrfs_acl_chmod(inode);
|
||||
return err;
|
||||
}
|
||||
|
||||
void btrfs_delete_inode(struct inode *inode)
|
||||
void btrfs_evict_inode(struct inode *inode)
|
||||
{
|
||||
struct btrfs_trans_handle *trans;
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
@ -3674,10 +3675,14 @@ void btrfs_delete_inode(struct inode *inode)
|
||||
int ret;
|
||||
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
if (inode->i_nlink && btrfs_root_refs(&root->root_item) != 0)
|
||||
goto no_delete;
|
||||
|
||||
if (is_bad_inode(inode)) {
|
||||
btrfs_orphan_del(NULL, inode);
|
||||
goto no_delete;
|
||||
}
|
||||
/* do we really want it for ->i_nlink > 0 and zero btrfs_root_refs? */
|
||||
btrfs_wait_ordered_range(inode, 0, (u64)-1);
|
||||
|
||||
if (root->fs_info->log_root_recovering) {
|
||||
@ -3727,7 +3732,7 @@ void btrfs_delete_inode(struct inode *inode)
|
||||
btrfs_end_transaction(trans, root);
|
||||
btrfs_btree_balance_dirty(root, nr);
|
||||
no_delete:
|
||||
clear_inode(inode);
|
||||
end_writeback(inode);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3858,7 +3863,7 @@ 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)
|
||||
|
@ -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,
|
||||
|
180
fs/buffer.c
180
fs/buffer.c
@ -1833,9 +1833,10 @@ void page_zero_new_buffers(struct page *page, unsigned from, unsigned to)
|
||||
}
|
||||
EXPORT_SYMBOL(page_zero_new_buffers);
|
||||
|
||||
static int __block_prepare_write(struct inode *inode, struct page *page,
|
||||
unsigned from, unsigned to, get_block_t *get_block)
|
||||
int block_prepare_write(struct page *page, unsigned from, unsigned to,
|
||||
get_block_t *get_block)
|
||||
{
|
||||
struct inode *inode = page->mapping->host;
|
||||
unsigned block_start, block_end;
|
||||
sector_t block;
|
||||
int err = 0;
|
||||
@ -1908,10 +1909,13 @@ static int __block_prepare_write(struct inode *inode, struct page *page,
|
||||
if (!buffer_uptodate(*wait_bh))
|
||||
err = -EIO;
|
||||
}
|
||||
if (unlikely(err))
|
||||
if (unlikely(err)) {
|
||||
page_zero_new_buffers(page, from, to);
|
||||
ClearPageUptodate(page);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(block_prepare_write);
|
||||
|
||||
static int __block_commit_write(struct inode *inode, struct page *page,
|
||||
unsigned from, unsigned to)
|
||||
@ -1948,90 +1952,41 @@ static int __block_commit_write(struct inode *inode, struct page *page,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Filesystems implementing the new truncate sequence should use the
|
||||
* _newtrunc postfix variant which won't incorrectly call vmtruncate.
|
||||
* The filesystem needs to handle block truncation upon failure.
|
||||
*/
|
||||
int block_write_begin_newtrunc(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned flags,
|
||||
struct page **pagep, void **fsdata,
|
||||
get_block_t *get_block)
|
||||
int __block_write_begin(struct page *page, loff_t pos, unsigned len,
|
||||
get_block_t *get_block)
|
||||
{
|
||||
struct inode *inode = mapping->host;
|
||||
int status = 0;
|
||||
struct page *page;
|
||||
pgoff_t index;
|
||||
unsigned start, end;
|
||||
int ownpage = 0;
|
||||
unsigned start = pos & (PAGE_CACHE_SIZE - 1);
|
||||
|
||||
index = pos >> PAGE_CACHE_SHIFT;
|
||||
start = pos & (PAGE_CACHE_SIZE - 1);
|
||||
end = start + len;
|
||||
|
||||
page = *pagep;
|
||||
if (page == NULL) {
|
||||
ownpage = 1;
|
||||
page = grab_cache_page_write_begin(mapping, index, flags);
|
||||
if (!page) {
|
||||
status = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
*pagep = page;
|
||||
} else
|
||||
BUG_ON(!PageLocked(page));
|
||||
|
||||
status = __block_prepare_write(inode, page, start, end, get_block);
|
||||
if (unlikely(status)) {
|
||||
ClearPageUptodate(page);
|
||||
|
||||
if (ownpage) {
|
||||
unlock_page(page);
|
||||
page_cache_release(page);
|
||||
*pagep = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return status;
|
||||
return block_prepare_write(page, start, start + len, get_block);
|
||||
}
|
||||
EXPORT_SYMBOL(block_write_begin_newtrunc);
|
||||
EXPORT_SYMBOL(__block_write_begin);
|
||||
|
||||
/*
|
||||
* block_write_begin takes care of the basic task of block allocation and
|
||||
* bringing partial write blocks uptodate first.
|
||||
*
|
||||
* If *pagep is not NULL, then block_write_begin uses the locked page
|
||||
* at *pagep rather than allocating its own. In this case, the page will
|
||||
* not be unlocked or deallocated on failure.
|
||||
* The filesystem needs to handle block truncation upon failure.
|
||||
*/
|
||||
int block_write_begin(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned flags,
|
||||
struct page **pagep, void **fsdata,
|
||||
get_block_t *get_block)
|
||||
int block_write_begin(struct address_space *mapping, loff_t pos, unsigned len,
|
||||
unsigned flags, struct page **pagep, get_block_t *get_block)
|
||||
{
|
||||
int ret;
|
||||
pgoff_t index = pos >> PAGE_CACHE_SHIFT;
|
||||
struct page *page;
|
||||
int status;
|
||||
|
||||
ret = block_write_begin_newtrunc(file, mapping, pos, len, flags,
|
||||
pagep, fsdata, get_block);
|
||||
page = grab_cache_page_write_begin(mapping, index, flags);
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* prepare_write() may have instantiated a few blocks
|
||||
* outside i_size. Trim these off again. Don't need
|
||||
* i_size_read because we hold i_mutex.
|
||||
*
|
||||
* Filesystems which pass down their own page also cannot
|
||||
* call into vmtruncate here because it would lead to lock
|
||||
* inversion problems (*pagep is locked). This is a further
|
||||
* example of where the old truncate sequence is inadequate.
|
||||
*/
|
||||
if (unlikely(ret) && *pagep == NULL) {
|
||||
loff_t isize = mapping->host->i_size;
|
||||
if (pos + len > isize)
|
||||
vmtruncate(mapping->host, isize);
|
||||
status = __block_write_begin(page, pos, len, get_block);
|
||||
if (unlikely(status)) {
|
||||
unlock_page(page);
|
||||
page_cache_release(page);
|
||||
page = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
*pagep = page;
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL(block_write_begin);
|
||||
|
||||
@ -2351,7 +2306,7 @@ 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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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)
|
||||
|
@ -1698,26 +1698,16 @@ static int cifs_truncate_page(struct address_space *mapping, loff_t from)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cifs_vmtruncate(struct inode *inode, loff_t offset)
|
||||
static void cifs_setsize(struct inode *inode, loff_t offset)
|
||||
{
|
||||
loff_t oldsize;
|
||||
int err;
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
err = inode_newsize_ok(inode, offset);
|
||||
if (err) {
|
||||
spin_unlock(&inode->i_lock);
|
||||
goto out;
|
||||
}
|
||||
|
||||
oldsize = inode->i_size;
|
||||
i_size_write(inode, offset);
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
||||
truncate_pagecache(inode, oldsize, offset);
|
||||
if (inode->i_op->truncate)
|
||||
inode->i_op->truncate(inode);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1790,7 +1780,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
|
||||
|
||||
if (rc == 0) {
|
||||
cifsInode->server_eof = attrs->ia_size;
|
||||
rc = cifs_vmtruncate(inode, attrs->ia_size);
|
||||
cifs_setsize(inode, attrs->ia_size);
|
||||
cifs_truncate_page(inode->i_mapping, inode->i_size);
|
||||
}
|
||||
|
||||
@ -1815,14 +1805,12 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
|
||||
/* check if we have permission to change attrs */
|
||||
rc = inode_change_ok(inode, attrs);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
else
|
||||
rc = 0;
|
||||
}
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
|
||||
attrs->ia_valid |= ATTR_FORCE;
|
||||
|
||||
rc = inode_change_ok(inode, attrs);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
full_path = build_path_from_dentry(direntry);
|
||||
if (full_path == NULL) {
|
||||
@ -1908,18 +1896,24 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
}
|
||||
|
||||
if (!rc) {
|
||||
rc = inode_setattr(inode, attrs);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
/* force revalidate when any of these times are set since some
|
||||
of the fs types (eg ext3, fat) do not have fine enough
|
||||
time granularity to match protocol, and we do not have a
|
||||
a way (yet) to query the server fs's time granularity (and
|
||||
whether it rounds times down).
|
||||
*/
|
||||
if (!rc && (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME)))
|
||||
cifsInode->time = 0;
|
||||
}
|
||||
if ((attrs->ia_valid & ATTR_SIZE) &&
|
||||
attrs->ia_size != i_size_read(inode))
|
||||
truncate_setsize(inode, attrs->ia_size);
|
||||
|
||||
setattr_copy(inode, attrs);
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
/* force revalidate when any of these times are set since some
|
||||
of the fs types (eg ext3, fat) do not have fine enough
|
||||
time granularity to match protocol, and we do not have a
|
||||
a way (yet) to query the server fs's time granularity (and
|
||||
whether it rounds times down).
|
||||
*/
|
||||
if (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME))
|
||||
cifsInode->time = 0;
|
||||
out:
|
||||
kfree(args);
|
||||
kfree(full_path);
|
||||
@ -1944,14 +1938,13 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
|
||||
cFYI(1, "setattr on file %s attrs->iavalid 0x%x",
|
||||
direntry->d_name.name, attrs->ia_valid);
|
||||
|
||||
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
|
||||
/* check if we have permission to change attrs */
|
||||
rc = inode_change_ok(inode, attrs);
|
||||
if (rc < 0) {
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
} else
|
||||
rc = 0;
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
|
||||
attrs->ia_valid |= ATTR_FORCE;
|
||||
|
||||
rc = inode_change_ok(inode, attrs);
|
||||
if (rc < 0) {
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
full_path = build_path_from_dentry(direntry);
|
||||
@ -2059,8 +2052,17 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
|
||||
|
||||
/* do not need local check to inode_check_ok since the server does
|
||||
that */
|
||||
if (!rc)
|
||||
rc = inode_setattr(inode, attrs);
|
||||
if (rc)
|
||||
goto cifs_setattr_exit;
|
||||
|
||||
if ((attrs->ia_valid & ATTR_SIZE) &&
|
||||
attrs->ia_size != i_size_read(inode))
|
||||
truncate_setsize(inode, attrs->ia_size);
|
||||
|
||||
setattr_copy(inode, attrs);
|
||||
mark_inode_dirty(inode);
|
||||
return 0;
|
||||
|
||||
cifs_setattr_exit:
|
||||
kfree(full_path);
|
||||
FreeXid(xid);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
10
fs/compat.c
10
fs/compat.c
@ -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;
|
||||
|
@ -39,66 +39,55 @@ static DEFINE_MUTEX(read_mutex);
|
||||
#define CRAMINO(x) (((x)->offset && (x)->size)?(x)->offset<<2:1)
|
||||
#define OFFSET(x) ((x)->i_ino)
|
||||
|
||||
|
||||
static int cramfs_iget5_test(struct inode *inode, void *opaque)
|
||||
static void setup_inode(struct inode *inode, struct cramfs_inode * cramfs_inode)
|
||||
{
|
||||
struct cramfs_inode *cramfs_inode = opaque;
|
||||
return inode->i_ino == CRAMINO(cramfs_inode) && inode->i_ino != 1;
|
||||
}
|
||||
|
||||
static int cramfs_iget5_set(struct inode *inode, void *opaque)
|
||||
{
|
||||
struct cramfs_inode *cramfs_inode = opaque;
|
||||
inode->i_ino = CRAMINO(cramfs_inode);
|
||||
return 0;
|
||||
static struct timespec zerotime;
|
||||
inode->i_mode = cramfs_inode->mode;
|
||||
inode->i_uid = cramfs_inode->uid;
|
||||
inode->i_size = cramfs_inode->size;
|
||||
inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1;
|
||||
inode->i_gid = cramfs_inode->gid;
|
||||
/* Struct copy intentional */
|
||||
inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime;
|
||||
/* inode->i_nlink is left 1 - arguably wrong for directories,
|
||||
but it's the best we can do without reading the directory
|
||||
contents. 1 yields the right result in GNU find, even
|
||||
without -noleaf option. */
|
||||
if (S_ISREG(inode->i_mode)) {
|
||||
inode->i_fop = &generic_ro_fops;
|
||||
inode->i_data.a_ops = &cramfs_aops;
|
||||
} else if (S_ISDIR(inode->i_mode)) {
|
||||
inode->i_op = &cramfs_dir_inode_operations;
|
||||
inode->i_fop = &cramfs_directory_operations;
|
||||
} else if (S_ISLNK(inode->i_mode)) {
|
||||
inode->i_op = &page_symlink_inode_operations;
|
||||
inode->i_data.a_ops = &cramfs_aops;
|
||||
} else {
|
||||
init_special_inode(inode, inode->i_mode,
|
||||
old_decode_dev(cramfs_inode->size));
|
||||
}
|
||||
}
|
||||
|
||||
static struct inode *get_cramfs_inode(struct super_block *sb,
|
||||
struct cramfs_inode * cramfs_inode)
|
||||
{
|
||||
struct inode *inode = iget5_locked(sb, CRAMINO(cramfs_inode),
|
||||
cramfs_iget5_test, cramfs_iget5_set,
|
||||
cramfs_inode);
|
||||
static struct timespec zerotime;
|
||||
|
||||
if (inode && (inode->i_state & I_NEW)) {
|
||||
inode->i_mode = cramfs_inode->mode;
|
||||
inode->i_uid = cramfs_inode->uid;
|
||||
inode->i_size = cramfs_inode->size;
|
||||
inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1;
|
||||
inode->i_gid = cramfs_inode->gid;
|
||||
/* Struct copy intentional */
|
||||
inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime;
|
||||
/* inode->i_nlink is left 1 - arguably wrong for directories,
|
||||
but it's the best we can do without reading the directory
|
||||
contents. 1 yields the right result in GNU find, even
|
||||
without -noleaf option. */
|
||||
if (S_ISREG(inode->i_mode)) {
|
||||
inode->i_fop = &generic_ro_fops;
|
||||
inode->i_data.a_ops = &cramfs_aops;
|
||||
} else if (S_ISDIR(inode->i_mode)) {
|
||||
inode->i_op = &cramfs_dir_inode_operations;
|
||||
inode->i_fop = &cramfs_directory_operations;
|
||||
} else if (S_ISLNK(inode->i_mode)) {
|
||||
inode->i_op = &page_symlink_inode_operations;
|
||||
inode->i_data.a_ops = &cramfs_aops;
|
||||
} else {
|
||||
init_special_inode(inode, inode->i_mode,
|
||||
old_decode_dev(cramfs_inode->size));
|
||||
struct inode *inode;
|
||||
if (CRAMINO(cramfs_inode) == 1) {
|
||||
inode = new_inode(sb);
|
||||
if (inode) {
|
||||
inode->i_ino = 1;
|
||||
setup_inode(inode, cramfs_inode);
|
||||
}
|
||||
} else {
|
||||
inode = iget_locked(sb, CRAMINO(cramfs_inode));
|
||||
if (inode) {
|
||||
setup_inode(inode, cramfs_inode);
|
||||
unlock_new_inode(inode);
|
||||
}
|
||||
unlock_new_inode(inode);
|
||||
}
|
||||
return inode;
|
||||
}
|
||||
|
||||
static void cramfs_drop_inode(struct inode *inode)
|
||||
{
|
||||
if (inode->i_ino == 1)
|
||||
generic_delete_inode(inode);
|
||||
else
|
||||
generic_drop_inode(inode);
|
||||
}
|
||||
|
||||
/*
|
||||
* We have our own block cache: don't fill up the buffer cache
|
||||
* with the rom-image, because the way the filesystem is set
|
||||
@ -542,7 +531,6 @@ static const struct super_operations cramfs_ops = {
|
||||
.put_super = cramfs_put_super,
|
||||
.remount_fs = cramfs_remount,
|
||||
.statfs = cramfs_statfs,
|
||||
.drop_inode = cramfs_drop_inode,
|
||||
};
|
||||
|
||||
static int cramfs_get_sb(struct file_system_type *fs_type,
|
||||
|
39
fs/dcache.c
39
fs/dcache.c
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -804,10 +804,20 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
|
||||
size_t num_zeros = (PAGE_CACHE_SIZE
|
||||
- (ia->ia_size & ~PAGE_CACHE_MASK));
|
||||
|
||||
|
||||
/*
|
||||
* XXX(truncate) this should really happen at the begginning
|
||||
* of ->setattr. But the code is too messy to that as part
|
||||
* of a larger patch. ecryptfs is also totally missing out
|
||||
* on the inode_change_ok check at the beginning of
|
||||
* ->setattr while would include this.
|
||||
*/
|
||||
rc = inode_newsize_ok(inode, ia->ia_size);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
|
||||
rc = simple_setsize(inode, ia->ia_size);
|
||||
if (rc)
|
||||
goto out;
|
||||
truncate_setsize(inode, ia->ia_size);
|
||||
lower_ia->ia_size = ia->ia_size;
|
||||
lower_ia->ia_valid |= ATTR_SIZE;
|
||||
goto out;
|
||||
@ -830,7 +840,7 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
simple_setsize(inode, ia->ia_size);
|
||||
truncate_setsize(inode, ia->ia_size);
|
||||
rc = ecryptfs_write_inode_size_to_metadata(inode);
|
||||
if (rc) {
|
||||
printk(KERN_ERR "Problem with "
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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 *);
|
||||
|
@ -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,
|
||||
};
|
||||
|
131
fs/exofs/inode.c
131
fs/exofs/inode.c
@ -697,6 +697,13 @@ static int exofs_writepage(struct page *page, struct writeback_control *wbc)
|
||||
return write_exec(&pcol);
|
||||
}
|
||||
|
||||
/* i_mutex held using inode->i_size directly */
|
||||
static void _write_failed(struct inode *inode, loff_t to)
|
||||
{
|
||||
if (to > inode->i_size)
|
||||
truncate_pagecache(inode, to, inode->i_size);
|
||||
}
|
||||
|
||||
int exofs_write_begin(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned flags,
|
||||
struct page **pagep, void **fsdata)
|
||||
@ -710,7 +717,7 @@ int exofs_write_begin(struct file *file, struct address_space *mapping,
|
||||
fsdata);
|
||||
if (ret) {
|
||||
EXOFS_DBGMSG("simple_write_begin faild\n");
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
page = *pagep;
|
||||
@ -725,6 +732,9 @@ int exofs_write_begin(struct file *file, struct address_space *mapping,
|
||||
EXOFS_DBGMSG("__readpage_filler faild\n");
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (unlikely(ret))
|
||||
_write_failed(mapping->host, pos + len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -750,6 +760,10 @@ static int exofs_write_end(struct file *file, struct address_space *mapping,
|
||||
int ret;
|
||||
|
||||
ret = simple_write_end(file, mapping,pos, len, copied, page, fsdata);
|
||||
if (unlikely(ret))
|
||||
_write_failed(inode, pos + len);
|
||||
|
||||
/* TODO: once simple_write_end marks inode dirty remove */
|
||||
if (i_size != inode->i_size)
|
||||
mark_inode_dirty(inode);
|
||||
return ret;
|
||||
@ -808,87 +822,55 @@ static inline int exofs_inode_is_fast_symlink(struct inode *inode)
|
||||
return S_ISLNK(inode->i_mode) && (oi->i_data[0] != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_block_t - Fill in a buffer_head
|
||||
* An OSD takes care of block allocation so we just fake an allocation by
|
||||
* putting in the inode's sector_t in the buffer_head.
|
||||
* TODO: What about the case of create==0 and @iblock does not exist in the
|
||||
* object?
|
||||
*/
|
||||
static int exofs_get_block(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh_result, int create)
|
||||
{
|
||||
map_bh(bh_result, inode->i_sb, iblock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct osd_attr g_attr_logical_length = ATTR_DEF(
|
||||
OSD_APAGE_OBJECT_INFORMATION, OSD_ATTR_OI_LOGICAL_LENGTH, 8);
|
||||
|
||||
static int _do_truncate(struct inode *inode)
|
||||
static int _do_truncate(struct inode *inode, loff_t newsize)
|
||||
{
|
||||
struct exofs_i_info *oi = exofs_i(inode);
|
||||
loff_t isize = i_size_read(inode);
|
||||
int ret;
|
||||
|
||||
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
|
||||
|
||||
nobh_truncate_page(inode->i_mapping, isize, exofs_get_block);
|
||||
ret = exofs_oi_truncate(oi, (u64)newsize);
|
||||
if (likely(!ret))
|
||||
truncate_setsize(inode, newsize);
|
||||
|
||||
ret = exofs_oi_truncate(oi, (u64)isize);
|
||||
EXOFS_DBGMSG("(0x%lx) size=0x%llx\n", inode->i_ino, isize);
|
||||
EXOFS_DBGMSG("(0x%lx) size=0x%llx ret=>%d\n",
|
||||
inode->i_ino, newsize, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Truncate a file to the specified size - all we have to do is set the size
|
||||
* attribute. We make sure the object exists first.
|
||||
*/
|
||||
void exofs_truncate(struct inode *inode)
|
||||
{
|
||||
struct exofs_i_info *oi = exofs_i(inode);
|
||||
int ret;
|
||||
|
||||
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
|
||||
|| S_ISLNK(inode->i_mode)))
|
||||
return;
|
||||
if (exofs_inode_is_fast_symlink(inode))
|
||||
return;
|
||||
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
|
||||
return;
|
||||
|
||||
/* if we are about to truncate an object, and it hasn't been
|
||||
* created yet, wait
|
||||
*/
|
||||
if (unlikely(wait_obj_created(oi)))
|
||||
goto fail;
|
||||
|
||||
ret = _do_truncate(inode);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
out:
|
||||
mark_inode_dirty(inode);
|
||||
return;
|
||||
fail:
|
||||
make_bad_inode(inode);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set inode attributes - just call generic functions.
|
||||
* Set inode attributes - update size attribute on OSD if needed,
|
||||
* otherwise just call generic functions.
|
||||
*/
|
||||
int exofs_setattr(struct dentry *dentry, struct iattr *iattr)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
|
||||
error = inode_change_ok(inode, iattr);
|
||||
if (error)
|
||||
/* if we are about to modify an object, and it hasn't been
|
||||
* created yet, wait
|
||||
*/
|
||||
error = wait_obj_created(exofs_i(inode));
|
||||
if (unlikely(error))
|
||||
return error;
|
||||
|
||||
error = inode_setattr(inode, iattr);
|
||||
return error;
|
||||
error = inode_change_ok(inode, iattr);
|
||||
if (unlikely(error))
|
||||
return error;
|
||||
|
||||
if ((iattr->ia_valid & ATTR_SIZE) &&
|
||||
iattr->ia_size != i_size_read(inode)) {
|
||||
error = _do_truncate(inode, iattr->ia_size);
|
||||
if (unlikely(error))
|
||||
return error;
|
||||
}
|
||||
|
||||
setattr_copy(inode, iattr);
|
||||
mark_inode_dirty(inode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct osd_attr g_attr_inode_file_layout = ATTR_DEF(
|
||||
@ -1325,7 +1307,7 @@ static void delete_done(struct exofs_io_state *ios, void *p)
|
||||
* from the OSD here. We make sure the object was created before we try and
|
||||
* delete it.
|
||||
*/
|
||||
void exofs_delete_inode(struct inode *inode)
|
||||
void exofs_evict_inode(struct inode *inode)
|
||||
{
|
||||
struct exofs_i_info *oi = exofs_i(inode);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
@ -1335,28 +1317,25 @@ void exofs_delete_inode(struct inode *inode)
|
||||
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
|
||||
if (is_bad_inode(inode))
|
||||
/* TODO: should do better here */
|
||||
if (inode->i_nlink || is_bad_inode(inode))
|
||||
goto no_delete;
|
||||
|
||||
mark_inode_dirty(inode);
|
||||
exofs_update_inode(inode, inode_needs_sync(inode));
|
||||
|
||||
inode->i_size = 0;
|
||||
if (inode->i_blocks)
|
||||
exofs_truncate(inode);
|
||||
|
||||
clear_inode(inode);
|
||||
|
||||
ret = exofs_get_io_state(&sbi->layout, &ios);
|
||||
if (unlikely(ret)) {
|
||||
EXOFS_ERR("%s: exofs_get_io_state failed\n", __func__);
|
||||
return;
|
||||
}
|
||||
end_writeback(inode);
|
||||
|
||||
/* if we are deleting an obj that hasn't been created yet, wait */
|
||||
if (!obj_created(oi)) {
|
||||
BUG_ON(!obj_2bcreated(oi));
|
||||
wait_event(oi->i_wq, obj_created(oi));
|
||||
/* ignore the error attempt a remove anyway */
|
||||
}
|
||||
|
||||
/* Now Remove the OSD objects */
|
||||
ret = exofs_get_io_state(&sbi->layout, &ios);
|
||||
if (unlikely(ret)) {
|
||||
EXOFS_ERR("%s: exofs_get_io_state failed\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
ios->obj.id = exofs_oi_objno(oi);
|
||||
@ -1374,5 +1353,5 @@ void exofs_delete_inode(struct inode *inode)
|
||||
return;
|
||||
|
||||
no_delete:
|
||||
clear_inode(inode);
|
||||
end_writeback(inode);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -118,19 +118,14 @@ void ext2_free_inode (struct inode * inode)
|
||||
* Note: we must free any quota before locking the superblock,
|
||||
* as writing the quota to disk may need the lock as well.
|
||||
*/
|
||||
if (!is_bad_inode(inode)) {
|
||||
/* Quota is already initialized in iput() */
|
||||
ext2_xattr_delete_inode(inode);
|
||||
dquot_free_inode(inode);
|
||||
dquot_drop(inode);
|
||||
}
|
||||
/* Quota is already initialized in iput() */
|
||||
ext2_xattr_delete_inode(inode);
|
||||
dquot_free_inode(inode);
|
||||
dquot_drop(inode);
|
||||
|
||||
es = EXT2_SB(sb)->s_es;
|
||||
is_directory = S_ISDIR(inode->i_mode);
|
||||
|
||||
/* Do this BEFORE marking the inode not in use or returning an error */
|
||||
clear_inode (inode);
|
||||
|
||||
if (ino < EXT2_FIRST_INO(sb) ||
|
||||
ino > le32_to_cpu(es->s_inodes_count)) {
|
||||
ext2_error (sb, "ext2_free_inode",
|
||||
|
@ -69,26 +69,42 @@ static void ext2_write_failed(struct address_space *mapping, loff_t to)
|
||||
/*
|
||||
* Called at the last iput() if i_nlink is zero.
|
||||
*/
|
||||
void ext2_delete_inode (struct inode * inode)
|
||||
void ext2_evict_inode(struct inode * inode)
|
||||
{
|
||||
if (!is_bad_inode(inode))
|
||||
struct ext2_block_alloc_info *rsv;
|
||||
int want_delete = 0;
|
||||
|
||||
if (!inode->i_nlink && !is_bad_inode(inode)) {
|
||||
want_delete = 1;
|
||||
dquot_initialize(inode);
|
||||
} else {
|
||||
dquot_drop(inode);
|
||||
}
|
||||
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
|
||||
if (is_bad_inode(inode))
|
||||
goto no_delete;
|
||||
EXT2_I(inode)->i_dtime = get_seconds();
|
||||
mark_inode_dirty(inode);
|
||||
__ext2_write_inode(inode, inode_needs_sync(inode));
|
||||
if (want_delete) {
|
||||
/* set dtime */
|
||||
EXT2_I(inode)->i_dtime = get_seconds();
|
||||
mark_inode_dirty(inode);
|
||||
__ext2_write_inode(inode, inode_needs_sync(inode));
|
||||
/* truncate to 0 */
|
||||
inode->i_size = 0;
|
||||
if (inode->i_blocks)
|
||||
ext2_truncate_blocks(inode, 0);
|
||||
}
|
||||
|
||||
inode->i_size = 0;
|
||||
if (inode->i_blocks)
|
||||
ext2_truncate_blocks(inode, 0);
|
||||
ext2_free_inode (inode);
|
||||
invalidate_inode_buffers(inode);
|
||||
end_writeback(inode);
|
||||
|
||||
return;
|
||||
no_delete:
|
||||
clear_inode(inode); /* We must guarantee clearing of inode... */
|
||||
ext2_discard_reservation(inode);
|
||||
rsv = EXT2_I(inode)->i_block_alloc_info;
|
||||
EXT2_I(inode)->i_block_alloc_info = NULL;
|
||||
if (unlikely(rsv))
|
||||
kfree(rsv);
|
||||
|
||||
if (want_delete)
|
||||
ext2_free_inode(inode);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
@ -423,6 +439,8 @@ static int ext2_alloc_blocks(struct inode *inode,
|
||||
failed_out:
|
||||
for (i = 0; i <index; i++)
|
||||
ext2_free_blocks(inode, new_blocks[i], 1);
|
||||
if (index)
|
||||
mark_inode_dirty(inode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -765,14 +783,6 @@ ext2_readpages(struct file *file, struct address_space *mapping,
|
||||
return mpage_readpages(mapping, pages, nr_pages, ext2_get_block);
|
||||
}
|
||||
|
||||
int __ext2_write_begin(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned flags,
|
||||
struct page **pagep, void **fsdata)
|
||||
{
|
||||
return block_write_begin_newtrunc(file, mapping, pos, len, flags,
|
||||
pagep, fsdata, ext2_get_block);
|
||||
}
|
||||
|
||||
static int
|
||||
ext2_write_begin(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned flags,
|
||||
@ -780,8 +790,8 @@ ext2_write_begin(struct file *file, struct address_space *mapping,
|
||||
{
|
||||
int ret;
|
||||
|
||||
*pagep = NULL;
|
||||
ret = __ext2_write_begin(file, mapping, pos, len, flags, pagep, fsdata);
|
||||
ret = block_write_begin(mapping, pos, len, flags, pagep,
|
||||
ext2_get_block);
|
||||
if (ret < 0)
|
||||
ext2_write_failed(mapping, pos + len);
|
||||
return ret;
|
||||
@ -806,13 +816,8 @@ ext2_nobh_write_begin(struct file *file, struct address_space *mapping,
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Dir-in-pagecache still uses ext2_write_begin. Would have to rework
|
||||
* directory handling code to pass around offsets rather than struct
|
||||
* pages in order to make this work easily.
|
||||
*/
|
||||
ret = nobh_write_begin_newtrunc(file, mapping, pos, len, flags, pagep,
|
||||
fsdata, ext2_get_block);
|
||||
ret = nobh_write_begin(mapping, pos, len, flags, pagep, fsdata,
|
||||
ext2_get_block);
|
||||
if (ret < 0)
|
||||
ext2_write_failed(mapping, pos + len);
|
||||
return ret;
|
||||
@ -838,7 +843,7 @@ ext2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
|
||||
struct inode *inode = mapping->host;
|
||||
ssize_t ret;
|
||||
|
||||
ret = blockdev_direct_IO_newtrunc(rw, iocb, inode, inode->i_sb->s_bdev,
|
||||
ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev,
|
||||
iov, offset, nr_segs, ext2_get_block, NULL);
|
||||
if (ret < 0 && (rw & WRITE))
|
||||
ext2_write_failed(mapping, offset + iov_length(iov, nr_segs));
|
||||
@ -1006,8 +1011,8 @@ static inline void ext2_free_data(struct inode *inode, __le32 *p, __le32 *q)
|
||||
else if (block_to_free == nr - count)
|
||||
count++;
|
||||
else {
|
||||
mark_inode_dirty(inode);
|
||||
ext2_free_blocks (inode, block_to_free, count);
|
||||
mark_inode_dirty(inode);
|
||||
free_this:
|
||||
block_to_free = nr;
|
||||
count = 1;
|
||||
@ -1015,8 +1020,8 @@ static inline void ext2_free_data(struct inode *inode, __le32 *p, __le32 *q)
|
||||
}
|
||||
}
|
||||
if (count > 0) {
|
||||
mark_inode_dirty(inode);
|
||||
ext2_free_blocks (inode, block_to_free, count);
|
||||
mark_inode_dirty(inode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1169,15 +1174,10 @@ static void ext2_truncate_blocks(struct inode *inode, loff_t offset)
|
||||
__ext2_truncate_blocks(inode, offset);
|
||||
}
|
||||
|
||||
int ext2_setsize(struct inode *inode, loff_t newsize)
|
||||
static int ext2_setsize(struct inode *inode, loff_t newsize)
|
||||
{
|
||||
loff_t oldsize;
|
||||
int error;
|
||||
|
||||
error = inode_newsize_ok(inode, newsize);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
|
||||
S_ISLNK(inode->i_mode)))
|
||||
return -EINVAL;
|
||||
@ -1197,10 +1197,7 @@ int ext2_setsize(struct inode *inode, loff_t newsize)
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
oldsize = inode->i_size;
|
||||
i_size_write(inode, newsize);
|
||||
truncate_pagecache(inode, oldsize, newsize);
|
||||
|
||||
truncate_setsize(inode, newsize);
|
||||
__ext2_truncate_blocks(inode, newsize);
|
||||
|
||||
inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
|
||||
@ -1557,7 +1554,7 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
generic_setattr(inode, iattr);
|
||||
setattr_copy(inode, iattr);
|
||||
if (iattr->ia_valid & ATTR_MODE)
|
||||
error = ext2_acl_chmod(inode);
|
||||
mark_inode_dirty(inode);
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
|
@ -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:
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -159,7 +159,7 @@ static int fat_write_begin(struct file *file, struct address_space *mapping,
|
||||
int err;
|
||||
|
||||
*pagep = NULL;
|
||||
err = cont_write_begin_newtrunc(file, mapping, pos, len, flags,
|
||||
err = cont_write_begin(file, mapping, pos, len, flags,
|
||||
pagep, fsdata, fat_get_block,
|
||||
&MSDOS_I(mapping->host)->mmu_private);
|
||||
if (err < 0)
|
||||
@ -212,8 +212,8 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,
|
||||
* FAT need to use the DIO_LOCKING for avoiding the race
|
||||
* condition of fat_get_block() and ->truncate().
|
||||
*/
|
||||
ret = blockdev_direct_IO_newtrunc(rw, iocb, inode, inode->i_sb->s_bdev,
|
||||
iov, offset, nr_segs, fat_get_block, NULL);
|
||||
ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev,
|
||||
iov, offset, nr_segs, fat_get_block, NULL);
|
||||
if (ret < 0 && (rw & WRITE))
|
||||
fat_write_failed(mapping, offset + iov_length(iov, nr_segs));
|
||||
|
||||
@ -263,7 +263,7 @@ static const struct address_space_operations fat_aops = {
|
||||
* check if the location is still valid and retry if it
|
||||
* isn't. Otherwise we do changes.
|
||||
* 5. Spinlock is used to protect hash/unhash/location check/lookup
|
||||
* 6. fat_clear_inode() unhashes the F-d-c entry.
|
||||
* 6. fat_evict_inode() unhashes the F-d-c entry.
|
||||
* 7. lookup() and readdir() do igrab() if they find a F-d-c entry
|
||||
* and consider negative result as cache miss.
|
||||
*/
|
||||
@ -448,16 +448,15 @@ 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);
|
||||
inode->i_size = 0;
|
||||
fat_truncate_blocks(inode, 0);
|
||||
clear_inode(inode);
|
||||
}
|
||||
|
||||
static void fat_clear_inode(struct inode *inode)
|
||||
{
|
||||
if (!inode->i_nlink) {
|
||||
inode->i_size = 0;
|
||||
fat_truncate_blocks(inode, 0);
|
||||
}
|
||||
invalidate_inode_buffers(inode);
|
||||
end_writeback(inode);
|
||||
fat_cache_inval_inode(inode);
|
||||
fat_detach(inode);
|
||||
}
|
||||
@ -674,12 +673,11 @@ static const struct super_operations fat_sops = {
|
||||
.alloc_inode = fat_alloc_inode,
|
||||
.destroy_inode = fat_destroy_inode,
|
||||
.write_inode = fat_write_inode,
|
||||
.delete_inode = fat_delete_inode,
|
||||
.evict_inode = fat_evict_inode,
|
||||
.put_super = fat_put_super,
|
||||
.write_super = fat_write_super,
|
||||
.sync_fs = fat_sync_fs,
|
||||
.statfs = fat_statfs,
|
||||
.clear_inode = fat_clear_inode,
|
||||
.remount_fs = fat_remount,
|
||||
|
||||
.show_options = fat_show_options,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -1270,21 +1270,18 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
|
||||
if (!fuse_allow_task(fc, current))
|
||||
return -EACCES;
|
||||
|
||||
if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
|
||||
err = inode_change_ok(inode, attr);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
|
||||
attr->ia_valid |= ATTR_FORCE;
|
||||
|
||||
err = inode_change_ok(inode, attr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if ((attr->ia_valid & ATTR_OPEN) && fc->atomic_o_trunc)
|
||||
return 0;
|
||||
|
||||
if (attr->ia_valid & ATTR_SIZE) {
|
||||
err = inode_newsize_ok(inode, attr->ia_size);
|
||||
if (err)
|
||||
return err;
|
||||
if (attr->ia_valid & ATTR_SIZE)
|
||||
is_truncate = true;
|
||||
}
|
||||
|
||||
req = fuse_get_req(fc);
|
||||
if (IS_ERR(req))
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
|
||||
gfs2_dinode_out(ip, dibh->b_data);
|
||||
brelse(dibh);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if ((attr->ia_valid & ATTR_SIZE) &&
|
||||
attr->ia_size != i_size_read(inode)) {
|
||||
error = vmtruncate(inode, attr->ia_size);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
return error;
|
||||
|
||||
setattr_copy(inode, attr);
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
gfs2_assert_warn(GFS2_SB(inode), !error);
|
||||
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
|
||||
gfs2_dinode_out(ip, dibh->b_data);
|
||||
brelse(dibh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1072,7 +1072,7 @@ int gfs2_permission(struct inode *inode, int mask)
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: should be changed to have proper ordering by opencoding simple_setsize
|
||||
* XXX(truncate): the truncate_setsize calls should be moved to the end.
|
||||
*/
|
||||
static int setattr_size(struct inode *inode, struct iattr *attr)
|
||||
{
|
||||
@ -1084,10 +1084,8 @@ static int setattr_size(struct inode *inode, struct iattr *attr)
|
||||
error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
|
||||
if (error)
|
||||
return error;
|
||||
error = simple_setsize(inode, attr->ia_size);
|
||||
truncate_setsize(inode, attr->ia_size);
|
||||
gfs2_trans_end(sdp);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
error = gfs2_truncatei(ip, attr->ia_size);
|
||||
@ -1136,8 +1134,16 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
|
||||
if (error)
|
||||
goto out_end_trans;
|
||||
|
||||
error = inode_setattr(inode, attr);
|
||||
gfs2_assert_warn(sdp, !error);
|
||||
if ((attr->ia_valid & ATTR_SIZE) &&
|
||||
attr->ia_size != i_size_read(inode)) {
|
||||
int error;
|
||||
|
||||
error = vmtruncate(inode, attr->ia_size);
|
||||
gfs2_assert_warn(sdp, !error);
|
||||
}
|
||||
|
||||
setattr_copy(inode, attr);
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
|
||||
gfs2_dinode_out(ip, dibh->b_data);
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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);
|
||||
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
|
||||
gfs2_dinode_out(ip, dibh->b_data);
|
||||
brelse(dibh);
|
||||
if (error)
|
||||
goto out_trans_end;
|
||||
|
||||
if ((attr->ia_valid & ATTR_SIZE) &&
|
||||
attr->ia_size != i_size_read(inode)) {
|
||||
int error;
|
||||
|
||||
error = vmtruncate(inode, attr->ia_size);
|
||||
gfs2_assert_warn(GFS2_SB(inode), !error);
|
||||
}
|
||||
|
||||
setattr_copy(inode, attr);
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
|
||||
gfs2_dinode_out(ip, dibh->b_data);
|
||||
brelse(dibh);
|
||||
|
||||
out_trans_end:
|
||||
gfs2_trans_end(sdp);
|
||||
return error;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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 (error)
|
||||
return error;
|
||||
|
||||
if ((attr->ia_valid & ATTR_SIZE) &&
|
||||
attr->ia_size != i_size_read(inode)) {
|
||||
error = vmtruncate(inode, attr->ia_size);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
setattr_copy(inode, attr);
|
||||
mark_inode_dirty(inode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hfs_file_fsync(struct file *filp, int datasync)
|
||||
{
|
||||
struct inode *inode = filp->f_mapping->host;
|
||||
struct super_block * sb;
|
||||
int ret, err;
|
||||
|
||||
/* sync the inode to buffers */
|
||||
ret = write_inode_now(inode, 0);
|
||||
|
||||
/* sync the superblock to buffers */
|
||||
sb = inode->i_sb;
|
||||
if (sb->s_dirt) {
|
||||
lock_super(sb);
|
||||
sb->s_dirt = 0;
|
||||
if (!(sb->s_flags & MS_RDONLY))
|
||||
hfs_mdb_commit(sb);
|
||||
unlock_super(sb);
|
||||
}
|
||||
/* .. finally sync the buffers to disk */
|
||||
err = sync_blockdev(sb->s_bdev);
|
||||
if (!ret)
|
||||
ret = err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations hfs_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
@ -604,7 +660,7 @@ static const struct file_operations hfs_file_operations = {
|
||||
.aio_write = generic_file_aio_write,
|
||||
.mmap = generic_file_mmap,
|
||||
.splice_read = generic_file_splice_read,
|
||||
.fsync = file_fsync,
|
||||
.fsync = hfs_file_fsync,
|
||||
.open = hfs_file_open,
|
||||
.release = hfs_file_release,
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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[];
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -14,12 +14,12 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/namei.h>
|
||||
#include "hostfs.h"
|
||||
#include "init.h"
|
||||
#include "kern.h"
|
||||
|
||||
struct hostfs_inode_info {
|
||||
char *host_filename;
|
||||
int fd;
|
||||
fmode_t mode;
|
||||
struct inode vfs_inode;
|
||||
@ -49,7 +49,7 @@ static int append = 0;
|
||||
|
||||
static const struct inode_operations hostfs_iops;
|
||||
static const struct inode_operations hostfs_dir_iops;
|
||||
static const struct address_space_operations hostfs_link_aops;
|
||||
static const struct inode_operations hostfs_link_iops;
|
||||
|
||||
#ifndef MODULE
|
||||
static int __init hostfs_args(char *options, int *add)
|
||||
@ -90,71 +90,58 @@ __uml_setup("hostfs=", hostfs_args,
|
||||
);
|
||||
#endif
|
||||
|
||||
static char *dentry_name(struct dentry *dentry, int extra)
|
||||
static char *__dentry_name(struct dentry *dentry, char *name)
|
||||
{
|
||||
struct dentry *parent;
|
||||
char *root, *name;
|
||||
int len;
|
||||
char *p = __dentry_path(dentry, name, PATH_MAX);
|
||||
char *root;
|
||||
size_t len;
|
||||
|
||||
len = 0;
|
||||
parent = dentry;
|
||||
while (parent->d_parent != parent) {
|
||||
len += parent->d_name.len + 1;
|
||||
parent = parent->d_parent;
|
||||
}
|
||||
spin_unlock(&dcache_lock);
|
||||
|
||||
root = HOSTFS_I(parent->d_inode)->host_filename;
|
||||
len += strlen(root);
|
||||
name = kmalloc(len + extra + 1, GFP_KERNEL);
|
||||
if (name == NULL)
|
||||
root = dentry->d_sb->s_fs_info;
|
||||
len = strlen(root);
|
||||
if (IS_ERR(p)) {
|
||||
__putname(name);
|
||||
return NULL;
|
||||
|
||||
name[len] = '\0';
|
||||
parent = dentry;
|
||||
while (parent->d_parent != parent) {
|
||||
len -= parent->d_name.len + 1;
|
||||
name[len] = '/';
|
||||
strncpy(&name[len + 1], parent->d_name.name,
|
||||
parent->d_name.len);
|
||||
parent = parent->d_parent;
|
||||
}
|
||||
strncpy(name, root, strlen(root));
|
||||
strncpy(name, root, PATH_MAX);
|
||||
if (len > p - name) {
|
||||
__putname(name);
|
||||
return NULL;
|
||||
}
|
||||
if (p > name + len) {
|
||||
char *s = name + len;
|
||||
while ((*s++ = *p++) != '\0')
|
||||
;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
static char *inode_name(struct inode *ino, int extra)
|
||||
static char *dentry_name(struct dentry *dentry)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
char *name = __getname();
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
|
||||
return dentry_name(dentry, extra);
|
||||
spin_lock(&dcache_lock);
|
||||
return __dentry_name(dentry, name); /* will unlock */
|
||||
}
|
||||
|
||||
static int read_name(struct inode *ino, char *name)
|
||||
static char *inode_name(struct inode *ino)
|
||||
{
|
||||
/*
|
||||
* The non-int inode fields are copied into ints by stat_file and
|
||||
* then copied into the inode because passing the actual pointers
|
||||
* in and having them treated as int * breaks on big-endian machines
|
||||
*/
|
||||
int err;
|
||||
int i_mode, i_nlink, i_blksize;
|
||||
unsigned long long i_size;
|
||||
unsigned long long i_ino;
|
||||
unsigned long long i_blocks;
|
||||
struct dentry *dentry;
|
||||
char *name = __getname();
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
err = stat_file(name, &i_ino, &i_mode, &i_nlink, &ino->i_uid,
|
||||
&ino->i_gid, &i_size, &ino->i_atime, &ino->i_mtime,
|
||||
&ino->i_ctime, &i_blksize, &i_blocks, -1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ino->i_ino = i_ino;
|
||||
ino->i_mode = i_mode;
|
||||
ino->i_nlink = i_nlink;
|
||||
ino->i_size = i_size;
|
||||
ino->i_blocks = i_blocks;
|
||||
return 0;
|
||||
spin_lock(&dcache_lock);
|
||||
if (list_empty(&ino->i_dentry)) {
|
||||
spin_unlock(&dcache_lock);
|
||||
__putname(name);
|
||||
return NULL;
|
||||
}
|
||||
dentry = list_first_entry(&ino->i_dentry, struct dentry, d_alias);
|
||||
return __dentry_name(dentry, name); /* will unlock */
|
||||
}
|
||||
|
||||
static char *follow_link(char *link)
|
||||
@ -205,53 +192,11 @@ static char *follow_link(char *link)
|
||||
return ERR_PTR(n);
|
||||
}
|
||||
|
||||
static int hostfs_read_inode(struct inode *ino)
|
||||
{
|
||||
char *name;
|
||||
int err = 0;
|
||||
|
||||
/*
|
||||
* Unfortunately, we are called from iget() when we don't have a dentry
|
||||
* allocated yet.
|
||||
*/
|
||||
if (list_empty(&ino->i_dentry))
|
||||
goto out;
|
||||
|
||||
err = -ENOMEM;
|
||||
name = inode_name(ino, 0);
|
||||
if (name == NULL)
|
||||
goto out;
|
||||
|
||||
if (file_type(name, NULL, NULL) == OS_TYPE_SYMLINK) {
|
||||
name = follow_link(name);
|
||||
if (IS_ERR(name)) {
|
||||
err = PTR_ERR(name);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
err = read_name(ino, name);
|
||||
kfree(name);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct inode *hostfs_iget(struct super_block *sb)
|
||||
{
|
||||
struct inode *inode;
|
||||
long ret;
|
||||
|
||||
inode = iget_locked(sb, 0);
|
||||
struct inode *inode = new_inode(sb);
|
||||
if (!inode)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
if (inode->i_state & I_NEW) {
|
||||
ret = hostfs_read_inode(inode);
|
||||
if (ret < 0) {
|
||||
iget_failed(inode);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
unlock_new_inode(inode);
|
||||
}
|
||||
return inode;
|
||||
}
|
||||
|
||||
@ -269,7 +214,7 @@ int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
|
||||
long long f_files;
|
||||
long long f_ffree;
|
||||
|
||||
err = do_statfs(HOSTFS_I(dentry->d_sb->s_root->d_inode)->host_filename,
|
||||
err = do_statfs(dentry->d_sb->s_fs_info,
|
||||
&sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
|
||||
&f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
|
||||
&sf->f_namelen, sf->f_spare);
|
||||
@ -288,47 +233,32 @@ static struct inode *hostfs_alloc_inode(struct super_block *sb)
|
||||
{
|
||||
struct hostfs_inode_info *hi;
|
||||
|
||||
hi = kmalloc(sizeof(*hi), GFP_KERNEL);
|
||||
hi = kzalloc(sizeof(*hi), GFP_KERNEL);
|
||||
if (hi == NULL)
|
||||
return NULL;
|
||||
|
||||
*hi = ((struct hostfs_inode_info) { .host_filename = NULL,
|
||||
.fd = -1,
|
||||
.mode = 0 });
|
||||
hi->fd = -1;
|
||||
inode_init_once(&hi->vfs_inode);
|
||||
return &hi->vfs_inode;
|
||||
}
|
||||
|
||||
static void hostfs_delete_inode(struct inode *inode)
|
||||
static void hostfs_evict_inode(struct inode *inode)
|
||||
{
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
end_writeback(inode);
|
||||
if (HOSTFS_I(inode)->fd != -1) {
|
||||
close_file(&HOSTFS_I(inode)->fd);
|
||||
HOSTFS_I(inode)->fd = -1;
|
||||
}
|
||||
clear_inode(inode);
|
||||
}
|
||||
|
||||
static void hostfs_destroy_inode(struct inode *inode)
|
||||
{
|
||||
kfree(HOSTFS_I(inode)->host_filename);
|
||||
|
||||
/*
|
||||
* XXX: This should not happen, probably. The check is here for
|
||||
* additional safety.
|
||||
*/
|
||||
if (HOSTFS_I(inode)->fd != -1) {
|
||||
close_file(&HOSTFS_I(inode)->fd);
|
||||
printk(KERN_DEBUG "Closing host fd in .destroy_inode\n");
|
||||
}
|
||||
|
||||
kfree(HOSTFS_I(inode));
|
||||
}
|
||||
|
||||
static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
|
||||
{
|
||||
struct inode *root = vfs->mnt_sb->s_root->d_inode;
|
||||
const char *root_path = HOSTFS_I(root)->host_filename;
|
||||
const char *root_path = vfs->mnt_sb->s_fs_info;
|
||||
size_t offset = strlen(root_ino) + 1;
|
||||
|
||||
if (strlen(root_path) > offset)
|
||||
@ -339,9 +269,8 @@ static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
|
||||
|
||||
static const struct super_operations hostfs_sbops = {
|
||||
.alloc_inode = hostfs_alloc_inode,
|
||||
.drop_inode = generic_delete_inode,
|
||||
.delete_inode = hostfs_delete_inode,
|
||||
.destroy_inode = hostfs_destroy_inode,
|
||||
.evict_inode = hostfs_evict_inode,
|
||||
.statfs = hostfs_statfs,
|
||||
.show_options = hostfs_show_options,
|
||||
};
|
||||
@ -353,11 +282,11 @@ int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
|
||||
unsigned long long next, ino;
|
||||
int error, len;
|
||||
|
||||
name = dentry_name(file->f_path.dentry, 0);
|
||||
name = dentry_name(file->f_path.dentry);
|
||||
if (name == NULL)
|
||||
return -ENOMEM;
|
||||
dir = open_dir(name, &error);
|
||||
kfree(name);
|
||||
__putname(name);
|
||||
if (dir == NULL)
|
||||
return -error;
|
||||
next = file->f_pos;
|
||||
@ -373,40 +302,59 @@ int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
|
||||
|
||||
int hostfs_file_open(struct inode *ino, struct file *file)
|
||||
{
|
||||
static DEFINE_MUTEX(open_mutex);
|
||||
char *name;
|
||||
fmode_t mode = 0;
|
||||
int err;
|
||||
int r = 0, w = 0, fd;
|
||||
|
||||
mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
|
||||
if ((mode & HOSTFS_I(ino)->mode) == mode)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* The file may already have been opened, but with the wrong access,
|
||||
* so this resets things and reopens the file with the new access.
|
||||
*/
|
||||
if (HOSTFS_I(ino)->fd != -1) {
|
||||
close_file(&HOSTFS_I(ino)->fd);
|
||||
HOSTFS_I(ino)->fd = -1;
|
||||
}
|
||||
mode |= HOSTFS_I(ino)->mode;
|
||||
|
||||
HOSTFS_I(ino)->mode |= mode;
|
||||
if (HOSTFS_I(ino)->mode & FMODE_READ)
|
||||
retry:
|
||||
if (mode & FMODE_READ)
|
||||
r = 1;
|
||||
if (HOSTFS_I(ino)->mode & FMODE_WRITE)
|
||||
if (mode & FMODE_WRITE)
|
||||
w = 1;
|
||||
if (w)
|
||||
r = 1;
|
||||
|
||||
name = dentry_name(file->f_path.dentry, 0);
|
||||
name = dentry_name(file->f_path.dentry);
|
||||
if (name == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
fd = open_file(name, r, w, append);
|
||||
kfree(name);
|
||||
__putname(name);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
FILE_HOSTFS_I(file)->fd = fd;
|
||||
|
||||
mutex_lock(&open_mutex);
|
||||
/* somebody else had handled it first? */
|
||||
if ((mode & HOSTFS_I(ino)->mode) == mode) {
|
||||
mutex_unlock(&open_mutex);
|
||||
return 0;
|
||||
}
|
||||
if ((mode | HOSTFS_I(ino)->mode) != mode) {
|
||||
mode |= HOSTFS_I(ino)->mode;
|
||||
mutex_unlock(&open_mutex);
|
||||
close_file(&fd);
|
||||
goto retry;
|
||||
}
|
||||
if (HOSTFS_I(ino)->fd == -1) {
|
||||
HOSTFS_I(ino)->fd = fd;
|
||||
} else {
|
||||
err = replace_file(fd, HOSTFS_I(ino)->fd);
|
||||
close_file(&fd);
|
||||
if (err < 0) {
|
||||
mutex_unlock(&open_mutex);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
HOSTFS_I(ino)->mode = mode;
|
||||
mutex_unlock(&open_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -544,54 +492,50 @@ static const struct address_space_operations hostfs_aops = {
|
||||
.write_end = hostfs_write_end,
|
||||
};
|
||||
|
||||
static int init_inode(struct inode *inode, struct dentry *dentry)
|
||||
static int read_name(struct inode *ino, char *name)
|
||||
{
|
||||
char *name;
|
||||
int type, err = -ENOMEM;
|
||||
int maj, min;
|
||||
dev_t rdev = 0;
|
||||
dev_t rdev;
|
||||
struct hostfs_stat st;
|
||||
int err = stat_file(name, &st, -1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (dentry) {
|
||||
name = dentry_name(dentry, 0);
|
||||
if (name == NULL)
|
||||
goto out;
|
||||
type = file_type(name, &maj, &min);
|
||||
/* Reencode maj and min with the kernel encoding.*/
|
||||
rdev = MKDEV(maj, min);
|
||||
kfree(name);
|
||||
/* Reencode maj and min with the kernel encoding.*/
|
||||
rdev = MKDEV(st.maj, st.min);
|
||||
|
||||
switch (st.mode & S_IFMT) {
|
||||
case S_IFLNK:
|
||||
ino->i_op = &hostfs_link_iops;
|
||||
break;
|
||||
case S_IFDIR:
|
||||
ino->i_op = &hostfs_dir_iops;
|
||||
ino->i_fop = &hostfs_dir_fops;
|
||||
break;
|
||||
case S_IFCHR:
|
||||
case S_IFBLK:
|
||||
case S_IFIFO:
|
||||
case S_IFSOCK:
|
||||
init_special_inode(ino, st.mode & S_IFMT, rdev);
|
||||
ino->i_op = &hostfs_iops;
|
||||
break;
|
||||
|
||||
default:
|
||||
ino->i_op = &hostfs_iops;
|
||||
ino->i_fop = &hostfs_file_fops;
|
||||
ino->i_mapping->a_ops = &hostfs_aops;
|
||||
}
|
||||
else type = OS_TYPE_DIR;
|
||||
|
||||
err = 0;
|
||||
if (type == OS_TYPE_SYMLINK)
|
||||
inode->i_op = &page_symlink_inode_operations;
|
||||
else if (type == OS_TYPE_DIR)
|
||||
inode->i_op = &hostfs_dir_iops;
|
||||
else inode->i_op = &hostfs_iops;
|
||||
|
||||
if (type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops;
|
||||
else inode->i_fop = &hostfs_file_fops;
|
||||
|
||||
if (type == OS_TYPE_SYMLINK)
|
||||
inode->i_mapping->a_ops = &hostfs_link_aops;
|
||||
else inode->i_mapping->a_ops = &hostfs_aops;
|
||||
|
||||
switch (type) {
|
||||
case OS_TYPE_CHARDEV:
|
||||
init_special_inode(inode, S_IFCHR, rdev);
|
||||
break;
|
||||
case OS_TYPE_BLOCKDEV:
|
||||
init_special_inode(inode, S_IFBLK, rdev);
|
||||
break;
|
||||
case OS_TYPE_FIFO:
|
||||
init_special_inode(inode, S_IFIFO, 0);
|
||||
break;
|
||||
case OS_TYPE_SOCK:
|
||||
init_special_inode(inode, S_IFSOCK, 0);
|
||||
break;
|
||||
}
|
||||
out:
|
||||
return err;
|
||||
ino->i_ino = st.ino;
|
||||
ino->i_mode = st.mode;
|
||||
ino->i_nlink = st.nlink;
|
||||
ino->i_uid = st.uid;
|
||||
ino->i_gid = st.gid;
|
||||
ino->i_atime = st.atime;
|
||||
ino->i_mtime = st.mtime;
|
||||
ino->i_ctime = st.ctime;
|
||||
ino->i_size = st.size;
|
||||
ino->i_blocks = st.blocks;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
|
||||
@ -607,12 +551,8 @@ int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = init_inode(inode, dentry);
|
||||
if (error)
|
||||
goto out_put;
|
||||
|
||||
error = -ENOMEM;
|
||||
name = dentry_name(dentry, 0);
|
||||
name = dentry_name(dentry);
|
||||
if (name == NULL)
|
||||
goto out_put;
|
||||
|
||||
@ -622,9 +562,10 @@ int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
|
||||
mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
|
||||
if (fd < 0)
|
||||
error = fd;
|
||||
else error = read_name(inode, name);
|
||||
else
|
||||
error = read_name(inode, name);
|
||||
|
||||
kfree(name);
|
||||
__putname(name);
|
||||
if (error)
|
||||
goto out_put;
|
||||
|
||||
@ -652,17 +593,14 @@ struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = init_inode(inode, dentry);
|
||||
if (err)
|
||||
goto out_put;
|
||||
|
||||
err = -ENOMEM;
|
||||
name = dentry_name(dentry, 0);
|
||||
name = dentry_name(dentry);
|
||||
if (name == NULL)
|
||||
goto out_put;
|
||||
|
||||
err = read_name(inode, name);
|
||||
kfree(name);
|
||||
|
||||
__putname(name);
|
||||
if (err == -ENOENT) {
|
||||
iput(inode);
|
||||
inode = NULL;
|
||||
@ -680,36 +618,21 @@ struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
|
||||
{
|
||||
char *file;
|
||||
int len;
|
||||
|
||||
file = inode_name(ino, dentry->d_name.len + 1);
|
||||
if (file == NULL)
|
||||
return NULL;
|
||||
strcat(file, "/");
|
||||
len = strlen(file);
|
||||
strncat(file, dentry->d_name.name, dentry->d_name.len);
|
||||
file[len + dentry->d_name.len] = '\0';
|
||||
return file;
|
||||
}
|
||||
|
||||
int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
|
||||
{
|
||||
char *from_name, *to_name;
|
||||
int err;
|
||||
|
||||
if ((from_name = inode_dentry_name(ino, from)) == NULL)
|
||||
if ((from_name = dentry_name(from)) == NULL)
|
||||
return -ENOMEM;
|
||||
to_name = dentry_name(to, 0);
|
||||
to_name = dentry_name(to);
|
||||
if (to_name == NULL) {
|
||||
kfree(from_name);
|
||||
__putname(from_name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
err = link_file(to_name, from_name);
|
||||
kfree(from_name);
|
||||
kfree(to_name);
|
||||
__putname(from_name);
|
||||
__putname(to_name);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -718,13 +641,14 @@ int hostfs_unlink(struct inode *ino, struct dentry *dentry)
|
||||
char *file;
|
||||
int err;
|
||||
|
||||
if ((file = inode_dentry_name(ino, dentry)) == NULL)
|
||||
return -ENOMEM;
|
||||
if (append)
|
||||
return -EPERM;
|
||||
|
||||
if ((file = dentry_name(dentry)) == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
err = unlink_file(file);
|
||||
kfree(file);
|
||||
__putname(file);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -733,10 +657,10 @@ int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
|
||||
char *file;
|
||||
int err;
|
||||
|
||||
if ((file = inode_dentry_name(ino, dentry)) == NULL)
|
||||
if ((file = dentry_name(dentry)) == NULL)
|
||||
return -ENOMEM;
|
||||
err = make_symlink(file, to);
|
||||
kfree(file);
|
||||
__putname(file);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -745,10 +669,10 @@ int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
|
||||
char *file;
|
||||
int err;
|
||||
|
||||
if ((file = inode_dentry_name(ino, dentry)) == NULL)
|
||||
if ((file = dentry_name(dentry)) == NULL)
|
||||
return -ENOMEM;
|
||||
err = do_mkdir(file, mode);
|
||||
kfree(file);
|
||||
__putname(file);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -757,10 +681,10 @@ int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
|
||||
char *file;
|
||||
int err;
|
||||
|
||||
if ((file = inode_dentry_name(ino, dentry)) == NULL)
|
||||
if ((file = dentry_name(dentry)) == NULL)
|
||||
return -ENOMEM;
|
||||
err = do_rmdir(file);
|
||||
kfree(file);
|
||||
__putname(file);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -776,22 +700,20 @@ int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = init_inode(inode, dentry);
|
||||
if (err)
|
||||
goto out_put;
|
||||
|
||||
err = -ENOMEM;
|
||||
name = dentry_name(dentry, 0);
|
||||
name = dentry_name(dentry);
|
||||
if (name == NULL)
|
||||
goto out_put;
|
||||
|
||||
init_special_inode(inode, mode, dev);
|
||||
err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
|
||||
if (err)
|
||||
if (!err)
|
||||
goto out_free;
|
||||
|
||||
err = read_name(inode, name);
|
||||
kfree(name);
|
||||
__putname(name);
|
||||
if (err)
|
||||
goto out_put;
|
||||
if (err)
|
||||
goto out_put;
|
||||
|
||||
@ -799,7 +721,7 @@ int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
|
||||
return 0;
|
||||
|
||||
out_free:
|
||||
kfree(name);
|
||||
__putname(name);
|
||||
out_put:
|
||||
iput(inode);
|
||||
out:
|
||||
@ -812,15 +734,15 @@ int hostfs_rename(struct inode *from_ino, struct dentry *from,
|
||||
char *from_name, *to_name;
|
||||
int err;
|
||||
|
||||
if ((from_name = inode_dentry_name(from_ino, from)) == NULL)
|
||||
if ((from_name = dentry_name(from)) == NULL)
|
||||
return -ENOMEM;
|
||||
if ((to_name = inode_dentry_name(to_ino, to)) == NULL) {
|
||||
kfree(from_name);
|
||||
if ((to_name = dentry_name(to)) == NULL) {
|
||||
__putname(from_name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
err = rename_file(from_name, to_name);
|
||||
kfree(from_name);
|
||||
kfree(to_name);
|
||||
__putname(from_name);
|
||||
__putname(to_name);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -832,7 +754,7 @@ int hostfs_permission(struct inode *ino, int desired)
|
||||
if (desired & MAY_READ) r = 1;
|
||||
if (desired & MAY_WRITE) w = 1;
|
||||
if (desired & MAY_EXEC) x = 1;
|
||||
name = inode_name(ino, 0);
|
||||
name = inode_name(ino);
|
||||
if (name == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -841,7 +763,7 @@ int hostfs_permission(struct inode *ino, int desired)
|
||||
err = 0;
|
||||
else
|
||||
err = access_file(name, r, w, x);
|
||||
kfree(name);
|
||||
__putname(name);
|
||||
if (!err)
|
||||
err = generic_permission(ino, desired, NULL);
|
||||
return err;
|
||||
@ -849,13 +771,14 @@ int hostfs_permission(struct inode *ino, int desired)
|
||||
|
||||
int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct hostfs_iattr attrs;
|
||||
char *name;
|
||||
int err;
|
||||
|
||||
int fd = HOSTFS_I(dentry->d_inode)->fd;
|
||||
int fd = HOSTFS_I(inode)->fd;
|
||||
|
||||
err = inode_change_ok(dentry->d_inode, attr);
|
||||
err = inode_change_ok(inode, attr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -897,15 +820,26 @@ int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
if (attr->ia_valid & ATTR_MTIME_SET) {
|
||||
attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
|
||||
}
|
||||
name = dentry_name(dentry, 0);
|
||||
name = dentry_name(dentry);
|
||||
if (name == NULL)
|
||||
return -ENOMEM;
|
||||
err = set_attr(name, &attrs, fd);
|
||||
kfree(name);
|
||||
__putname(name);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return inode_setattr(dentry->d_inode, attr);
|
||||
if ((attr->ia_valid & ATTR_SIZE) &&
|
||||
attr->ia_size != i_size_read(inode)) {
|
||||
int error;
|
||||
|
||||
error = vmtruncate(inode, attr->ia_size);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
setattr_copy(inode, attr);
|
||||
mark_inode_dirty(inode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct inode_operations hostfs_iops = {
|
||||
@ -935,32 +869,41 @@ static const struct inode_operations hostfs_dir_iops = {
|
||||
.setattr = hostfs_setattr,
|
||||
};
|
||||
|
||||
int hostfs_link_readpage(struct file *file, struct page *page)
|
||||
static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
char *buffer, *name;
|
||||
int err;
|
||||
|
||||
buffer = kmap(page);
|
||||
name = inode_name(page->mapping->host, 0);
|
||||
if (name == NULL)
|
||||
return -ENOMEM;
|
||||
err = hostfs_do_readlink(name, buffer, PAGE_CACHE_SIZE);
|
||||
kfree(name);
|
||||
if (err == PAGE_CACHE_SIZE)
|
||||
err = -E2BIG;
|
||||
else if (err > 0) {
|
||||
flush_dcache_page(page);
|
||||
SetPageUptodate(page);
|
||||
if (PageError(page)) ClearPageError(page);
|
||||
err = 0;
|
||||
char *link = __getname();
|
||||
if (link) {
|
||||
char *path = dentry_name(dentry);
|
||||
int err = -ENOMEM;
|
||||
if (path) {
|
||||
int err = hostfs_do_readlink(path, link, PATH_MAX);
|
||||
if (err == PATH_MAX)
|
||||
err = -E2BIG;
|
||||
__putname(path);
|
||||
}
|
||||
if (err < 0) {
|
||||
__putname(link);
|
||||
link = ERR_PTR(err);
|
||||
}
|
||||
} else {
|
||||
link = ERR_PTR(-ENOMEM);
|
||||
}
|
||||
kunmap(page);
|
||||
unlock_page(page);
|
||||
return err;
|
||||
|
||||
nd_set_link(nd, link);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const struct address_space_operations hostfs_link_aops = {
|
||||
.readpage = hostfs_link_readpage,
|
||||
static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
|
||||
{
|
||||
char *s = nd_get_link(nd);
|
||||
if (!IS_ERR(s))
|
||||
__putname(s);
|
||||
}
|
||||
|
||||
static const struct inode_operations hostfs_link_iops = {
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = hostfs_follow_link,
|
||||
.put_link = hostfs_put_link,
|
||||
};
|
||||
|
||||
static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
|
||||
@ -980,49 +923,41 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
|
||||
req_root = "";
|
||||
|
||||
err = -ENOMEM;
|
||||
host_root_path = kmalloc(strlen(root_ino) + 1
|
||||
+ strlen(req_root) + 1, GFP_KERNEL);
|
||||
sb->s_fs_info = host_root_path =
|
||||
kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
|
||||
if (host_root_path == NULL)
|
||||
goto out;
|
||||
|
||||
sprintf(host_root_path, "%s/%s", root_ino, req_root);
|
||||
|
||||
root_inode = hostfs_iget(sb);
|
||||
if (IS_ERR(root_inode)) {
|
||||
err = PTR_ERR(root_inode);
|
||||
goto out_free;
|
||||
}
|
||||
root_inode = new_inode(sb);
|
||||
if (!root_inode)
|
||||
goto out;
|
||||
|
||||
err = init_inode(root_inode, NULL);
|
||||
err = read_name(root_inode, host_root_path);
|
||||
if (err)
|
||||
goto out_put;
|
||||
|
||||
HOSTFS_I(root_inode)->host_filename = host_root_path;
|
||||
/*
|
||||
* Avoid that in the error path, iput(root_inode) frees again
|
||||
* host_root_path through hostfs_destroy_inode!
|
||||
*/
|
||||
host_root_path = NULL;
|
||||
if (S_ISLNK(root_inode->i_mode)) {
|
||||
char *name = follow_link(host_root_path);
|
||||
if (IS_ERR(name))
|
||||
err = PTR_ERR(name);
|
||||
else
|
||||
err = read_name(root_inode, name);
|
||||
kfree(name);
|
||||
if (err)
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
err = -ENOMEM;
|
||||
sb->s_root = d_alloc_root(root_inode);
|
||||
if (sb->s_root == NULL)
|
||||
goto out_put;
|
||||
|
||||
err = hostfs_read_inode(root_inode);
|
||||
if (err) {
|
||||
/* No iput in this case because the dput does that for us */
|
||||
dput(sb->s_root);
|
||||
sb->s_root = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_put:
|
||||
iput(root_inode);
|
||||
out_free:
|
||||
kfree(host_root_path);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
@ -1034,11 +969,17 @@ static int hostfs_read_sb(struct file_system_type *type,
|
||||
return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt);
|
||||
}
|
||||
|
||||
static void hostfs_kill_sb(struct super_block *s)
|
||||
{
|
||||
kill_anon_super(s);
|
||||
kfree(s->s_fs_info);
|
||||
}
|
||||
|
||||
static struct file_system_type hostfs_type = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "hostfs",
|
||||
.get_sb = hostfs_read_sb,
|
||||
.kill_sb = kill_anon_super,
|
||||
.kill_sb = hostfs_kill_sb,
|
||||
.fs_flags = 0,
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -277,9 +277,15 @@ int hpfs_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
if (error)
|
||||
goto out_unlock;
|
||||
|
||||
error = inode_setattr(inode, attr);
|
||||
if (error)
|
||||
goto out_unlock;
|
||||
if ((attr->ia_valid & ATTR_SIZE) &&
|
||||
attr->ia_size != i_size_read(inode)) {
|
||||
error = vmtruncate(inode, attr->ia_size);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
setattr_copy(inode, attr);
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
hpfs_write_inode(inode);
|
||||
|
||||
@ -296,11 +302,13 @@ void hpfs_write_if_changed(struct inode *inode)
|
||||
hpfs_write_inode(inode);
|
||||
}
|
||||
|
||||
void hpfs_delete_inode(struct inode *inode)
|
||||
void hpfs_evict_inode(struct inode *inode)
|
||||
{
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
lock_kernel();
|
||||
hpfs_remove_fnode(inode->i_sb, inode->i_ino);
|
||||
unlock_kernel();
|
||||
clear_inode(inode);
|
||||
end_writeback(inode);
|
||||
if (!inode->i_nlink) {
|
||||
lock_kernel();
|
||||
hpfs_remove_fnode(inode->i_sb, inode->i_ino);
|
||||
unlock_kernel();
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -371,27 +371,10 @@ static void truncate_hugepages(struct inode *inode, loff_t lstart)
|
||||
hugetlb_unreserve_pages(inode, start, freed);
|
||||
}
|
||||
|
||||
static void hugetlbfs_delete_inode(struct inode *inode)
|
||||
static void hugetlbfs_evict_inode(struct inode *inode)
|
||||
{
|
||||
truncate_hugepages(inode, 0);
|
||||
clear_inode(inode);
|
||||
}
|
||||
|
||||
static void hugetlbfs_forget_inode(struct inode *inode) __releases(inode_lock)
|
||||
{
|
||||
if (generic_detach_inode(inode)) {
|
||||
truncate_hugepages(inode, 0);
|
||||
clear_inode(inode);
|
||||
destroy_inode(inode);
|
||||
}
|
||||
}
|
||||
|
||||
static void hugetlbfs_drop_inode(struct inode *inode)
|
||||
{
|
||||
if (!inode->i_nlink)
|
||||
generic_delete_inode(inode);
|
||||
else
|
||||
hugetlbfs_forget_inode(inode);
|
||||
end_writeback(inode);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -448,19 +431,20 @@ static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
|
||||
error = inode_change_ok(inode, attr);
|
||||
if (error)
|
||||
goto out;
|
||||
return error;
|
||||
|
||||
if (ia_valid & ATTR_SIZE) {
|
||||
error = -EINVAL;
|
||||
if (!(attr->ia_size & ~huge_page_mask(h)))
|
||||
error = hugetlb_vmtruncate(inode, attr->ia_size);
|
||||
if (attr->ia_size & ~huge_page_mask(h))
|
||||
return -EINVAL;
|
||||
error = hugetlb_vmtruncate(inode, attr->ia_size);
|
||||
if (error)
|
||||
goto out;
|
||||
attr->ia_valid &= ~ATTR_SIZE;
|
||||
return error;
|
||||
}
|
||||
error = inode_setattr(inode, attr);
|
||||
out:
|
||||
return error;
|
||||
|
||||
setattr_copy(inode, attr);
|
||||
mark_inode_dirty(inode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid,
|
||||
@ -712,9 +696,8 @@ static const struct inode_operations hugetlbfs_inode_operations = {
|
||||
static const struct super_operations hugetlbfs_ops = {
|
||||
.alloc_inode = hugetlbfs_alloc_inode,
|
||||
.destroy_inode = hugetlbfs_destroy_inode,
|
||||
.evict_inode = hugetlbfs_evict_inode,
|
||||
.statfs = hugetlbfs_statfs,
|
||||
.delete_inode = hugetlbfs_delete_inode,
|
||||
.drop_inode = hugetlbfs_drop_inode,
|
||||
.put_super = hugetlbfs_put_super,
|
||||
.show_options = generic_show_options,
|
||||
};
|
||||
|
181
fs/inode.c
181
fs/inode.c
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user