lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Wed, 5 Dec 2007 20:08:30 +0530
From:	Bharata B Rao <bharata@...ux.vnet.ibm.com>
To:	linux-kernel@...r.kernel.org, linux-fsdevel@...r.kernel.org
Cc:	Jan Blunck <jblunck@...e.de>, Erez Zadok <ezk@...sunysb.edu>,
	viro@...iv.linux.org.uk, Christoph Hellwig <hch@....de>,
	Dave Hansen <haveblue@...ibm.com>
Subject: [RFC PATCH 1/5] Remove existing directory listing implementation

Remove the existing readdir implementation.

Signed-off-by: Bharata B Rao <bharata@...ux.vnet.ibm.com>
---
 fs/readdir.c          |   10 +
 fs/union.c            |  333 --------------------------------------------------
 include/linux/union.h |   23 ---
 3 files changed, 8 insertions(+), 358 deletions(-)

--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -16,12 +16,12 @@
 #include <linux/security.h>
 #include <linux/syscalls.h>
 #include <linux/unistd.h>
-#include <linux/union.h>
 
 #include <asm/uaccess.h>
 
 int vfs_readdir(struct file *file, filldir_t filler, void *buf)
 {
+	struct inode *inode = file->f_path.dentry->d_inode;
 	int res = -ENOTDIR;
 
 	if (!file->f_op || !file->f_op->readdir)
@@ -31,7 +31,13 @@ int vfs_readdir(struct file *file, filld
 	if (res)
 		goto out;
 
-	res = do_readdir(file, buf, filler);
+	mutex_lock(&inode->i_mutex);
+	res = -ENOENT;
+	if (!IS_DEADDIR(inode)) {
+		res = file->f_op->readdir(file, buf, filler);
+		file_accessed(file);
+	}
+	mutex_unlock(&inode->i_mutex);
 out:
 	return res;
 }
--- a/fs/union.c
+++ b/fs/union.c
@@ -516,339 +516,6 @@ int last_union_is_root(struct path *path
 }
 
 /*
- * Union mounts support for readdir.
- */
-
-/* This is a copy from fs/readdir.c */
-struct getdents_callback {
-	struct linux_dirent __user *current_dir;
-	struct linux_dirent __user *previous;
-	int count;
-	int error;
-};
-
-/* The readdir union cache object */
-struct union_cache_entry {
-	struct list_head list;
-	struct qstr name;
-};
-
-static int union_cache_add_entry(struct list_head *list,
-				 const char *name, int namelen)
-{
-	struct union_cache_entry *this;
-	char *tmp_name;
-
-	this = kmalloc(sizeof(*this), GFP_KERNEL);
-	if (!this) {
-		printk(KERN_CRIT
-		       "union_cache_add_entry(): out of kernel memory\n");
-		return -ENOMEM;
-	}
-
-	tmp_name = kmalloc(namelen + 1, GFP_KERNEL);
-	if (!tmp_name) {
-		printk(KERN_CRIT
-		       "union_cache_add_entry(): out of kernel memory\n");
-		kfree(this);
-		return -ENOMEM;
-	}
-
-	this->name.name = tmp_name;
-	this->name.len = namelen;
-	this->name.hash = 0;
-	memcpy(tmp_name, name, namelen);
-	tmp_name[namelen] = 0;
-	INIT_LIST_HEAD(&this->list);
-	list_add(&this->list, list);
-	return 0;
-}
-
-static void union_cache_free(struct list_head *uc_list)
-{
-	struct list_head *p;
-	struct list_head *ptmp;
-	int count = 0;
-
-	list_for_each_safe(p, ptmp, uc_list) {
-		struct union_cache_entry *this;
-
-		this = list_entry(p, struct union_cache_entry, list);
-		list_del_init(&this->list);
-		kfree(this->name.name);
-		kfree(this);
-		count++;
-	}
-	return;
-}
-
-static int union_cache_find_entry(struct list_head *uc_list,
-				  const char *name, int namelen)
-{
-	struct union_cache_entry *p;
-	int ret = 0;
-
-	list_for_each_entry(p, uc_list, list) {
-		if (p->name.len != namelen)
-			continue;
-		if (strncmp(p->name.name, name, namelen) == 0) {
-			ret = 1;
-			break;
-		}
-	}
-
-	return ret;
-}
-
-/*
- * There are four filldir() wrapper necessary for the union mount readdir
- * implementation:
- *
- * - filldir_topmost(): fills the union's readdir cache and the user space
- *			buffer. This is only used for the topmost directory
- *			in the union stack.
- * - filldir_topmost_cacheonly(): only fills the union's readdir cache.
- *			This is only used for the topmost directory in the
- *			union stack.
- * - filldir_overlaid(): fills the union's readdir cache and the user space
- *			buffer. This is only used for directories on the
- *			stack's lower layers.
- * - filldir_overlaid_cacheonly(): only fills the union's readdir cache.
- *			This is only used for directories on the stack's
- *			lower layers.
- */
-
-struct union_cache_callback {
-	struct getdents_callback *buf;	/* original getdents_callback */
-	struct list_head list;		/* list of union cache entries */
-	filldir_t filler;		/* the filldir() we should call */
-	loff_t offset;			/* base offset of our dirents */
-	loff_t count;			/* maximum number of bytes to "read" */
-};
-
-static int filldir_topmost(void *buf, const char *name, int namlen,
-			   loff_t offset, u64 ino, unsigned int d_type)
-{
-	struct union_cache_callback *cb = buf;
-
-	union_cache_add_entry(&cb->list, name, namlen);
-	return cb->filler(cb->buf, name, namlen, cb->offset + offset, ino,
-			  d_type);
-}
-
-static int filldir_topmost_cacheonly(void *buf, const char *name, int namlen,
-				     loff_t offset, u64 ino,
-				     unsigned int d_type)
-{
-	struct union_cache_callback *cb = buf;
-
-	if (offset > cb->count)
-		return -EINVAL;
-
-	union_cache_add_entry(&cb->list, name, namlen);
-	return 0;
-}
-
-static int filldir_overlaid(void *buf, const char *name, int namlen,
-			    loff_t offset, u64 ino, unsigned int d_type)
-{
-	struct union_cache_callback *cb = buf;
-
-	switch (namlen) {
-	case 2:
-		if (name[1] != '.')
-			break;
-	case 1:
-		if (name[0] != '.')
-			break;
-		return 0;
-	}
-
-	if (union_cache_find_entry(&cb->list, name, namlen))
-		return 0;
-
-	union_cache_add_entry(&cb->list, name, namlen);
-	return cb->filler(cb->buf, name, namlen, cb->offset + offset, ino,
-			  d_type);
-}
-
-static int filldir_overlaid_cacheonly(void *buf, const char *name, int namlen,
-				      loff_t offset, u64 ino,
-				      unsigned int d_type)
-{
-	struct union_cache_callback *cb = buf;
-
-	if (offset > cb->count)
-		return -EINVAL;
-
-	switch (namlen) {
-	case 2:
-		if (name[1] != '.')
-			break;
-	case 1:
-		if (name[0] != '.')
-			break;
-		return 0;
-	}
-
-	if (union_cache_find_entry(&cb->list, name, namlen))
-		return 0;
-
-	union_cache_add_entry(&cb->list, name, namlen);
-	return 0;
-}
-
-/*
- * readdir_union_cache - A helper to fill the readdir cache
- */
-static int readdir_union_cache(struct file *file, void *_buf, filldir_t filler)
-{
-	struct union_cache_callback *cb = _buf;
-	int old_count;
-	loff_t old_pos;
-	int res;
-
-	old_count = cb->count;
-	cb->count = ((file->f_pos > i_size_read(file->f_path.dentry->d_inode)) ?
-		      i_size_read(file->f_path.dentry->d_inode) :
-		      file->f_pos) & INT_MAX;
-	old_pos = file->f_pos;
-	file->f_pos = 0;
-	res = file->f_op->readdir(file, _buf, filler);
-	file->f_pos = old_pos;
-	cb->count = old_count;
-	return res;
-}
-
-/*
- * readdir_union - A wrapper around ->readdir()
- *
- * This is a wrapper around the filesystems readdir(), which is walking
- * the union stack and calls ->readdir() for every directory in the stack.
- * The directory entries are read into the union mounts readdir cache to
- * support whiteout's and duplicate removal.
- */
-int readdir_union(struct file *file, void *buf, filldir_t filler)
-{
-	struct inode *inode = file->f_path.dentry->d_inode;
-	struct union_cache_callback cb;
-	struct path path;
-	loff_t offset = 0;
-	int res = 0;
-
-	mutex_lock(&inode->i_mutex);
-	if (IS_DEADDIR(inode)) {
-		mutex_unlock(&inode->i_mutex);
-		return -ENOENT;
-	}
-
-	INIT_LIST_HEAD(&cb.list);
-	cb.buf = buf;
-	cb.filler = filler;
-	cb.offset = 0;
-	offset = i_size_read(file->f_path.dentry->d_inode);
-	cb.count = file->f_pos;
-
-	if (file->f_pos > 0) {
-		/*
-		 * We have already read from this dir, lets read that stuff to
-		 * our union-cache only
-		 */
-		res = readdir_union_cache(file, &cb,
-					  filldir_topmost_cacheonly);
-		if (res) {
-			mutex_unlock(&inode->i_mutex);
-			goto out;
-		}
-	}
-
-	if (file->f_pos < offset) {
-		res = file->f_op->readdir(file, &cb, filldir_topmost);
-		file_accessed(file);
-		if (res) {
-			mutex_unlock(&inode->i_mutex);
-			goto out;
-		}
-		/* We read until EOF of this directory */
-		file->f_pos = offset;
-	}
-
-	mutex_unlock(&inode->i_mutex);
-
-	path = file->f_path;
-	path_get(&path);
-	while (follow_union_down(&path.mnt, &path.dentry)) {
-		struct file *ftmp;
-
-		/* get path reference for filep */
-		path_get(&path);
-		ftmp = dentry_open(path.dentry, path.mnt,
-				   ((file->f_flags & ~(O_ACCMODE)) |
-				    O_RDONLY | O_DIRECTORY | O_NOATIME));
-		if (IS_ERR(ftmp)) {
-			res = PTR_ERR(ftmp);
-			break;
-		}
-
-		inode = path.dentry->d_inode;
-		mutex_lock(&inode->i_mutex);
-
-		/* rearrange the file position */
-		cb.offset += offset;
-		offset = i_size_read(inode);
-		ftmp->f_pos = file->f_pos - cb.offset;
-		cb.count = ftmp->f_pos;
-		if (ftmp->f_pos < 0) {
-			mutex_unlock(&inode->i_mutex);
-			fput(ftmp);
-			break;
-		}
-
-		res = -ENOENT;
-		if (IS_DEADDIR(inode))
-			goto out_fput;
-
-		if (ftmp->f_pos > 0) {
-			/*
-			 * We have already read from this dir, lets read that
-			 * stuff to our union-cache only
-			 */
-			res = readdir_union_cache(ftmp, &cb,
-						  filldir_overlaid_cacheonly);
-			if (res)
-				goto out_fput;
-		}
-
-		if (ftmp->f_pos < offset) {
-			res = ftmp->f_op->readdir(ftmp, &cb, filldir_overlaid);
-			file_accessed(ftmp);
-			if (res)
-				file->f_pos += ftmp->f_pos;
-			else
-				/*
-				 * We read until EOF of this directory, so lets
-				 * advance the f_pos by the maximum offset
-				 * (i_size) of this directory
-				 */
-				file->f_pos += offset;
-		}
-
-		file_accessed(ftmp);
-
-out_fput:
-		mutex_unlock(&inode->i_mutex);
-		fput(ftmp);
-
-		if (res)
-			break;
-	}
-	path_put(&path);
-out:
-	union_cache_free(&cb.list);
-	return res;
-}
-
-/*
  * Union mount copyup support
  */
 
--- a/include/linux/union.h
+++ b/include/linux/union.h
@@ -54,7 +54,6 @@ extern int attach_mnt_union(struct vfsmo
 			    struct dentry *);
 extern void detach_mnt_union(struct vfsmount *);
 extern int last_union_is_root(struct path *);
-extern int readdir_union(struct file *, void *, filldir_t);
 extern int is_dir_unioned(struct path *);
 extern int union_relookup_topmost(struct nameidata *, int);
 extern struct dentry *union_create_topmost(struct nameidata *, struct qstr *,
@@ -83,27 +82,5 @@ extern int union_copyup(struct nameidata
 
 #endif	/* CONFIG_UNION_MOUNT */
 
-static inline int do_readdir(struct file *file, void *buf, filldir_t filler)
-{
-	int res = 0;
-	struct inode *inode = file->f_path.dentry->d_inode;
-
-#ifdef CONFIG_UNION_MOUNT
-	if (IS_MNT_UNION(file->f_path.mnt) && is_dir_unioned(&file->f_path))
-		res = readdir_union(file, buf, filler);
-	else
-#endif
-	{
-		mutex_lock(&inode->i_mutex);
-		res = -ENOENT;
-		if (!IS_DEADDIR(inode)) {
-			res = file->f_op->readdir(file, buf, filler);
-			file_accessed(file);
-		}
-		mutex_unlock(&inode->i_mutex);
-	}
-	return res;
-}
-
 #endif	/* __KERNEL__ */
 #endif	/* __LINUX_UNION_H */
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists