[PATCH 20/24] Unionfs: Internal include file

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Josef "Jeff" Sipek <[email protected]>

This patch contains an internal Unionfs include file. The include file is
specific to kernel code only, and therefore is separate from
include/linux/unionfs.h.

Signed-off-by: Josef "Jeff" Sipek <[email protected]>
Signed-off-by: David Quigley <[email protected]>
Signed-off-by: Erez Zadok <[email protected]>
---
 fs/unionfs/union.h |  495 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 495 insertions(+), 0 deletions(-)

diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h
new file mode 100644
index 0000000..624132b
--- /dev/null
+++ b/fs/unionfs/union.h
@@ -0,0 +1,495 @@
+/*
+ * Copyright (c) 2003-2006 Erez Zadok
+ * Copyright (c) 2003-2006 Charles P. Wright
+ * Copyright (c) 2005-2006 Josef Sipek
+ * Copyright (c) 2005      Arun M. Krishnakumar
+ * Copyright (c) 2004-2006 David P. Quigley
+ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
+ * Copyright (c) 2003      Puja Gupta
+ * Copyright (c) 2003      Harikesavan Krishnan
+ * Copyright (c) 2003-2006 Stony Brook University
+ * Copyright (c) 2003-2006 The Research Foundation of State University of New York
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _UNION_H_
+#define _UNION_H_
+
+#include <linux/dcache.h>
+#include <linux/file.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/page-flags.h>
+#include <linux/pagemap.h>
+#include <linux/poll.h>
+#include <linux/security.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/statfs.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include <linux/writeback.h>
+#include <linux/fs_stack.h>
+#include <linux/magic.h>
+
+#include <asm/mman.h>
+#include <asm/system.h>
+
+#include <linux/union_fs.h>
+
+/* the file system name */
+#define UNIONFS_NAME "unionfs"
+
+/* unionfs root inode number */
+#define UNIONFS_ROOT_INO     1
+
+/* Mount time flags */
+#define MOUNT_FLAG(sb)     (UNIONFS_SB(sb)->mount_flag)
+
+/* number of characters while generating unique temporary file names */
+#define	UNIONFS_TMPNAM_LEN	12
+
+/* number of times we try to get a unique temporary file name */
+#define GET_TMPNAM_MAX_RETRY	5
+
+/* Operations vectors defined in specific files. */
+extern struct file_operations unionfs_main_fops;
+extern struct file_operations unionfs_dir_fops;
+extern struct inode_operations unionfs_main_iops;
+extern struct inode_operations unionfs_dir_iops;
+extern struct inode_operations unionfs_symlink_iops;
+extern struct super_operations unionfs_sops;
+extern struct dentry_operations unionfs_dops;
+
+/* How long should an entry be allowed to persist */
+#define RDCACHE_JIFFIES	(5*HZ)
+
+/* file private data. */
+struct unionfs_file_info {
+	int bstart;
+	int bend;
+	atomic_t generation;
+
+	struct unionfs_dir_state *rdstate;
+	struct file **lower_files;
+};
+
+/* unionfs inode data in memory */
+struct unionfs_inode_info {
+	int bstart;
+	int bend;
+	atomic_t generation;
+	int stale;
+	/* Stuff for readdir over NFS. */
+	spinlock_t rdlock;
+	struct list_head readdircache;
+	int rdcount;
+	int hashsize;
+	int cookie;
+	
+	/* The hidden inodes */
+	struct inode **lower_inodes;
+	/* to keep track of reads/writes for unlinks before closes */
+	atomic_t totalopens;
+
+	struct inode vfs_inode;
+};
+
+/* unionfs dentry data in memory */
+struct unionfs_dentry_info {
+	/* The semaphore is used to lock the dentry as soon as we get into a
+	 * unionfs function from the VFS.  Our lock ordering is that children
+	 * go before their parents.
+	 */
+	struct semaphore sem;
+	int bstart;
+	int bend;
+	int bopaque;
+	int bcount;
+	atomic_t generation;
+	struct path *lower_paths;
+};
+
+/* These are the pointers to our various objects. */
+struct unionfs_data {
+	struct super_block *sb;
+	struct vfsmount *hidden_mnt;
+	atomic_t sbcount;
+	int branchperms;
+};
+
+/* unionfs super-block data in memory */
+struct unionfs_sb_info {
+	int bend;
+
+	atomic_t generation;
+	unsigned long mount_flag;
+	struct rw_semaphore rwsem;
+
+	struct unionfs_data *data;
+};
+
+/*
+ * structure for making the linked list of entries by readdir on left branch
+ * to compare with entries on right branch
+ */
+struct filldir_node {
+	struct list_head file_list;	/* list for directory entries */
+	char *name;		/* name entry */
+	int hash;		/* name hash */
+	int namelen;		/* name len since name is not 0 terminated */
+
+	/* we can check for duplicate whiteouts and files in the same branch
+	 * in order to return -EIO.
+	 */ 
+	int bindex;		
+
+	/* is this a whiteout entry? */
+	int whiteout;
+
+	/* Inline name, so we don't need to separately kmalloc small ones */
+	char iname[DNAME_INLINE_LEN_MIN];
+};
+
+/* Directory hash table. */
+struct unionfs_dir_state {
+	unsigned int cookie;	/* The cookie, which is based off of rdversion */
+	unsigned int offset;	/* The entry we have returned. */
+	int bindex;
+	loff_t dirpos;		/* The offset within the lower level directory. */
+	int size;		/* How big is the hash table? */
+	int hashentries;	/* How many entries have been inserted? */
+	unsigned long access;
+
+	/* This cache list is used when the inode keeps us around. */
+	struct list_head cache;
+	struct list_head list[0];
+};
+
+/* include miscellaneous macros */
+#include "fanout.h"
+#include "sioq.h"
+
+/* Cache creation/deletion routines. */
+void unionfs_destroy_filldir_cache(void);
+int unionfs_init_filldir_cache(void);
+int unionfs_init_inode_cache(void);
+void unionfs_destroy_inode_cache(void);
+int unionfs_init_dentry_cache(void);
+void unionfs_destroy_dentry_cache(void);
+
+/* Initialize and free readdir-specific  state. */
+int init_rdstate(struct file *file);
+struct unionfs_dir_state *alloc_rdstate(struct inode *inode, int bindex);
+struct unionfs_dir_state *find_rdstate(struct inode *inode, loff_t fpos);
+void free_rdstate(struct unionfs_dir_state *state);
+int add_filldir_node(struct unionfs_dir_state *rdstate, const char *name,
+		     int namelen, int bindex, int whiteout);
+struct filldir_node *find_filldir_node(struct unionfs_dir_state *rdstate,
+				       const char *name, int namelen);
+
+struct dentry **alloc_new_dentries(int objs);
+struct unionfs_data *alloc_new_data(int objs);
+
+/* We can only use 32-bits of offset for rdstate --- blech! */
+#define DIREOF (0xfffff)
+#define RDOFFBITS 20		/* This is the number of bits in DIREOF. */
+#define MAXRDCOOKIE (0xfff)
+/* Turn an rdstate into an offset. */
+static inline off_t rdstate2offset(struct unionfs_dir_state *buf)
+{
+	off_t tmp;
+	tmp = ((buf->cookie & MAXRDCOOKIE) << RDOFFBITS)
+		| (buf->offset & DIREOF);
+	return tmp;
+}
+
+#define unionfs_read_lock(sb)	 down_read(&UNIONFS_SB(sb)->rwsem)
+#define unionfs_read_unlock(sb)	 up_read(&UNIONFS_SB(sb)->rwsem)
+#define unionfs_write_lock(sb)	 down_write(&UNIONFS_SB(sb)->rwsem)
+#define unionfs_write_unlock(sb) up_write(&UNIONFS_SB(sb)->rwsem)
+
+static inline void double_lock_dentry(struct dentry *d1, struct dentry *d2)
+{
+	if (d2 < d1) {
+		struct dentry *tmp = d1;
+		d1 = d2;
+		d2 = tmp;
+	}
+	lock_dentry(d1);
+	lock_dentry(d2);
+}
+
+extern int new_dentry_private_data(struct dentry *dentry);
+void free_dentry_private_data(struct unionfs_dentry_info *udi);
+void update_bstart(struct dentry *dentry);
+
+/*
+ * EXTERNALS:
+ */
+
+/* replicates the directory structure upto given dentry in given branch */
+extern struct dentry *create_parents(struct inode *dir, struct dentry *dentry,
+				     int bindex);
+struct dentry *create_parents_named(struct inode *dir, struct dentry *dentry,
+				    const char *name, int bindex);
+
+/* check if two branches overlap */
+extern int is_branch_overlap(struct dentry *dent1, struct dentry *dent2);
+
+/* partial lookup */
+extern int unionfs_partial_lookup(struct dentry *dentry);
+
+/* Pass an unionfs dentry and an index and it will try to create a whiteout
+ * in branch 'index'.
+ *
+ * On error, it will proceed to a branch to the left
+ */
+extern int create_whiteout(struct dentry *dentry, int start);
+/* copies a file from dbstart to newbindex branch */
+extern int copyup_file(struct inode *dir, struct file *file, int bstart,
+		       int newbindex, loff_t size);
+extern int copyup_named_file(struct inode *dir, struct file *file,
+			     char *name, int bstart, int new_bindex,
+			     loff_t len);
+/* copies a dentry from dbstart to newbindex branch */
+extern int copyup_dentry(struct inode *dir, struct dentry *dentry, int bstart,
+			 int new_bindex, struct file **copyup_file, loff_t len);
+extern int copyup_named_dentry(struct inode *dir, struct dentry *dentry,
+			       int bstart, int new_bindex, const char *name,
+			       int namelen, struct file **copyup_file,
+			       loff_t len);
+
+extern int remove_whiteouts(struct dentry *dentry, struct dentry *hidden_dentry,
+			    int bindex);
+
+extern int do_delete_whiteouts(struct dentry *dentry, int bindex,
+		     struct unionfs_dir_state *namelist);
+
+/* Is this directory empty: 0 if it is empty, -ENOTEMPTY if not. */
+extern int check_empty(struct dentry *dentry,
+		       struct unionfs_dir_state **namelist);
+/* Delete whiteouts from this directory in branch bindex. */
+extern int delete_whiteouts(struct dentry *dentry, int bindex,
+			    struct unionfs_dir_state *namelist);
+
+/* Re-lookup a hidden dentry. */
+extern int unionfs_refresh_hidden_dentry(struct dentry *dentry, int bindex);
+
+extern void unionfs_reinterpose(struct dentry *this_dentry);
+extern struct super_block *unionfs_duplicate_super(struct super_block *sb);
+
+/* Locking functions. */
+extern int unionfs_setlk(struct file *file, int cmd, struct file_lock *fl);
+extern int unionfs_getlk(struct file *file, struct file_lock *fl);
+
+/* Common file operations. */
+extern int unionfs_file_revalidate(struct file *file, int willwrite);
+extern int unionfs_open(struct inode *inode, struct file *file);
+extern int unionfs_file_release(struct inode *inode, struct file *file);
+extern int unionfs_flush(struct file *file, fl_owner_t id);
+extern long unionfs_ioctl(struct file *file, unsigned int cmd,
+			  unsigned long arg);
+
+/* Inode operations */
+extern int unionfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+			  struct inode *new_dir, struct dentry *new_dentry);
+int unionfs_unlink(struct inode *dir, struct dentry *dentry);
+int unionfs_rmdir(struct inode *dir, struct dentry *dentry);
+
+int unionfs_d_revalidate(struct dentry *dentry, struct nameidata *nd);
+
+/* The values for unionfs_interpose's flag. */
+#define INTERPOSE_DEFAULT	0
+#define INTERPOSE_LOOKUP	1
+#define INTERPOSE_REVAL		2
+#define INTERPOSE_REVAL_NEG	3
+#define INTERPOSE_PARTIAL	4
+
+extern int unionfs_interpose(struct dentry *this_dentry, struct super_block *sb,
+			     int flag);
+
+/* Branch management ioctls. */
+int unionfs_ioctl_incgen(struct file *file, unsigned int cmd,
+			 unsigned long arg);
+int unionfs_ioctl_queryfile(struct file *file, unsigned int cmd,
+			    unsigned long arg);
+
+/* Verify that a branch is valid. */
+int check_branch(struct nameidata *nd);
+
+/* The root directory is unhashed, but isn't deleted. */
+static inline int d_deleted(struct dentry *d)
+{
+	return d_unhashed(d) && (d != d->d_sb->s_root);
+}
+
+/* returns the sum of the n_link values of all the underlying inodes of the
+ * passed inode
+ */
+static inline int unionfs_get_nlinks(struct inode *inode)
+{
+	int sum_nlinks = 0;
+	int dirs = 0;
+	int bindex;
+	struct inode *hidden_inode;
+
+	/* don't bother to do all the work since we're unlinked */
+	if (inode->i_nlink == 0)
+		return 0;
+
+	if (!S_ISDIR(inode->i_mode))
+		return unionfs_lower_inode(inode)->i_nlink;
+
+	for (bindex = ibstart(inode); bindex <= ibend(inode); bindex++) {
+		hidden_inode = unionfs_lower_inode_idx(inode, bindex);
+
+		/* ignore files */
+		if (!hidden_inode || !S_ISDIR(hidden_inode->i_mode))
+			continue;
+
+		BUG_ON(hidden_inode->i_nlink < 0);
+
+		/* A deleted directory. */
+		if (hidden_inode->i_nlink == 0)
+			continue;
+		dirs++;
+
+		/*
+		 * A broken directory...
+		 *
+		 * Some filesystems don't properly set the number of links
+		 * on empty directories
+		 */
+		if (hidden_inode->i_nlink == 1)
+			sum_nlinks += 2;
+		else
+			sum_nlinks += (hidden_inode->i_nlink - 2);
+	}
+
+	return (!dirs ? 0 : sum_nlinks + 2);
+}
+
+struct dentry *unionfs_lookup_backend(struct dentry *dentry, struct nameidata *nd, int lookupmode);
+int is_stale_inode(struct inode *inode);
+void make_stale_inode(struct inode *inode);
+
+#define IS_SET(sb, check_flag) ((check_flag) & MOUNT_FLAG(sb))
+
+/* unionfs_permission, check if we should bypass error to facilitate copyup */
+#define IS_COPYUP_ERR(err) ((err) == -EROFS)
+
+/* unionfs_open, check if we need to copyup the file */
+#define OPEN_WRITE_FLAGS (O_WRONLY | O_RDWR | O_APPEND)
+#define IS_WRITE_FLAG(flag) ((flag) & OPEN_WRITE_FLAGS)
+
+static inline int branchperms(const struct super_block *sb, int index)
+{
+	BUG_ON(index < 0);
+
+	return UNIONFS_SB(sb)->data[index].branchperms;
+}
+
+static inline int set_branchperms(struct super_block *sb, int index, int perms)
+{
+	BUG_ON(index < 0);
+
+	UNIONFS_SB(sb)->data[index].branchperms = perms;
+
+	return perms;
+}
+
+/* Is this file on a read-only branch? */
+static inline int is_robranch_super(const struct super_block *sb, int index)
+{
+	return (!(branchperms(sb, index) & MAY_WRITE)) ? -EROFS : 0;
+}
+
+/* Is this file on a read-only branch? */
+static inline int is_robranch_idx(const struct dentry *dentry, int index)
+{
+	int err = 0;
+
+	BUG_ON(index < 0);
+
+	if ((!(branchperms(dentry->d_sb, index) & MAY_WRITE)) ||
+	    IS_RDONLY(unionfs_lower_dentry_idx(dentry, index)->d_inode))
+		err = -EROFS;
+
+	return err;
+}
+
+static inline int is_robranch(const struct dentry *dentry)
+{
+	int index;
+
+	index = UNIONFS_D(dentry)->bstart;
+	BUG_ON(index < 0);
+
+	return is_robranch_idx(dentry, index);
+}
+
+/* What do we use for whiteouts. */
+#define UNIONFS_WHPFX ".wh."
+#define UNIONFS_WHLEN 4
+/* If a directory contains this file, then it is opaque.  We start with the
+ * .wh. flag so that it is blocked by lookup.
+ */
+#define UNIONFS_DIR_OPAQUE_NAME "__dir_opaque"
+#define UNIONFS_DIR_OPAQUE UNIONFS_WHPFX UNIONFS_DIR_OPAQUE_NAME
+
+/* construct whiteout filename */
+static inline char *alloc_whname(const char *name, int len)
+{
+	char *buf;
+
+	buf = kmalloc(len + UNIONFS_WHLEN + 1, GFP_KERNEL);
+	if (!buf)
+		return ERR_PTR(-ENOMEM);
+
+	strcpy(buf, UNIONFS_WHPFX);
+	strlcat(buf, name, len + UNIONFS_WHLEN + 1);
+
+	return buf;
+}
+
+#define VALID_MOUNT_FLAGS (0)
+
+#ifndef DEFAULT_POLLMASK
+#define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)
+#endif
+
+/*
+ * EXTERNALS:
+ */
+
+/* These two functions are here because it is kind of daft to copy and paste the
+ * contents of the two functions to 32+ places in unionfs
+ */
+static inline struct dentry *lock_parent(struct dentry *dentry)
+{
+	struct dentry *dir = dget(dentry->d_parent);
+
+	mutex_lock(&dir->d_inode->i_mutex);
+	return dir;
+}
+
+static inline void unlock_dir(struct dentry *dir)
+{
+	mutex_unlock(&dir->d_inode->i_mutex);
+	dput(dir);
+}
+
+extern int make_dir_opaque(struct dentry *dir, int bindex);
+
+#endif	/* not _UNION_H_ */
+
-- 
1.4.4.2

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux