/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2005-2019 Junjiro R. Okajima
*
* This program, aufs is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
/*
* sub-routines for VFS
*/
#ifndef __AUFS_VFSUB_H__
#define __AUFS_VFSUB_H__
#ifdef __KERNEL__
#include
#include
#include
#include
#include "debug.h"
/* copied from linux/fs/internal.h */
/* todo: BAD approach!! */
extern void __mnt_drop_write(struct vfsmount *);
extern struct file *alloc_empty_file(int, const struct cred *);
/* ---------------------------------------------------------------------- */
/* lock subclass for lower inode */
/* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */
/* reduce? gave up. */
enum {
AuLsc_I_Begin = I_MUTEX_PARENT2, /* 5 */
AuLsc_I_PARENT, /* lower inode, parent first */
AuLsc_I_PARENT2, /* copyup dirs */
AuLsc_I_PARENT3, /* copyup wh */
AuLsc_I_CHILD,
AuLsc_I_CHILD2,
AuLsc_I_End
};
/* to debug easier, do not make them inlined functions */
#define MtxMustLock(mtx) AuDebugOn(!mutex_is_locked(mtx))
#define IMustLock(i) AuDebugOn(!inode_is_locked(i))
/* ---------------------------------------------------------------------- */
static inline void vfsub_drop_nlink(struct inode *inode)
{
AuDebugOn(!inode->i_nlink);
drop_nlink(inode);
}
static inline void vfsub_dead_dir(struct inode *inode)
{
AuDebugOn(!S_ISDIR(inode->i_mode));
inode->i_flags |= S_DEAD;
clear_nlink(inode);
}
static inline int vfsub_native_ro(struct inode *inode)
{
return sb_rdonly(inode->i_sb)
|| IS_RDONLY(inode)
/* || IS_APPEND(inode) */
|| IS_IMMUTABLE(inode);
}
#ifdef CONFIG_AUFS_BR_FUSE
int vfsub_test_mntns(struct vfsmount *mnt, struct super_block *h_sb);
#else
AuStubInt0(vfsub_test_mntns, struct vfsmount *mnt, struct super_block *h_sb);
#endif
int vfsub_sync_filesystem(struct super_block *h_sb, int wait);
/* ---------------------------------------------------------------------- */
int vfsub_update_h_iattr(struct path *h_path, int *did);
struct file *vfsub_dentry_open(struct path *path, int flags);
struct file *vfsub_filp_open(const char *path, int oflags, int mode);
struct au_branch;
struct vfsub_aopen_args {
struct file *file;
unsigned int open_flag;
umode_t create_mode;
struct au_branch *br;
};
int vfsub_atomic_open(struct inode *dir, struct dentry *dentry,
struct vfsub_aopen_args *args);
int vfsub_kern_path(const char *name, unsigned int flags, struct path *path);
struct dentry *vfsub_lookup_one_len_unlocked(const char *name,
struct dentry *parent, int len);
struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent,
int len);
struct vfsub_lkup_one_args {
struct dentry **errp;
struct qstr *name;
struct dentry *parent;
};
static inline struct dentry *vfsub_lkup_one(struct qstr *name,
struct dentry *parent)
{
return vfsub_lookup_one_len(name->name, parent, name->len);
}
void vfsub_call_lkup_one(void *args);
/* ---------------------------------------------------------------------- */
static inline int vfsub_mnt_want_write(struct vfsmount *mnt)
{
int err;
lockdep_off();
err = mnt_want_write(mnt);
lockdep_on();
return err;
}
static inline void vfsub_mnt_drop_write(struct vfsmount *mnt)
{
lockdep_off();
mnt_drop_write(mnt);
lockdep_on();
}
#if 0 /* reserved */
static inline void vfsub_mnt_drop_write_file(struct file *file)
{
lockdep_off();
mnt_drop_write_file(file);
lockdep_on();
}
#endif
/* ---------------------------------------------------------------------- */
struct au_hinode;
struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1,
struct dentry *d2, struct au_hinode *hdir2);
void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1,
struct dentry *d2, struct au_hinode *hdir2);
int vfsub_create(struct inode *dir, struct path *path, int mode,
bool want_excl);
int vfsub_symlink(struct inode *dir, struct path *path,
const char *symname);
int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev);
int vfsub_link(struct dentry *src_dentry, struct inode *dir,
struct path *path, struct inode **delegated_inode);
int vfsub_rename(struct inode *src_hdir, struct dentry *src_dentry,
struct inode *hdir, struct path *path,
struct inode **delegated_inode, unsigned int flags);
int vfsub_mkdir(struct inode *dir, struct path *path, int mode);
int vfsub_rmdir(struct inode *dir, struct path *path);
/* ---------------------------------------------------------------------- */
ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count,
loff_t *ppos);
ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count,
loff_t *ppos);
ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count,
loff_t *ppos);
ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count,
loff_t *ppos);
int vfsub_flush(struct file *file, fl_owner_t id);
int vfsub_iterate_dir(struct file *file, struct dir_context *ctx);
static inline loff_t vfsub_f_size_read(struct file *file)
{
return i_size_read(file_inode(file));
}
static inline unsigned int vfsub_file_flags(struct file *file)
{
unsigned int flags;
spin_lock(&file->f_lock);
flags = file->f_flags;
spin_unlock(&file->f_lock);
return flags;
}
static inline int vfsub_file_execed(struct file *file)
{
/* todo: direct access f_flags */
return !!(vfsub_file_flags(file) & __FMODE_EXEC);
}
#if 0 /* reserved */
static inline void vfsub_file_accessed(struct file *h_file)
{
file_accessed(h_file);
vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); /*ignore*/
}
#endif
#if 0 /* reserved */
static inline void vfsub_touch_atime(struct vfsmount *h_mnt,
struct dentry *h_dentry)
{
struct path h_path = {
.dentry = h_dentry,
.mnt = h_mnt
};
touch_atime(&h_path);
vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/
}
#endif
static inline int vfsub_update_time(struct inode *h_inode,
struct timespec64 *ts, int flags)
{
return update_time(h_inode, ts, flags);
/* no vfsub_update_h_iattr() since we don't have struct path */
}
#ifdef CONFIG_FS_POSIX_ACL
static inline int vfsub_acl_chmod(struct inode *h_inode, umode_t h_mode)
{
int err;
err = posix_acl_chmod(h_inode, h_mode);
if (err == -EOPNOTSUPP)
err = 0;
return err;
}
#else
AuStubInt0(vfsub_acl_chmod, struct inode *h_inode, umode_t h_mode);
#endif
long vfsub_splice_to(struct file *in, loff_t *ppos,
struct pipe_inode_info *pipe, size_t len,
unsigned int flags);
long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out,
loff_t *ppos, size_t len, unsigned int flags);
static inline long vfsub_truncate(struct path *path, loff_t length)
{
long err;
lockdep_off();
err = vfs_truncate(path, length);
lockdep_on();
return err;
}
int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr,
struct file *h_file);
int vfsub_fsync(struct file *file, struct path *path, int datasync);
/*
* re-use branch fs's ioctl(FICLONE) while aufs itself doesn't support such
* ioctl.
*/
static inline loff_t vfsub_clone_file_range(struct file *src, struct file *dst,
loff_t len)
{
loff_t err;
lockdep_off();
err = vfs_clone_file_range(src, 0, dst, 0, len, /*remap_flags*/0);
lockdep_on();
return err;
}
/* copy_file_range(2) is a systemcall */
static inline ssize_t vfsub_copy_file_range(struct file *src, loff_t src_pos,
struct file *dst, loff_t dst_pos,
size_t len, unsigned int flags)
{
ssize_t ssz;
lockdep_off();
ssz = vfs_copy_file_range(src, src_pos, dst, dst_pos, len, flags);
lockdep_on();
return ssz;
}
/* ---------------------------------------------------------------------- */
static inline loff_t vfsub_llseek(struct file *file, loff_t offset, int origin)
{
loff_t err;
lockdep_off();
err = vfs_llseek(file, offset, origin);
lockdep_on();
return err;
}
/* ---------------------------------------------------------------------- */
int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode);
int vfsub_sio_rmdir(struct inode *dir, struct path *path);
int vfsub_sio_notify_change(struct path *path, struct iattr *ia,
struct inode **delegated_inode);
int vfsub_notify_change(struct path *path, struct iattr *ia,
struct inode **delegated_inode);
int vfsub_unlink(struct inode *dir, struct path *path,
struct inode **delegated_inode, int force);
static inline int vfsub_getattr(const struct path *path, struct kstat *st)
{
return vfs_getattr(path, st, STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT);
}
/* ---------------------------------------------------------------------- */
static inline int vfsub_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
int err;
lockdep_off();
err = vfs_setxattr(dentry, name, value, size, flags);
lockdep_on();
return err;
}
static inline int vfsub_removexattr(struct dentry *dentry, const char *name)
{
int err;
lockdep_off();
err = vfs_removexattr(dentry, name);
lockdep_on();
return err;
}
#endif /* __KERNEL__ */
#endif /* __AUFS_VFSUB_H__ */