]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - fs/aufs/file.h
UBUNTU: SAUCE: Import aufs driver
[mirror_ubuntu-zesty-kernel.git] / fs / aufs / file.h
diff --git a/fs/aufs/file.h b/fs/aufs/file.h
new file mode 100644 (file)
index 0000000..47cd520
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2005-2016 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 <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * file operations
+ */
+
+#ifndef __AUFS_FILE_H__
+#define __AUFS_FILE_H__
+
+#ifdef __KERNEL__
+
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include "rwsem.h"
+
+struct au_branch;
+struct au_hfile {
+       struct file             *hf_file;
+       struct au_branch        *hf_br;
+};
+
+struct au_vdir;
+struct au_fidir {
+       aufs_bindex_t           fd_bbot;
+       aufs_bindex_t           fd_nent;
+       struct au_vdir          *fd_vdir_cache;
+       struct au_hfile         fd_hfile[];
+};
+
+static inline int au_fidir_sz(int nent)
+{
+       AuDebugOn(nent < 0);
+       return sizeof(struct au_fidir) + sizeof(struct au_hfile) * nent;
+}
+
+struct au_finfo {
+       atomic_t                fi_generation;
+
+       struct au_rwsem         fi_rwsem;
+       aufs_bindex_t           fi_btop;
+
+       /* do not union them */
+       struct {                                /* for non-dir */
+               struct au_hfile                 fi_htop;
+               atomic_t                        fi_mmapped;
+       };
+       struct au_fidir         *fi_hdir;       /* for dir only */
+
+       struct hlist_node       fi_hlist;
+       union {
+               struct file             *fi_file;       /* very ugly */
+               struct llist_node       fi_lnode;       /* delayed free */
+       };
+} ____cacheline_aligned_in_smp;
+
+/* ---------------------------------------------------------------------- */
+
+/* file.c */
+extern const struct address_space_operations aufs_aop;
+unsigned int au_file_roflags(unsigned int flags);
+struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags,
+                      struct file *file, int force_wr);
+struct au_do_open_args {
+       int             no_lock;
+       int             (*open)(struct file *file, int flags,
+                               struct file *h_file);
+       struct au_fidir *fidir;
+       struct file     *h_file;
+};
+int au_do_open(struct file *file, struct au_do_open_args *args);
+int au_reopen_nondir(struct file *file);
+struct au_pin;
+int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin);
+int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file),
+                         int wlock);
+int au_do_flush(struct file *file, fl_owner_t id,
+               int (*flush)(struct file *file, fl_owner_t id));
+
+/* poll.c */
+#ifdef CONFIG_AUFS_POLL
+unsigned int aufs_poll(struct file *file, poll_table *wait);
+#endif
+
+#ifdef CONFIG_AUFS_BR_HFSPLUS
+/* hfsplus.c */
+struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex,
+                          int force_wr);
+void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex,
+                   struct file *h_file);
+#else
+AuStub(struct file *, au_h_open_pre, return NULL, struct dentry *dentry,
+       aufs_bindex_t bindex, int force_wr)
+AuStubVoid(au_h_open_post, struct dentry *dentry, aufs_bindex_t bindex,
+          struct file *h_file);
+#endif
+
+/* f_op.c */
+extern const struct file_operations aufs_file_fop;
+int au_do_open_nondir(struct file *file, int flags, struct file *h_file);
+int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file);
+struct file *au_read_pre(struct file *file, int keep_fi);
+
+/* finfo.c */
+void au_hfput(struct au_hfile *hf, int execed);
+void au_set_h_fptr(struct file *file, aufs_bindex_t bindex,
+                  struct file *h_file);
+
+void au_update_figen(struct file *file);
+struct au_fidir *au_fidir_alloc(struct super_block *sb);
+int au_fidir_realloc(struct au_finfo *finfo, int nbr, int may_shrink);
+
+void au_fi_init_once(void *_fi);
+void au_finfo_fin(struct file *file, int atonce);
+int au_finfo_init(struct file *file, struct au_fidir *fidir);
+
+/* ioctl.c */
+long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg);
+#ifdef CONFIG_COMPAT
+long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd,
+                          unsigned long arg);
+long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd,
+                             unsigned long arg);
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+static inline struct au_finfo *au_fi(struct file *file)
+{
+       return file->private_data;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * fi_read_lock, fi_write_lock,
+ * fi_read_unlock, fi_write_unlock, fi_downgrade_lock
+ */
+AuSimpleRwsemFuncs(fi, struct file *f, &au_fi(f)->fi_rwsem);
+
+#define FiMustNoWaiters(f)     AuRwMustNoWaiters(&au_fi(f)->fi_rwsem)
+#define FiMustAnyLock(f)       AuRwMustAnyLock(&au_fi(f)->fi_rwsem)
+#define FiMustWriteLock(f)     AuRwMustWriteLock(&au_fi(f)->fi_rwsem)
+
+/* ---------------------------------------------------------------------- */
+
+/* todo: hard/soft set? */
+static inline aufs_bindex_t au_fbtop(struct file *file)
+{
+       FiMustAnyLock(file);
+       return au_fi(file)->fi_btop;
+}
+
+static inline aufs_bindex_t au_fbbot_dir(struct file *file)
+{
+       FiMustAnyLock(file);
+       AuDebugOn(!au_fi(file)->fi_hdir);
+       return au_fi(file)->fi_hdir->fd_bbot;
+}
+
+static inline struct au_vdir *au_fvdir_cache(struct file *file)
+{
+       FiMustAnyLock(file);
+       AuDebugOn(!au_fi(file)->fi_hdir);
+       return au_fi(file)->fi_hdir->fd_vdir_cache;
+}
+
+static inline void au_set_fbtop(struct file *file, aufs_bindex_t bindex)
+{
+       FiMustWriteLock(file);
+       au_fi(file)->fi_btop = bindex;
+}
+
+static inline void au_set_fbbot_dir(struct file *file, aufs_bindex_t bindex)
+{
+       FiMustWriteLock(file);
+       AuDebugOn(!au_fi(file)->fi_hdir);
+       au_fi(file)->fi_hdir->fd_bbot = bindex;
+}
+
+static inline void au_set_fvdir_cache(struct file *file,
+                                     struct au_vdir *vdir_cache)
+{
+       FiMustWriteLock(file);
+       AuDebugOn(!au_fi(file)->fi_hdir);
+       au_fi(file)->fi_hdir->fd_vdir_cache = vdir_cache;
+}
+
+static inline struct file *au_hf_top(struct file *file)
+{
+       FiMustAnyLock(file);
+       AuDebugOn(au_fi(file)->fi_hdir);
+       return au_fi(file)->fi_htop.hf_file;
+}
+
+static inline struct file *au_hf_dir(struct file *file, aufs_bindex_t bindex)
+{
+       FiMustAnyLock(file);
+       AuDebugOn(!au_fi(file)->fi_hdir);
+       return au_fi(file)->fi_hdir->fd_hfile[0 + bindex].hf_file;
+}
+
+/* todo: memory barrier? */
+static inline unsigned int au_figen(struct file *f)
+{
+       return atomic_read(&au_fi(f)->fi_generation);
+}
+
+static inline void au_set_mmapped(struct file *f)
+{
+       if (atomic_inc_return(&au_fi(f)->fi_mmapped))
+               return;
+       pr_warn("fi_mmapped wrapped around\n");
+       while (!atomic_inc_return(&au_fi(f)->fi_mmapped))
+               ;
+}
+
+static inline void au_unset_mmapped(struct file *f)
+{
+       atomic_dec(&au_fi(f)->fi_mmapped);
+}
+
+static inline int au_test_mmapped(struct file *f)
+{
+       return atomic_read(&au_fi(f)->fi_mmapped);
+}
+
+/* customize vma->vm_file */
+
+static inline void au_do_vm_file_reset(struct vm_area_struct *vma,
+                                      struct file *file)
+{
+       struct file *f;
+
+       f = vma->vm_file;
+       get_file(file);
+       vma->vm_file = file;
+       fput(f);
+}
+
+#ifdef CONFIG_MMU
+#define AuDbgVmRegion(file, vma) do {} while (0)
+
+static inline void au_vm_file_reset(struct vm_area_struct *vma,
+                                   struct file *file)
+{
+       au_do_vm_file_reset(vma, file);
+}
+#else
+#define AuDbgVmRegion(file, vma) \
+       AuDebugOn((vma)->vm_region && (vma)->vm_region->vm_file != (file))
+
+static inline void au_vm_file_reset(struct vm_area_struct *vma,
+                                   struct file *file)
+{
+       struct file *f;
+
+       au_do_vm_file_reset(vma, file);
+       f = vma->vm_region->vm_file;
+       get_file(file);
+       vma->vm_region->vm_file = file;
+       fput(f);
+}
+#endif /* CONFIG_MMU */
+
+/* handle vma->vm_prfile */
+static inline void au_vm_prfile_set(struct vm_area_struct *vma,
+                                   struct file *file)
+{
+       get_file(file);
+       vma->vm_prfile = file;
+#ifndef CONFIG_MMU
+       get_file(file);
+       vma->vm_region->vm_prfile = file;
+#endif
+}
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_FILE_H__ */