* [PATCH 15/28] VFS: Mountpoint file descriptor umount support
[not found] <10987155332448@sun.com>
@ 2004-10-25 14:46 ` Mike Waychison
2004-10-25 14:46 ` [PATCH 16/28] VFS: Mountpoint file descriptor attach support Mike Waychison
2004-10-26 10:28 ` [PATCH 15/28] VFS: Mountpoint file descriptor umount support Christoph Hellwig
0 siblings, 2 replies; 21+ messages in thread
From: Mike Waychison @ 2004-10-25 14:46 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel; +Cc: raven
This patch adds functionality to mountfd so that a user can perform the
various types of umount (forced umount, not-busy umount, lazy-umount).
Signed-off-by: Mike Waychison <michael.waychison@sun.com>
---
fs/mountfd.c | 20 ++++++++++++++++++++
fs/namespace.c | 2 +-
include/linux/fs.h | 5 ++++-
3 files changed, 25 insertions(+), 2 deletions(-)
Index: linux-2.6.9-quilt/fs/mountfd.c
===================================================================
--- linux-2.6.9-quilt.orig/fs/mountfd.c 2004-10-22 17:17:40.736271288 -0400
+++ linux-2.6.9-quilt/fs/mountfd.c 2004-10-22 17:17:41.367175376 -0400
@@ -11,6 +11,8 @@
#define VFSMOUNT(filp) ((struct vfsmount *)((filp)->private_data))
+extern int do_umount(struct vfsmount *mnt, int flags);
+
static struct vfsmount *mfdfs_mnt;
static void mfdfs_read_inode(struct inode *inode);
@@ -72,6 +74,18 @@ static int mfd_release(struct inode *ino
return 0;
}
+static long mfd_umount(struct file *mountfilp, int flags)
+{
+ struct vfsmount *mnt;
+ int error;
+
+ mnt = mntget(VFSMOUNT(mountfilp));
+
+ error = do_umount(mnt, flags);
+
+ return error;
+}
+
static int mfd_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
static struct file_operations mfd_file_ops = {
@@ -243,6 +257,12 @@ static int mfd_ioctl(struct inode *inode
switch (cmd) {
case MOUNTFD_IOC_GETDIRFD:
return mfd_getdirfd(filp);
+ case MOUNTFD_IOC_DETACH:
+ return mfd_umount(filp, MNT_DETACH);
+ case MOUNTFD_IOC_UNMOUNT:
+ return mfd_umount(filp, 0);
+ case MOUNTFD_IOC_FORCEDUNMOUNT:
+ return mfd_umount(filp, MNT_FORCE);
}
return -ENOTTY;
}
Index: linux-2.6.9-quilt/fs/namespace.c
===================================================================
--- linux-2.6.9-quilt.orig/fs/namespace.c 2004-10-22 17:17:40.738270984 -0400
+++ linux-2.6.9-quilt/fs/namespace.c 2004-10-22 17:17:41.368175224 -0400
@@ -601,7 +601,7 @@ static void umount_tree(struct vfsmount
spin_lock(&vfsmount_lock);
}
-static int do_umount(struct vfsmount *mnt, int flags)
+int do_umount(struct vfsmount *mnt, int flags)
{
struct super_block * sb = mnt->mnt_sb;
int retval;
Index: linux-2.6.9-quilt/include/linux/fs.h
===================================================================
--- linux-2.6.9-quilt.orig/include/linux/fs.h 2004-10-22 17:17:40.739270832 -0400
+++ linux-2.6.9-quilt/include/linux/fs.h 2004-10-22 17:17:41.369175072 -0400
@@ -214,7 +214,10 @@ extern int leases_enable, dir_notify_ena
#define FIBMAP _IO(0x00,1) /* bmap access */
#define FIGETBSZ _IO(0x00,2) /* get the block size used for bmap */
-#define MOUNTFD_IOC_GETDIRFD _IO('p', 0xa0)
+#define MOUNTFD_IOC_GETDIRFD _IO('p', 0xa0)
+#define MOUNTFD_IOC_UNMOUNT _IO('p', 0xa1)
+#define MOUNTFD_IOC_DETACH _IO('p', 0xa2)
+#define MOUNTFD_IOC_FORCEDUNMOUNT _IO('p', 0xa3)
#ifdef __KERNEL__
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 16/28] VFS: Mountpoint file descriptor attach support
2004-10-25 14:46 ` [PATCH 15/28] VFS: Mountpoint file descriptor umount support Mike Waychison
@ 2004-10-25 14:46 ` Mike Waychison
2004-10-25 14:47 ` [PATCH 17/28] VFS: Mountpoint file descriptor walking Mike Waychison
2004-10-26 10:28 ` [PATCH 15/28] VFS: Mountpoint file descriptor umount support Christoph Hellwig
1 sibling, 1 reply; 21+ messages in thread
From: Mike Waychison @ 2004-10-25 14:46 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel; +Cc: raven
This patch allows an unattached mountfd to be attached to a directory given a
direct fd.
NOTE: Probably requires CAP_SYSADMIN.. depends on what we want the security
model to be.
Signed-off-by: Mike Waychison <michael.waychison@sun.com>
---
fs/mountfd.c | 35 +++++++++++++++++++++++++++++++++++
include/linux/fs.h | 1 +
2 files changed, 36 insertions(+)
Index: linux-2.6.9-quilt/fs/mountfd.c
===================================================================
--- linux-2.6.9-quilt.orig/fs/mountfd.c 2004-10-22 17:17:41.367175376 -0400
+++ linux-2.6.9-quilt/fs/mountfd.c 2004-10-22 17:17:42.011077488 -0400
@@ -5,6 +5,7 @@
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/security.h>
+#include <linux/namei.h>
#define MFDFS_MAGIC 0x4A9F2E43
#define MFDFS_ROOT_INO 1
@@ -251,6 +252,38 @@ out_filp:
return error;
}
+static long mfd_attach(struct file *mountfilp, int dirfd)
+{
+ struct file *dir;
+ struct vfsmount *mnt;
+ struct nameidata nd;
+ int ret;
+
+ mnt = mntget(VFSMOUNT(mountfilp));
+
+ ret = -EBADF;
+ dir = fget(dirfd);
+ if (!dir)
+ goto out;
+
+ ret = -ENOTDIR;
+ if (!S_ISDIR(dir->f_dentry->d_inode->i_mode))
+ goto out2;
+
+ memset(&nd, 0, sizeof(nd));
+ nd.dentry = dget(dir->f_dentry);
+ nd.mnt = mntget(dir->f_vfsmnt);
+
+ ret = do_graft_mount(mnt, &nd);
+
+ path_release(&nd);
+out2:
+ put_filp(dir);
+out:
+ mntput(mnt);
+ return ret;
+}
+
static int mfd_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
@@ -263,6 +296,8 @@ static int mfd_ioctl(struct inode *inode
return mfd_umount(filp, 0);
case MOUNTFD_IOC_FORCEDUNMOUNT:
return mfd_umount(filp, MNT_FORCE);
+ case MOUNTFD_IOC_ATTACH:
+ return mfd_attach(filp, arg);
}
return -ENOTTY;
}
Index: linux-2.6.9-quilt/include/linux/fs.h
===================================================================
--- linux-2.6.9-quilt.orig/include/linux/fs.h 2004-10-22 17:17:41.369175072 -0400
+++ linux-2.6.9-quilt/include/linux/fs.h 2004-10-22 17:17:42.012077336 -0400
@@ -218,6 +218,7 @@ extern int leases_enable, dir_notify_ena
#define MOUNTFD_IOC_UNMOUNT _IO('p', 0xa1)
#define MOUNTFD_IOC_DETACH _IO('p', 0xa2)
#define MOUNTFD_IOC_FORCEDUNMOUNT _IO('p', 0xa3)
+#define MOUNTFD_IOC_ATTACH _IOW('p', 0xa4, int)
#ifdef __KERNEL__
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 17/28] VFS: Mountpoint file descriptor walking
2004-10-25 14:46 ` [PATCH 16/28] VFS: Mountpoint file descriptor attach support Mike Waychison
@ 2004-10-25 14:47 ` Mike Waychison
2004-10-25 14:47 ` [PATCH 18/28] VFS: Mountpoint file descriptor read properties Mike Waychison
0 siblings, 1 reply; 21+ messages in thread
From: Mike Waychison @ 2004-10-25 14:47 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel; +Cc: raven
This patch allows one to walk the mountpoint tree given a mountfd. There are
two operations permitted:
MOUNTFD_IOC_GETFIRSTCHILD - Given a mountfd, return the first child mountpoint
as a mountfd.
MOUNTFD_IOC_GETNEXTCHILD - Given a mountfd, return the next mountpoint sibling
to it. (*)
(*) XXX: This should be modified to also take a parent mountfd so that you
can't walk out of a chroot.
We explicitly don't allow walks to the parent of a mountpoint as that would
allow for a user to easily walk out of a chroot.
Signed-off-by: Mike Waychison <michael.waychison@sun.com>
---
fs/mountfd.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
include/linux/fs.h | 3 +++
2 files changed, 49 insertions(+)
Index: linux-2.6.9-quilt/include/linux/fs.h
===================================================================
--- linux-2.6.9-quilt.orig/include/linux/fs.h 2004-10-22 17:17:42.012077336 -0400
+++ linux-2.6.9-quilt/include/linux/fs.h 2004-10-22 17:17:42.625984008 -0400
@@ -219,6 +219,9 @@ extern int leases_enable, dir_notify_ena
#define MOUNTFD_IOC_DETACH _IO('p', 0xa2)
#define MOUNTFD_IOC_FORCEDUNMOUNT _IO('p', 0xa3)
#define MOUNTFD_IOC_ATTACH _IOW('p', 0xa4, int)
+#define MOUNTFD_IOC_GETFIRSTCHILD _IO('p', 0xa5)
+/* TODO: change this interface to require the parent mfd as well */
+#define MOUNTFD_IOC_GETNEXTCHILD _IO('p', 0xa6)
#ifdef __KERNEL__
Index: linux-2.6.9-quilt/fs/mountfd.c
===================================================================
--- linux-2.6.9-quilt.orig/fs/mountfd.c 2004-10-22 17:17:42.011077488 -0400
+++ linux-2.6.9-quilt/fs/mountfd.c 2004-10-22 17:17:42.625984008 -0400
@@ -284,6 +284,48 @@ out:
return ret;
}
+static long mfd_firstchild(struct file *mountfilp)
+{
+ struct vfsmount *mnt, *childmnt = NULL;
+ int ret;
+
+ mnt = mntget(VFSMOUNT(mountfilp));
+
+ spin_lock(&vfsmount_lock);
+ if (!list_empty(&mnt->mnt_mounts))
+ childmnt = mntget(container_of(mnt->mnt_mounts.next, struct vfsmount, mnt_child));
+ spin_unlock(&vfsmount_lock);
+
+ ret = -ENOENT;
+ if (childmnt)
+ ret = open_mfd(childmnt);
+
+ mntput(childmnt);
+ mntput(mnt);
+ return ret;
+}
+
+static long mfd_nextchild(struct file *mountfilp)
+{
+ struct vfsmount *mnt, *nextmnt = NULL;
+ int ret;
+
+ mnt = mntget(VFSMOUNT(mountfilp));
+
+ spin_lock(&vfsmount_lock);
+ if (mnt->mnt_child.next != &mnt->mnt_parent->mnt_mounts)
+ nextmnt = mntget(container_of(mnt->mnt_child.next, struct vfsmount, mnt_child));
+ spin_unlock(&vfsmount_lock);
+
+ ret = -ENOENT;
+ if (nextmnt)
+ ret = open_mfd(nextmnt);
+
+ mntput(nextmnt);
+ mntput(mnt);
+ return ret;
+}
+
static int mfd_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
@@ -298,6 +340,10 @@ static int mfd_ioctl(struct inode *inode
return mfd_umount(filp, MNT_FORCE);
case MOUNTFD_IOC_ATTACH:
return mfd_attach(filp, arg);
+ case MOUNTFD_IOC_GETFIRSTCHILD:
+ return mfd_firstchild(filp);
+ case MOUNTFD_IOC_GETNEXTCHILD:
+ return mfd_nextchild(filp);
}
return -ENOTTY;
}
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 18/28] VFS: Mountpoint file descriptor read properties
2004-10-25 14:47 ` [PATCH 17/28] VFS: Mountpoint file descriptor walking Mike Waychison
@ 2004-10-25 14:47 ` Mike Waychison
2004-10-25 14:48 ` [PATCH 19/28] VFS: Mountpoint file descriptor expiry support Mike Waychison
0 siblings, 1 reply; 21+ messages in thread
From: Mike Waychison @ 2004-10-25 14:47 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel; +Cc: raven
This patch allows userspace to query a mountpoint file descriptor for
information using the ioctl interface.
The properties exported in this patch are for _example only_ to demonstrate
what the interface might look like. This patch allows mountfds to show the
following information:
MOUNTFD_IOC_GETDEV - Get the associated block device (if any)
MOUNTFD_IOC_GETFSTYPE - Get the fstype of the mountpoint.
MOUNTFD_IOC_GETVFSOPTIONS - Get the vfs specific options of the
mountpoint/superblock
MOUNTFD_IOC_GETFSOPTIONS - Get the fstype-specific options (if any)
Signed-off-by: Mike Waychison <michael.waychison@sun.com>
---
fs/mountfd.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
include/linux/fs.h | 6 ++
2 files changed, 119 insertions(+), 1 deletion(-)
Index: linux-2.6.9-quilt/fs/mountfd.c
===================================================================
--- linux-2.6.9-quilt.orig/fs/mountfd.c 2004-10-22 17:17:42.625984008 -0400
+++ linux-2.6.9-quilt/fs/mountfd.c 2004-10-22 17:17:43.230892048 -0400
@@ -160,6 +160,72 @@ static struct dentry *get_mfd_dentry(str
return dget(dentry);
}
+static int mfd_read_fstype(struct vfsmount *mnt, char *buf)
+{
+ return scnprintf(buf, MOUNTFD_READSIZE-1, "%s", mnt->mnt_sb->s_type->name) + 1;
+}
+
+static int mfd_read_dev(struct vfsmount *mnt, char *buf)
+{
+ return scnprintf(buf, MOUNTFD_READSIZE-1, "%s", mnt->mnt_sb->s_id) + 1;
+}
+
+static int mfd_read_vfsoptions(struct vfsmount *mnt, char *buf)
+{
+ static struct vfs_info {
+ int flag;
+ char *str;
+ } vfs_info[] = {
+ { MS_RDONLY, "ro" },
+ { MS_DIRSYNC, "dirsync" },
+ { MS_MANDLOCK, "mand" },
+ { MS_NOATIME, "noatime" },
+ { MS_NODIRATIME, "nodiratime" },
+ { 0, NULL }
+ };
+ struct vfs_info *vfs_infop;
+ static struct mnt_info {
+ int flag;
+ char *str;
+ } mnt_info[] = {
+ { MNT_NOSUID, "nosuid" },
+ { MNT_NODEV, "nodev" },
+ { MNT_NOEXEC, "noexec" },
+ { 0, NULL }
+ };
+ struct mnt_info *mnt_infop;
+
+ char *p = buf;
+
+ int sb_flags = mnt->mnt_sb->s_flags;
+ int mnt_flags = mnt->mnt_flags;
+ int first = 0;
+
+ /*
+ * Note: we skip length checks below because we assume we can't overrun
+ * MOUNTFD_READSIZE.
+ */
+
+ for (vfs_infop = vfs_info; vfs_infop->flag; vfs_infop++) {
+ if (sb_flags & vfs_infop->flag) {
+ if (first++)
+ *p++ = ',';
+ strcpy(p, vfs_infop->str);
+ p += strlen(vfs_infop->str);
+ }
+ }
+
+ for (mnt_infop = mnt_info; mnt_infop->flag; mnt_infop++) {
+ if (mnt_flags & mnt_infop->flag) {
+ if (first++)
+ *p++ = ',';
+ strcpy(p, mnt_infop->str);
+ p += strlen(mnt_infop->str);
+ }
+ }
+ return p - buf + 1;
+}
+
static long open_mfd(struct vfsmount *mnt)
{
struct file *file;
@@ -176,6 +242,7 @@ static long open_mfd(struct vfsmount *mn
if (fd < 0)
goto out_putfilp;
+ error = -ENOMEM;
file->private_data = mnt;
file->f_dentry = get_mfd_dentry(mnt);
if (IS_ERR(file->f_dentry)) {
@@ -326,9 +393,53 @@ static long mfd_nextchild(struct file *m
return ret;
}
+static int mfd_ioctl_reads(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ char __user *user_buf = (char __user *)arg;
+ struct vfsmount *mnt;
+ char *buf;
+ int ret;
+
+ mnt = VFSMOUNT(filp);
+
+ buf = (char *)get_zeroed_page(GFP_KERNEL);
+ if (buf)
+ return -ENOMEM;
+ switch (cmd) {
+ /*
+ * The following calls are expected to return the total number of bytes to write out, including '\0'.
+ */
+ case MOUNTFD_IOC_GETDEV:
+ ret = mfd_read_dev(mnt, buf);
+ break;
+ case MOUNTFD_IOC_GETFSTYPE:
+ ret = mfd_read_fstype(mnt, buf);
+ break;
+ case MOUNTFD_IOC_GETVFSOPTIONS:
+ ret = mfd_read_vfsoptions(mnt, buf);
+ break;
+ case MOUNTFD_IOC_GETFSOPTIONS:
+ /* TODO: need super_block op that doesn't take a seq_file */
+ ret = -ENOSYS;
+ break;
+ default:
+ ret = -ENOTTY;
+ }
+
+ if (ret >= 0) {
+ if (copy_to_user(user_buf, buf, ret))
+ ret = -EFAULT;
+ }
+
+ free_page((unsigned long)buf);
+ return ret;
+}
+
static int mfd_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
+ int ret;
switch (cmd) {
case MOUNTFD_IOC_GETDIRFD:
return mfd_getdirfd(filp);
@@ -345,7 +456,8 @@ static int mfd_ioctl(struct inode *inode
case MOUNTFD_IOC_GETNEXTCHILD:
return mfd_nextchild(filp);
}
- return -ENOTTY;
+ ret = mfd_ioctl_reads(inode, filp, cmd, arg);
+ return ret;
}
asmlinkage long sys_mountfd(int dirfd)
Index: linux-2.6.9-quilt/include/linux/fs.h
===================================================================
--- linux-2.6.9-quilt.orig/include/linux/fs.h 2004-10-22 17:17:42.625984008 -0400
+++ linux-2.6.9-quilt/include/linux/fs.h 2004-10-22 17:17:43.232891744 -0400
@@ -223,6 +223,12 @@ extern int leases_enable, dir_notify_ena
/* TODO: change this interface to require the parent mfd as well */
#define MOUNTFD_IOC_GETNEXTCHILD _IO('p', 0xa6)
+#define MOUNTFD_READSIZE PAGE_SIZE
+#define MOUNTFD_IOC_GETDEV _IOR('p', 0xa7, char [MOUNTFD_READSIZE])
+#define MOUNTFD_IOC_GETFSTYPE _IOR('p', 0xa8, char [MOUNTFD_READSIZE])
+#define MOUNTFD_IOC_GETVFSOPTIONS _IOR('p', 0xa9, char [MOUNTFD_READSIZE])
+#define MOUNTFD_IOC_GETFSOPTIONS _IOR('p', 0xaa, char [MOUNTFD_READSIZE])
+
#ifdef __KERNEL__
#include <linux/list.h>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 19/28] VFS: Mountpoint file descriptor expiry support
2004-10-25 14:47 ` [PATCH 18/28] VFS: Mountpoint file descriptor read properties Mike Waychison
@ 2004-10-25 14:48 ` Mike Waychison
2004-10-25 14:48 ` [PATCH 20/28] HOTPLUG: call_usermodehelper callback support Mike Waychison
0 siblings, 1 reply; 21+ messages in thread
From: Mike Waychison @ 2004-10-25 14:48 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel; +Cc: raven
This patch adds support for letting userspcae set the expiry information on a
given mountpoint.
Signed-off-by: Mike Waychison <michael.waychison@sun.com>
---
fs/mountfd.c | 10 ++++++++++
include/linux/fs.h | 1 +
2 files changed, 11 insertions(+)
Index: linux-2.6.9-quilt/include/linux/fs.h
===================================================================
--- linux-2.6.9-quilt.orig/include/linux/fs.h 2004-10-22 17:17:43.232891744 -0400
+++ linux-2.6.9-quilt/include/linux/fs.h 2004-10-22 17:17:43.766810576 -0400
@@ -228,6 +228,7 @@ extern int leases_enable, dir_notify_ena
#define MOUNTFD_IOC_GETFSTYPE _IOR('p', 0xa8, char [MOUNTFD_READSIZE])
#define MOUNTFD_IOC_GETVFSOPTIONS _IOR('p', 0xa9, char [MOUNTFD_READSIZE])
#define MOUNTFD_IOC_GETFSOPTIONS _IOR('p', 0xaa, char [MOUNTFD_READSIZE])
+#define MOUNTFD_IOC_SETVFSEXPIRE _IOW('p', 0xab, int)
#ifdef __KERNEL__
Index: linux-2.6.9-quilt/fs/mountfd.c
===================================================================
--- linux-2.6.9-quilt.orig/fs/mountfd.c 2004-10-22 17:17:43.230892048 -0400
+++ linux-2.6.9-quilt/fs/mountfd.c 2004-10-22 17:17:43.767810424 -0400
@@ -393,6 +393,14 @@ static long mfd_nextchild(struct file *m
return ret;
}
+static int mfd_vfsexpire(struct file *mountfilp, int arg)
+{
+ struct vfsmount *mnt;
+
+ mnt = VFSMOUNT(mountfilp);
+ return mnt_expire(mnt, arg);
+}
+
static int mfd_ioctl_reads(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
@@ -455,6 +463,8 @@ static int mfd_ioctl(struct inode *inode
return mfd_firstchild(filp);
case MOUNTFD_IOC_GETNEXTCHILD:
return mfd_nextchild(filp);
+ case MOUNTFD_IOC_SETVFSEXPIRE:
+ return mfd_vfsexpire(filp, (int)arg);
}
ret = mfd_ioctl_reads(inode, filp, cmd, arg);
return ret;
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 20/28] HOTPLUG: call_usermodehelper callback support
2004-10-25 14:48 ` [PATCH 19/28] VFS: Mountpoint file descriptor expiry support Mike Waychison
@ 2004-10-25 14:48 ` Mike Waychison
2004-10-25 14:49 ` [PATCH 21/28] HOTPLUG: Hack to allow for call to execve Mike Waychison
2004-10-25 15:18 ` [PATCH 20/28] HOTPLUG: call_usermodehelper callback support Christoph Hellwig
0 siblings, 2 replies; 21+ messages in thread
From: Mike Waychison @ 2004-10-25 14:48 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel; +Cc: raven
This patch extends the call_usermodehelper api by adding a callback variant.
The callback is made right when the system is about to call execve into the
new process. This allows for the caller to provide changes to the default
environment right before the exec takes place. Note: the context of the
callback will be _from within another process_.
Signed-off-by: Mike Waychison <michael.waychison@sun.com>
---
include/linux/kmod.h | 2 +
kernel/kmod.c | 80 ++++++++++++++++++++++++++++++++++++++-------------
2 files changed, 63 insertions(+), 19 deletions(-)
Index: linux-2.6.9-quilt/kernel/kmod.c
===================================================================
--- linux-2.6.9-quilt.orig/kernel/kmod.c 2004-08-14 01:36:44.000000000 -0400
+++ linux-2.6.9-quilt/kernel/kmod.c 2004-10-22 17:17:44.279732600 -0400
@@ -140,17 +140,22 @@ EXPORT_SYMBOL(hotplug_path);
struct subprocess_info {
struct completion *complete;
+ call_usermodehelper_cb_t cb;
+ void *cbdata;
+ int wait;
+ int retval;
+};
+
+struct simple_usermodehelper_info {
char *path;
char **argv;
char **envp;
- int wait;
- int retval;
};
/*
* This is the task which runs the usermode application
*/
-static int ____call_usermodehelper(void *data)
+static int ____call_usermodehelper_cb(void *data)
{
struct subprocess_info *sub_info = data;
int retval;
@@ -168,7 +173,7 @@ static int ____call_usermodehelper(void
retval = -EPERM;
if (current->fs->root)
- retval = execve(sub_info->path, sub_info->argv,sub_info->envp);
+ retval = (*sub_info->cb)(sub_info->cbdata);
/* Exec failed? */
sub_info->retval = retval;
@@ -190,7 +195,7 @@ static int wait_for_helper(void *data)
do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);
allow_signal(SIGCHLD);
- pid = kernel_thread(____call_usermodehelper, sub_info, SIGCHLD);
+ pid = kernel_thread(____call_usermodehelper_cb, sub_info, SIGCHLD);
if (pid < 0) {
sub_info->retval = pid;
} else {
@@ -211,7 +216,7 @@ static int wait_for_helper(void *data)
}
/* This is run by khelper thread */
-static void __call_usermodehelper(void *data)
+static void __call_usermodehelper_cb(void *data)
{
struct subprocess_info *sub_info = data;
pid_t pid;
@@ -223,7 +228,7 @@ static void __call_usermodehelper(void *
pid = kernel_thread(wait_for_helper, sub_info,
CLONE_FS | CLONE_FILES | SIGCHLD);
else
- pid = kernel_thread(____call_usermodehelper, sub_info,
+ pid = kernel_thread(____call_usermodehelper_cb, sub_info,
CLONE_VFORK | SIGCHLD);
if (pid < 0) {
@@ -234,12 +239,16 @@ static void __call_usermodehelper(void *
}
/**
- * call_usermodehelper - start a usermode application
- * @path: pathname for the application
- * @argv: null-terminated argument list
- * @envp: null-terminated environment list
+ * call_usermodehelper_cb - start a usermode application with a callback
+ * @cb: A user provided callback that will eventually execve.
+ * @cbdata: User supplied information that will be passed back to the callback.
* @wait: wait for the application to finish and return status.
*
+ * This call will do all the work required for setting up a usermode helper
+ * except perform the actual exec. It is the caller's responsibility to
+ * provide a callback that will eventually exec. This allows last minute
+ * changes to current.
+ *
* Runs a user-space application. The application is started
* asynchronously if wait is not set, and runs as a child of keventd.
* (ie. it runs with full root capabilities).
@@ -247,29 +256,62 @@ static void __call_usermodehelper(void *
* Must be called from process context. Returns a negative error code
* if program was not execed successfully, or 0.
*/
-int call_usermodehelper(char *path, char **argv, char **envp, int wait)
+int call_usermodehelper_cb(call_usermodehelper_cb_t cb, void *cbdata, int wait)
{
DECLARE_COMPLETION(done);
struct subprocess_info sub_info = {
.complete = &done,
- .path = path,
- .argv = argv,
- .envp = envp,
+ .cb = cb,
+ .cbdata = cbdata,
.wait = wait,
.retval = 0,
};
- DECLARE_WORK(work, __call_usermodehelper, &sub_info);
+ DECLARE_WORK(work, __call_usermodehelper_cb, &sub_info);
+ BUG_ON(!cb || !cbdata);
if (!khelper_wq)
return -EBUSY;
- if (path[0] == '\0')
- return 0;
-
queue_work(khelper_wq, &work);
wait_for_completion(&done);
return sub_info.retval;
}
+EXPORT_SYMBOL(call_usermodehelper_cb);
+
+static int call_usermodehelper_simple(void *cbdata)
+{
+ struct simple_usermodehelper_info *info = cbdata;
+ return execve(info->path, info->argv, info->envp);
+}
+
+/**
+ * call_usermodehelper - start a usermode application
+ * @path: pathname for the application
+ * @argv: null-terminated argument list
+ * @envp: null-terminated environment list
+ * @wait: wait for the application to finish and return status.
+ *
+ * Runs a user-space application. The application is started
+ * asynchronously if wait is not set, and runs as a child of keventd.
+ * (ie. it runs with full root capabilities).
+ *
+ * Must be called from process context. Returns a negative error code
+ * if program was not execed successfully, or 0.
+ */
+
+int call_usermodehelper(char *path, char **argv, char **envp, int wait)
+{
+ struct simple_usermodehelper_info info = {
+ .path = path,
+ .argv = argv,
+ .envp = envp,
+ };
+
+ if (path[0] == '\0')
+ return 0;
+
+ return call_usermodehelper_cb(call_usermodehelper_simple, &info, wait);
+}
EXPORT_SYMBOL(call_usermodehelper);
static __init int usermodehelper_init(void)
Index: linux-2.6.9-quilt/include/linux/kmod.h
===================================================================
--- linux-2.6.9-quilt.orig/include/linux/kmod.h 2004-08-14 01:36:32.000000000 -0400
+++ linux-2.6.9-quilt/include/linux/kmod.h 2004-10-22 17:17:44.279732600 -0400
@@ -34,6 +34,8 @@ static inline int request_module(const c
#endif
#define try_then_request_module(x, mod...) ((x) ?: (request_module(mod), (x)))
+typedef int (*call_usermodehelper_cb_t)(void *cbdata);
+extern int call_usermodehelper_cb(call_usermodehelper_cb_t cb, void *cbdata, int wait);
extern int call_usermodehelper(char *path, char *argv[], char *envp[], int wait);
#ifdef CONFIG_HOTPLUG
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 21/28] HOTPLUG: Hack to allow for call to execve
2004-10-25 14:48 ` [PATCH 20/28] HOTPLUG: call_usermodehelper callback support Mike Waychison
@ 2004-10-25 14:49 ` Mike Waychison
2004-10-25 14:49 ` [PATCH 22/28] VFS: Export put_namespace Mike Waychison
2004-10-25 15:18 ` [PATCH 20/28] HOTPLUG: call_usermodehelper callback support Christoph Hellwig
1 sibling, 1 reply; 21+ messages in thread
From: Mike Waychison @ 2004-10-25 14:49 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel; +Cc: raven
This patch is a hack while we don't have a proper way for code to call
execve. It simply introduces call_usermodehelper_execve(path, argv, envp)
that call the execve syscall with an errno set.
We need to figure out a proper way for code to call execve!
Signed-off-by: Mike Waychison <michael.waychison@sun.com>
---
include/linux/kmod.h | 1 +
kernel/kmod.c | 7 +++++++
2 files changed, 8 insertions(+)
Index: linux-2.6.9-quilt/kernel/kmod.c
===================================================================
--- linux-2.6.9-quilt.orig/kernel/kmod.c 2004-10-22 17:17:44.279732600 -0400
+++ linux-2.6.9-quilt/kernel/kmod.c 2004-10-22 17:17:44.879641400 -0400
@@ -278,6 +278,13 @@ int call_usermodehelper_cb(call_usermode
}
EXPORT_SYMBOL(call_usermodehelper_cb);
+/* This is an ugly hack while the __KERNEL_SYSCALLS__ cleanup occurs */
+int call_usermodehelper_execve(char *path, char *argv[], char *envp[])
+{
+ return execve(path, argv, envp);
+}
+EXPORT_SYMBOL(call_usermodehelper_execve);
+
static int call_usermodehelper_simple(void *cbdata)
{
struct simple_usermodehelper_info *info = cbdata;
Index: linux-2.6.9-quilt/include/linux/kmod.h
===================================================================
--- linux-2.6.9-quilt.orig/include/linux/kmod.h 2004-10-22 17:17:44.279732600 -0400
+++ linux-2.6.9-quilt/include/linux/kmod.h 2004-10-22 17:17:44.879641400 -0400
@@ -36,6 +36,7 @@ static inline int request_module(const c
#define try_then_request_module(x, mod...) ((x) ?: (request_module(mod), (x)))
typedef int (*call_usermodehelper_cb_t)(void *cbdata);
extern int call_usermodehelper_cb(call_usermodehelper_cb_t cb, void *cbdata, int wait);
+extern int call_usermodehelper_execve(char *path, char *argv[], char *envp[]);
extern int call_usermodehelper(char *path, char *argv[], char *envp[], int wait);
#ifdef CONFIG_HOTPLUG
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 22/28] VFS: Export put_namespace
2004-10-25 14:49 ` [PATCH 21/28] HOTPLUG: Hack to allow for call to execve Mike Waychison
@ 2004-10-25 14:49 ` Mike Waychison
2004-10-25 14:50 ` [PATCH 23/28] VFS: Export get_sb_pseudo Mike Waychison
0 siblings, 1 reply; 21+ messages in thread
From: Mike Waychison @ 2004-10-25 14:49 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel; +Cc: raven
This patch exports the __put_namespace symbol so that autofsng can call it as
a module (used as part of the call-out mechanism).
Signed-off-by: Mike Waychison <michael.waychison@sun.com>
---
namespace.c | 1 +
1 files changed, 1 insertion(+)
Index: linux-2.6.9-quilt/fs/namespace.c
===================================================================
--- linux-2.6.9-quilt.orig/fs/namespace.c 2004-10-22 17:17:41.368175224 -0400
+++ linux-2.6.9-quilt/fs/namespace.c 2004-10-22 17:17:45.491548376 -0400
@@ -1733,3 +1733,4 @@ void __put_namespace(struct namespace *n
mntput(namespace->root);
kfree(namespace);
}
+EXPORT_SYMBOL(__put_namespace);
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 23/28] VFS: Export get_sb_pseudo
2004-10-25 14:49 ` [PATCH 22/28] VFS: Export put_namespace Mike Waychison
@ 2004-10-25 14:50 ` Mike Waychison
2004-10-25 14:50 ` [PATCH 24/28] VFS: Fixup for ->follow_link on root of filesystem Mike Waychison
0 siblings, 1 reply; 21+ messages in thread
From: Mike Waychison @ 2004-10-25 14:50 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel; +Cc: raven
Export get_sb_pseudo for module use. Autofsng uses it to create files that
are used for feeding browsing information.
Signed-off-by: Mike Waychison <michael.waychison@sun.com>
---
libfs.c | 1 +
1 files changed, 1 insertion(+)
Index: linux-2.6.9-quilt/fs/libfs.c
===================================================================
--- linux-2.6.9-quilt.orig/fs/libfs.c 2004-08-14 01:36:11.000000000 -0400
+++ linux-2.6.9-quilt/fs/libfs.c 2004-10-22 17:17:46.009469640 -0400
@@ -222,6 +222,7 @@ Enomem:
deactivate_super(s);
return ERR_PTR(-ENOMEM);
}
+EXPORT_SYMBOL(get_sb_pseudo);
int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
{
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 24/28] VFS: Fixup for ->follow_link on root of filesystem
2004-10-25 14:50 ` [PATCH 23/28] VFS: Export get_sb_pseudo Mike Waychison
@ 2004-10-25 14:50 ` Mike Waychison
2004-10-25 14:51 ` [PATCH 25/28] VFS: statfs(64) shouldn't follow last component symlink Mike Waychison
0 siblings, 1 reply; 21+ messages in thread
From: Mike Waychison @ 2004-10-25 14:50 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel; +Cc: raven
When a follow_link dentry call is made, the implementation expects the
dentry to be followed as well as a nameidata struct to be filled in.
The received nd->mnt is expected to contain the vfsmount of the dentry
being followed, so that a subsequent call to vfs_follow_link may
properly pivot off that mount and onto another vfsmount as the path of
the link is walked, thus keeping reference counts proper.
The changes made in fs/namei.c@1.42 break this behaviour if the dentry
being follow_link'ed is a root dentry. This is because follow_mount
follows down next.mnt and not nd->mnt like it used to. So, if a root
dentry has a follow_link op, the nd->mnt it receives is in fact the
vfsmount of the mount it is mounted upon (which breaks reference counts).
Signed-off-by: Mike Waychison <michael.waychison@sun.com>
---
namei.c | 2 ++
1 files changed, 2 insertions(+)
Index: linux-2.6.9-quilt/fs/namei.c
===================================================================
--- linux-2.6.9-quilt.orig/fs/namei.c 2004-10-22 17:17:34.762179488 -0400
+++ linux-2.6.9-quilt/fs/namei.c 2004-10-22 17:17:46.571384216 -0400
@@ -755,6 +755,7 @@ int fastcall link_path_walk(const char *
if (inode->i_op->follow_link) {
mntget(next.mnt);
+ nd->mnt = next.mnt;
err = do_follow_link(next.dentry, nd);
dput(next.dentry);
mntput(next.mnt);
@@ -809,6 +810,7 @@ last_component:
if ((lookup_flags & LOOKUP_FOLLOW)
&& inode && inode->i_op && inode->i_op->follow_link) {
mntget(next.mnt);
+ nd->mnt = next.mnt;
err = do_follow_link(next.dentry, nd);
dput(next.dentry);
mntput(next.mnt);
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 25/28] VFS: statfs(64) shouldn't follow last component symlink
2004-10-25 14:50 ` [PATCH 24/28] VFS: Fixup for ->follow_link on root of filesystem Mike Waychison
@ 2004-10-25 14:51 ` Mike Waychison
2004-10-25 14:51 ` [PATCH 26/28] VFS: Introduce MNT_NOFOLLOW Mike Waychison
2004-10-25 15:14 ` [PATCH 25/28] VFS: statfs(64) shouldn't follow last component symlink Christoph Hellwig
0 siblings, 2 replies; 21+ messages in thread
From: Mike Waychison @ 2004-10-25 14:51 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel; +Cc: raven
Mount-related userspace tools will require the ability to detect whether what
looks like a regular directory is actually a autofs trigger. To handle this,
tools can statfs a given directory and check to see if statfs->f_type ==
AUTOFSNG_SUPER_MAGIC before walking into the directory (and causing the a
filesystem to automount).
To make this happen, we cannot allow statfs to follow_link.
NOTE: This may break any userspace that assumes it can statfs across a
last-component symlink. I can't think of any real world breakage however, as
mount(8) will drop the real path in /etc/mtab and /proc/mounts will always
show the true path.
Signed-off-by: Mike Waychison <michael.waychison@sun.com>
---
open.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
Index: linux-2.6.9-quilt/fs/open.c
===================================================================
--- linux-2.6.9-quilt.orig/fs/open.c 2004-08-14 01:36:13.000000000 -0400
+++ linux-2.6.9-quilt/fs/open.c 2004-10-22 17:17:47.180291648 -0400
@@ -121,7 +121,7 @@ asmlinkage long sys_statfs(const char __
struct nameidata nd;
int error;
- error = user_path_walk(path, &nd);
+ error = user_path_walk_link(path, &nd);
if (!error) {
struct statfs tmp;
error = vfs_statfs_native(nd.dentry->d_inode->i_sb, &tmp);
@@ -140,7 +140,7 @@ asmlinkage long sys_statfs64(const char
if (sz != sizeof(*buf))
return -EINVAL;
- error = user_path_walk(path, &nd);
+ error = user_path_walk_link(path, &nd);
if (!error) {
struct statfs64 tmp;
error = vfs_statfs64(nd.dentry->d_inode->i_sb, &tmp);
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 26/28] VFS: Introduce MNT_NOFOLLOW
2004-10-25 14:51 ` [PATCH 25/28] VFS: statfs(64) shouldn't follow last component symlink Mike Waychison
@ 2004-10-25 14:51 ` Mike Waychison
2004-10-25 14:52 ` [PATCH 27/28] Testing syscall for expiry Mike Waychison
2004-10-25 15:14 ` [PATCH 25/28] VFS: statfs(64) shouldn't follow last component symlink Christoph Hellwig
1 sibling, 1 reply; 21+ messages in thread
From: Mike Waychison @ 2004-10-25 14:51 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel; +Cc: raven
Umounting direct mounts requires the ability to umount without following
->follow_link. We do this by adding a new flag called MNT_NOFOLLOW to
umount2.
Signed-off-by: Mike Waychison <michael.waychison@sun.com>
---
fs/namespace.c | 3 ++-
include/linux/fs.h | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)
Index: linux-2.6.9-quilt/include/linux/fs.h
===================================================================
--- linux-2.6.9-quilt.orig/include/linux/fs.h 2004-10-22 17:17:43.766810576 -0400
+++ linux-2.6.9-quilt/include/linux/fs.h 2004-10-22 17:17:47.808196192 -0400
@@ -735,6 +735,7 @@ extern int send_sigurg(struct fown_struc
#define MNT_FORCE 0x00000001 /* Attempt to forcibily umount */
#define MNT_DETACH 0x00000002 /* Just detach from the tree */
+#define MNT_NOFOLLOW 0x00000004 /* Do not follow symlinks */
extern struct list_head super_blocks;
extern spinlock_t sb_lock;
Index: linux-2.6.9-quilt/fs/namespace.c
===================================================================
--- linux-2.6.9-quilt.orig/fs/namespace.c 2004-10-22 17:17:45.491548376 -0400
+++ linux-2.6.9-quilt/fs/namespace.c 2004-10-22 17:17:47.809196040 -0400
@@ -693,8 +693,9 @@ asmlinkage long sys_umount(char __user *
{
struct nameidata nd;
int retval;
+ int walk_flags = flags & MNT_NOFOLLOW ? 0 : LOOKUP_FOLLOW;
- retval = __user_walk(name, LOOKUP_FOLLOW, &nd);
+ retval = __user_walk(name, walk_flags, &nd);
if (retval)
goto out;
retval = -EINVAL;
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 27/28] Testing syscall for expiry
2004-10-25 14:51 ` [PATCH 26/28] VFS: Introduce MNT_NOFOLLOW Mike Waychison
@ 2004-10-25 14:52 ` Mike Waychison
2004-10-25 15:01 ` Christoph Hellwig
2004-10-25 15:37 ` [PATCH 28/28] AUTOFSNG: New autofs filesystem (resend) Mike Waychison
0 siblings, 2 replies; 21+ messages in thread
From: Mike Waychison @ 2004-10-25 14:52 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel; +Cc: raven
This patch adds a temporary syscall (to x86 only) that allows for quick
testing to make sure that mnt_expire works properly. Tests can be found in
the autofsng userspace package.
Signed-off-by: Mike Waychison <michael.waychison@sun.com>
---
arch/i386/kernel/entry.S | 1 +
fs/namespace.c | 32 ++++++++++++++++++++++++++++++++
include/asm-i386/unistd.h | 3 ++-
3 files changed, 35 insertions(+), 1 deletion(-)
Index: linux-2.6.9-quilt/arch/i386/kernel/entry.S
===================================================================
--- linux-2.6.9-quilt.orig/arch/i386/kernel/entry.S 2004-10-22 17:17:40.735271440 -0400
+++ linux-2.6.9-quilt/arch/i386/kernel/entry.S 2004-10-22 17:17:48.436100736 -0400
@@ -903,5 +903,6 @@ ENTRY(sys_call_table)
.long sys_ni_syscall
.long sys_ni_syscall
.long sys_mountfd /* 300 */
+ .long sys_mnt_expire
syscall_table_size=(.-sys_call_table)
Index: linux-2.6.9-quilt/include/asm-i386/unistd.h
===================================================================
--- linux-2.6.9-quilt.orig/include/asm-i386/unistd.h 2004-10-22 17:17:40.735271440 -0400
+++ linux-2.6.9-quilt/include/asm-i386/unistd.h 2004-10-22 17:17:48.436100736 -0400
@@ -290,8 +290,9 @@
#define __NR_mq_getsetattr (__NR_mq_open+5)
#define __NR_sys_kexec_load 283
#define __NR_mountfd 300
+#define __NR_mnt_expire 301
-#define NR_syscalls 301
+#define NR_syscalls 302
/* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
Index: linux-2.6.9-quilt/fs/namespace.c
===================================================================
--- linux-2.6.9-quilt.orig/fs/namespace.c 2004-10-22 17:17:47.809196040 -0400
+++ linux-2.6.9-quilt/fs/namespace.c 2004-10-22 17:17:48.437100584 -0400
@@ -1119,6 +1119,38 @@ static void bump_expiry_counter(struct v
parent->mnt_expiry_countdown = diff;
}
+/* TESTING PURPOSES ONLY: THIS IS NOT A REAL SYSCALL!! - IT WILL GO AWAY */
+asmlinkage int sys_mnt_expire(char __user *_path, int ticks)
+{
+ struct nameidata nd;
+ char *path;
+ int err;
+
+ path = getname(_path);
+ err = PTR_ERR(path);
+ if (IS_ERR(path))
+ goto out;
+
+ err = path_lookup(path, LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_NOALT, &nd);
+ if (err)
+ goto out_name;
+
+ err = -EINVAL;
+ if (nd.mnt->mnt_root != nd.dentry)
+ goto out_nd;
+
+ err = -EBUSY;
+ if (!mnt_expire(nd.mnt, ticks))
+ err = 0;
+
+out_nd:
+ path_release(&nd);
+out_name:
+ putname(path);
+out:
+ return err;
+}
+
/*
* process a list of expirable mountpoints with the intent of discarding any
* mountpoints that aren't in use and haven't been touched since last we came
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 27/28] Testing syscall for expiry
2004-10-25 14:52 ` [PATCH 27/28] Testing syscall for expiry Mike Waychison
@ 2004-10-25 15:01 ` Christoph Hellwig
2004-10-25 15:37 ` [PATCH 28/28] AUTOFSNG: New autofs filesystem (resend) Mike Waychison
1 sibling, 0 replies; 21+ messages in thread
From: Christoph Hellwig @ 2004-10-25 15:01 UTC (permalink / raw)
To: Mike Waychison; +Cc: linux-kernel, linux-fsdevel, raven
On Mon, Oct 25, 2004 at 10:52:12AM -0400, Mike Waychison wrote:
> This patch adds a temporary syscall (to x86 only) that allows for quick
> testing to make sure that mnt_expire works properly. Tests can be found in
> the autofsng userspace package.
> +/* TESTING PURPOSES ONLY: THIS IS NOT A REAL SYSCALL!! - IT WILL GO AWAY */
> +asmlinkage int sys_mnt_expire(char __user *_path, int ticks)
so don't submit it..
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 25/28] VFS: statfs(64) shouldn't follow last component symlink
2004-10-25 14:51 ` [PATCH 25/28] VFS: statfs(64) shouldn't follow last component symlink Mike Waychison
2004-10-25 14:51 ` [PATCH 26/28] VFS: Introduce MNT_NOFOLLOW Mike Waychison
@ 2004-10-25 15:14 ` Christoph Hellwig
2004-10-25 15:21 ` Mike Waychison
1 sibling, 1 reply; 21+ messages in thread
From: Christoph Hellwig @ 2004-10-25 15:14 UTC (permalink / raw)
To: Mike Waychison; +Cc: linux-kernel, linux-fsdevel, raven
On Mon, Oct 25, 2004 at 10:51:11AM -0400, Mike Waychison wrote:
> Mount-related userspace tools will require the ability to detect whether what
> looks like a regular directory is actually a autofs trigger. To handle this,
> tools can statfs a given directory and check to see if statfs->f_type ==
> AUTOFSNG_SUPER_MAGIC before walking into the directory (and causing the a
> filesystem to automount).
>
> To make this happen, we cannot allow statfs to follow_link.
>
> NOTE: This may break any userspace that assumes it can statfs across a
> last-component symlink. I can't think of any real world breakage however, as
> mount(8) will drop the real path in /etc/mtab and /proc/mounts will always
> show the true path.
Which means it's vetoed. It's a big change in syscall semantics. And
propabably breaks SuS (for statvfs(3) which requires full symlink
resolution when it just refers to a path on the filesystem.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 20/28] HOTPLUG: call_usermodehelper callback support
2004-10-25 14:48 ` [PATCH 20/28] HOTPLUG: call_usermodehelper callback support Mike Waychison
2004-10-25 14:49 ` [PATCH 21/28] HOTPLUG: Hack to allow for call to execve Mike Waychison
@ 2004-10-25 15:18 ` Christoph Hellwig
2004-10-25 15:29 ` Mike Waychison
1 sibling, 1 reply; 21+ messages in thread
From: Christoph Hellwig @ 2004-10-25 15:18 UTC (permalink / raw)
To: Mike Waychison; +Cc: linux-kernel, linux-fsdevel, raven
On Mon, Oct 25, 2004 at 10:48:40AM -0400, Mike Waychison wrote:
> This patch extends the call_usermodehelper api by adding a callback variant.
> The callback is made right when the system is about to call execve into the
> new process. This allows for the caller to provide changes to the default
> environment right before the exec takes place. Note: the context of the
> callback will be _from within another process_.
I don't like this at all. First it's the usual fork() + exec() vs spawn() with
gazillions of arguments debatte, second this sounds far too complex to do it in
kernelspace to me. Why can't you do the enviroment changes from the program
beeing executed?
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 25/28] VFS: statfs(64) shouldn't follow last component symlink
2004-10-25 15:14 ` [PATCH 25/28] VFS: statfs(64) shouldn't follow last component symlink Christoph Hellwig
@ 2004-10-25 15:21 ` Mike Waychison
0 siblings, 0 replies; 21+ messages in thread
From: Mike Waychison @ 2004-10-25 15:21 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: linux-kernel, linux-fsdevel, raven
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Christoph Hellwig wrote:
> On Mon, Oct 25, 2004 at 10:51:11AM -0400, Mike Waychison wrote:
>
>>Mount-related userspace tools will require the ability to detect whether what
>>looks like a regular directory is actually a autofs trigger. To handle this,
>>tools can statfs a given directory and check to see if statfs->f_type ==
>>AUTOFSNG_SUPER_MAGIC before walking into the directory (and causing the a
>>filesystem to automount).
>>
>>To make this happen, we cannot allow statfs to follow_link.
>>
>>NOTE: This may break any userspace that assumes it can statfs across a
>>last-component symlink. I can't think of any real world breakage however, as
>>mount(8) will drop the real path in /etc/mtab and /proc/mounts will always
>>show the true path.
>
>
> Which means it's vetoed. It's a big change in syscall semantics. And
> propabably breaks SuS (for statvfs(3) which requires full symlink
> resolution when it just refers to a path on the filesystem.
>
Ya, I figured that would be the case. What do folks think about a
lstatfs(64)?
- --
Mike Waychison
Sun Microsystems, Inc.
1 (650) 352-5299 voice
1 (416) 202-8336 voice
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
NOTICE: The opinions expressed in this email are held by me,
and may not represent the views of Sun Microsystems, Inc.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.5 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org
iD8DBQFBfRoUdQs4kOxk3/MRAgHoAKCApqvkE2hgLAJKXDkLWWJE7BqevgCfQlh9
BxBlFSMUPoo1VyOcntae7Y0=
=rR8G
-----END PGP SIGNATURE-----
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 20/28] HOTPLUG: call_usermodehelper callback support
2004-10-25 15:18 ` [PATCH 20/28] HOTPLUG: call_usermodehelper callback support Christoph Hellwig
@ 2004-10-25 15:29 ` Mike Waychison
0 siblings, 0 replies; 21+ messages in thread
From: Mike Waychison @ 2004-10-25 15:29 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: linux-kernel, linux-fsdevel, raven
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Christoph Hellwig wrote:
> On Mon, Oct 25, 2004 at 10:48:40AM -0400, Mike Waychison wrote:
>
>>This patch extends the call_usermodehelper api by adding a callback variant.
>>The callback is made right when the system is about to call execve into the
>>new process. This allows for the caller to provide changes to the default
>>environment right before the exec takes place. Note: the context of the
>>callback will be _from within another process_.
>
>
> I don't like this at all. First it's the usual fork() + exec() vs spawn() with
> gazillions of arguments debatte, second this sounds far too complex to do it in
> kernelspace to me. Why can't you do the enviroment changes from the program
> beeing executed?
>
I want to be able to do two things:
- - To 'call_usermodehelper' a program, but in current's namespace.
Namespaces can't be passed around in userspace.
- - To give the execed program an open file. The current interface
doesn't allow me to do that.
I figured the _cb way of doing it remove any need for adding ad-hoc api
anytime somebody wants to tweak a task before calling execve.
Does this clarify why I added this?
- --
Mike Waychison
Sun Microsystems, Inc.
1 (650) 352-5299 voice
1 (416) 202-8336 voice
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
NOTICE: The opinions expressed in this email are held by me,
and may not represent the views of Sun Microsystems, Inc.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.5 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org
iD4DBQFBfRvNdQs4kOxk3/MRAvInAJYmn4GlPasI0r7VcwSKv03GXoygAJ90FWDM
LVQOfOrpbKp7NDSmlFRt+A==
=aQ04
-----END PGP SIGNATURE-----
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 28/28] AUTOFSNG: New autofs filesystem (resend)
2004-10-25 14:52 ` [PATCH 27/28] Testing syscall for expiry Mike Waychison
2004-10-25 15:01 ` Christoph Hellwig
@ 2004-10-25 15:37 ` Mike Waychison
1 sibling, 0 replies; 21+ messages in thread
From: Mike Waychison @ 2004-10-25 15:37 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel; +Cc: raven
[-- Attachment #1: Type: text/plain, Size: 312 bytes --]
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Enigmail
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.5 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org
iD8DBQFBfR22dQs4kOxk3/MRAp3oAJ47d7sziVXF160UzQ4HBzLh3upjcACeNMaE
JUeekjsmZaQsGt/yZgGh2c8=
=WqbX
-----END PGP SIGNATURE-----
[-- Attachment #2: 28-autofsng_support.diff --]
[-- Type: text/x-patch, Size: 59591 bytes --]
This patch introduces a new fs implementation for the 'autofs' filesystem.
If compiled as a module, the module is called 'autofsng'. NOTE: It may prove
a better idea to simply change the name of the fs to 'autofsng' as well, so
as to not be confused with the two other autofs implementations already in
the kernel.
Please see:
ftp://ftp-eng.cobalt.com/pub/whitepapers/autofs/towards_a_modern_autofs.txt
for a description of how it works.
Signed-off-by: Mike Waychison <michael.waychison@sun.com>
---
Kconfig | 26 ++
Makefile | 1
autofsng/Makefile | 3
autofsng/autofs.h | 93 +++++++
autofsng/cachetree.c | 206 ++++++++++++++++
autofsng/direct.c | 76 ++++++
autofsng/indirect.c | 482 ++++++++++++++++++++++++++++++++++++++
autofsng/init.c | 53 ++++
autofsng/mapcache.c | 638 +++++++++++++++++++++++++++++++++++++++++++++++++++
autofsng/request.c | 295 +++++++++++++++++++++++
autofsng/super.c | 234 ++++++++++++++++++
11 files changed, 2107 insertions(+)
Index: linux-2.6.9-quilt/fs/autofsng/Makefile
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.9-quilt/fs/autofsng/Makefile 2004-10-22 17:17:48.981017896 -0400
@@ -0,0 +1,3 @@
+obj-$(CONFIG_AUTOFSNG_FS) += autofsng.o
+
+autofsng-objs := super.o init.o direct.o request.o indirect.o mapcache.o cachetree.o
Index: linux-2.6.9-quilt/fs/autofsng/init.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.9-quilt/fs/autofsng/init.c 2004-10-22 17:17:48.981017896 -0400
@@ -0,0 +1,53 @@
+/* -*- linux-c -*- --------------------------------------------------------- *
+ *
+ * linux/fs/autofs/init.c
+ *
+ * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
+ * Copyright 2004 Sun Microsystems Inc. -- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * ------------------------------------------------------------------------- */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include "autofs.h"
+
+static struct super_block *autofs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data)
+{
+ return get_sb_nodev(fs_type, flags, data, autofs_fill_super);
+}
+
+static struct file_system_type autofsng_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "autofs",
+ .get_sb = autofs_get_sb,
+ .kill_sb = kill_anon_super,
+};
+
+static int __init init_autofs_fs(void)
+{
+ int ret;
+ ret = register_filesystem(&autofsng_fs_type);
+ if (ret)
+ return ret;
+ ret = mapcache_setup();
+ if (ret) {
+ unregister_filesystem(&autofsng_fs_type);
+ return ret;
+ }
+ return 0;
+}
+
+static void __exit exit_autofs_fs(void)
+{
+ unregister_filesystem(&autofsng_fs_type);
+ mapcache_shutdown();
+}
+
+module_init(init_autofs_fs)
+module_exit(exit_autofs_fs)
+MODULE_LICENSE("GPL");
Index: linux-2.6.9-quilt/fs/autofsng/direct.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.9-quilt/fs/autofsng/direct.c 2004-10-22 17:17:48.982017744 -0400
@@ -0,0 +1,76 @@
+#include <linux/sched.h>
+#include "autofs.h"
+
+static int autofs_direct_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+ /* hold references to ourself for the fall-back case */
+ struct autofs_sb_info *sbi = autofs_sbi(dentry->d_sb);
+ int ret;
+
+ dprintk("direct_follow_link\n");
+ dprintk("\tdentry=%08x, nd->dentry=%08x, nd->mnt=%08x\n",
+ (unsigned)dentry, (unsigned)nd->dentry,
+ (unsigned)nd->mnt);
+
+ /* Set the nd up to point to the current directory, ->mnt is setup by
+ * the VFS layer. */
+ dput(nd->dentry);
+ nd->dentry = dget(dentry);
+ ret = request_mount(nd, nd->mnt->mnt_devname, sbi->mapkey,
+ sbi->mapoffset, sbi->mapoptions);
+
+ if (ret) {
+ dprintk("request_mount returned %d\n", ret);
+ /* fail */
+ path_release(nd);
+ return -EPERM;
+ }
+
+ /* Direct mounts act like procfs style magic symlinks to namei. This is
+ * critical for the open path when follow_link is hit. */
+ nd->last_type = LAST_BIND;
+
+ return 0;
+}
+
+static struct dentry *autofs_direct_lookup(struct inode *dir, struct dentry
+*dentry, struct nameidata *nd)
+{
+ return ERR_PTR(-ENOENT);
+}
+
+/* If readdir is ever called, it's cause we didn't get an overlayed mount */
+static int autofs_direct_readdir(struct file *filp, void *dirent, filldir_t filldir) {
+ off_t nr;
+
+ nr = filp->f_pos;
+
+ dprintk("autofs(%x): readdir called on a direct mount. (pid=%d)\n", (unsigned)autofs_sbi(filp->f_vfsmnt->mnt_sb), current->pid);
+
+ switch(nr)
+ {
+ case 0:
+ if (filldir(dirent, ".", 1, nr, AUTOFSNG_ROOT_INO, DT_DIR) < 0)
+ return 0;
+ filp->f_pos = ++nr;
+ /* fall through */
+ case 1:
+ if (filldir(dirent, "..", 2, nr, AUTOFSNG_ROOT_INO, DT_DIR) < 0)
+ return 0;
+ filp->f_pos = ++nr;
+ /* fall through */
+ }
+ return 0;
+}
+
+
+/* Direct mounts work using follow_link magic. Nevertheless, we are supposed to
+ * look like a directory, hence the dummy .lookup. */
+struct inode_operations autofs_direct_root_inode_operations = {
+ .follow_link = autofs_direct_follow_link,
+ .lookup = autofs_direct_lookup,
+};
+
+struct file_operations autofs_direct_root_operations = {
+ .readdir = autofs_direct_readdir,
+};
Index: linux-2.6.9-quilt/fs/autofsng/autofs.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.9-quilt/fs/autofsng/autofs.h 2004-10-22 17:17:48.982017744 -0400
@@ -0,0 +1,93 @@
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include <linux/rbtree.h>
+
+#if 0
+#define DEBUG 1
+#endif
+
+#define AUTOFSNG_SUPER_MAGIC 0x7d92b1a0
+#define AUTOFSNG_ROOT_INO 1
+#define AGENT_PATH "/sbin/autofs"
+
+
+struct autofs_sb_info {
+ int flags;
+ char *mapkey;
+ char *mapoffset;
+ char *mapoptions; /* Stores string data passed back to the agent */
+ struct mapcache *mapcache;
+};
+
+struct mapcache_entry {
+ atomic_t count;
+ unsigned hash;
+ char name[0]; /* name of directory */
+};
+
+struct mapcache_treenode {
+ struct rb_node node;
+ struct mapcache_entry *entry;
+};
+
+struct mapcache_tree {
+ atomic_t count;
+ unsigned nentries;
+ struct rb_root root;
+};
+
+#define autofs_sbi(sb) ((struct autofs_sb_info *)(sb->s_fs_info))
+
+#define AUTOFSNG_FDIRECT 0x01
+#define AUTOFSNG_BROWSE 0x02
+
+extern struct super_operations autofs_sops;
+extern struct inode_operations autofs_direct_root_inode_operations;
+extern struct file_operations autofs_direct_root_operations;
+extern struct inode_operations autofs_indirect_root_inode_operations;
+extern struct file_operations autofs_indirect_root_operations;
+extern struct inode_operations autofs_indirect_dir_inode_operations;
+extern struct file_operations autofs_indirect_dir_operations;
+extern struct dentry_operations autofs_indirect_dir_d_operations;
+
+int parse_options(char *options, struct autofs_sb_info *sbi);
+int autofs_fill_super(struct super_block *s, void *data, int silent);
+int request_mount(struct nameidata *mounton, const char *map, const char *key, const char *offset, const char *options);
+
+
+/* setup and teardown a mapcache for a given super_block */
+int mapcache_init(struct super_block *s);
+void mapcache_destroy(struct super_block *s);
+
+/* the following are used to work with snapshots of the tree */
+struct mapcache_tree *get_snapshot(struct super_block *s, const char *mapname);
+void put_snapshot(struct mapcache_tree *tree);
+struct mapcache_treenode *snapshot_first(struct mapcache_tree *tree);
+struct mapcache_treenode *snapshot_next(struct mapcache_treenode *node);
+int snapshot_exists(struct mapcache_tree *tree, const char *name);
+
+/* Setup and teardown the entire mapcache system */
+int mapcache_setup(void);
+void mapcache_shutdown(void);
+
+/* used internally by the cache system */
+struct mapcache_tree *new_tree(void);
+void put_tree(struct mapcache_tree *tree);
+struct mapcache_tree *get_tree(struct mapcache_tree *tree);
+
+struct mapcache_entry *new_entry(const char *name, unsigned hash,
+ struct mapcache_tree *oldtree);
+struct mapcache_entry *find_entry(struct mapcache_tree *tree, const char *name,
+ unsigned hash);
+void put_entry(struct mapcache_entry *entry);
+int add_entry_to_tree(struct mapcache_entry *entry, struct mapcache_tree *tree);
+unsigned entry_hash(const char *name);
+
+void dump_tree(struct mapcache_tree *tree);
+
+#ifdef DEBUG
+#define dprintk(format, args...) printk(format, ##args)
+#else
+#define dprintk(format, args...) (void)(0)
+#endif
Index: linux-2.6.9-quilt/fs/Makefile
===================================================================
--- linux-2.6.9-quilt.orig/fs/Makefile 2004-10-22 17:17:40.736271288 -0400
+++ linux-2.6.9-quilt/fs/Makefile 2004-10-22 17:17:48.983017592 -0400
@@ -84,6 +84,7 @@ obj-$(CONFIG_ROMFS_FS) += romfs/
obj-$(CONFIG_QNX4FS_FS) += qnx4/
obj-$(CONFIG_AUTOFS_FS) += autofs/
obj-$(CONFIG_AUTOFS4_FS) += autofs4/
+obj-$(CONFIG_AUTOFSNG_FS) += autofsng/
obj-$(CONFIG_ADFS_FS) += adfs/
obj-$(CONFIG_UDF_FS) += udf/
obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/
Index: linux-2.6.9-quilt/fs/autofsng/super.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.9-quilt/fs/autofsng/super.c 2004-10-22 17:17:48.983017592 -0400
@@ -0,0 +1,234 @@
+#include <linux/parser.h>
+#include "autofs.h"
+
+enum {
+ Opt_err,
+ Opt_mapkey, Opt_mapoffset,
+ Opt_direct, Opt_indirect,
+ Opt_browse, Opt_nobrowse,
+ Opt_opt,
+};
+
+static match_table_t autofs_tokens = {
+ {Opt_mapkey, "mapkey=%s"},
+ {Opt_mapoffset, "mapoffset=%s"},
+ {Opt_direct, "direct"},
+ {Opt_indirect, "indirect"},
+ {Opt_browse, "browse"},
+ {Opt_nobrowse, "nobrowse"},
+ {Opt_opt, "opt=%s"}, /* Used for option passing */
+ {Opt_err, NULL},
+};
+
+int autofs_fill_super(struct super_block *s, void *data, int silent)
+{
+ struct inode * root_inode;
+ struct dentry * root;
+ struct autofs_sb_info *sbi;
+ int err;
+
+ err = -ENOMEM;
+ sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
+ if ( !sbi )
+ goto fail_unlock;
+ dprintk("autofs: starting up, sbi = %p\n",sbi);
+
+ memset(sbi, 0, sizeof(*sbi));
+
+ err = -EINVAL;
+ if ( parse_options(data, sbi) ) {
+ printk("autofs: called with bogus options\n");
+ goto fail_free;
+ }
+
+ s->s_fs_info = sbi;
+ err = mapcache_init(s);
+ if (err)
+ goto fail_parse;
+
+ err = -ENOMEM;
+ s->s_blocksize = 1024;
+ s->s_blocksize_bits = 10;
+ s->s_magic = AUTOFSNG_SUPER_MAGIC;
+ s->s_op = &autofs_sops;
+ root_inode = iget(s, AUTOFSNG_ROOT_INO);
+ if (!root_inode)
+ goto fail_mapcache;
+ root = d_alloc_root(root_inode);
+ if (!root)
+ goto fail_iput;
+
+ /*
+ * Success! Install the root dentry now to indicate completion.
+ */
+ s->s_root = root;
+
+ return 0;
+
+fail_iput:
+ printk("autofs: get root dentry failed\n");
+ iput(root_inode);
+fail_mapcache:
+ mapcache_destroy(s);
+fail_parse:
+ kfree(sbi->mapkey);
+ kfree(sbi->mapoffset);
+ kfree(sbi->mapoptions);
+fail_free:
+ kfree(sbi);
+fail_unlock:
+ return err;
+}
+
+static void autofs_read_root_inode(struct inode *inode)
+{
+ struct autofs_sb_info *sbi = autofs_sbi(inode->i_sb);
+ if (sbi->flags & AUTOFSNG_FDIRECT) {
+ inode->i_op = &autofs_direct_root_inode_operations;
+ inode->i_fop = &autofs_direct_root_operations;
+ } else {
+ inode->i_op = &autofs_indirect_root_inode_operations;
+ inode->i_fop = &autofs_indirect_root_operations;
+ }
+}
+
+static void autofs_read_dir_inode(struct inode *inode)
+{
+ struct autofs_sb_info *sbi = autofs_sbi(inode->i_sb);
+ if (sbi->flags & AUTOFSNG_FDIRECT) {
+ printk("autofs_read_dir_inode called in a direct mount!");
+ return;
+ }
+
+ inode->i_op = &autofs_indirect_dir_inode_operations;
+ inode->i_fop = &autofs_indirect_dir_operations;
+}
+
+static void autofs_read_inode(struct inode *inode)
+{
+ ino_t ino = inode->i_ino;
+
+ /* for the moment, assume all other inodes are directories.. */
+ inode->i_op = &simple_dir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
+ inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
+ inode->i_nlink = 2; /* TODO: empty dirs ? */
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_blocks = 0;
+ inode->i_blksize = 1024;
+
+ if (ino == AUTOFSNG_ROOT_INO) {
+ autofs_read_root_inode(inode);
+ } else {
+ autofs_read_dir_inode(inode);
+ }
+}
+
+int parse_options(char *options, struct autofs_sb_info *sbi)
+{
+ substring_t args[MAX_OPT_ARGS];
+ char *p;
+
+ if (!options)
+ return 0;
+
+ while ((p = strsep(&options, ",")) != NULL) {
+ int token;
+ if (!*p)
+ continue;
+
+ token = match_token(p, autofs_tokens, args);
+ switch(token) {
+ case Opt_direct:
+ sbi->flags |= AUTOFSNG_FDIRECT;
+ break;
+ case Opt_indirect:
+ sbi->flags &= ~AUTOFSNG_FDIRECT;
+ break;
+ case Opt_browse:
+ sbi->flags |= AUTOFSNG_BROWSE;
+ break;
+ case Opt_nobrowse:
+ sbi->flags &= ~AUTOFSNG_BROWSE;
+ break;
+ case Opt_mapkey:
+ if (sbi->mapkey) {
+ printk("autofs: mapkey specified twice\n");
+ goto cleanup;
+ }
+ sbi->mapkey = match_strdup(&args[0]);
+ if (!sbi->mapkey)
+ goto nomem;
+ break;
+ case Opt_mapoffset:
+ if (sbi->mapoffset) {
+ printk("autofs: mapoffset specified twice\n");
+ goto cleanup;
+ }
+ sbi->mapoffset = match_strdup(&args[0]);
+ if (!sbi->mapoffset)
+ goto nomem;
+ break;
+ case Opt_opt:
+ if (sbi->mapoptions) {
+ printk("autofs: opt specified twice\n");
+ goto cleanup;
+ }
+ sbi->mapoptions = match_strdup(&args[0]);
+ if (!sbi->mapoptions)
+ goto nomem;
+ break;
+ default:
+ return 1;
+ }
+ }
+
+ /* check that the options make sense */
+ if (sbi->flags & AUTOFSNG_FDIRECT) {
+ if (!sbi->mapkey) {
+ printk("autofs: mapkey option required for "
+ "direct mounts\n");
+ goto cleanup;
+ }
+ if (!sbi->mapoffset) {
+ printk("autofs: mapoffset option required for "
+ "direct mounts\n");
+ goto cleanup;
+ }
+ } else {
+ if (sbi->mapkey || sbi->mapoffset) {
+ printk("autofs: indirect mounts do not accept the "
+ "mapkey and mapoffset options\n");
+ goto cleanup;
+ }
+ }
+
+ return 0;
+nomem:
+ printk("autofs: couldn't allocate memory while parsing "
+ "mount options\n");
+cleanup:
+ kfree(sbi->mapkey);
+ kfree(sbi->mapoffset);
+ kfree(sbi->mapoptions);
+ sbi->mapkey = NULL;
+ sbi->mapoffset = NULL;
+ sbi->mapoptions = NULL;
+ return 1;
+}
+
+static void autofs_put_super(struct super_block *sb)
+{
+ struct autofs_sb_info *sbi = autofs_sbi(sb);
+ mapcache_destroy(sb);
+ kfree(sbi->mapkey);
+ kfree(sbi->mapoffset);
+ kfree(sbi->mapoptions);
+ kfree(sbi);
+}
+
+struct super_operations autofs_sops = {
+ .read_inode = autofs_read_inode,
+ .put_super = autofs_put_super,
+ .statfs = simple_statfs,
+};
Index: linux-2.6.9-quilt/fs/autofsng/request.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.9-quilt/fs/autofsng/request.c 2004-10-22 17:17:48.984017440 -0400
@@ -0,0 +1,295 @@
+#include <linux/sched.h>
+#include <asm/atomic.h>
+#include <linux/list.h>
+#include <linux/kmod.h>
+#include <linux/file.h>
+#include <linux/namespace.h>
+#include <linux/smp_lock.h>
+#include "autofs.h"
+
+struct req {
+ struct list_head list;
+ atomic_t count;
+ struct vfsmount *mnt;
+ struct dentry *dentry;
+ struct completion done;
+ struct file *file;
+ struct namespace *namespace;
+ const char *map;
+ const char *key;
+ const char *offset;
+ const char *options;
+ char buf[];
+};
+#define BUFSIZE (PAGE_SIZE - sizeof(struct req))
+
+static LIST_HEAD(req_list);
+static spinlock_t req_lock = SPIN_LOCK_UNLOCKED;
+
+static struct req *alloc_req(struct vfsmount *mnt, struct dentry *dentry)
+{
+ struct req *req;
+
+ req = (void *)get_zeroed_page(GFP_KERNEL);
+ if (!req)
+ return NULL;
+
+ memset(req, 0, sizeof(*req));
+ INIT_LIST_HEAD(&req->list);
+ atomic_set(&req->count, 2);
+ req->mnt = mntget(mnt);
+ req->dentry = dget(dentry);
+ init_completion(&req->done);
+
+ return req;
+}
+
+static void free_req(struct req *req)
+{
+ dput(req->dentry);
+ mntput(req->mnt);
+ free_page((unsigned long)req);
+}
+
+static void complete_req(struct req *req)
+{
+ spin_lock(&req_lock);
+ list_del_init(&req->list);
+ spin_unlock(&req_lock);
+ atomic_dec(&req->count);
+ complete_all(&req->done);
+}
+
+static void release_req(struct req *req)
+{
+ if (atomic_dec_and_test(&req->count))
+ free_req(req);
+}
+
+static struct req *find_req(struct vfsmount *mnt, struct dentry *dentry)
+{
+ struct req *p;
+
+ list_for_each_entry(p, &req_list, list)
+ if (p->mnt == mnt && p->dentry == dentry)
+ return p;
+ return NULL;
+}
+
+/* TODO: fix locking */
+static int try_to_follow(struct nameidata *nd)
+{
+ int following;
+ struct dentry *d;
+ int rv;
+ int didsomething = 0;
+
+ do {
+ following = 0;
+ while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry))
+ following = 1;
+ if (!following)
+ break;
+ didsomething = 1;
+ following = 0;
+ d = nd->dentry;
+ while (d->d_inode->i_op && d->d_inode->i_op->follow_link) {
+ dprintk("autofs: followed a link on ->mnt=%d, ->dentry=%d\n", (unsigned)nd->mnt, (unsigned)nd->dentry);
+ down(&d->d_inode->i_sem);
+ rv = d->d_inode->i_op->follow_link(d, nd);
+ up(&d->d_inode->i_sem);
+ dput(d);
+ if (rv) {
+ path_release(nd);
+ return rv;
+ }
+ /*
+ * XXX: We should never see a link path in nd. This is
+ * because we assume that we are following into a
+ * mounted filesystem, whose root is a directory. The
+ * only people who do this (us and procfs) use symlink
+ * magic anyway.
+ */
+ BUG_ON(nd_get_link(nd) != NULL);
+
+ d = nd->dentry;
+ following = 1;
+ }
+ } while (following);
+
+ if (!didsomething) {
+ path_release(nd);
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+static int wait_for_request(struct req *req, struct nameidata *nd)
+{
+ wait_for_completion(&req->done);
+ /* once complete, we assume the mount is already moved onto the
+ * follow_link dentry */
+ return try_to_follow(nd);
+}
+
+#define do_envp(index, name, value) \
+ count = snprintf(p, left, (name), (value)); \
+ if (count < 0) \
+ return -ENOMEM; \
+ envp[(index)] = p; \
+ p += count + 1; \
+ left -= count + 1;
+
+static int issue_request_usermode_cb(void *_req)
+{
+ struct req *req = _req;
+ int fd;
+ char *argv[] = { AGENT_PATH, "lookup", NULL };
+ char *envp[8];
+ char *p = req->buf;
+ int count;
+ int left = BUFSIZE - 1;
+ int ret;
+ struct nameidata rootnd;
+
+ p[BUFSIZE-1] = '\0';
+
+ /* handle file magic */
+ fd = get_unused_fd();
+ if (fd < 0)
+ return -ENOMEM;
+ dprintk("installing fd at %d\n", fd);
+ dprintk("req->file is %08x\n", (unsigned)req->file);
+ get_file(req->file);
+ fd_install(fd, req->file);
+ dprintk("after fd_install\n");
+
+ /* pivot namespace ! */
+ put_namespace(current->namespace);
+ get_namespace(req->namespace);
+ current->namespace = req->namespace;
+
+ dprintk("after pivot namespace\n");
+
+ /*
+ * pivot root !
+ * We first have to try_to_follow because the namespace root is most
+ * likely a rootfs
+ */
+ memset(&rootnd, 0, sizeof(rootnd));
+ rootnd.dentry = dget(req->namespace->root->mnt_root);
+ rootnd.mnt = mntget(req->namespace->root);
+ ret = try_to_follow(&rootnd);
+ if (ret)
+ return -EBUSY;
+
+ lock_kernel();
+ set_fs_root(current->fs, rootnd.mnt, rootnd.dentry);
+ /*set_fs_altroot(); TODO*/
+ set_fs_pwd(current->fs, rootnd.mnt, rootnd.dentry);
+ unlock_kernel();
+
+ path_release(&rootnd);
+
+ dprintk("after pivot root\n");
+
+ do_envp(0, "MAPNAME=%s", req->map);
+ do_envp(1, "MAPKEY=%s", req->key);
+ do_envp(2, "MAPOFFSET=%s", req->offset);
+ do_envp(3, "MOUNTFD=%d", fd);
+ do_envp(4, "MAPOPTIONS=%s", req->options ? req->options : "");
+ envp[5] = "HOME=/";
+ envp[6] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+ envp[7] = NULL;
+
+ dprintk("after building env\n");
+
+ dprintk("ABOUT TO EXECUTE\n");
+
+ ret = call_usermodehelper_execve(AGENT_PATH, argv, envp);
+ dprintk("execve returned %d\n", ret);
+ return ret;
+}
+
+static int issue_request(struct req *req, struct nameidata *nd)
+{
+ int ret;
+ struct nameidata follownd;
+ dprintk("in issue_request\n");
+
+ req->file = dentry_open(dget(req->dentry), mntget(req->mnt), O_DIRECTORY | O_RDONLY);
+ if (IS_ERR(req->file)) {
+ printk("dentry_open failed (%ld)\n", PTR_ERR(req->file));
+ return PTR_ERR(req->file);
+ }
+
+ req->namespace = current->namespace;
+ get_namespace(req->namespace);
+
+ dprintk("ABOUT TO CALL_USERMODEHELPER_CB\n");
+ ret = call_usermodehelper_cb(issue_request_usermode_cb, req, 1);
+ if (ret) {
+ printk("call_usermodehelper_cb errored out with returned %d\n", ret);
+ /* fallthrough and try anyway */
+ }
+
+ /* cool beans. The fs should be mounted on nd->mnt/req->dentry now */
+ /* TODO: this is a mess, do we *need* follownd? */
+ memset(&follownd, 0, sizeof(follownd));
+ follownd.dentry = dget(req->dentry);
+ follownd.mnt = mntget(nd->mnt);
+ ret = try_to_follow(&follownd);
+ if (ret) {
+ /* oops. that didn't work :( */
+ dprintk("autofs agent ran, but no mount found\n");
+ } else {
+ /* Switch up the mount we have */
+ path_release(nd);
+ /* move the references in follownd over to nd */
+ nd->mnt = follownd.mnt;
+ nd->dentry = follownd.dentry;
+ }
+
+/* out: */
+ put_namespace(req->namespace);
+ fput(req->file);
+
+ complete_req(req);
+ return ret;
+}
+
+int request_mount(struct nameidata *mounton, const char *map, const char *key, const char *offset, const char *options)
+{
+ struct req *req, *newreq;
+ int err;
+
+ newreq = alloc_req(mounton->mnt, mounton->dentry);
+ if (!newreq)
+ return -ENOMEM;
+
+ newreq->map = map;
+ newreq->key = key;
+ newreq->offset = offset;
+ newreq->options = options;
+
+ spin_lock(&req_lock);
+ req = find_req(mounton->mnt, mounton->dentry);
+ if (req) {
+ /* this request already exists */
+ atomic_inc(&req->count);
+ spin_unlock(&req_lock);
+ release_req(newreq);
+ dprintk("GOING TO WAIT on %p\n", req);
+ err = wait_for_request(req, mounton);
+ release_req(req);
+ return err;
+ }
+ /* add this req to the global list */
+ list_add(&newreq->list, &req_list);
+ spin_unlock(&req_lock);
+ dprintk("ISSUING %p\n", newreq);
+ err = issue_request(newreq, mounton);
+ release_req(newreq);
+ return err;
+}
Index: linux-2.6.9-quilt/fs/Kconfig
===================================================================
--- linux-2.6.9-quilt.orig/fs/Kconfig 2004-08-14 01:37:14.000000000 -0400
+++ linux-2.6.9-quilt/fs/Kconfig 2004-10-22 17:17:48.985017288 -0400
@@ -481,6 +481,32 @@ config AUTOFS4_FS
local network, you probably do not need an automounter, and can say
N here.
+config AUTOFSNG_FS
+ tristate "Kernel automounter next-gen support"
+ depends on EXPERIMENTAL
+ help
+ The automounter is a tool to automatically mount remote file systems
+ on demand. This implementation is partially kernel-based to reduce
+ overhead in the already-mounted case; this is unlike the BSD
+ automounter (amd), which is a pure user space daemon.
+
+ Unlike the previous kernel-based automounter solutions, this 'NG'
+ version does not use a persistent daemon. Instead, the kernel calls
+ out to a userspace application much like how the hotplug system works.
+ This allows the implementation to work well with namespaces and
+ simplifies the complexity involved.
+
+ To use the automounter you need the user-space tools from <TODO>; you
+ also want to answer Y to "NFS file system support".
+
+ To compile this support as a module, choose M here: the module will be
+ called autofsng. You will need to add "alias autofs autofsng" to your
+ modules configuration file.
+
+ If you are not a part of a fairly large, distributed network or don't
+ have a laptop which needs to dynamically reconfiger to the local
+ network, you probably do not need an automounter, and can say N here.
+
menu "CD-ROM/DVD Filesystems"
config ISO9660_FS
Index: linux-2.6.9-quilt/fs/autofsng/indirect.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.9-quilt/fs/autofsng/indirect.c 2004-10-22 17:17:48.986017136 -0400
@@ -0,0 +1,482 @@
+#include <linux/sched.h>
+#include "autofs.h"
+
+enum cursor_type {
+ CURSOR_DCACHE,
+ CURSOR_MAPCACHE,
+};
+struct cursor_data {
+ struct dentry *dcursor;
+ struct mapcache_treenode *cpointer;
+ struct mapcache_tree *snapshot;
+ enum cursor_type type;
+};
+
+/*
+ * return 0 to invalidate
+ * return 1 to validate something is mounted, or we found it in the mapcache
+ */
+static int autofs_indirect_dir_revalidate(struct dentry *dentry,
+ struct nameidata *nd)
+{
+ struct autofs_sb_info *sbi = autofs_sbi(dentry->d_sb);
+ struct nameidata testnd;
+ int found;
+ int err;
+
+ if (nd == NULL) {
+ /* this came from a lookup_hash for a file creation */
+ return 0;
+ }
+
+ /* is something mounted on us? */
+ testnd.dentry = dget(dentry);
+ testnd.mnt = mntget(nd->mnt);
+ /* TODO: check locking */
+ found = follow_down(&testnd.mnt, &testnd.dentry);
+ path_release(&testnd);
+
+ if (found)
+ return 1;
+
+ /*
+ * If we are browsing, then this entry is fine if it's in the cache.
+ * If it's not in the cache when we are browsing, we have to try and
+ * mount.
+ */
+ if (sbi->flags & AUTOFSNG_BROWSE) {
+ struct mapcache_tree *snapshot;
+
+ /* is it in the cache? */
+ snapshot = get_snapshot(dentry->d_sb, nd->mnt->mnt_devname);
+ found = snapshot_exists(snapshot, dentry->d_name.name);
+ put_snapshot(snapshot);
+
+ if (found)
+ return 1;
+
+ /*
+ * we have to try and get something mounted on us.
+ * fall through to the nobrowse case.
+ */
+ }
+
+ /* nobrowse case */
+ testnd.dentry = dget(dentry);
+ testnd.mnt = mntget(nd->mnt);
+ err = request_mount(&testnd, testnd.mnt->mnt_devname,
+ dentry->d_name.name, dentry->d_name.name,
+ sbi->mapoptions);
+ path_release(&testnd);
+
+ if (err == 0)
+ return 1;
+ return 0;
+}
+
+/*
+ * Indirect mounts work as follows:
+ * - Create a follow_link directory trap for any ->lookup.
+ * - We blindly allow all lookups to succeed, as any real work is handled in
+ * revalidate portion.
+ * - On root dir readdir, we only show the children that are mounted upon.
+ */
+
+static struct dentry *autofs_indirect_lookup(struct inode *dir, struct dentry
+ *dentry, struct nameidata *nd)
+{
+ struct inode *inode;
+ int ret;
+ ino_t ino;
+
+ /* if nd is null, then this lookup is looking for a negative dentry
+ * (from lookup_hash). */
+ if (nd == NULL)
+ return ERR_PTR(-EPERM);
+
+ ino = iunique(dir->i_sb, AUTOFSNG_ROOT_INO);
+ inode = iget(dir->i_sb, ino);
+ if (!inode)
+ return ERR_PTR(-EACCES);
+ dentry->d_op = &autofs_indirect_dir_d_operations;
+
+ /*
+ * Mark the dentry incomplete, but add it. This is needed so
+ * that the VFS layer knows about the dentry, and we can count
+ * on catching any lookups through the revalidate.
+ *
+ * Let all the hard work be done by the revalidate function that
+ * needs to be able to do this anyway..
+ *
+ * We need to do this before we release the directory semaphore.
+ */
+
+ d_add(dentry, inode);
+
+ up(&dir->i_sem);
+ ret = autofs_indirect_dir_revalidate(dentry, nd);
+ down(&dir->i_sem);
+
+ if (ret == 0) {
+ struct nameidata testnd;
+ /*
+ * need to check again if something is mounted there. we may
+ * have raced with a revalidate while waiting for the dir->i_sem
+ */
+ testnd.dentry = dget(dentry);
+ testnd.mnt = mntget(nd->mnt);
+ /* TODO: check locking */
+ ret = follow_down(&testnd.mnt, &testnd.dentry);
+ path_release(&testnd);
+
+ if (ret == 0) {
+ /* nope, nothing there, we can safely drop the dentry */
+ d_drop(dentry);
+ return ERR_PTR(-ENOENT);
+ }
+ }
+
+ return NULL;
+}
+
+static struct dentry *autofs_indirect_dir_lookup(struct inode *dir,
+ struct dentry *dentry, struct nameidata *nd)
+{
+ return ERR_PTR(-ENOENT);
+}
+
+/* If readdir is ever called, it's cause we didn't get an overlayed mount */
+static int autofs_indirect_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) {
+ off_t nr;
+
+ nr = filp->f_pos;
+
+ dprintk("autofs(%x): readdir called on a indirect mount. (pid=%d)\n", (unsigned)autofs_sbi(filp->f_vfsmnt->mnt_sb), current->pid);
+
+ switch(nr)
+ {
+ case 0:
+ if (filldir(dirent, ".", 1, nr, AUTOFSNG_ROOT_INO, DT_DIR) < 0)
+ return 0;
+ filp->f_pos = ++nr;
+ /* fall through */
+ case 1:
+ if (filldir(dirent, "..", 2, nr, AUTOFSNG_ROOT_INO, DT_DIR) < 0)
+ return 0;
+ filp->f_pos = ++nr;
+ /* fall through */
+ }
+ return 0;
+}
+
+static int autofs_indirect_dir_follow_link(struct dentry *dentry,
+ struct nameidata *nd)
+{
+ struct autofs_sb_info *sbi = autofs_sbi(dentry->d_sb);
+
+ /* hold references to ourself for the fall-back case */
+ struct dentry *mydentry = dget(dentry);
+ struct vfsmount *mymnt = mntget(nd->mnt);
+ int ret;
+
+ dprintk("indirect_follow_link\n");
+ dprintk("\tdentry=%08x, nd->dentry=%08x, nd->mnt=%08x\n",
+ (unsigned)dentry, (unsigned)nd->dentry,
+ (unsigned)nd->mnt);
+
+ /* Set the nd up to point to the current directory, ->mnt is setup by
+ * the VFS layer. */
+ dput(nd->dentry);
+ nd->dentry = dget(dentry);
+ ret = request_mount(nd, nd->mnt->mnt_devname, dentry->d_name.name,
+ dentry->d_name.name, sbi->mapoptions);
+
+ if (ret == -ENOENT) {
+ /*
+ * We didn't succeed in mounting anything. Our real return value
+ * depends on whether we are in the cache or not.
+ */
+ if (sbi->flags & AUTOFSNG_BROWSE) {
+ struct mapcache_tree *snapshot;
+ snapshot = get_snapshot(dentry->d_sb,
+ nd->mnt->mnt_devname);
+ if (snapshot_exists(snapshot, dentry->d_name.name)) {
+ ret = -EPERM;
+ } else {
+ /* we shouldn't be listing this node */
+ d_drop(dentry);
+ }
+ } else {
+ d_drop(dentry);
+ }
+ path_release(nd);
+ } else if (ret != 0) {
+ /* Any other error */
+ dprintk("request_mount returned %d\n", ret);
+ /*
+ * Browsing was disabled. Don't show directories with nothing
+ * mounted on them.
+ */
+ d_drop(dentry);
+ path_release(nd);
+ } else if (ret == 0) {
+ /* We succeeded in mounting somthing. We set LAST_BIND as the
+ * open path requires it */
+ nd->last_type = LAST_BIND;
+ }
+ dput(mydentry);
+ mntput(mymnt);
+ dprintk("out of follow_link: nd->mnt: %d nd->dentry: %d\n",
+ atomic_read(&nd->mnt->mnt_count),
+ atomic_read(&nd->dentry->d_count));
+ return ret;
+}
+
+/* The following directory ops for the root dentry are copied from libfs,
+ * however we also check to make sure that subdirs are mounted upon when doing
+ * the readdir */
+static int autofs_indirect_root_open(struct inode *inode, struct file *file)
+{
+ static struct qstr cursor_name = {.len = 1, .name = "."};
+ struct autofs_sb_info *sbi = autofs_sbi(inode->i_sb);
+ struct cursor_data *cd;
+ int err;
+
+ err = -ENOMEM;
+ cd = kmalloc(sizeof (*cd), GFP_KERNEL);
+ if (!cd)
+ goto out;
+ cd->dcursor = d_alloc(file->f_dentry, &cursor_name);
+ if (!cd->dcursor)
+ goto out_kfree;
+ if (sbi->flags & AUTOFSNG_BROWSE) {
+ cd->snapshot = get_snapshot(inode->i_sb,
+ file->f_vfsmnt->mnt_devname);
+ if (!cd->snapshot)
+ goto out_dput;
+ }
+ cd->cpointer = NULL;
+ cd->type = CURSOR_DCACHE;
+
+ file->private_data = cd;
+
+ return 0;
+out_dput:
+ dput(cd->dcursor);
+out_kfree:
+ kfree(cd);
+out:
+ return err;
+}
+
+static int autofs_indirect_root_close(struct inode *inode, struct file *file)
+{
+ struct cursor_data *cd = file->private_data;
+ struct autofs_sb_info *sbi = autofs_sbi(inode->i_sb);
+
+ if (sbi->flags & AUTOFSNG_BROWSE)
+ put_snapshot(cd->snapshot);
+ dput(cd->dcursor);
+ return 0;
+}
+
+static loff_t autofs_indirect_root_lseek(struct file *file, loff_t offset,
+ int origin)
+{
+ struct autofs_sb_info *sbi = autofs_sbi(file->f_dentry->d_sb);
+ struct cursor_data *cd = file->private_data;
+
+ down(&file->f_dentry->d_inode->i_sem);
+ switch (origin) {
+ case 1:
+ offset += file->f_pos;
+ case 0:
+ if (offset >= 0)
+ break;
+ default:
+ up(&file->f_dentry->d_inode->i_sem);
+ return -EINVAL;
+ }
+ if (offset != file->f_pos) {
+ file->f_pos = offset;
+ cd->type = CURSOR_DCACHE;
+ if (file->f_pos >= 2) {
+ struct list_head *p;
+ struct dentry *cursor = cd->dcursor;
+ int hiteol = 0;
+ loff_t n = file->f_pos - 2;
+
+ spin_lock(&dcache_lock);
+ list_del(&cursor->d_child);
+ p = file->f_dentry->d_subdirs.next;
+ while (n && p != &file->f_dentry->d_subdirs) {
+ struct dentry *next;
+ next = list_entry(p, struct dentry, d_child);
+ if (!d_unhashed(next) && next->d_inode)
+ n--;
+ p = p->next;
+ }
+ list_add_tail(&cursor->d_child, p);
+ cd->cpointer = NULL;
+ if (cursor->d_child.next == &file->f_dentry->d_subdirs)
+ hiteol = 1;
+ spin_unlock(&dcache_lock);
+
+ /* now walk into cache if required */
+ if (sbi->flags & AUTOFSNG_BROWSE && hiteol) {
+ struct mapcache_treenode *node;
+
+ cd->type = CURSOR_MAPCACHE;
+ node = snapshot_first(cd->snapshot);
+ while (n && node) {
+ n--;
+ node = snapshot_next(node);
+ }
+ cd->cpointer = node;
+ }
+ }
+ }
+ up(&file->f_dentry->d_inode->i_sem);
+
+ return offset;
+}
+
+struct inode_operations autofs_indirect_root_inode_operations = {
+ .lookup = autofs_indirect_lookup,
+};
+
+/* Relationship between i_mode and the DT_xxx types */
+static inline unsigned char dt_type(struct inode *inode)
+{
+ return (inode->i_mode >> 12) & 15;
+}
+
+/*
+ * Directory is locked and all positive dentries in it are safe, since
+ * for ramfs-type trees they can't go away without unlink() or rmdir(),
+ * both impossible due to the lock on directory.
+ */
+
+static int autofs_indirect_root_readdir(struct file * filp, void * dirent,
+ filldir_t filldir)
+{
+ struct dentry *dentry = filp->f_dentry;
+ struct cursor_data *cd = filp->private_data;
+ struct dentry *cursor = cd->dcursor;
+ struct list_head *p, *q = &cursor->d_child;
+ struct autofs_sb_info *sbi = autofs_sbi(filp->f_dentry->d_sb);
+ ino_t ino;
+ int i = filp->f_pos;
+
+ switch (i) {
+ case 0:
+ ino = dentry->d_inode->i_ino;
+ if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
+ break;
+ filp->f_pos++;
+ i++;
+ /* fallthrough */
+ case 1:
+ ino = parent_ino(dentry);
+ if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
+ break;
+ filp->f_pos++;
+ i++;
+ /* fallthrough */
+ }
+ if (cd->type == CURSOR_DCACHE) {
+ spin_lock(&dcache_lock);
+ if (filp->f_pos == 2) {
+ list_del(q);
+ list_add(q, &dentry->d_subdirs);
+ }
+ for (p=q->next; p != &dentry->d_subdirs; p=p->next) {
+ struct dentry *next;
+ struct nameidata nd;
+ int followed = 0;
+
+ next = list_entry(p, struct dentry, d_child);
+ if (d_unhashed(next) || !next->d_inode)
+ continue;
+
+ if (!atomic_read(&next->d_count))
+ continue;
+
+ /* is this node from the cache, if so we don't
+ * display it */
+ if (sbi->flags & AUTOFSNG_BROWSE
+ && snapshot_exists(cd->snapshot, next->d_name.name))
+ continue;
+
+ /* is this node mounted upon? */
+ memset(&nd, 0, sizeof (nd));
+ nd.mnt = mntget(filp->f_vfsmnt);
+ nd.dentry = dget(next);
+ spin_unlock(&dcache_lock);
+
+ /* TODO: fix locking */
+ if (d_mountpoint(nd.dentry)
+ && follow_down(&nd.mnt, &nd.dentry))
+ followed = 1;
+ dput(nd.dentry);
+ _mntput(nd.mnt);
+ if (!followed) {
+ spin_lock(&dcache_lock);
+ continue;
+ }
+
+ if (filldir(dirent, next->d_name.name, next->d_name.len, filp->f_pos, next->d_inode->i_ino, dt_type(next->d_inode)) < 0)
+ return 0;
+ spin_lock(&dcache_lock);
+ /* next is still alive */
+ list_del(q);
+ list_add(q, p);
+ p = q;
+ filp->f_pos++;
+ }
+ spin_unlock(&dcache_lock);
+ /* did we just finish the dcache entries? */
+ if (sbi->flags & AUTOFSNG_BROWSE) {
+ cd->type = CURSOR_MAPCACHE;
+ cd->cpointer = snapshot_first(cd->snapshot);
+ }
+ }
+
+ if (cd->type == CURSOR_MAPCACHE) {
+ while (cd->cpointer) {
+ struct mapcache_entry *entry = cd->cpointer->entry;
+ int ret;
+
+ ret = filldir(dirent, entry->name, strlen(entry->name),
+ filp->f_pos, 1, DT_DIR);
+ if (ret < 0)
+ return 0;
+ cd->cpointer = snapshot_next(cd->cpointer);
+ filp->f_pos++;
+ }
+ }
+
+ update_atime(dentry->d_inode);
+ return 0;
+}
+
+struct file_operations autofs_indirect_root_operations = {
+ .open = autofs_indirect_root_open,
+ .release = autofs_indirect_root_close,
+ .llseek = autofs_indirect_root_lseek,
+ .read = generic_read_dir,
+ .readdir = autofs_indirect_root_readdir,
+};
+
+struct inode_operations autofs_indirect_dir_inode_operations = {
+ .follow_link = autofs_indirect_dir_follow_link,
+ .lookup = autofs_indirect_dir_lookup,
+};
+
+struct file_operations autofs_indirect_dir_operations = {
+ .readdir = autofs_indirect_dir_readdir,
+};
+
+struct dentry_operations autofs_indirect_dir_d_operations = {
+ .d_revalidate = autofs_indirect_dir_revalidate,
+};
Index: linux-2.6.9-quilt/fs/autofsng/mapcache.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.9-quilt/fs/autofsng/mapcache.c 2004-10-22 17:17:48.987016984 -0400
@@ -0,0 +1,638 @@
+#include <linux/pagemap.h>
+#include <linux/completion.h>
+#include <linux/jiffies.h>
+#include <linux/init.h>
+#include <linux/file.h>
+#include <linux/module.h>
+#include "autofs.h"
+
+#define TIMEOUT (10 * 60 * HZ)
+
+#define MAPCACHE_MAGIC 0x328d20a2
+
+#define BUFFSIZE PAGE_SIZE
+
+/*
+ * Mapcaches use a global rbtree for lookups (mapcache_rbtree) and are
+ * singly linked for iteration, which is headed by a mapcache_entry_list.
+ *
+ * Each super_block will have a single mapcache, which in turn has an rbtree
+ * protected by a rwlock.
+ */
+
+/* used for blocking tasks while the rbtree is being updated */
+struct mapcache_update {
+ atomic_t count;
+ struct completion done;
+};
+
+enum mapcache_state {
+ MC_REFRESH,
+ MC_UPDATING,
+ MC_OK,
+};
+
+struct mapcache {
+ enum mapcache_state state;
+ unsigned long lastupdate; /* time of last update */
+ struct mapcache_tree *tree; /* the current tree */
+ struct mapcache_tree *oldtree; /* reference to old tree */
+ unsigned hits; /* count of hits when updating */
+ spinlock_t lock; /* protects the state */
+ struct mapcache_update *update; /* refreshing task sets this
+ while others wait for refresh */
+};
+
+/*
+ * Entries in the buffer may only be up to a page long. If an entry longer than
+ * this is seen, we log an error and silently continue reading it until the next
+ * entry is found. If we see an entry with illegal char's (/), we also complain
+ * and silently continue reading.
+ */
+struct mapcache_file_buffer {
+ char *buffer;
+ int skip; /* skip input (entry is invalid) */
+ int pos; /* end of unflushed buffer data */
+ struct semaphore sem;
+ struct mapcache *mapcache;
+};
+
+static struct vfsmount *mapcache_mnt;
+static void mapcache_read_inode(struct inode *inode);
+static struct super_operations mapcache_fs_ops = {
+ .read_inode = mapcache_read_inode,
+ .statfs = simple_statfs,
+};
+
+static struct super_block *mapcache_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data)
+{
+ return get_sb_pseudo(fs_type, "autofsng_mapcache:", &mapcache_fs_ops,
+ MAPCACHE_MAGIC);
+}
+
+static struct file_system_type mapcache_fs_type = {
+ .name = "mapcachefs",
+ .get_sb = mapcache_get_sb,
+ .kill_sb = kill_anon_super,
+};
+
+static struct mapcache_file_buffer *
+new_mapcache_file_buffer(struct mapcache *mapcache)
+{
+ struct mapcache_file_buffer *buffer;
+
+ buffer = kmalloc(sizeof(*buffer), GFP_KERNEL);
+ if (!buffer)
+ return NULL;
+
+ buffer->buffer = (void *)get_zeroed_page(GFP_KERNEL);
+ if (!buffer->buffer) {
+ kfree(buffer);
+ return NULL;
+ }
+
+ init_MUTEX(&buffer->sem);
+ buffer->mapcache = mapcache;
+ buffer->skip = 0;
+ buffer->pos = 0;
+ return buffer;
+}
+
+static void free_mapcache_file_buffer(struct mapcache_file_buffer *buffer)
+{
+ free_page((unsigned long)buffer->buffer);
+ kfree(buffer);
+}
+
+static int mapcache_file_release(struct inode *inode, struct file *file)
+{
+ struct mapcache_file_buffer *buffer = file->private_data;
+ free_mapcache_file_buffer(buffer);
+ return 0;
+}
+
+static int handle_newline(struct mapcache_file_buffer *buffer)
+{
+ struct mapcache_entry *entry;
+ unsigned hash;
+ int ret;
+
+ /* skip over the null string */
+ if (!buffer->buffer[0])
+ return 0;
+
+ hash = entry_hash(buffer->buffer);
+ entry = new_entry(buffer->buffer, hash, buffer->mapcache->oldtree);
+ if (!entry)
+ return -ENOMEM;
+
+ ret = add_entry_to_tree(entry, buffer->mapcache->tree);
+ if (ret == 0) {
+ /* unique entry added successfully */
+ /* if the entry count is > 1, then we had a hit */
+ if (atomic_read(&entry->count) > 1)
+ buffer->mapcache->hits++;
+ } else if (ret == 1) {
+ /* was a duplicate */
+ ret = 0;
+ } else if (ret < 0) {
+ /* ran out of memory */
+ put_entry(entry);
+ } else
+ BUG();
+ return ret;
+}
+
+/*
+ * Fill in the buffer for later reading. We fill up to the end of the buffer,
+ * at which point we stop. While flushing, if we see that the entry is larger
+ * than the entire buffer, we mark ->skip and continue blindly slurping in the
+ * text
+ */
+static ssize_t mapcache_fill_write_buffer(struct mapcache_file_buffer *buffer,
+ const char __user *buf, ssize_t count)
+{
+ int error;
+
+ /* if we are skipping data, we don't care if the buffer is full */
+ if (buffer->skip)
+ buffer->pos = 0;
+
+ if (count + buffer->pos >= BUFFSIZE)
+ count = BUFFSIZE - buffer->pos;
+ error = copy_from_user(&buffer->buffer[buffer->pos], buf, count);
+ return error ? -EFAULT : count;
+}
+
+/*
+ * Read from ->pos on trying to find the end of the entry. If we hit the end of
+ * the buffer, we 'skip' the rest of the entry.
+ *
+ * Return the position of the last char we successfully read, or 0 otherwise.
+ */
+static ssize_t mapcache_flush_write_buffer(struct mapcache_file_buffer *buffer,
+ ssize_t new)
+{
+ char *p = &buffer->buffer[buffer->pos];
+ ssize_t charsleft = new;
+
+ while (charsleft--) {
+ /* Is this a delimiter? */
+ if (*p == '\n') {
+ int ret;
+ if (buffer->skip) {
+ /* we were looking for this.. */
+ buffer->skip = 0;
+ } else {
+ /* TODO: do something with this: */
+ *p = '\0';
+ ret = handle_newline(buffer);
+ /* propagate errors back out */
+ if (ret)
+ return ret;
+ }
+ ret = p - &buffer->buffer[buffer->pos] + 1;
+ buffer->pos = 0;
+ return ret;
+ }
+
+ /* illegal char? */
+ if (*p == '/' || *p == '*' || *p == '\0') {
+ buffer->skip = 1;
+ }
+
+ /* Is this the last char in the buffer? */
+ if (p == &buffer->buffer[BUFFSIZE -1]) {
+ buffer->skip = 1;
+ buffer->pos = 0;
+ return new;
+ }
+
+ p++;
+ }
+
+ /* didn't find the end of the entry, slurp it up */
+ buffer->pos += new;
+ return new;
+}
+
+static ssize_t mapcache_file_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct mapcache_file_buffer *buffer = file->private_data;
+ int filled;
+ int flusheduntil;
+ int ret;
+
+ down(&buffer->sem);
+ ret = filled = mapcache_fill_write_buffer(buffer, buf, count);
+ if (ret < 0)
+ goto out;
+ ret = flusheduntil = mapcache_flush_write_buffer(buffer, filled);
+ if (ret < 0)
+ goto out;
+ *ppos += ret;
+out:
+ up(&buffer->sem);
+ return ret;
+}
+
+static struct file_operations mapcache_file_ops = {
+ .owner = THIS_MODULE,
+ .write = mapcache_file_write,
+ .release = mapcache_file_release,
+};
+
+static void mapcache_read_inode(struct inode *inode)
+{
+ inode->i_fop = &mapcache_file_ops;
+ inode->i_mode = S_IFREG | S_IRUGO | S_IXUGO;
+ inode->i_nlink = 1;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+
+ inode->i_blocks = 0;
+ inode->i_blksize = 1024;
+}
+
+static struct dentry *get_mapcache_dentry(void)
+{
+ static struct qstr qstr = {
+ .name = "mapcachefd",
+ .len = 10,
+ };
+ struct dentry *dentry;
+ struct inode *inode;
+
+ dentry = d_alloc(mapcache_mnt->mnt_root, &qstr);
+ if (IS_ERR(dentry))
+ return dentry;
+
+ inode = iget(mapcache_mnt->mnt_sb, iunique(mapcache_mnt->mnt_sb, 0));
+ if (IS_ERR(inode)) {
+ int err = PTR_ERR(inode);
+ dput(dentry);
+ return ERR_PTR(err);
+ }
+
+ d_add(dentry, inode);
+
+ return dentry;
+}
+
+static long open_mapcache_file(struct mapcache *mapcache)
+{
+ struct file *file;
+ struct mapcache_file_buffer *buffer;
+ int err;
+ long fd;
+
+ /* We grab a ref count to our module which is used by the mapcache fd */
+ __module_get(THIS_MODULE);
+ err = -ENOMEM;
+ file = get_empty_filp();
+ if (!file)
+ goto out;
+
+ err = -ENFILE;
+ fd = get_unused_fd();
+ if (fd < 0)
+ goto out_putfilp;
+
+ err = -ENOMEM;
+ file->f_vfsmnt = mntget(mapcache_mnt);
+ file->f_dentry = get_mapcache_dentry();
+ if (IS_ERR(file->f_dentry))
+ goto out_mntput;
+
+ buffer = new_mapcache_file_buffer(mapcache);
+ if (!buffer)
+ goto out_dput;
+
+ /* We need to hold this sem to ensure that we are serialized with all
+ * other readers of the rbtree */
+ file->private_data = buffer;
+ file->f_op = &mapcache_file_ops;
+ file->f_mode = FMODE_WRITE;
+ file->f_flags = O_WRONLY;
+ file->f_pos = 0;
+
+ fd_install(fd, file);
+
+ return fd;
+
+out_dput:
+ dput(file->f_dentry);
+out_mntput:
+ mntput(file->f_vfsmnt);
+out_putfilp:
+ put_filp(file);
+out:
+ module_put(THIS_MODULE);
+ return err;
+
+}
+
+static struct mapcache_update *new_update(void)
+{
+ struct mapcache_update *update;
+
+ update = kmalloc(sizeof(*update), GFP_KERNEL);
+ if (!update)
+ return NULL;
+ atomic_set(&update->count, 1);
+ init_completion(&update->done);
+ return update;
+}
+
+/* called with mapcache->lock held */
+static void start_update(struct mapcache *mapcache, struct mapcache_update
+ *update)
+{
+ BUG_ON(mapcache->update);
+
+ mapcache->update = update;
+}
+
+/* called with mapcache->lock held */
+static void finish_update(struct mapcache *mapcache)
+{
+ struct mapcache_update *update = mapcache->update;
+ BUG_ON(!mapcache->update);
+ mapcache->update = NULL;
+ complete_all(&update->done);
+}
+
+/* called with mapcache->lock held */
+static struct mapcache_update *get_update(struct mapcache *mapcache)
+{
+ BUG_ON(!mapcache->update);
+ atomic_inc(&mapcache->update->count);
+ return mapcache->update;
+}
+
+/* FIXME: what about signals? */
+static void wait_for_update(struct mapcache_update *update)
+{
+ wait_for_completion(&update->done);
+}
+
+static void put_update(struct mapcache_update *update)
+{
+ might_sleep();
+ if (atomic_dec_and_test(&update->count)) {
+ kfree(update);
+ }
+}
+
+int __init mapcache_setup(void)
+{
+ int err;
+ err = register_filesystem(&mapcache_fs_type);
+ if (err)
+ return err;
+ mapcache_mnt = kern_mount(&mapcache_fs_type);
+ if (!mapcache_mnt)
+ return PTR_ERR(mapcache_mnt);
+ return 0;
+}
+
+void __exit mapcache_shutdown(void)
+{
+ mntput(mapcache_mnt);
+ unregister_filesystem(&mapcache_fs_type);
+}
+
+struct mapcache_refresh_info {
+ struct autofs_sb_info *sbi;
+ const char *mapname;
+};
+
+#define do_envp(index, name, value) \
+ count = snprintf(p, left, (name), (value)); \
+ if (count < 0) \
+ return -ENOMEM; \
+ envp[(index)] = p; \
+ p += count + 1; \
+ left -= count + 1;
+static int mapcache_refresh_cb(void *_info)
+{
+ struct mapcache_refresh_info *info = _info;
+ struct autofs_sb_info *sbi = info->sbi;
+ struct mapcache *mapcache = sbi->mapcache;
+ char *argv[] = { AGENT_PATH, "list", NULL };
+ char *envp[5];
+ char buf[100], *p = buf; /* FIXME: hard limit */
+ int left = 99;
+ int fd;
+ int count = 0;
+
+
+ fd = open_mapcache_file(mapcache);
+ if (fd < 0)
+ return fd;
+
+ /* FIXME: cleanup on failure */
+ do_envp(0, "MAPNAME=%s", info->mapname);
+ do_envp(1, "WRITEFD=%d", fd);
+ envp[2] = "HOME=/";
+ envp[3] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+ envp[4] = NULL;
+
+ return call_usermodehelper_execve(AGENT_PATH, argv, envp);
+}
+
+/* Try to update the mapcache. On error, we clear the cache */
+static int mapcache_refresh(struct super_block *s, const char *mapname)
+{
+ struct autofs_sb_info *sbi = autofs_sbi(s);
+ struct mapcache_refresh_info info;
+ int ret;
+
+ info.sbi = sbi;
+ info.mapname = mapname;
+
+ /*
+ * We can safely pass info from our stack because we are waiting
+ * for the usermode helper to return.
+ */
+ ret = call_usermodehelper_cb(mapcache_refresh_cb, &info, 1);
+ if (ret) {
+ printk("autofs mapcache: call_usermodehelper_cb errored out"
+ " with ret = %d\n", ret);
+ }
+ return ret;
+}
+
+int mapcache_init(struct super_block *s)
+{
+ struct mapcache *mapcache;
+ struct autofs_sb_info *sbi = autofs_sbi(s);
+
+ mapcache = kmalloc(sizeof(*mapcache), GFP_KERNEL);
+ if (!mapcache)
+ return -ENOMEM;
+
+ mapcache->state = MC_REFRESH;
+ mapcache->tree = NULL;
+ mapcache->oldtree = NULL;
+ mapcache->update = NULL;
+ spin_lock_init(&mapcache->lock);
+
+ sbi->mapcache = mapcache;
+
+ return 0;
+}
+
+struct mapcache_tree *get_snapshot(struct super_block *s, const char *mapname)
+{
+ struct autofs_sb_info *sbi = autofs_sbi(s);
+ struct mapcache *mapcache = sbi->mapcache;
+ struct mapcache_update *update, *wait_update;
+ struct mapcache_tree *tree;
+ int err;
+
+ update = new_update();
+ if (!update)
+ return NULL;
+
+ spin_lock(&mapcache->lock);
+again:
+ switch (mapcache->state) {
+ case MC_REFRESH:
+ mapcache->state = MC_UPDATING;
+ start_update(mapcache, update);
+ spin_unlock(&mapcache->lock);
+
+ BUG_ON(mapcache->oldtree != NULL);
+
+ /* store a pointer to the old tree */
+ mapcache->oldtree = mapcache->tree;
+ mapcache->tree = new_tree();
+ if (!mapcache->tree) {
+ /* bail out, try again later.. */
+ spin_lock(&mapcache->lock);
+ finish_update(mapcache);
+ mapcache->state = MC_REFRESH;
+ mapcache->tree = mapcache->oldtree;
+ if (mapcache->tree)
+ get_tree(mapcache->tree);
+ spin_unlock(&mapcache->lock);
+
+ put_update(update);
+
+ /* for now, log an error and return the old
+ * tree if possible */
+ return mapcache->tree;
+ }
+
+ mapcache->hits = 0;
+ err = mapcache_refresh(s, mapname);
+ if (err != 0) {
+ /* get rid of the new defunct tree */
+ put_tree(mapcache->tree);
+ spin_lock(&mapcache->lock);
+ /* restore old tree */
+ mapcache->tree = mapcache->oldtree;
+ mapcache->oldtree = NULL;
+ mapcache->state = MC_REFRESH;
+ if (mapcache->tree)
+ get_tree(mapcache->tree);
+ finish_update(mapcache);
+ spin_unlock(&mapcache->lock);
+
+ put_update(update);
+
+ /* again, log an error and return the old tree
+ * if possible */
+ return mapcache->tree;
+ }
+
+ /* check to see if the trees are identical */
+ if (mapcache->oldtree
+ && mapcache->oldtree->nentries ==
+ mapcache->tree->nentries
+ && mapcache->hits == mapcache->tree->nentries) {
+ /* the trees are the same. no need to update */
+ put_tree(mapcache->tree);
+ mapcache->tree = mapcache->oldtree;
+ mapcache->oldtree = NULL;
+ } else {
+
+ /*
+ * free up the old tree we aren't
+ * using anymore
+ */
+ put_tree(mapcache->oldtree);
+ mapcache->oldtree = NULL;
+ }
+
+ spin_lock(&mapcache->lock);
+
+ finish_update(mapcache);
+ mapcache->lastupdate = jiffies;
+ mapcache->state = MC_OK;
+ /* fall through */
+ case MC_OK:
+ if (time_after(jiffies, mapcache->lastupdate + TIMEOUT)) {
+ mapcache->state = MC_REFRESH;
+ goto again;
+ }
+ tree = get_tree(mapcache->tree);
+ spin_unlock(&mapcache->lock);
+
+ /* we allocated this unconditionally */
+ put_update(update);
+ return tree;
+ case MC_UPDATING:
+ wait_update = get_update(mapcache);
+ spin_unlock(&mapcache->lock);
+ wait_for_update(wait_update);
+ put_update(wait_update);
+ spin_lock(&mapcache->lock);
+ goto again;
+ default:
+ BUG();
+ }
+ BUG();
+ return NULL;
+}
+
+void put_snapshot(struct mapcache_tree *tree)
+{
+ put_tree(tree);
+}
+
+struct mapcache_treenode *snapshot_first(struct mapcache_tree *tree)
+{
+ struct rb_node *node;
+ node = rb_first(&tree->root);
+ if (!node)
+ return NULL;
+ return rb_entry(node, struct mapcache_treenode, node);
+}
+
+struct mapcache_treenode *snapshot_next(struct mapcache_treenode *node)
+{
+ struct rb_node *nextnode;
+ nextnode = rb_next(&node->node);
+ if (!nextnode)
+ return NULL;
+ return rb_entry(nextnode, struct mapcache_treenode, node);
+}
+
+int snapshot_exists(struct mapcache_tree *tree, const char *name)
+{
+ unsigned hash = entry_hash(name);
+ return find_entry(tree, name, hash) ? 1 : 0;
+}
+
+void mapcache_destroy(struct super_block *s)
+{
+ struct autofs_sb_info *sbi = autofs_sbi(s);
+
+ if (!sbi->mapcache)
+ return;
+ kfree(sbi->mapcache);
+ sbi->mapcache = NULL;
+}
Index: linux-2.6.9-quilt/fs/autofsng/cachetree.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.9-quilt/fs/autofsng/cachetree.c 2004-10-22 17:17:48.988016832 -0400
@@ -0,0 +1,206 @@
+#include "autofs.h"
+
+static int __node_is_left(const char *namea, unsigned hasha,
+ const char *nameb, unsigned hashb)
+{
+ if (hasha < hashb)
+ return 1;
+ if (hasha > hashb)
+ return 0;
+ return strcmp(namea, nameb);
+}
+
+static int __node_is_right(const char *namea, unsigned hasha,
+ const char *nameb, unsigned hashb)
+{
+ return __node_is_left(nameb, hashb, namea, hasha);
+}
+
+static int node_is_left(struct mapcache_treenode *a,
+ struct mapcache_treenode *b)
+{
+ return __node_is_left(a->entry->name, a->entry->hash,
+ b->entry->name, b->entry->hash);
+}
+
+static int node_is_right(struct mapcache_treenode *a,
+ struct mapcache_treenode *b)
+{
+ return node_is_left(b, a);
+}
+
+struct mapcache_entry *find_entry(struct mapcache_tree *tree, const char *name,
+ unsigned hash)
+{
+ struct rb_node *n = tree->root.rb_node;
+ struct mapcache_treenode *node;
+
+ while (n) {
+ node = rb_entry(n, struct mapcache_treenode, node);
+
+ if (__node_is_left(name, hash, node->entry->name,
+ node->entry->hash))
+ n = n->rb_left;
+ else if (__node_is_right(name, hash, node->entry->name,
+ node->entry->hash))
+ n = n->rb_right;
+ else
+ return node->entry;
+ }
+ return NULL;
+}
+
+/* Make a new entry given the name and hash value. Recycle a value from the
+ * oldtree if available (reference required) */
+struct mapcache_entry *new_entry(const char *name, unsigned hash,
+ struct mapcache_tree *oldtree)
+{
+ struct mapcache_entry *entry;
+ int len = strlen(name) + 1;
+
+ if (oldtree) {
+ entry = find_entry(oldtree, name, hash);
+ if (entry) {
+ atomic_inc(&entry->count);
+ return entry;
+ }
+ }
+
+ entry = kmalloc(sizeof(*entry) + len, GFP_KERNEL);
+ if (entry) {
+ atomic_set(&entry->count, 1);
+ memcpy(entry->name, name, len);
+ entry->hash = hash;
+ }
+ return entry;
+}
+
+void put_entry(struct mapcache_entry *entry)
+{
+ if (atomic_dec_and_test(&entry->count)) {
+ kfree(entry);
+ }
+}
+
+static struct mapcache_treenode *new_node(void)
+{
+ struct mapcache_treenode *node;
+ node = kmalloc(sizeof(*node), GFP_KERNEL);
+ return node;
+}
+
+static void delete_node(struct mapcache_treenode *node)
+{
+ BUG_ON(!node);
+ put_entry(node->entry);
+ kfree(node);
+}
+
+static struct mapcache_treenode *__add_node_to_tree(
+ struct mapcache_treenode *node, struct mapcache_tree *tree)
+{
+ struct rb_node **p = &tree->root.rb_node;
+ struct rb_node *parent = NULL;
+ struct mapcache_treenode *curnode;
+
+ while (*p) {
+ parent = *p;
+ curnode = rb_entry(parent, struct mapcache_treenode, node);
+
+ if (node_is_left(node, curnode))
+ p = &(*p)->rb_left;
+ else if (node_is_right(node, curnode))
+ p = &(*p)->rb_right;
+ else
+ return curnode;
+ }
+
+ rb_link_node(&node->node, parent, p);
+ return NULL;
+}
+
+/* add a node to the tree, free it if it's a dup */
+static int add_node_to_tree(
+ struct mapcache_treenode *node, struct mapcache_tree *tree)
+{
+ if (__add_node_to_tree(node, tree) != 0) {
+ /* oops, found a duplicate */
+ delete_node(node);
+ return 1;
+ }
+ tree->nentries++;
+ rb_insert_color(&node->node, &tree->root);
+ return 0;
+}
+
+/*
+ * Add the given entry to tree. Consumes entry reference.
+ * Returns 0 on success. Returns 1 on duplicate. -ENOMEM on error.
+ */
+int add_entry_to_tree(struct mapcache_entry *entry, struct mapcache_tree *tree)
+{
+ struct mapcache_treenode *node;
+
+ node = new_node();
+ if (!node)
+ return -ENOMEM;
+
+ node->entry = entry;
+
+ return add_node_to_tree(node, tree);
+}
+
+struct mapcache_tree *new_tree(void)
+{
+ struct mapcache_tree *tree;
+
+ tree = kmalloc(sizeof(*tree), GFP_KERNEL);
+ if (tree) {
+ atomic_set(&tree->count, 1);
+ tree->root = RB_ROOT;
+ tree->nentries = 0;
+ }
+ return tree;
+}
+
+static void release_tree(struct mapcache_tree *tree)
+{
+ struct rb_node **root = &tree->root.rb_node;
+
+ while (*root != NULL) {
+ struct mapcache_treenode *node = rb_entry(*root,
+ struct mapcache_treenode, node);
+ rb_erase(&node->node, &tree->root);
+ delete_node(node);
+ }
+}
+
+/* release a tree reference */
+void put_tree(struct mapcache_tree *tree)
+{
+ if (!tree)
+ return;
+ if (atomic_dec_and_test(&tree->count)) {
+ release_tree(tree);
+ }
+}
+
+/* grab a tree reference, called with mapcache locked */
+struct mapcache_tree *get_tree(struct mapcache_tree *tree)
+{
+ if (!tree)
+ BUG();
+ atomic_inc(&tree->count);
+ return tree;
+}
+
+unsigned int entry_hash(const char *name)
+{
+ const unsigned int hash_mult = 2654435387U;
+ unsigned int h = 0;
+
+ while (*name)
+ h = (h + (unsigned int) *name++) * hash_mult;
+
+ return h;
+}
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 15/28] VFS: Mountpoint file descriptor umount support
2004-10-25 14:46 ` [PATCH 15/28] VFS: Mountpoint file descriptor umount support Mike Waychison
2004-10-25 14:46 ` [PATCH 16/28] VFS: Mountpoint file descriptor attach support Mike Waychison
@ 2004-10-26 10:28 ` Christoph Hellwig
2004-10-26 14:16 ` Mike Waychison
1 sibling, 1 reply; 21+ messages in thread
From: Christoph Hellwig @ 2004-10-26 10:28 UTC (permalink / raw)
To: Mike Waychison; +Cc: linux-kernel, linux-fsdevel, raven
On Mon, Oct 25, 2004 at 10:46:09AM -0400, Mike Waychison wrote:
> This patch adds functionality to mountfd so that a user can perform the
> various types of umount (forced umount, not-busy umount, lazy-umount).
>
> Signed-off-by: Mike Waychison <michael.waychison@sun.com>
> ---
>
> fs/mountfd.c | 20 ++++++++++++++++++++
> fs/namespace.c | 2 +-
> include/linux/fs.h | 5 ++++-
> 3 files changed, 25 insertions(+), 2 deletions(-)
>
> Index: linux-2.6.9-quilt/fs/mountfd.c
> ===================================================================
> --- linux-2.6.9-quilt.orig/fs/mountfd.c 2004-10-22 17:17:40.736271288 -0400
> +++ linux-2.6.9-quilt/fs/mountfd.c 2004-10-22 17:17:41.367175376 -0400
> @@ -11,6 +11,8 @@
>
> #define VFSMOUNT(filp) ((struct vfsmount *)((filp)->private_data))
>
> +extern int do_umount(struct vfsmount *mnt, int flags);
> +
> static struct vfsmount *mfdfs_mnt;
>
> static void mfdfs_read_inode(struct inode *inode);
> @@ -72,6 +74,18 @@ static int mfd_release(struct inode *ino
> return 0;
> }
>
> +static long mfd_umount(struct file *mountfilp, int flags)
> +{
> + struct vfsmount *mnt;
> + int error;
> +
> + mnt = mntget(VFSMOUNT(mountfilp));
> +
> + error = do_umount(mnt, flags);
> +
> + return error;
> +}
> +
> static int mfd_ioctl(struct inode *inode, struct file *filp,
> unsigned int cmd, unsigned long arg);
> static struct file_operations mfd_file_ops = {
> @@ -243,6 +257,12 @@ static int mfd_ioctl(struct inode *inode
> switch (cmd) {
> case MOUNTFD_IOC_GETDIRFD:
> return mfd_getdirfd(filp);
> + case MOUNTFD_IOC_DETACH:
> + return mfd_umount(filp, MNT_DETACH);
> + case MOUNTFD_IOC_UNMOUNT:
> + return mfd_umount(filp, 0);
> + case MOUNTFD_IOC_FORCEDUNMOUNT:
> + return mfd_umount(filp, MNT_FORCE);
Urgg, you don't want to add gazillions of strange ioctls, do you?
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 15/28] VFS: Mountpoint file descriptor umount support
2004-10-26 10:28 ` [PATCH 15/28] VFS: Mountpoint file descriptor umount support Christoph Hellwig
@ 2004-10-26 14:16 ` Mike Waychison
0 siblings, 0 replies; 21+ messages in thread
From: Mike Waychison @ 2004-10-26 14:16 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: linux-kernel, linux-fsdevel, raven
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Christoph Hellwig wrote:
> On Mon, Oct 25, 2004 at 10:46:09AM -0400, Mike Waychison wrote:
>
>>This patch adds functionality to mountfd so that a user can perform the
>>various types of umount (forced umount, not-busy umount, lazy-umount).
>>
>>Signed-off-by: Mike Waychison <michael.waychison@sun.com>
>>---
>>
>> fs/mountfd.c | 20 ++++++++++++++++++++
>> fs/namespace.c | 2 +-
>> include/linux/fs.h | 5 ++++-
>> 3 files changed, 25 insertions(+), 2 deletions(-)
>>
>>Index: linux-2.6.9-quilt/fs/mountfd.c
>>===================================================================
>>--- linux-2.6.9-quilt.orig/fs/mountfd.c 2004-10-22 17:17:40.736271288 -0400
>>+++ linux-2.6.9-quilt/fs/mountfd.c 2004-10-22 17:17:41.367175376 -0400
>>@@ -11,6 +11,8 @@
>>
>> #define VFSMOUNT(filp) ((struct vfsmount *)((filp)->private_data))
>>
>>+extern int do_umount(struct vfsmount *mnt, int flags);
>>+
>> static struct vfsmount *mfdfs_mnt;
>>
>> static void mfdfs_read_inode(struct inode *inode);
>>@@ -72,6 +74,18 @@ static int mfd_release(struct inode *ino
>> return 0;
>> }
>>
>>+static long mfd_umount(struct file *mountfilp, int flags)
>>+{
>>+ struct vfsmount *mnt;
>>+ int error;
>>+
>>+ mnt = mntget(VFSMOUNT(mountfilp));
>>+
>>+ error = do_umount(mnt, flags);
>>+
>>+ return error;
>>+}
>>+
>> static int mfd_ioctl(struct inode *inode, struct file *filp,
>> unsigned int cmd, unsigned long arg);
>> static struct file_operations mfd_file_ops = {
>>@@ -243,6 +257,12 @@ static int mfd_ioctl(struct inode *inode
>> switch (cmd) {
>> case MOUNTFD_IOC_GETDIRFD:
>> return mfd_getdirfd(filp);
>>+ case MOUNTFD_IOC_DETACH:
>>+ return mfd_umount(filp, MNT_DETACH);
>>+ case MOUNTFD_IOC_UNMOUNT:
>>+ return mfd_umount(filp, 0);
>>+ case MOUNTFD_IOC_FORCEDUNMOUNT:
>>+ return mfd_umount(filp, MNT_FORCE);
>
>
> Urgg, you don't want to add gazillions of strange ioctls, do you?
>
Only a couple million ;)
I have toyed with different interfaces. I have older patches that would
allow you to read/write on the fd to perform ops, but the code is a mess
of parsing/data checks. I also toyed with a multiplexed syscall, but
realized real quick that it was an ioctl with a different name, that
only worked on mountfds.
ioctl ended up being the cleanest solution (I came up with) in the end.
Alternatives?
- --
Mike Waychison
Sun Microsystems, Inc.
1 (650) 352-5299 voice
1 (416) 202-8336 voice
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
NOTICE: The opinions expressed in this email are held by me,
and may not represent the views of Sun Microsystems, Inc.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.5 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org
iD8DBQFBflxTdQs4kOxk3/MRAq0NAJ9leUcfelicGndvtqGXqGgMlNoREACfXmXe
XsmXEDdefmJi7L8XmuKrQSk=
=xWa5
-----END PGP SIGNATURE-----
^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2004-10-26 14:17 UTC | newest]
Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <10987155332448@sun.com>
2004-10-25 14:46 ` [PATCH 15/28] VFS: Mountpoint file descriptor umount support Mike Waychison
2004-10-25 14:46 ` [PATCH 16/28] VFS: Mountpoint file descriptor attach support Mike Waychison
2004-10-25 14:47 ` [PATCH 17/28] VFS: Mountpoint file descriptor walking Mike Waychison
2004-10-25 14:47 ` [PATCH 18/28] VFS: Mountpoint file descriptor read properties Mike Waychison
2004-10-25 14:48 ` [PATCH 19/28] VFS: Mountpoint file descriptor expiry support Mike Waychison
2004-10-25 14:48 ` [PATCH 20/28] HOTPLUG: call_usermodehelper callback support Mike Waychison
2004-10-25 14:49 ` [PATCH 21/28] HOTPLUG: Hack to allow for call to execve Mike Waychison
2004-10-25 14:49 ` [PATCH 22/28] VFS: Export put_namespace Mike Waychison
2004-10-25 14:50 ` [PATCH 23/28] VFS: Export get_sb_pseudo Mike Waychison
2004-10-25 14:50 ` [PATCH 24/28] VFS: Fixup for ->follow_link on root of filesystem Mike Waychison
2004-10-25 14:51 ` [PATCH 25/28] VFS: statfs(64) shouldn't follow last component symlink Mike Waychison
2004-10-25 14:51 ` [PATCH 26/28] VFS: Introduce MNT_NOFOLLOW Mike Waychison
2004-10-25 14:52 ` [PATCH 27/28] Testing syscall for expiry Mike Waychison
2004-10-25 15:01 ` Christoph Hellwig
2004-10-25 15:37 ` [PATCH 28/28] AUTOFSNG: New autofs filesystem (resend) Mike Waychison
2004-10-25 15:14 ` [PATCH 25/28] VFS: statfs(64) shouldn't follow last component symlink Christoph Hellwig
2004-10-25 15:21 ` Mike Waychison
2004-10-25 15:18 ` [PATCH 20/28] HOTPLUG: call_usermodehelper callback support Christoph Hellwig
2004-10-25 15:29 ` Mike Waychison
2004-10-26 10:28 ` [PATCH 15/28] VFS: Mountpoint file descriptor umount support Christoph Hellwig
2004-10-26 14:16 ` Mike Waychison
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).