[autofs] [PATCH] autofs4: Use no_printk() for no-op DPRINTK() and use __VA_ARGS__ too

2011-08-08 Thread David Howells
Use no_printk() for autofs's no-op DPRINTK() to prevent unused statements from
becoming accidentally obsolete, and use __VA_ARGS__ too as that's the standard
way.

Signed-off-by: David Howells dhowe...@redhat.com
Signed-off-by: Ian Kent ra...@themaw.net
---

 fs/autofs4/autofs_i.h |   10 +++---
 fs/autofs4/waitq.c|3 ++-
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index 475f9c5..c3a419f 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -40,13 +40,17 @@
 /* #define DEBUG */
 
 #ifdef DEBUG
-#define DPRINTK(fmt, args...)  \
+#define DPRINTK(fmt, ...)  \
 do {   \
printk(KERN_DEBUG pid %d: %s:  fmt \n,  \
-   current-pid, __func__, ##args);\
+   current-pid, __func__, ##__VA_ARGS__); \
 } while (0)
 #else
-#define DPRINTK(fmt, args...) do {} while (0)
+#define DPRINTK(fmt, ...)  \
+do {   \
+   no_printk(KERN_DEBUG pid %d: %s:  fmt \n,   \
+ current-pid, __func__, ##__VA_ARGS__);   \
+} while (0)
 #endif
 
 #define AUTOFS_WARN(fmt, args...)  \
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index 2543598..6313a0d 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -104,7 +104,8 @@ static void autofs4_notify_daemon(struct autofs_sb_info 
*sbi,
size_t pktsz;
 
DPRINTK(wait id = 0x%08lx, name = %.*s, type=%d,
-   wq-wait_queue_token, wq-name.len, wq-name.name, type);
+   (unsigned long)wq-wait_queue_token,
+   wq-name.len, wq-name.name, type);
 
memset(pkt,0,sizeof pkt); /* For security reasons */
 

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH] VFS: Fix automount for negative autofs dentries

2011-07-11 Thread David Howells
Autofs may set the DCACHE_NEED_AUTOMOUNT flag on negative dentries.  These
need attention from the automounter daemon regardless of the LOOKUP_FOLLOW flag.

Signed-off-by: David Howells dhowe...@redhat.com
Acked-by: Ian Kent ra...@themaw.net
---

 fs/namei.c |   27 +++
 1 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index 0223c41..93e221e 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -777,18 +777,29 @@ static int follow_automount(struct path *path, unsigned 
flags,
if ((flags  LOOKUP_NO_AUTOMOUNT)  !(flags  LOOKUP_CONTINUE))
return -EISDIR; /* we actually want to stop here */
 
-   /* We want to mount if someone is trying to open/create a file of any
-* type under the mountpoint, wants to traverse through the mountpoint
-* or wants to open the mounted directory.
-*
-* We don't want to mount if someone's just doing a stat and they've
+   /* We don't want to mount if someone's just doing a stat and they've
 * set AT_SYMLINK_NOFOLLOW - unless they're stat'ing a directory and
 * appended a '/' to the name.
 */
-   if (!(flags  LOOKUP_FOLLOW) 
-   !(flags  (LOOKUP_CONTINUE | LOOKUP_DIRECTORY |
-  LOOKUP_OPEN | LOOKUP_CREATE)))
+   if (!(flags  LOOKUP_FOLLOW)) {
+   /* We do, however, want to mount if someone wants to open or
+* create a file of any type under the mountpoint, wants to
+* traverse through the mountpoint or wants to open the mounted
+* directory.
+*/
+   if (flags  (LOOKUP_CONTINUE | LOOKUP_DIRECTORY |
+LOOKUP_OPEN | LOOKUP_CREATE))
+   goto need_automount;
+
+   /* Also, autofs may mark negative dentries as being automount
+* points.  These will need the attentions of the daemon to
+* instantiate them before they can be used.
+*/
+   if (!path-dentry-d_inode)
+   goto need_automount;
return -EISDIR;
+   }
+need_automount:
 
current-total_link_count++;
if (current-total_link_count = 40)

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


Re: [autofs] [PATCH] VFS: Fix automount for negative autofs dentries

2011-07-11 Thread David Howells
Christoph Hellwig h...@infradead.org wrote:

 would do the same.

But is much less obvious.  The LOOKUP_FOLLOW flag is the primary reason for
this statement.  The rest are subordinate and would be wholly irrelevant if
LOOKUP_FOLLOW was to be removed from the list.

David

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH] autofs4: Use no_printk() for no-op DPRINTK() and use __VA_ARGS__ too

2011-06-17 Thread David Howells
Use no_printk() for autofs's no-op DPRINTK() to prevent unused statements from
becoming accidentally obsolete, and use __VA_ARGS__ too as that's the standard
way.

Signed-off-by: David Howells dhowe...@redhat.com
---

 fs/autofs4/autofs_i.h |   10 +++---
 fs/autofs4/waitq.c|3 ++-
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index 475f9c5..c3a419f 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -40,13 +40,17 @@
 /* #define DEBUG */
 
 #ifdef DEBUG
-#define DPRINTK(fmt, args...)  \
+#define DPRINTK(fmt, ...)  \
 do {   \
printk(KERN_DEBUG pid %d: %s:  fmt \n,  \
-   current-pid, __func__, ##args);\
+   current-pid, __func__, ##__VA_ARGS__); \
 } while (0)
 #else
-#define DPRINTK(fmt, args...) do {} while (0)
+#define DPRINTK(fmt, ...)  \
+do {   \
+   no_printk(KERN_DEBUG pid %d: %s:  fmt \n,   \
+ current-pid, __func__, ##__VA_ARGS__);   \
+} while (0)
 #endif
 
 #define AUTOFS_WARN(fmt, args...)  \
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index 2543598..6313a0d 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -104,7 +104,8 @@ static void autofs4_notify_daemon(struct autofs_sb_info 
*sbi,
size_t pktsz;
 
DPRINTK(wait id = 0x%08lx, name = %.*s, type=%d,
-   wq-wait_queue_token, wq-name.len, wq-name.name, type);
+   (unsigned long)wq-wait_queue_token,
+   wq-name.len, wq-name.name, type);
 
memset(pkt,0,sizeof pkt); /* For security reasons */
 

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] Bug in autofs4_d_automount()?

2011-06-17 Thread David Howells

Hi Ian,

At the top of autofs4_d_automount() you have:

/* The daemon never triggers a mount. */
if (autofs4_oz_mode(sbi))
return NULL;

I think this should be returning -EISDIR.  If by some chance we do get here in
Oz mode, this will cause the kernel to just loop forever.  A return of NULL is
meant to indicate that you got a collision and that it should recheck the
mountpoint - but it does not advance path in follow_managed().

-EISDIR is the return to indicate this is to be treated as a normal directory.

David

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH] AUTOFS4: Fix the return from autofs4_d_automount() and simplify autofs4_d_manage()

2011-06-17 Thread David Howells
autofs4_d_automount() returns 0 if it detects that the calling process is in Oz
mode (ie. it's the autofs userspace daemon).  This return, however, is meant to
indicate to follow_automount() that the caller should retry the check on the
the current path point.  In the Oz mode case, this is a bad idea because
nothing has changed on the path, and follow_managed() will just repeat until
follow_automount() hits the total_link_count limit and returns -ELOOP.

What it should do is return -EISDIR to indicate to the callers that actually it
wants the daemon to see this directory as an ordinary directory.


Now, given that change outlined above, it is then unnecessary for
autofs4_d_manage() to return -EISDIR if the current path point is not a
mountpoint.  If it returns 0 instead, and the path point isn't a mountpoint,
then follow_managed() will skip the attempt to transit to the mounted
filesystem and proceed to call autofs4_d_automount(), which will return
-EISDIR.

Signed-off-by: David Howells dhowe...@redhat.com
---

 fs/autofs4/root.c |9 ++---
 1 files changed, 2 insertions(+), 7 deletions(-)

diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index f55ae23..a6dc11c 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -334,7 +334,7 @@ static struct vfsmount *autofs4_d_automount(struct path 
*path)
 
/* The daemon never triggers a mount. */
if (autofs4_oz_mode(sbi))
-   return NULL;
+   return ERR_PTR(-EISDIR);
 
/*
 * If an expire request is pending everyone must wait.
@@ -435,13 +435,8 @@ int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
dentry, dentry-d_name.len, dentry-d_name.name);
 
/* The daemon never waits. */
-   if (autofs4_oz_mode(sbi)) {
-   if (rcu_walk)
-   return 0;
-   if (!d_mountpoint(dentry))
-   return -EISDIR;
+   if (autofs4_oz_mode(sbi))
return 0;
-   }
 
/* We need to sleep, so we need pathwalk to be in ref-mode */
if (rcu_walk)

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


Re: [autofs] stat -L triggering mount (behavior change starting with 2.6.38-rc1)

2011-04-01 Thread David Howells

Hi Leonardo,

Could you send us a strace of ls -l on your autofs directory?

I think the problem is not lstat() calls, but rather getxattr() calls.

Thanks,
David

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


Re: [autofs] stat -L triggering mount (behavior change starting with 2.6.38-rc1)

2011-04-01 Thread David Howells
Leonardo Chiquitto leonardo.li...@gmail.com wrote:

 open(/data, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
 fcntl(3, F_GETFD)   = 0x1 (flags FD_CLOEXEC)
 getdents64(3, /* 3 entries */, 32768)   = 72
 lstat(/data/isos, {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
 lgetxattr(/data/isos, security.selinux, 0x62ad60, 255) = -1 EOPNOTSUPP 
 (Operation not supported)
 getxattr(/data/isos, system.posix_acl_access, 0x0, 0) = -1 EOPNOTSUPP 
 (Operation not supported)
 getdents64(3, /* 0 entries */, 32768)   = 0

Yeah, I suspect the getxattr() is the problem.  ls calls libacl to get the
Posix ACL of the target file, but that uses the getxattr() which asserts
LOOKUP_FOLLOW during the pathwalk, causing the automount unconditionally:-/

I'm discussing this with the coreutils and acl package maintainers to see if
we can fix it in userspace.

David

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH 2/3] Make VFS handle mount autoexpiry

2011-03-03 Thread David Howells
Make the VFS handle mount autoexpiry, rather than doing it in the filesystems
(such as AFS, CIFS and NFS).  This simplifies the reference counting, since
do_add_mount() once again adds mounts to the expiration list, and simplifies
the filesystems since they no longer have to do anything barring set
MNT_EXPIRABLE on an expirable mount before returning it.

Additionally, provide a tuning knob to set the periodicity of the reaper in
seconds:

/proc/sys/fs/mount-expiry-period

The default is 10 minutes.

The NFS sysctl (nfs_mountpoint_timeout) is removed in its favour.

Signed-off-by: David Howells dhowe...@redhat.com
---

 Documentation/filesystems/vfs.txt |7 +-
 fs/afs/internal.h |1 
 fs/afs/mntpt.c|   60 ++---
 fs/afs/super.c|1 
 fs/cifs/cifs_dfs_ref.c|   53 ++-
 fs/cifs/cifsfs.c  |3 -
 fs/cifs/cifsproto.h   |1 
 fs/namei.c|8 +--
 fs/namespace.c|  106 -
 fs/nfs/client.c   |1 
 fs/nfs/namespace.c|   26 -
 fs/nfs/sysctl.c   |7 --
 include/linux/mount.h |5 +-
 kernel/sysctl.c   |   11 
 14 files changed, 76 insertions(+), 214 deletions(-)

diff --git a/Documentation/filesystems/vfs.txt 
b/Documentation/filesystems/vfs.txt
index c6878a0..3a40c31 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -943,10 +943,9 @@ struct dentry_operations {
ordinary directory and returned to pathwalk to continue walking.
 
If a vfsmount is returned, the caller will attempt to mount it on the
-   mountpoint and will remove the vfsmount from its expiration list in
-   the case of failure.  The vfsmount should be returned with 2 refs on
-   it to prevent automatic expiration - the caller will clean up the
-   additional ref.
+   mountpoint and will clean it up on failure.  If mnt_expiry_mark is set
+   on the vfsmount, the caller will add it to the global expiration list
+   if successfully mounted and clear the mark.
 
This function is only used if DCACHE_NEED_AUTOMOUNT is set on the
dentry.  This is set by __d_instantiate() if S_AUTOMOUNT is set on the
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 5a9b684..cb7d2c7 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -594,7 +594,6 @@ extern const struct file_operations 
afs_mntpt_file_operations;
 
 extern struct vfsmount *afs_d_automount(struct path *);
 extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *);
-extern void afs_mntpt_kill_timer(void);
 
 /*
  * proc.c
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index aa59184..74b43b9 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -24,7 +24,6 @@ static struct dentry *afs_mntpt_lookup(struct inode *dir,
   struct dentry *dentry,
   struct nameidata *nd);
 static int afs_mntpt_open(struct inode *inode, struct file *file);
-static void afs_mntpt_expiry_timed_out(struct work_struct *work);
 
 const struct file_operations afs_mntpt_file_operations = {
.open   = afs_mntpt_open,
@@ -41,11 +40,6 @@ const struct inode_operations afs_autocell_inode_operations 
= {
.getattr= afs_getattr,
 };
 
-static LIST_HEAD(afs_vfsmounts);
-static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, 
afs_mntpt_expiry_timed_out);
-
-static unsigned long afs_mntpt_expiry_timeout = 10 * 60;
-
 /*
  * check a symbolic link to see whether it actually encodes a mountpoint
  * - sets the AFS_VNODE_MOUNTPOINT flag on the vnode appropriately
@@ -136,11 +130,12 @@ static int afs_mntpt_open(struct inode *inode, struct 
file *file)
 /*
  * create a vfsmount to be automounted
  */
-static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
+struct vfsmount *afs_d_automount(struct path *mountpoint)
 {
struct afs_super_info *super;
struct vfsmount *mnt;
struct afs_vnode *vnode;
+   struct dentry *mntpt = mountpoint-dentry;
struct page *page;
char *devname, *options;
bool rwpath = false;
@@ -219,6 +214,9 @@ static struct vfsmount *afs_mntpt_do_automount(struct 
dentry *mntpt)
mnt = vfs_kern_mount(afs_fs_type, 0, devname, options);
_debug(--- mount result %p ---, mnt);
 
+   if (!IS_ERR(mnt))
+   mnt-mnt_expiry_mark = 1;
+
free_page((unsigned long) devname);
free_page((unsigned long) options);
_leave( = %p, mnt);
@@ -234,51 +232,3 @@ error_no_devname:
_leave( = %d, ret);
return ERR_PTR(ret);
 }
-
-/*
- * handle an automount point
- */
-struct vfsmount *afs_d_automount(struct path *path)
-{
-   struct vfsmount *newmnt;
-
-   _enter({%s,%s}, path-mnt-mnt_devname, path-dentry

[autofs] [PATCH] autofs4: Use no_printk() for no-op DPRINTK() and use __VA_ARGS__ too

2011-01-18 Thread David Howells
Use no_printk() for autofs's no-op DPRINTK() to prevent unused statements from
becoming accidentally obsolete, and use __VA_ARGS__ too as that's the standard
way.

Signed-off-by: David Howells dhowe...@redhat.com
---

 fs/autofs4/autofs_i.h |   10 +++---
 fs/autofs4/waitq.c|3 ++-
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index 54f9237..ef89828 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -40,13 +40,17 @@
 /* #define DEBUG */
 
 #ifdef DEBUG
-#define DPRINTK(fmt, args...)  \
+#define DPRINTK(fmt, ...)  \
 do {   \
printk(KERN_DEBUG pid %d: %s:  fmt \n,  \
-   current-pid, __func__, ##args);\
+   current-pid, __func__, ##__VA_ARGS__); \
 } while (0)
 #else
-#define DPRINTK(fmt, args...) do {} while (0)
+#define DPRINTK(fmt, ...)  \
+do {   \
+   no_printk(KERN_DEBUG pid %d: %s:  fmt \n,   \
+ current-pid, __func__, ##__VA_ARGS__);   \
+} while (0)
 #endif
 
 #define AUTOFS_WARN(fmt, args...)  \
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index 5601005..4d169cf 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -104,7 +104,8 @@ static void autofs4_notify_daemon(struct autofs_sb_info 
*sbi,
size_t pktsz;
 
DPRINTK(wait id = 0x%08lx, name = %.*s, type=%d,
-   wq-wait_queue_token, wq-name.len, wq-name.name, type);
+   (unsigned long)wq-wait_queue_token,
+   wq-name.len, wq-name.name, type);
 
memset(pkt,0,sizeof pkt); /* For security reasons */
 

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


Re: [autofs] [PATCH 01/18] Add a dentry op to handle automounting rather than abusing follow_link() [ver #4]

2011-01-16 Thread David Howells
Al Viro v...@zeniv.linux.org.uk wrote:

 OK, umount_tree bug (the source of AFS leak) got presumably fixed in
 #untested.  Have fun...

Works for me.

Acked-by: David Howells dhowe...@redhat.com

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH] autofs4: Merge the remaining dentry ops tables

2011-01-15 Thread David Howells
Merge the remaining autofs4 dentry ops tables.  It doesn't matter if
d_automount and d_manage are present on something that's not mountable or
holdable as these ops are only used if the appropriate flags are set in
dentry-d_flags.

Signed-off-by: David Howells dhowe...@redhat.com
---

 fs/autofs4/autofs_i.h |1 -
 fs/autofs4/inode.c|4 +---
 fs/autofs4/root.c |   13 ++---
 3 files changed, 3 insertions(+), 15 deletions(-)

diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index c28085c..1f016bf 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -207,7 +207,6 @@ extern const struct inode_operations 
autofs4_dir_inode_operations;
 extern const struct file_operations autofs4_dir_operations;
 extern const struct file_operations autofs4_root_operations;
 extern const struct dentry_operations autofs4_dentry_operations;
-extern const struct dentry_operations autofs4_mount_dentry_operations;
 
 /* VFS automount flags management functions */
 
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 3ecd2e2..2e80cf0 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -304,10 +304,8 @@ int autofs4_fill_super(struct super_block *s, void *data, 
int silent)
goto fail_dput;
}
 
-   if (autofs_type_trigger(sbi-type)) {
-   d_set_d_op(root, autofs4_mount_dentry_operations);
+   if (autofs_type_trigger(sbi-type))
__managed_dentry_set_managed(root);
-   }
 
root_inode-i_fop = autofs4_root_operations;
root_inode-i_op = autofs4_dir_inode_operations;
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index dbd9551..0db9d53 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -66,13 +66,7 @@ const struct inode_operations autofs4_dir_inode_operations = 
{
.rmdir  = autofs4_dir_rmdir,
 };
 
-/* For dentries that don't initiate mounting */
 const struct dentry_operations autofs4_dentry_operations = {
-   .d_release  = autofs4_dentry_release,
-};
-
-/* For dentries that do initiate mounting */
-const struct dentry_operations autofs4_mount_dentry_operations = {
.d_automount= autofs4_d_automount,
.d_manage   = autofs4_d_manage,
.d_release  = autofs4_dentry_release,
@@ -512,10 +506,8 @@ static struct dentry *autofs4_lookup(struct inode *dir, 
struct dentry *dentry, s
return ERR_PTR(-ENOENT);
 
/* Mark entries in the root as mount triggers */
-   if (autofs_type_indirect(sbi-type)  
IS_ROOT(dentry-d_parent)) {
-   d_set_d_op(dentry, autofs4_mount_dentry_operations);
+   if (autofs_type_indirect(sbi-type)  
IS_ROOT(dentry-d_parent))
__managed_dentry_set_managed(dentry);
-   }
 
ino = autofs4_init_ino(NULL, sbi, 0555);
if (!ino)
@@ -848,8 +840,7 @@ static inline int autofs4_ask_umount(struct vfsmount *mnt, 
int __user *p)
 int is_autofs4_dentry(struct dentry *dentry)
 {
return dentry  dentry-d_inode 
-   (dentry-d_op == autofs4_mount_dentry_operations ||
-dentry-d_op == autofs4_dentry_operations) 
+   dentry-d_op == autofs4_dentry_operations 
dentry-d_fsdata != NULL;
 }
 

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] autofs4_d_automount() can change path-dentry param

2011-01-15 Thread David Howells

Hi Ian,

I've just noticed that autofs4_d_automount() can change the dentry pointer in
the path parameter (via autofs4_mountpoint_changed()).  Is this just doing a
straight substitution of one dentry for its equivalent?  I don't think it'll
be a problem for follow_automount() and follow_managed(), provided the dentry
stays in the same namespace - but if we eliminate the vfsmount pointer and
just pass the dentry pointer in to d_automount(), you won't be able to do this
anymore.  Would it work to simply return NULL here and hope the recheck picks
up the substitution?

David

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


Re: [autofs] [PATCH 01/18] Add a dentry op to handle automounting rather than abusing follow_link()

2011-01-14 Thread David Howells
Nick Piggin npig...@gmail.com wrote:

 You still have to notice that it is .d_automount in rcu-walk mode, and bail
 out if it is. I can't see where you do that.

follow_managed(), and thus follow_automount() and -d_automount(), are never
reached in rcu_walk mode, from what I can tell of the code.

There are two places follow_managed() is called:

 (1) do_lookup() - where follow_managed() is only called in the else-part of
 an if-statement contingent on a check of LOOKUP_RCU.

 (2) do_last() - where follow_managed() is subsequent to a mutex having been
 taken, so rcu-walk mode must have been exited prior to this as the
 process may have needed to sleep.

At least, I'm assuming you may not sleep whilst in rcu-walk mode.

David

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


Re: [autofs] [PATCH 00/18] Introduce automount support in the VFS [ver #4]

2011-01-14 Thread David Howells
Al Viro v...@zeniv.linux.org.uk wrote:

  As the result, we stop abusing do_add_mount() in there.  Moreover, with
  pending mnt_devname nfs rework we will be able to get rid of passing
  vfsmount to -d_automount(), AFAICT, which would be nice...
 
 BTW, what do you need vfsmount for in case of the only -d_manage() instance
 you've got?

I'm not sure it's strictly necessary.  However, is it or will it be possible
for autofs to have per-namespace daemons?  I suspect I can probably downgrade
the path pointer to a dentry pointer.  It can always be upgraded later if we
find a need for it...

David

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


Re: [autofs] [PATCH 00/18] Introduce automount support in the VFS [ver #4]

2011-01-14 Thread David Howells
Al Viro v...@zeniv.linux.org.uk wrote:

   d_op-d_automount() may return one of:
  
   (a) The vfsmount mounted upon that dentry, in which case pathwalk will
   move to the root dentry of that vfsmount.  -d_automount() must
   have in some manner mounted this before returning.
  
   (b) NULL if something was already mounted there, in which case
   pathwalk will loop around and recheck the mountings.
 
 That makes very little sense as-is.  Look:
   * autofs4 never does (a)
   * everybody else could replace (a) with (b) just fine - we do (a)
 only when we'd just mounted new vfsmount on top of path.  So (b) would lead
 to follow_managed() looping over, finding DCACHE_MOUNTED and cheerfully
 transiting into the root of that vfsmount.

Indeed.  It's merely an optimisation and not strictly necessary.  I suppose
that, given the amount of time that's probably spent in performing the mount
part of the automount, repeating the check is negligible cost.

 Now, I'd like to have (a) and (b) distinct, but not in that fashion.  Namely,
 let's take do_add_mount() et.al. into follow_automount().

I presume that people aren't expected to do things like do_move_mount() here,
but might they want to do a bind mount?  Or do we just say if they want to do
something more exotic than do_add_mount(), they have to follow path (b)?

 Leave autofs4 as in your series; it'll be completely unaffected.  But switch
 all (b) in nfs/cifs/afs over to modified (a).  That is,
   * have vfsmount created as it's done in your series
   * grab extra reference and put it on chosen list.  That'd be done
 by helper in fs/namespace.c under namespace_sem.  Extra ref would make sure
 that nobody walking the list would decide that it's expirable.

It would be simpler, perhaps, to allow d_automount() to return the list also:

   struct vfsmount *(*d_automount)(struct path *mountpoint,
   struct list_head **expiry_list_to_use);

This pointer can then be passed directly to do_add_mount() and we don't have
to worry about having an extra reference or cleaning up the list on error.

   * schedule whatever expiry activity we currently do.
   * return vfsmount
 In follow_automount() we'd see that we have non-NULL and non-ERR_PTR.  Then
 we'd attempt do_add_mount(), without bothering to pass it expiry list.  And
 do the same checks for return value, etc. we currently do in the method
 instances; just remember that we have an extra vfsmount reference that will
 need to be dropped and that we'll need to take the sucker off the expiry list
 in case we decide we don't need it (again, namespace.c helper).
 
 As the result, we stop abusing do_add_mount() in there.  Moreover, with
 pending mnt_devname nfs rework we will be able to get rid of passing
 vfsmount to -d_automount(), AFAICT, which would be nice...

:-)

David

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


Re: [autofs] [PATCH 00/18] Introduce automount support in the VFS [ver #4]

2011-01-14 Thread David Howells
David Howells dhowe...@redhat.com wrote:

 It would be simpler, perhaps, to allow d_automount() to return the list also:
 
struct vfsmount *(*d_automount)(struct path *mountpoint,
  struct list_head **expiry_list_to_use);
 
 This pointer can then be passed directly to do_add_mount() and we don't have
 to worry about having an extra reference or cleaning up the list on error.

However, that isn't good enough as the filesystem may also need to start up
the time-based expirer, which in the case of AFS, NFS and CIFS doesn't repeat
if the list is empty - so if the mounting process gets preempted...

David

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


Re: [autofs] [PATCH 09/18] autofs4: Add d_manage() dentry operation [ver #4]

2011-01-14 Thread David Howells
Nick Piggin npig...@gmail.com wrote:

  On Thu, 2011-01-13 at 21:54 +, David Howells wrote:
  From: Ian Kent ra...@themaw.net
  + //spin_lock(dcache_lock);  /// JUST DELETE THIS LOCK?
  + if (!d_mountpoint(dentry)  list_empty(dentry-d_subdirs)) {
  + spin_lock(dentry-d_lock);
  + if (!(dentry-d_flags  DCACHE_MANAGE_TRANSIT) 
  +  (dentry-d_flags  DCACHE_NEED_AUTOMOUNT))
  + __managed_dentry_set_transit(path-dentry);
  + spin_unlock(dentry-d_lock);
  + }
  + //spin_unlock(dcache_lock);
 
  In this case I think the dcache_lock needs to be deleted and the d_lock
  moved out of the if to protect the d_subdirs access.
 
 Right. If you follow the vfs-scale-working git branch series of
 patches leading up to dcache_lock removal, it gives a pretty
 good template of how to convert old dcache_lock using code
 to new locking.
 
 Although you can also just look at locking in fs/dcache.c and
 convert code from that.
 
 Any time you are dealing with just a *single* dentry, then
 -d_lock would be enough to replace dcache_lock (it
 actually protects more than dcache_lock alone did).

Does it make sense to leave the lock where it is and repeat the outer test
after we've taken the lock?

David

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH 19/18] Unexport do_add_mount() and add in follow_automount(), not -d_automount()

2011-01-14 Thread David Howells

Unexport do_add_mount() and make -d_automount() return the vfsmount to be
added rather than calling do_add_mount() itself.  follow_automount() will then
do the addition.

This slightly complicates things as -d_automount() normally wants to add the
new vfsmount to an expiration list and start an expiration timer.  The problem
with that is that the vfsmount will be deleted if it has a refcount of 1 and
the timer will not repeat if the expiration list is empty.

To this end, we require the vfsmount to be returned from d_automount() with a
refcount of (at least) 2.  One of these refs will be dropped unconditionally.
In addition, follow_automount() must get a 3rd ref around the call to
do_add_mount() lest it eat a ref and return an error, leaving the mount we
have open to being expired as we would otherwise have only 1 ref on it.  This
would mean the currently upstream code is buggy for AFS, CIFS and NFS.

d_automount() should also add the the vfsmount to the expiration list (by
calling mnt_set_expiry()) and start the expiration timer before returning, if
this mechanism is to be used.  The vfsmount will be unlinked from the
expiration list by follow_automount() if do_add_mount() fails.

This patch also fixes the call to do_add_mount() for AFS and CIFS to propagate
the mount flags from the parent vfsmount.

Signed-off-by: David Howells dhowe...@redhat.com
---

 Documentation/filesystems/vfs.txt |   23 
 fs/afs/mntpt.c|   25 +-
 fs/cifs/cifs_dfs_ref.c|   26 +--
 fs/internal.h |2 ++
 fs/namei.c|   42 +++--
 fs/namespace.c|   41 +---
 fs/nfs/namespace.c|   24 -
 include/linux/mount.h |7 +-
 8 files changed, 101 insertions(+), 89 deletions(-)


diff --git a/Documentation/filesystems/vfs.txt 
b/Documentation/filesystems/vfs.txt
index 3c4b2f1..94cf97b 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -933,15 +933,20 @@ struct dentry_operations {
dynamic_dname() helper function is provided to take care of this.
 
   d_automount: called when an automount dentry is to be traversed (optional).
-   This should create a new VFS mount record, mount it on the directory
-   and return the record to the caller.  The caller is supplied with a
-   path parameter giving the automount directory to describe the automount
-   target and the parent VFS mount record to provide inheritable mount
-   parameters.  NULL should be returned if someone else managed to make
-   the automount first.  If the automount failed, then an error code
-   should be returned.  If -EISDIR is returned, then the directory will
-   be treated as an ordinary directory and returned to pathwalk to
-   continue walking.
+   This should create a new VFS mount record and return the record to the
+   caller.  The caller is supplied with a path parameter giving the
+   automount directory to describe the automount target and the parent
+   VFS mount record to provide inheritable mount parameters.  NULL should
+   be returned if someone else managed to make the automount first.  If
+   the vfsmount creation failed, then an error code should be returned.
+   If -EISDIR is returned, then the directory will be treated as an
+   ordinary directory and returned to pathwalk to continue walking.
+
+   If a vfsmount is returned, the caller will attempt to mount it on the
+   mountpoint and will remove the vfsmount from its expiration list in
+   the case of failure.  The vfsmount should be returned with 2 refs on
+   it to prevent automatic expiration - the caller will clean up the
+   additional ref.
 
This function is only used if DCACHE_NEED_AUTOMOUNT is set on the
dentry.  This is set by __d_instantiate() if S_AUTOMOUNT is set on the
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index 0f7dd7a..0d74c2c 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -241,7 +241,6 @@ error_no_devname:
 struct vfsmount *afs_d_automount(struct path *path)
 {
struct vfsmount *newmnt;
-   int err;
 
_enter({%s,%s}, path-mnt-mnt_devname, path-dentry-d_name.name);
 
@@ -249,24 +248,12 @@ struct vfsmount *afs_d_automount(struct path *path)
if (IS_ERR(newmnt))
return newmnt;
 
-   mntget(newmnt);
-   err = do_add_mount(newmnt, path, MNT_SHRINKABLE, afs_vfsmounts);
-   switch (err) {
-   case 0:
-   schedule_delayed_work(afs_mntpt_expiry_timer,
- afs_mntpt_expiry_timeout * HZ);
-   _leave( = %p {%s}, newmnt, newmnt-mnt_devname);
-   return newmnt;
-   case -EBUSY:
-   /* someone else made a mount here whilst we were busy

Re: [autofs] [PATCH 19/18] Unexport do_add_mount() and add in follow_automount(), not -d_automount()

2011-01-14 Thread David Howells
David Howells dhowe...@redhat.com wrote:

 This would mean the currently upstream code is buggy for AFS, CIFS and NFS.

Actually, no it wouldn't, since do_add_mount() is what adds the mount to the
expiration list.

David

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


Re: [autofs] [PATCH 01/18] Add a dentry op to handle automounting rather than abusing follow_link()

2011-01-13 Thread David Howells
Nick Piggin npig...@gmail.com wrote:

 So something has gone wrong here. You have documented .d_automount
 can be called in rcu-walk mode, but it doesn't seem to be the case.

Ah.  You removed a column and installed a new one, and I didn't notice.

Neither d_automount() and d_manage() should be entered in rcu-walk mode since
they're both expected to sleep.

Btw, should you add a fifth column for d_seq?

I should also add a column for namespace_sem as d_manage() may be called with
that held (and d_automount() must not be called with that held).

David

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


Re: [autofs] [PATCH 01/18] Add a dentry op to handle automounting rather than abusing follow_link()

2011-01-13 Thread David Howells
Nick Piggin npig...@gmail.com wrote:

  I would still prefer to see a .follow_mount API, and not tie in this
  automount specific inode detail to what could be a more flexible
  dentry-only API.
 
  The default NULL implementation would do nothing, and follow_automount
  stuff can be in fs/libfs.c to be used by filesystem, rather than
  fs/namei.c.
 
 Looking further in the patchset at the d_managed thing, that's almost what
 I'm getting at.
 
 But I don't see why any of this stuff has to happen in fs/namei.c. Just call
 the function from path walk, and provide helpers in libfs or something if
 there is a lot of common code between autofs4 and others (and leave it autofs
 specifc when that is the case).
 
 Of course, that would be the obvious and naive first approach. So really my
 question is why did that not work? And can we make it work?

You have a strange idea of what is 'obvious and naive'.  These are parts of
pathwalk, and as such should be in fs/namei.c.  I'd rather not expose
pathwalking directly to the filesystem, though I acknowledge that sometimes it
is necessary to let the filesystem influence it.

You need to consider d_automount() and d_manage() separately as they provide
two quite different hooks with different properties.

Firstly, d_automount().  The following are my points of consideration.

 (0) You're only allowed to automount on a directory.

 (1) Automounting does not need to be done when we follow .. to an automount
 point.

 (2) Automount points that are mounted upon within the current namespace can
 just be skipped over.  This is the fast path.

 (3) All the filesystem should need as a parameter to determine what it is
 allowed to mount is the inode and dentry of the automount point.  This
 holds true for all the things that currently do automounting (AFS, CIFS,
 NFS, autofs).

 (4) All the filesystem should need to do is set up a vfsmount struct and
 publish it or return an indication that there was a collision and the
 transit should be retried.

 (5) The filesystem is expected to sleep to achieve the automount, so
 spinlocks, RCU locks, preemption disablements or interrupt disablements
 may not be held across this function.

 (6) The filesystem is expected to need a write lock on namespace_sem at some
 point, so this must not be held across the call to d_automount().

 (7) The filesystem won't necessarily be calling do_add_mount() itself in
 d_automount() - in autofs's case, the construction is performed by the
 userspace daemon and then autofs4_d_automount() indicates a collision - so
 we can't move the do_add_mount() to the caller.  Additionally, the
 filesystem may want to use an expiration list.

 (8) There needs to be some limitation in place to prevent runaway
 automounting.  The ELOOP detection mechanism can be used for this.

Taking these considerations, it shows that a small amount of code can be
inserted into pathwalk and used for everything.  However, having worked with
Ian to try and get autofs4 to work with this, we came up with d_manage() to add
in a missing piece.

Note that autofs4 also uses d_automount() to build directory structures behind
the mountpoint rather than mounting on the mountpoint.  In this case, it clears
the AUTOMOUNT flag when construction is complete.

I've allowed d_automount() to return -EISDIR to follow_automount() to indicate
that no mount should be attempted here, and the directory should be given back
to pathwalk to treat as a directory.  This allows autofs's daemon access to the
directory.

Having follow_automount() update the path it has been given with the new
vfsmount and root dentry is purely an optimisation; we could instead simply
return and __follow_mount() will do lookup_mnt() again as it would if a
collision is reported.

In answer to why I haven't made __follow_mount_rcu() handle automount points, I
thought previously I saw a reason why it was unnecessary, but now I'm not so
sure.  It may be that if there are child objects of this dentry then it will
walk onto those rather than automounting - but for some reason it seems still
to automount rather than doing that.


Secondly, d_manage().  The following are the points of consideration:

 (1) A filesystem may want to hold up client processes that want to transit
 from directories in its control during pathwalk - such as when autofs is
 letting its userspace daemon tear down the stuff mounted on or created
 behind a directory.

 (2) A transit may be from a directory to a directory mounted over it, or from
 a directory to an object (file, dir, etc.) pointed to by an entry in that
 directoy.

 (3) The management of dentries in this fashion is a transient affair.

 (4) The mode in which the filesystem is normally entered for this purpose
 should be disabled as soon as possible, though it may be reenabled later
 if needed.

 (5) When the filesystem is ready it should let the held processes proceed 

[autofs] [PATCH 00/18] Introduce automount support in the VFS [ver #4]

2011-01-13 Thread David Howells
 Piggin's RCU-based pathwalk changes.

 [ver #2]
   - Fixed a EXDEV in patch 6 to be EISDIR.  We were previously using EXDEV to
 indicate we wanted to handle a directory as a directory and not to process
 it as a mountpoint.
   - Move some autofs v4 pseudo mount bits into the v4 pseudo direct mount
 patch [patch 16].
   - Move a comment fix to the autofs d_automount() patch [patch 10 - 9].
   - Adjust the patch titles of the last three autofs patches.

David
---

David Howells (9):
  Allow d_manage() to be used in RCU-walk mode
  Remove a further kludge from __do_follow_link()
  Remove the automount through follow_link() kludge code from pathwalk
  CIFS: Use d_automount() rather than abusing follow_link()
  NFS: Use d_automount() rather than abusing follow_link()
  AFS: Use d_automount() rather than abusing follow_link()
  From: David Howells dhowe...@redhat.com
  Add a dentry op to allow processes to be held during pathwalk transit
  Add a dentry op to handle automounting rather than abusing follow_link()

Ian Kent (9):
  autofs4: Bump version
  autofs4: Add v4 pseudo direct mount support
  autofs4: Fix wait validation
  autofs4: Clean up autofs4_free_ino()
  autofs4: Clean up dentry operations
  autofs4: Clean up inode operations
  autofs4: Remove unused code
  autofs4: Add d_manage() dentry operation
  autofs4: Add d_automount() dentry operation


 Documentation/filesystems/Locking |3 
 Documentation/filesystems/vfs.txt |   38 ++
 drivers/staging/autofs/dirhash.c  |5 
 fs/afs/dir.c  |1 
 fs/afs/inode.c|3 
 fs/afs/internal.h |1 
 fs/afs/mntpt.c|   47 +--
 fs/autofs4/autofs_i.h |  100 -
 fs/autofs4/dev-ioctl.c|2 
 fs/autofs4/expire.c   |   51 ++-
 fs/autofs4/inode.c|   28 --
 fs/autofs4/root.c |  685 -
 fs/autofs4/waitq.c|   17 +
 fs/cifs/cifs_dfs_ref.c|  134 ---
 fs/cifs/cifsfs.h  |6 
 fs/cifs/dir.c |2 
 fs/cifs/inode.c   |8 
 fs/dcache.c   |5 
 fs/namei.c|  307 +
 fs/namespace.c|   14 -
 fs/nfs/dir.c  |4 
 fs/nfs/inode.c|4 
 fs/nfs/internal.h |1 
 fs/nfs/namespace.c|   87 ++---
 fs/nfsd/vfs.c |5 
 fs/stat.c |4 
 include/linux/auto_fs4.h  |2 
 include/linux/dcache.h|   16 +
 include/linux/fcntl.h |1 
 include/linux/fs.h|2 
 include/linux/namei.h |5 
 include/linux/nfs_fs.h|1 
 32 files changed, 894 insertions(+), 695 deletions(-)

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH 01/18] Add a dentry op to handle automounting rather than abusing follow_link() [ver #4]

2011-01-13 Thread David Howells
Add a dentry op (d_automount) to handle automounting directories rather than
abusing the follow_link() inode operation.  The operation is keyed off a new
dentry flag (DCACHE_NEED_AUTOMOUNT).

This also makes it easier to add an AT_ flag to suppress terminal segment
automount during pathwalk and removes the need for the kludge code in the
pathwalk algorithm to handle directories with follow_link() semantics.

The -d_automount() dentry operation:

struct vfsmount *(*d_automount)(struct path *mountpoint);

takes a pointer to the directory to be mounted upon, which is expected to
provide sufficient data to determine what should be mounted.  If successful, it
should return the vfsmount struct it creates (which it should also have added
to the namespace using do_add_mount() or similar).  If there's a collision with
another automount attempt, NULL should be returned.  If the directory specified
by the parameter should be used directly rather than being mounted upon,
-EISDIR should be returned.  In any other case, an error code should be
returned.

The -d_automount() operation is called with no locks held and may sleep.  At
this point the pathwalk algorithm will be in ref-walk mode.


Within fs/namei.c itself, a new pathwalk subroutine (follow_automount()) is
added to handle mountpoints.  It will return -EREMOTE if the automount flag was
set, but no d_automount() op was supplied, -ELOOP if we've encountered too many
symlinks or mountpoints, -EISDIR if the walk point should be used without
mounting and 0 if successful.  The path will be updated to point to the mounted
filesystem if a successful automount took place.

__follow_mount() is replaced by follow_managed() which is more generic
(especially with the patch that adds -d_manage()).  This handles transits from
directories during pathwalk, including automounting and skipping over
mountpoints (and holding processes with the next patch).

__follow_mount_rcu() will jump out of RCU-walk mode if it encounters an
automount point with nothing mounted on it.

follow_dotdot*() does not handle automounts as you don't want to trigger them
whilst following ...

I've also extracted the mount/don't-mount logic from autofs4 and included it
here.  It makes the mount go ahead anyway if someone calls open() or creat(),
tries to traverse the directory, tries to chdir/chroot/etc. into the directory,
or sticks a '/' on the end of the pathname.  If they do a stat(), however,
they'll only trigger the automount if they didn't also say O_NOFOLLOW.

I've also added an inode flag (S_AUTOMOUNT) so that filesystems can mark their
inodes as automount points.  This flag is automatically propagated to the
dentry as DCACHE_NEED_AUTOMOUNT by __d_instantiate().  This saves NFS and could
save AFS a private flag bit apiece, but is not strictly necessary.  It would be
preferable to do the propagation in d_set_d_op(), but that doesn't normally
have access to the inode.

Signed-off-by: David Howells dhowe...@redhat.com
Was-Acked-by: Ian Kent ra...@themaw.net
---

 Documentation/filesystems/Locking |2 
 Documentation/filesystems/vfs.txt |   14 +++
 fs/dcache.c   |5 +
 fs/namei.c|  205 +
 include/linux/dcache.h|7 +
 include/linux/fs.h|2 
 6 files changed, 187 insertions(+), 48 deletions(-)

diff --git a/Documentation/filesystems/Locking 
b/Documentation/filesystems/Locking
index 977d891..5f0c52a 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -19,6 +19,7 @@ prototypes:
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen);
+   struct vfsmount *(*d_automount)(struct path *path);
 
 locking rules:
rename_lock -d_lockmay block   rcu-walk
@@ -29,6 +30,7 @@ d_delete: no  yes no  
no
 d_release: no  no  yes no
 d_iput:no  no  yes no
 d_dname:   no  no  no  no
+d_automount:   no  no  yes no
 
 --- inode_operations --- 
 prototypes:
diff --git a/Documentation/filesystems/vfs.txt 
b/Documentation/filesystems/vfs.txt
index fbb324e..992cf74 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -864,6 +864,7 @@ struct dentry_operations {
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
+   struct vfsmount *(*d_automount)(struct path *);
 };
 
   d_revalidate: called when the VFS needs to revalidate a dentry. This
@@ -930,6 +931,19 @@ struct dentry_operations {
at the end of the buffer

[autofs] [PATCH 03/18] From: David Howells dhowe...@redhat.com [ver #4]

2011-01-13 Thread David Howells
Add an AT_NO_AUTOMOUNT flag to suppress terminal automount

Add an AT_NO_AUTOMOUNT flag to suppress terminal automounting of automount
point directories.  This can be used by fstatat() users to permit the
gathering of attributes on an automount point and also prevent
mass-automounting of a directory of automount points by ls.

Signed-off-by: David Howells dhowe...@redhat.com
Acked-by: Ian Kent ra...@themaw.net
---

 fs/namei.c|6 ++
 fs/stat.c |4 +++-
 include/linux/fcntl.h |1 +
 include/linux/namei.h |2 ++
 4 files changed, 12 insertions(+), 1 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index e46a56b..249d0f2 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -889,6 +889,12 @@ static int follow_automount(struct path *path, unsigned 
flags,
if (!path-dentry-d_op || !path-dentry-d_op-d_automount)
return -EREMOTE;
 
+   /* We don't want to mount if someone supplied AT_NO_AUTOMOUNT
+* and this is the terminal part of the path.
+*/
+   if ((flags  LOOKUP_NO_AUTOMOUNT)  !(flags  LOOKUP_CONTINUE))
+   return -EISDIR; /* we actually want to stop here */
+
/* We want to mount if someone is trying to open/create a file of any
 * type under the mountpoint, wants to traverse through the mountpoint
 * or wants to open the mounted directory.
diff --git a/fs/stat.c b/fs/stat.c
index 12e90e2..d5c61cf 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -75,11 +75,13 @@ int vfs_fstatat(int dfd, const char __user *filename, 
struct kstat *stat,
int error = -EINVAL;
int lookup_flags = 0;
 
-   if ((flag  ~AT_SYMLINK_NOFOLLOW) != 0)
+   if ((flag  ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT)) != 0)
goto out;
 
if (!(flag  AT_SYMLINK_NOFOLLOW))
lookup_flags |= LOOKUP_FOLLOW;
+   if (flag  AT_NO_AUTOMOUNT)
+   lookup_flags |= LOOKUP_NO_AUTOMOUNT;
 
error = user_path_at(dfd, filename, lookup_flags, path);
if (error)
diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h
index afc00af..a562fa5 100644
--- a/include/linux/fcntl.h
+++ b/include/linux/fcntl.h
@@ -45,6 +45,7 @@
 #define AT_REMOVEDIR   0x200   /* Remove directory instead of
unlinking file.  */
 #define AT_SYMLINK_FOLLOW  0x400   /* Follow symbolic links.  */
+#define AT_NO_AUTOMOUNT0x800   /* Suppress terminal automount 
traversal */
 
 #ifdef __KERNEL__
 
diff --git a/include/linux/namei.h b/include/linux/namei.h
index 8ef2c78..f276d4f 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -45,6 +45,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
  *  - ending slashes ok even for nonexistent files
  *  - internal there are more path components flag
  *  - dentry cache is untrusted; force a real lookup
+ *  - suppress terminal automount
  */
 #define LOOKUP_FOLLOW  0x0001
 #define LOOKUP_DIRECTORY   0x0002
@@ -53,6 +54,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
 #define LOOKUP_PARENT  0x0010
 #define LOOKUP_REVAL   0x0020
 #define LOOKUP_RCU 0x0040
+#define LOOKUP_NO_AUTOMOUNT0x0080
 /*
  * Intent data
  */

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH 09/18] autofs4: Add d_manage() dentry operation [ver #4]

2011-01-13 Thread David Howells
From: Ian Kent ra...@themaw.net

This patch required a previous patch to add the -d_automount()
dentry operation.

Add a function to use the newly defined -d_manage() dentry operation
for blocking during mount and expire.

Whether the VFS calls the dentry operations d_automount() and d_manage()
is controled by the DMANAGED_AUTOMOUNT and DMANAGED_TRANSIT flags. autofs
uses the d_automount() operation to callback to user space to request
mount operations and the d_manage() operation to block walks into mounts
that are under construction or destruction.

In order to prevent these functions from being called unnecessarily the
DMANAGED_* flags are cleared for cases which would cause this. In the
common case the DMANAGED_AUTOMOUNT and DMANAGED_TRANSIT flags are both
set for dentrys waiting to be mounted. The DMANAGED_TRANSIT flag is
cleared upon successful mount request completion and set during expire
runs, both during the dentry expire check, and if selected for expire,
is left set until a subsequent successful mount request completes.

The exception to this is the so-called rootless multi-mount which has
no actual mount at its base. In this case the DMANAGED_AUTOMOUNT flag
is cleared upon successful mount request completion as well and set
again after a successful expire.

Signed-off-by: Ian Kent ra...@themaw.net
Signed-off-by: David Howells dhowe...@redhat.com
---

 fs/autofs4/autofs_i.h |   50 -
 fs/autofs4/expire.c   |   51 +
 fs/autofs4/inode.c|3 +
 fs/autofs4/root.c |  100 +++--
 4 files changed, 164 insertions(+), 40 deletions(-)

diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index 1ebfe53..7eff538 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -99,7 +99,6 @@ struct autofs_info {
 };
 
 #define AUTOFS_INF_EXPIRING(10) /* dentry is in the process of expiring 
*/
-#define AUTOFS_INF_MOUNTPOINT  (11) /* mountpoint status for direct expire */
 #define AUTOFS_INF_PENDING (12) /* dentry pending mount */
 
 struct autofs_wait_queue {
@@ -221,6 +220,7 @@ extern const struct file_operations autofs4_root_operations;
 /* Operations methods */
 
 struct vfsmount *autofs4_d_automount(struct path *);
+int autofs4_d_manage(struct path *, bool);
 
 /* VFS automount flags management functions */
 
@@ -248,6 +248,54 @@ static inline void managed_dentry_clear_automount(struct 
dentry *dentry)
spin_unlock(dentry-d_lock);
 }
 
+static inline void __managed_dentry_set_transit(struct dentry *dentry)
+{
+   dentry-d_flags |= DCACHE_MANAGE_TRANSIT;
+}
+
+static inline void managed_dentry_set_transit(struct dentry *dentry)
+{
+   spin_lock(dentry-d_lock);
+   __managed_dentry_set_transit(dentry);
+   spin_unlock(dentry-d_lock);
+}
+
+static inline void __managed_dentry_clear_transit(struct dentry *dentry)
+{
+   dentry-d_flags = ~DCACHE_MANAGE_TRANSIT;
+}
+
+static inline void managed_dentry_clear_transit(struct dentry *dentry)
+{
+   spin_lock(dentry-d_lock);
+   __managed_dentry_clear_transit(dentry);
+   spin_unlock(dentry-d_lock);
+}
+
+static inline void __managed_dentry_set_managed(struct dentry *dentry)
+{
+   dentry-d_flags |= (DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT);
+}
+
+static inline void managed_dentry_set_managed(struct dentry *dentry)
+{
+   spin_lock(dentry-d_lock);
+   __managed_dentry_set_managed(dentry);
+   spin_unlock(dentry-d_lock);
+}
+
+static inline void __managed_dentry_clear_managed(struct dentry *dentry)
+{
+   dentry-d_flags = ~(DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT);
+}
+
+static inline void managed_dentry_clear_managed(struct dentry *dentry)
+{
+   spin_lock(dentry-d_lock);
+   __managed_dentry_clear_managed(dentry);
+   spin_unlock(dentry-d_lock);
+}
+
 /* Initializing function */
 
 int autofs4_fill_super(struct super_block *, void *, int);
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index 0571ec8..3ed79d7 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -26,10 +26,6 @@ static inline int autofs4_can_expire(struct dentry *dentry,
if (ino == NULL)
return 0;
 
-   /* No point expiring a pending mount */
-   if (ino-flags  AUTOFS_INF_PENDING)
-   return 0;
-
if (!do_now) {
/* Too young to die */
if (!timeout || time_after(ino-last_used + timeout, now))
@@ -283,6 +279,7 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
unsigned long timeout;
struct dentry *root = dget(sb-s_root);
int do_now = how  AUTOFS_EXP_IMMEDIATE;
+   struct autofs_info *ino;
 
if (!root)
return NULL;
@@ -291,20 +288,21 @@ struct dentry *autofs4_expire_direct(struct super_block 
*sb,
timeout = sbi-exp_timeout;
 
spin_lock(sbi-fs_lock);
+   ino = autofs4_dentry_ino(root);
+   /* No point expiring a pending mount

[autofs] [PATCH 11/18] autofs4: Clean up inode operations [ver #4]

2011-01-13 Thread David Howells
From: Ian Kent ra...@themaw.net

Since the use of -follow_link() has been eliminated there is no
need to separate the indirect and direct inode operations.

Signed-off-by: Ian Kent ra...@themaw.net
Signed-off-by: David Howells dhowe...@redhat.com
---

 fs/autofs4/autofs_i.h |3 ---
 fs/autofs4/inode.c|4 +---
 fs/autofs4/root.c |   15 ---
 3 files changed, 1 insertions(+), 21 deletions(-)

diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index 8b746f6..c3b0afe 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -204,9 +204,6 @@ void autofs_dev_ioctl_exit(void);
 
 extern const struct inode_operations autofs4_symlink_inode_operations;
 extern const struct inode_operations autofs4_dir_inode_operations;
-extern const struct inode_operations autofs4_root_inode_operations;
-extern const struct inode_operations autofs4_indirect_root_inode_operations;
-extern const struct inode_operations autofs4_direct_root_inode_operations;
 extern const struct file_operations autofs4_dir_operations;
 extern const struct file_operations autofs4_root_operations;
 
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 75c1ed8..dac3dc7 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -326,9 +326,7 @@ int autofs4_fill_super(struct super_block *s, void *data, 
int silent)
__managed_dentry_set_managed(root);
 
root_inode-i_fop = autofs4_root_operations;
-   root_inode-i_op = autofs_type_trigger(sbi-type) ?
-   autofs4_direct_root_inode_operations :
-   autofs4_indirect_root_inode_operations;
+   root_inode-i_op = autofs4_dir_inode_operations;
 
/* Couldn't this be tested earlier? */
if (sbi-max_proto  AUTOFS_MIN_PROTO_VERSION ||
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 91db5dd..ab391d4 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -56,21 +56,6 @@ const struct file_operations autofs4_dir_operations = {
.llseek = dcache_dir_lseek,
 };
 
-const struct inode_operations autofs4_indirect_root_inode_operations = {
-   .lookup = autofs4_lookup,
-   .unlink = autofs4_dir_unlink,
-   .symlink= autofs4_dir_symlink,
-   .mkdir  = autofs4_dir_mkdir,
-   .rmdir  = autofs4_dir_rmdir,
-};
-
-const struct inode_operations autofs4_direct_root_inode_operations = {
-   .lookup = autofs4_lookup,
-   .unlink = autofs4_dir_unlink,
-   .mkdir  = autofs4_dir_mkdir,
-   .rmdir  = autofs4_dir_rmdir,
-};
-
 const struct inode_operations autofs4_dir_inode_operations = {
.lookup = autofs4_lookup,
.unlink = autofs4_dir_unlink,

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH 12/18] autofs4: Clean up dentry operations [ver #4]

2011-01-13 Thread David Howells
From: Ian Kent ra...@themaw.net

There are now two distinct dentry operations uses. One for dentrys
that trigger mounts and one for dentrys that do not.

Rationalize the use of these dentry operations and rename them to
reflect their function.

Signed-off-by: Ian Kent ra...@themaw.net
Signed-off-by: David Howells dhowe...@redhat.com
---

 fs/autofs4/autofs_i.h |7 ++-
 fs/autofs4/inode.c|   12 
 fs/autofs4/root.c |   36 
 3 files changed, 26 insertions(+), 29 deletions(-)

diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index c3b0afe..c28085c 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -206,11 +206,8 @@ extern const struct inode_operations 
autofs4_symlink_inode_operations;
 extern const struct inode_operations autofs4_dir_inode_operations;
 extern const struct file_operations autofs4_dir_operations;
 extern const struct file_operations autofs4_root_operations;
-
-/* Operations methods */
-
-struct vfsmount *autofs4_d_automount(struct path *);
-int autofs4_d_manage(struct path *, bool);
+extern const struct dentry_operations autofs4_dentry_operations;
+extern const struct dentry_operations autofs4_mount_dentry_operations;
 
 /* VFS automount flags management functions */
 
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index dac3dc7..427c357 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -251,12 +251,6 @@ static struct autofs_info *autofs4_mkroot(struct 
autofs_sb_info *sbi)
return ino;
 }
 
-static const struct dentry_operations autofs4_sb_dentry_operations = {
-   .d_automount= autofs4_d_automount,
-   .d_manage   = autofs4_d_manage,
-   .d_release  = autofs4_dentry_release,
-};
-
 int autofs4_fill_super(struct super_block *s, void *data, int silent)
 {
struct inode * root_inode;
@@ -311,7 +305,7 @@ int autofs4_fill_super(struct super_block *s, void *data, 
int silent)
goto fail_iput;
pipe = NULL;
 
-   d_set_d_op(root, autofs4_sb_dentry_operations);
+   d_set_d_op(root, autofs4_dentry_operations);
root-d_fsdata = ino;
 
/* Can this call block? */
@@ -322,8 +316,10 @@ int autofs4_fill_super(struct super_block *s, void *data, 
int silent)
goto fail_dput;
}
 
-   if (autofs_type_trigger(sbi-type))
+   if (autofs_type_trigger(sbi-type)) {
+   d_set_d_op(root, autofs4_mount_dentry_operations);
__managed_dentry_set_managed(root);
+   }
 
root_inode-i_fop = autofs4_root_operations;
root_inode-i_op = autofs4_dir_inode_operations;
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index ab391d4..b3ab9e9 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -35,6 +35,8 @@ static long autofs4_root_compat_ioctl(struct file *,unsigned 
int,unsigned long);
 #endif
 static int autofs4_dir_open(struct inode *inode, struct file *file);
 static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct 
nameidata *);
+static struct vfsmount *autofs4_d_automount(struct path *);
+static int autofs4_d_manage(struct path *, bool);
 
 const struct file_operations autofs4_root_operations = {
.open   = dcache_dir_open,
@@ -64,6 +66,18 @@ const struct inode_operations autofs4_dir_inode_operations = 
{
.rmdir  = autofs4_dir_rmdir,
 };
 
+/* For dentries that don't initiate mounting */
+const struct dentry_operations autofs4_dentry_operations = {
+   .d_release  = autofs4_dentry_release,
+};
+
+/* For dentries that do initiate mounting */
+const struct dentry_operations autofs4_mount_dentry_operations = {
+   .d_automount= autofs4_d_automount,
+   .d_manage   = autofs4_d_manage,
+   .d_release  = autofs4_dentry_release,
+};
+
 static void autofs4_add_active(struct dentry *dentry)
 {
struct autofs_sb_info *sbi = autofs4_sbi(dentry-d_sb);
@@ -158,18 +172,6 @@ void autofs4_dentry_release(struct dentry *de)
}
 }
 
-/* For dentries of directories in the root dir */
-static const struct dentry_operations autofs4_root_dentry_operations = {
-   .d_release  = autofs4_dentry_release,
-};
-
-/* For other dentries */
-static const struct dentry_operations autofs4_dentry_operations = {
-   .d_automount= autofs4_d_automount,
-   .d_manage   = autofs4_d_manage,
-   .d_release  = autofs4_dentry_release,
-};
-
 static struct dentry *autofs4_lookup_active(struct dentry *dentry)
 {
struct autofs_sb_info *sbi = autofs4_sbi(dentry-d_sb);
@@ -337,7 +339,7 @@ static struct dentry *autofs4_mountpoint_changed(struct 
path *path)
return path-dentry;
 }
 
-struct vfsmount *autofs4_d_automount(struct path *path)
+static struct vfsmount *autofs4_d_automount(struct path *path)
 {
struct dentry *dentry = path-dentry;
struct autofs_sb_info *sbi = autofs4_sbi(dentry-d_sb);
@@ -506,7 +508,7 @@ static struct dentry *autofs4_lookup

[autofs] [PATCH 13/18] autofs4: Clean up autofs4_free_ino() [ver #4]

2011-01-13 Thread David Howells
From: Ian Kent ra...@themaw.net

When this function is called the local reference count does't need to
be updated since the dentry is going away and dput definitely must
not be called here.

Also the autofs info struct field inode isn't used so remove it.

Signed-off-by: Ian Kent ra...@themaw.net
Signed-off-by: David Howells dhowe...@redhat.com
---

 fs/autofs4/inode.c |   13 -
 fs/autofs4/root.c  |9 -
 2 files changed, 0 insertions(+), 22 deletions(-)

diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 427c357..3ecd2e2 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -45,7 +45,6 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino,
 
if (!reinit) {
ino-flags = 0;
-   ino-inode = NULL;
ino-dentry = NULL;
ino-size = 0;
INIT_LIST_HEAD(ino-active);
@@ -76,19 +75,8 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino,
 
 void autofs4_free_ino(struct autofs_info *ino)
 {
-   struct autofs_info *p_ino;
-
if (ino-dentry) {
ino-dentry-d_fsdata = NULL;
-   if (ino-dentry-d_inode) {
-   struct dentry *parent = ino-dentry-d_parent;
-   if (atomic_dec_and_test(ino-count)) {
-   p_ino = autofs4_dentry_ino(parent);
-   if (p_ino  parent != ino-dentry)
-   atomic_dec(p_ino-count);
-   }
-   dput(ino-dentry);
-   }
ino-dentry = NULL;
}
if (ino-free)
@@ -390,7 +378,6 @@ struct inode *autofs4_get_inode(struct super_block *sb,
if (inode == NULL)
return NULL;
 
-   inf-inode = inode;
inode-i_mode = inf-mode;
if (sb-s_root) {
inode-i_uid = sb-s_root-d_inode-i_uid;
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index b3ab9e9..51a4c2a 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -151,11 +151,8 @@ void autofs4_dentry_release(struct dentry *de)
DPRINTK(releasing %p, de);
 
inf = autofs4_dentry_ino(de);
-   de-d_fsdata = NULL;
-
if (inf) {
struct autofs_sb_info *sbi = autofs4_sbi(de-d_sb);
-
if (sbi) {
spin_lock(sbi-lookup_lock);
if (!list_empty(inf-active))
@@ -164,10 +161,6 @@ void autofs4_dentry_release(struct dentry *de)
list_del(inf-expiring);
spin_unlock(sbi-lookup_lock);
}
-
-   inf-dentry = NULL;
-   inf-inode = NULL;
-
autofs4_free_ino(inf);
}
 }
@@ -588,7 +581,6 @@ static int autofs4_dir_symlink(struct inode *dir,
p_ino = autofs4_dentry_ino(dentry-d_parent);
if (p_ino  dentry-d_parent != dentry)
atomic_inc(p_ino-count);
-   ino-inode = inode;
 
ino-u.symlink = cp;
dir-i_mtime = CURRENT_TIME;
@@ -718,7 +710,6 @@ static int autofs4_dir_mkdir(struct inode *dir, struct 
dentry *dentry, int mode)
p_ino = autofs4_dentry_ino(dentry-d_parent);
if (p_ino  dentry-d_parent != dentry)
atomic_inc(p_ino-count);
-   ino-inode = inode;
inc_nlink(dir);
dir-i_mtime = CURRENT_TIME;
 

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH 14/18] autofs4: Fix wait validation [ver #4]

2011-01-13 Thread David Howells
From: Ian Kent ra...@themaw.net

It is possible for the check in wait.c:validate_request() to return
an incorrect result if the dentry that was mounted upon has changed
during the callback.

Signed-off-by: Ian Kent ra...@themaw.net
Signed-off-by: David Howells dhowe...@redhat.com
---

 fs/autofs4/waitq.c |   17 -
 1 files changed, 16 insertions(+), 1 deletions(-)

diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index c5f8459..5601005 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -309,6 +309,9 @@ static int validate_request(struct autofs_wait_queue **wait,
 * completed while we waited on the mutex ...
 */
if (notify == NFY_MOUNT) {
+   struct dentry *new = NULL;
+   int valid = 1;
+
/*
 * If the dentry was successfully mounted while we slept
 * on the wait queue mutex we can return success. If it
@@ -316,8 +319,20 @@ static int validate_request(struct autofs_wait_queue 
**wait,
 * a multi-mount with no mount at it's base) we can
 * continue on and create a new request.
 */
+   if (!IS_ROOT(dentry)) {
+   if (dentry-d_inode  d_unhashed(dentry)) {
+   struct dentry *parent = dentry-d_parent;
+   new = d_lookup(parent, dentry-d_name);
+   if (new)
+   dentry = new;
+   }
+   }
if (have_submounts(dentry))
-   return 0;
+   valid = 0;
+
+   if (new)
+   dput(new);
+   return valid;
}
 
return 1;

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH 16/18] autofs4: Bump version [ver #4]

2011-01-13 Thread David Howells
From: Ian Kent ra...@themaw.net

Increase the autofs module sub-version so we can tell what kernel
implementation is being used from user space debug logging.

Signed-off-by: Ian Kent ra...@themaw.net
Signed-off-by: David Howells dhowe...@redhat.com
---

 include/linux/auto_fs4.h |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/include/linux/auto_fs4.h b/include/linux/auto_fs4.h
index 8b49ac4..e02982f 100644
--- a/include/linux/auto_fs4.h
+++ b/include/linux/auto_fs4.h
@@ -24,7 +24,7 @@
 #define AUTOFS_MIN_PROTO_VERSION   3
 #define AUTOFS_MAX_PROTO_VERSION   5
 
-#define AUTOFS_PROTO_SUBVERSION1
+#define AUTOFS_PROTO_SUBVERSION2
 
 /* Mask for expire behaviour */
 #define AUTOFS_EXP_IMMEDIATE   1

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH 18/18] Allow d_manage() to be used in RCU-walk mode [ver #4]

2011-01-13 Thread David Howells
Allow d_manage() to be called from pathwalk when it is in RCU-walk mode as well
as when it is in Ref-walk mode.  This permits __follow_mount_rcu() to call
d_manage() directly.  d_manage() needs a parameter to indicate that it is in
RCU-walk mode as it isn't allowed to sleep if in that mode (but should return
-ECHILD instead).

autofs4_d_manage() can then be set to retain RCU-walk mode if the daemon
accesses it and otherwise request dropping back to ref-walk mode.

Signed-off-by: David Howells dhowe...@redhat.com
---

 Documentation/filesystems/Locking |2 +-
 Documentation/filesystems/vfs.txt |7 ++-
 fs/autofs4/root.c |8 ++--
 fs/namei.c|   14 +++---
 include/linux/dcache.h|2 +-
 5 files changed, 21 insertions(+), 12 deletions(-)

diff --git a/Documentation/filesystems/Locking 
b/Documentation/filesystems/Locking
index 621ee98..b3b0ac4 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -31,7 +31,7 @@ d_release:no  no  yes 
no
 d_iput:no  no  yes no
 d_dname:   no  no  no  no
 d_automount:   no  no  yes no
-d_manage:  no  no  yes no
+d_manage:  no  no  yes (ref-walk)  maybe
 
 --- inode_operations --- 
 prototypes:
diff --git a/Documentation/filesystems/vfs.txt 
b/Documentation/filesystems/vfs.txt
index 3d68c2e..9bc28c2f 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -865,7 +865,7 @@ struct dentry_operations {
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
struct vfsmount *(*d_automount)(struct path *);
-   int (*d_manage)(struct path *, bool);
+   int (*d_manage)(struct path *, bool, bool);
 };
 
   d_revalidate: called when the VFS needs to revalidate a dentry. This
@@ -960,6 +960,11 @@ struct dentry_operations {
held by the caller and the function should not initiate any mounts or
unmounts that it will then wait for.
 
+   If the 'rcu_walk' parameter is true, then the caller is doing a
+   pathwalk in RCU-walk mode.  Sleeping is not permitted in this mode,
+   and the caller can be asked to leave it and call again by returing
+   -ECHILD.
+
This function is only used if DCACHE_MANAGE_TRANSIT is set on the
dentry being transited from.
 
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 752693f..c46d6fb 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -36,7 +36,7 @@ static long autofs4_root_compat_ioctl(struct file *,unsigned 
int,unsigned long);
 static int autofs4_dir_open(struct inode *inode, struct file *file);
 static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct 
nameidata *);
 static struct vfsmount *autofs4_d_automount(struct path *);
-static int autofs4_d_manage(struct path *, bool);
+static int autofs4_d_manage(struct path *, bool, bool);
 
 const struct file_operations autofs4_root_operations = {
.open   = dcache_dir_open,
@@ -454,7 +454,7 @@ done:
return NULL;
 }
 
-int autofs4_d_manage(struct path *path, bool mounting_here)
+int autofs4_d_manage(struct path *path, bool mounting_here, bool rcu_walk)
 {
struct dentry *dentry = path-dentry;
struct autofs_sb_info *sbi = autofs4_sbi(dentry-d_sb);
@@ -469,6 +469,10 @@ int autofs4_d_manage(struct path *path, bool mounting_here)
return 0;
}
 
+   /* We need to sleep, so we need pathwalk to be in ref-mode */
+   if (rcu_walk)
+   return -ECHILD;
+
/* Wait for pending expires */
do_expire_wait(dentry);
 
diff --git a/fs/namei.c b/fs/namei.c
index c983c92..5c15daa 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -967,7 +967,7 @@ static int follow_managed(struct path *path, unsigned flags)
if (managed  DCACHE_MANAGE_TRANSIT) {
BUG_ON(!path-dentry-d_op);
BUG_ON(!path-dentry-d_op-d_manage);
-   ret = path-dentry-d_op-d_manage(path, false);
+   ret = path-dentry-d_op-d_manage(path, false, false);
if (ret  0)
return ret == -EISDIR ? 0 : ret;
}
@@ -1028,13 +1028,12 @@ int follow_down_one(struct path *path)
 static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
   struct inode **inode, bool reverse_transit)
 {
-   unsigned abort_mask =
-   reverse_transit ? 0 : DCACHE_MANAGE_TRANSIT;
-
while (d_mountpoint(path-dentry)) {
struct vfsmount *mounted;
-   if (path-dentry-d_flags  abort_mask

Re: [autofs] [PATCH 07/18] Add more dentry flags for special function directories [UPDATE]

2011-01-12 Thread David Howells

Here's an updated patch 7.  d_set_d_op() can't be used to set
DCACHE_NEED_AUTOMOUNT as d_inode is not set at that point.  It has to be done
in __d_instantiate() at the latest.

David
---
From: David Howells dhowe...@redhat.com
Subject: [PATCH] Add more dentry flags for special function directories

Add more flags to the d_flags in struct dentry for special function directories
such as mountpoints and autofs substructures.  The relevant flags are:

 (*) DCACHE_MOUNTED.

 (Already exists).  Indicates that this dentry has things mounted upon it.

 (*) DCACHE_NEED_AUTOMOUNT.

 This is a reflection of the S_AUTOMOUNT inode flag.  This is reflected by
 __d_instantiate() and similar.  follow_automount() is now keyed off of the
 dcache flag rather than being keyed off S_AUTOMOUNT directly.  Possibly
 S_AUTOMOUNT should shift to the dentry entirely.

 This may also be tweaked live (such as by the autofs4 filesystem) to alter
 the effect.

 (*) DCACHE_MANAGE_TRANSIT.

 This is an indicator that the filesystem that owns the dentry wants to
 manage processes transiting away from that dentry.  If this is set on a
 dentry, then a new dentry op:

int (*d_manage)(struct path *);

 is invoked.  This is allowed to sleep and is allowed to return an error.

 This allows autofs to hold non-Oz-mode processes here without any
 filesystem locks being held.

__follow_mount() is replaced by managed_dentry() which now handles transit to a
mountpoint's root dentry, automount points and points that the filesystem wants
to manage.


==
WHAT THIS MEANS FOR AUTOFS
==

autofs currently uses the lookup() inode op and the d_revalidate() dentry op to
trigger the automounting of indirect mounts, and both of these can be called
with i_mutex held.

autofs knows that the i_mutex will be held by the caller in lookup(), and so
can drop it before invoking the daemon - but this isn't so for d_revalidate(),
since the lock is only held on _some_ of the code paths that call it.  This
means that autofs can't risk dropping i_mutex from its d_revalidate() function
before it calls the daemon.

The bug could manifest itself as, for example, a process that's trying to
validate an automount dentry that gets made to wait because that dentry is
expired and needs cleaning up:

mkdir S 8014e05a 0 32580  24956
Call Trace:
 [885371fd] :autofs4:autofs4_wait+0x674/0x897
 [80127f7d] avc_has_perm+0x46/0x58
 [8009fdcf] autoremove_wake_function+0x0/0x2e
 [88537be6] :autofs4:autofs4_expire_wait+0x41/0x6b
 [88535cfc] :autofs4:autofs4_revalidate+0x91/0x149
 [80036d96] __lookup_hash+0xa0/0x12f
 [80057a2f] lookup_create+0x46/0x80
 [800e6e31] sys_mkdirat+0x56/0xe4

versus the automount daemon which wants to remove that dentry, but can't
because the normal process is holding the i_mutex lock:

automount D 8014e05a 0 32581  1  32561
Call Trace:
 [80063c3f] __mutex_lock_slowpath+0x60/0x9b
 [8000ccf1] do_path_lookup+0x2ca/0x2f1
 [80063c89] .text.lock.mutex+0xf/0x14
 [800e6d55] do_rmdir+0x77/0xde
 [8005d229] tracesys+0x71/0xe0
 [8005d28d] tracesys+0xd5/0xe0

which means that the system is deadlocked.

This patch allows autofs to hold up normal processes whilst the daemon goes
ahead and does things to the dentry tree behind the automouter point without
risking a deadlock as no locks are held in d_manage() or d_automount().

Signed-off-by: David Howells dhowe...@redhat.com
Acked-by: Ian Kent ra...@themaw.net
---

 Documentation/filesystems/vfs.txt |   13 +++
 fs/dcache.c   |5 +
 fs/namei.c|  153 ++---
 include/linux/dcache.h|   13 ++-
 4 files changed, 132 insertions(+), 52 deletions(-)


diff --git a/Documentation/filesystems/vfs.txt 
b/Documentation/filesystems/vfs.txt
index bb8d277..99f0127 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -865,6 +865,7 @@ struct dentry_operations {
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
struct vfsmount *(*d_automount)(struct path *);
+   int (*d_manage)(struct path *);
 };
 
   d_revalidate: called when the VFS needs to revalidate a dentry. This
@@ -940,8 +941,16 @@ struct dentry_operations {
the automount first.  If the automount failed, then an error code
should be returned.
 
-   This function is only used if S_AUTOMOUNT is set on the inode to which
-   the dentry refers.
+   This function is only used if DMANAGED_AUTOMOUNT is set on the dentry.
+   This is set by d_add

Re: [autofs] [PATCH 00/18] Introduce automount support in the VFS

2011-01-12 Thread David Howells

I've updated:

http://git.kernel.org/?p=linux/kernel/git/dhowells/linux-2.6-automount.git;a=summary

to Linus's latest GIT tree with my latest patches on top.

David

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH 10/18] autofs4: Add d_manage() dentry operation

2011-01-11 Thread David Howells
From: Ian Kent ra...@themaw.net

This patch required a previous patch to add the -d_automount()
dentry operation.

Add a function to use the newly defined -d_manage() dentry operation
for blocking during mount and expire.

Whether the VFS calls the dentry operations d_automount() and d_manage()
is controled by the DMANAGED_AUTOMOUNT and DMANAGED_TRANSIT flags. autofs
uses the d_automount() operation to callback to user space to request
mount operations and the d_manage() operation to block walks into mounts
that are under construction or destruction.

In order to prevent these functions from being called unnecessarily the
DMANAGED_* flags are cleared for cases which would cause this. In the
common case the DMANAGED_AUTOMOUNT and DMANAGED_TRANSIT flags are both
set for dentrys waiting to be mounted. The DMANAGED_TRANSIT flag is
cleared upon successful mount request completion and set during expire
runs, both during the dentry expire check, and if selected for expire,
is left set until a subsequent successful mount request completes.

The exception to this is the so-called rootless multi-mount which has
no actual mount at its base. In this case the DMANAGED_AUTOMOUNT flag
is cleared upon successful mount request completion as well and set
again after a successful expire.

Signed-off-by: Ian Kent ra...@themaw.net
Signed-off-by: David Howells dhowe...@redhat.com
---

 fs/autofs4/autofs_i.h |   50 -
 fs/autofs4/expire.c   |   51 +
 fs/autofs4/inode.c|3 +
 fs/autofs4/root.c |  100 +++--
 4 files changed, 164 insertions(+), 40 deletions(-)

diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index 1ebfe53..7eff538 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -99,7 +99,6 @@ struct autofs_info {
 };
 
 #define AUTOFS_INF_EXPIRING(10) /* dentry is in the process of expiring 
*/
-#define AUTOFS_INF_MOUNTPOINT  (11) /* mountpoint status for direct expire */
 #define AUTOFS_INF_PENDING (12) /* dentry pending mount */
 
 struct autofs_wait_queue {
@@ -221,6 +220,7 @@ extern const struct file_operations autofs4_root_operations;
 /* Operations methods */
 
 struct vfsmount *autofs4_d_automount(struct path *);
+int autofs4_d_manage(struct path *, bool);
 
 /* VFS automount flags management functions */
 
@@ -248,6 +248,54 @@ static inline void managed_dentry_clear_automount(struct 
dentry *dentry)
spin_unlock(dentry-d_lock);
 }
 
+static inline void __managed_dentry_set_transit(struct dentry *dentry)
+{
+   dentry-d_flags |= DCACHE_MANAGE_TRANSIT;
+}
+
+static inline void managed_dentry_set_transit(struct dentry *dentry)
+{
+   spin_lock(dentry-d_lock);
+   __managed_dentry_set_transit(dentry);
+   spin_unlock(dentry-d_lock);
+}
+
+static inline void __managed_dentry_clear_transit(struct dentry *dentry)
+{
+   dentry-d_flags = ~DCACHE_MANAGE_TRANSIT;
+}
+
+static inline void managed_dentry_clear_transit(struct dentry *dentry)
+{
+   spin_lock(dentry-d_lock);
+   __managed_dentry_clear_transit(dentry);
+   spin_unlock(dentry-d_lock);
+}
+
+static inline void __managed_dentry_set_managed(struct dentry *dentry)
+{
+   dentry-d_flags |= (DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT);
+}
+
+static inline void managed_dentry_set_managed(struct dentry *dentry)
+{
+   spin_lock(dentry-d_lock);
+   __managed_dentry_set_managed(dentry);
+   spin_unlock(dentry-d_lock);
+}
+
+static inline void __managed_dentry_clear_managed(struct dentry *dentry)
+{
+   dentry-d_flags = ~(DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT);
+}
+
+static inline void managed_dentry_clear_managed(struct dentry *dentry)
+{
+   spin_lock(dentry-d_lock);
+   __managed_dentry_clear_managed(dentry);
+   spin_unlock(dentry-d_lock);
+}
+
 /* Initializing function */
 
 int autofs4_fill_super(struct super_block *, void *, int);
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index 0571ec8..3ed79d7 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -26,10 +26,6 @@ static inline int autofs4_can_expire(struct dentry *dentry,
if (ino == NULL)
return 0;
 
-   /* No point expiring a pending mount */
-   if (ino-flags  AUTOFS_INF_PENDING)
-   return 0;
-
if (!do_now) {
/* Too young to die */
if (!timeout || time_after(ino-last_used + timeout, now))
@@ -283,6 +279,7 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
unsigned long timeout;
struct dentry *root = dget(sb-s_root);
int do_now = how  AUTOFS_EXP_IMMEDIATE;
+   struct autofs_info *ino;
 
if (!root)
return NULL;
@@ -291,20 +288,21 @@ struct dentry *autofs4_expire_direct(struct super_block 
*sb,
timeout = sbi-exp_timeout;
 
spin_lock(sbi-fs_lock);
+   ino = autofs4_dentry_ino(root);
+   /* No point expiring a pending mount

[autofs] [PATCH 15/18] autofs4: Fix wait validation

2011-01-11 Thread David Howells
From: Ian Kent ra...@themaw.net

It is possible for the check in wait.c:validate_request() to return
an incorrect result if the dentry that was mounted upon has changed
during the callback.

Signed-off-by: Ian Kent ra...@themaw.net
Signed-off-by: David Howells dhowe...@redhat.com
---

 fs/autofs4/waitq.c |   17 -
 1 files changed, 16 insertions(+), 1 deletions(-)

diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index c5f8459..5601005 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -309,6 +309,9 @@ static int validate_request(struct autofs_wait_queue **wait,
 * completed while we waited on the mutex ...
 */
if (notify == NFY_MOUNT) {
+   struct dentry *new = NULL;
+   int valid = 1;
+
/*
 * If the dentry was successfully mounted while we slept
 * on the wait queue mutex we can return success. If it
@@ -316,8 +319,20 @@ static int validate_request(struct autofs_wait_queue 
**wait,
 * a multi-mount with no mount at it's base) we can
 * continue on and create a new request.
 */
+   if (!IS_ROOT(dentry)) {
+   if (dentry-d_inode  d_unhashed(dentry)) {
+   struct dentry *parent = dentry-d_parent;
+   new = d_lookup(parent, dentry-d_name);
+   if (new)
+   dentry = new;
+   }
+   }
if (have_submounts(dentry))
-   return 0;
+   valid = 0;
+
+   if (new)
+   dput(new);
+   return valid;
}
 
return 1;

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH 16/18] autofs4: Add v4 pseudo direct mount support

2011-01-11 Thread David Howells
From: Ian Kent ra...@themaw.net

Version 4 of autofs provides a pseudo direct mount implementation
that relies on directories at the leaves of a directory tree under
an indirect mount to trigger mounts.

This patch adds support for that functionality.

Signed-off-by: Ian Kent ra...@themaw.net
Signed-off-by: David Howells dhowe...@redhat.com
---

 fs/autofs4/root.c |   60 +
 1 files changed, 60 insertions(+), 0 deletions(-)

diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 51a4c2a..752693f 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -635,6 +635,60 @@ static int autofs4_dir_unlink(struct inode *dir, struct 
dentry *dentry)
return 0;
 }
 
+/*
+ * Version 4 of autofs provides a pseudo direct mount implementation
+ * that relies on directories at the leaves of a directory tree under
+ * an indirect mount to trigger mounts. To allow for this we need to
+ * set the DMANAGED_AUTOMOUNT and DMANAGED_TRANSIT flags on the leaves
+ * of the directory tree. There is no need to clear the automount flag
+ * following a mount or restore it after an expire because these mounts
+ * are always covered. However, it is neccessary to ensure that these
+ * flags are clear on non-empty directories to avoid unnecessary calls
+ * during path walks.
+ */
+static void autofs_set_leaf_automount_flags(struct dentry *dentry)
+{
+   struct dentry *parent;
+
+   /* root and dentrys in the root are already handled */
+   if (IS_ROOT(dentry-d_parent))
+   return;
+
+   managed_dentry_set_managed(dentry);
+
+   parent = dentry-d_parent;
+   /* only consider parents below dentrys in the root */
+   if (IS_ROOT(parent-d_parent))
+   return;
+   managed_dentry_clear_managed(parent);
+   return;
+}
+
+static void autofs_clear_leaf_automount_flags(struct dentry *dentry)
+{
+   struct list_head *d_child;
+   struct dentry *parent;
+
+   /* flags for dentrys in the root are handled elsewhere */
+   if (IS_ROOT(dentry-d_parent))
+   return;
+
+   managed_dentry_clear_managed(dentry);
+
+   parent = dentry-d_parent;
+   /* only consider parents below dentrys in the root */
+   if (IS_ROOT(parent-d_parent))
+   return;
+   d_child = dentry-d_u.d_child;
+   //spin_lock(dcache_lock);  // JUST DELETE THIS LOCK?
+   /* Set parent managed if it's becoming empty */
+   if (d_child-next == parent-d_subdirs 
+   d_child-prev == parent-d_subdirs)
+   managed_dentry_set_managed(parent);
+   //spin_unlock(dcache_lock);
+   return;
+}
+
 static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)
 {
struct autofs_sb_info *sbi = autofs4_sbi(dir-i_sb);
@@ -662,6 +716,9 @@ static int autofs4_dir_rmdir(struct inode *dir, struct 
dentry *dentry)
spin_unlock(dentry-d_lock);
spin_unlock(autofs4_lock);
 
+   if (sbi-version  5)
+   autofs_clear_leaf_automount_flags(dentry);
+
if (atomic_dec_and_test(ino-count)) {
p_ino = autofs4_dentry_ino(dentry-d_parent);
if (p_ino  dentry-d_parent != dentry)
@@ -704,6 +761,9 @@ static int autofs4_dir_mkdir(struct inode *dir, struct 
dentry *dentry, int mode)
}
d_add(dentry, inode);
 
+   if (sbi-version  5)
+   autofs_set_leaf_automount_flags(dentry);
+
dentry-d_fsdata = ino;
ino-dentry = dget(dentry);
atomic_inc(ino-count);

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH 11/18] autofs4: Remove unused code

2011-01-11 Thread David Howells
From: Ian Kent ra...@themaw.net

Remove code that is not used due to the use of -d_automount()
and -d_manage().

Signed-off-by: Ian Kent ra...@themaw.net
Signed-off-by: David Howells dhowe...@redhat.com
---

 fs/autofs4/autofs_i.h |7 -
 fs/autofs4/root.c |  243 -
 2 files changed, 0 insertions(+), 250 deletions(-)

diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index 7eff538..8b746f6 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -175,13 +175,6 @@ static inline int autofs4_ispending(struct dentry *dentry)
return 0;
 }
 
-static inline void autofs4_copy_atime(struct file *src, struct file *dst)
-{
-   dst-f_path.dentry-d_inode-i_atime =
-   src-f_path.dentry-d_inode-i_atime;
-   return;
-}
-
 struct inode *autofs4_get_inode(struct super_block *, struct autofs_info *);
 void autofs4_free_ino(struct autofs_info *);
 
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index b2cc422..91db5dd 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -36,9 +36,6 @@ static long autofs4_root_compat_ioctl(struct file *,unsigned 
int,unsigned long);
 static int autofs4_dir_open(struct inode *inode, struct file *file);
 static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct 
nameidata *);
 
-#define TRIGGER_FLAGS   (LOOKUP_CONTINUE | LOOKUP_DIRECTORY)
-#define TRIGGER_INTENTS (LOOKUP_OPEN | LOOKUP_CREATE)
-
 const struct file_operations autofs4_root_operations = {
.open   = dcache_dir_open,
.release= dcache_dir_close,
@@ -114,14 +111,6 @@ static void autofs4_del_active(struct dentry *dentry)
return;
 }
 
-static unsigned int autofs4_need_mount(unsigned int flags)
-{
-   unsigned int res = 0;
-   if (flags  (TRIGGER_FLAGS | TRIGGER_INTENTS))
-   res = 1;
-   return res;
-}
-
 static int autofs4_dir_open(struct inode *inode, struct file *file)
 {
struct dentry *dentry = file-f_path.dentry;
@@ -156,238 +145,6 @@ out:
return dcache_dir_open(inode, file);
 }
 
-static int try_to_fill_dentry(struct dentry *dentry, int flags)
-{
-   struct autofs_sb_info *sbi = autofs4_sbi(dentry-d_sb);
-   struct autofs_info *ino = autofs4_dentry_ino(dentry);
-   int status;
-
-   DPRINTK(dentry=%p %.*s ino=%p,
-dentry, dentry-d_name.len, dentry-d_name.name, 
dentry-d_inode);
-
-   /*
-* Wait for a pending mount, triggering one if there
-* isn't one already
-*/
-   if (dentry-d_inode == NULL) {
-   DPRINTK(waiting for mount name=%.*s,
-dentry-d_name.len, dentry-d_name.name);
-
-   status = autofs4_wait(sbi, dentry, NFY_MOUNT);
-
-   DPRINTK(mount done status=%d, status);
-
-   /* Turn this into a real negative dentry? */
-   if (status == -ENOENT) {
-   spin_lock(sbi-fs_lock);
-   ino-flags = ~AUTOFS_INF_PENDING;
-   spin_unlock(sbi-fs_lock);
-   return status;
-   } else if (status) {
-   /* Return a negative dentry, but leave it pending */
-   return status;
-   }
-   /* Trigger mount for path component or follow link */
-   } else if (ino-flags  AUTOFS_INF_PENDING ||
-   autofs4_need_mount(flags)) {
-   DPRINTK(waiting for mount name=%.*s,
-   dentry-d_name.len, dentry-d_name.name);
-
-   spin_lock(sbi-fs_lock);
-   ino-flags |= AUTOFS_INF_PENDING;
-   spin_unlock(sbi-fs_lock);
-   status = autofs4_wait(sbi, dentry, NFY_MOUNT);
-
-   DPRINTK(mount done status=%d, status);
-
-   if (status) {
-   spin_lock(sbi-fs_lock);
-   ino-flags = ~AUTOFS_INF_PENDING;
-   spin_unlock(sbi-fs_lock);
-   return status;
-   }
-   }
-
-   /* Initialize expiry counter after successful mount */
-   ino-last_used = jiffies;
-
-   spin_lock(sbi-fs_lock);
-   ino-flags = ~AUTOFS_INF_PENDING;
-   spin_unlock(sbi-fs_lock);
-
-   return 0;
-}
-
-/* For autofs direct mounts the follow link triggers the mount */
-static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)
-{
-   struct autofs_sb_info *sbi = autofs4_sbi(dentry-d_sb);
-   struct autofs_info *ino = autofs4_dentry_ino(dentry);
-   int oz_mode = autofs4_oz_mode(sbi);
-   unsigned int lookup_type;
-   int status;
-
-   DPRINTK(dentry=%p %.*s oz_mode=%d nd-flags=%d,
-   dentry, dentry-d_name.len, dentry-d_name.name, oz_mode,
-   nd-flags);
-   /*
-* For an expire of a covered direct or offset mount we need
-* to break out of follow_down_one() at the autofs mount trigger

[autofs] [PATCH 14/18] autofs4: Clean up autofs4_free_ino()

2011-01-11 Thread David Howells
From: Ian Kent ra...@themaw.net

When this function is called the local reference count does't need to
be updated since the dentry is going away and dput definitely must
not be called here.

Also the autofs info struct field inode isn't used so remove it.

Signed-off-by: Ian Kent ra...@themaw.net
Signed-off-by: David Howells dhowe...@redhat.com
---

 fs/autofs4/inode.c |   13 -
 fs/autofs4/root.c  |9 -
 2 files changed, 0 insertions(+), 22 deletions(-)

diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 427c357..3ecd2e2 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -45,7 +45,6 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino,
 
if (!reinit) {
ino-flags = 0;
-   ino-inode = NULL;
ino-dentry = NULL;
ino-size = 0;
INIT_LIST_HEAD(ino-active);
@@ -76,19 +75,8 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino,
 
 void autofs4_free_ino(struct autofs_info *ino)
 {
-   struct autofs_info *p_ino;
-
if (ino-dentry) {
ino-dentry-d_fsdata = NULL;
-   if (ino-dentry-d_inode) {
-   struct dentry *parent = ino-dentry-d_parent;
-   if (atomic_dec_and_test(ino-count)) {
-   p_ino = autofs4_dentry_ino(parent);
-   if (p_ino  parent != ino-dentry)
-   atomic_dec(p_ino-count);
-   }
-   dput(ino-dentry);
-   }
ino-dentry = NULL;
}
if (ino-free)
@@ -390,7 +378,6 @@ struct inode *autofs4_get_inode(struct super_block *sb,
if (inode == NULL)
return NULL;
 
-   inf-inode = inode;
inode-i_mode = inf-mode;
if (sb-s_root) {
inode-i_uid = sb-s_root-d_inode-i_uid;
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index b3ab9e9..51a4c2a 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -151,11 +151,8 @@ void autofs4_dentry_release(struct dentry *de)
DPRINTK(releasing %p, de);
 
inf = autofs4_dentry_ino(de);
-   de-d_fsdata = NULL;
-
if (inf) {
struct autofs_sb_info *sbi = autofs4_sbi(de-d_sb);
-
if (sbi) {
spin_lock(sbi-lookup_lock);
if (!list_empty(inf-active))
@@ -164,10 +161,6 @@ void autofs4_dentry_release(struct dentry *de)
list_del(inf-expiring);
spin_unlock(sbi-lookup_lock);
}
-
-   inf-dentry = NULL;
-   inf-inode = NULL;
-
autofs4_free_ino(inf);
}
 }
@@ -588,7 +581,6 @@ static int autofs4_dir_symlink(struct inode *dir,
p_ino = autofs4_dentry_ino(dentry-d_parent);
if (p_ino  dentry-d_parent != dentry)
atomic_inc(p_ino-count);
-   ino-inode = inode;
 
ino-u.symlink = cp;
dir-i_mtime = CURRENT_TIME;
@@ -718,7 +710,6 @@ static int autofs4_dir_mkdir(struct inode *dir, struct 
dentry *dentry, int mode)
p_ino = autofs4_dentry_ino(dentry-d_parent);
if (p_ino  dentry-d_parent != dentry)
atomic_inc(p_ino-count);
-   ino-inode = inode;
inc_nlink(dir);
dir-i_mtime = CURRENT_TIME;
 

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH 03/18] NFS: Use d_automount() rather than abusing follow_link()

2011-01-11 Thread David Howells
Make NFS use the new d_automount() dentry operation rather than abusing
follow_link() on directories.

Signed-off-by: David Howells dhowe...@redhat.com
Acked-by: Trond Myklebust trond.mykleb...@netapp.com
Acked-by: Ian Kent ra...@themaw.net
---

 fs/nfs/dir.c   |4 ++
 fs/nfs/inode.c |4 +-
 fs/nfs/internal.h  |1 +
 fs/nfs/namespace.c |   87 ++--
 include/linux/nfs_fs.h |1 -
 5 files changed, 46 insertions(+), 51 deletions(-)

diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index d33da53..959927c 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -970,7 +970,7 @@ int nfs_lookup_verify_inode(struct inode *inode, struct 
nameidata *nd)
 {
struct nfs_server *server = NFS_SERVER(inode);
 
-   if (test_bit(NFS_INO_MOUNTPOINT, NFS_I(inode)-flags))
+   if (IS_AUTOMOUNT(inode))
return 0;
if (nd != NULL) {
/* VFS wants an on-the-wire revalidation */
@@ -1173,6 +1173,7 @@ const struct dentry_operations nfs_dentry_operations = {
.d_revalidate   = nfs_lookup_revalidate,
.d_delete   = nfs_dentry_delete,
.d_iput = nfs_dentry_iput,
+   .d_automount= nfs_d_automount,
 };
 
 static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, 
struct nameidata *nd)
@@ -1248,6 +1249,7 @@ const struct dentry_operations nfs4_dentry_operations = {
.d_revalidate   = nfs_open_revalidate,
.d_delete   = nfs_dentry_delete,
.d_iput = nfs_dentry_iput,
+   .d_automount= nfs_d_automount,
 };
 
 /*
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 017daa3..6ace134 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -300,7 +300,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct 
nfs_fattr *fattr)
else
inode-i_op = 
nfs_mountpoint_inode_operations;
inode-i_fop = NULL;
-   set_bit(NFS_INO_MOUNTPOINT, nfsi-flags);
+   inode-i_flags |= S_AUTOMOUNT;
}
} else if (S_ISLNK(inode-i_mode))
inode-i_op = nfs_symlink_inode_operations;
@@ -1208,7 +1208,7 @@ static int nfs_update_inode(struct inode *inode, struct 
nfs_fattr *fattr)
/* Update the fsid? */
if (S_ISDIR(inode-i_mode)  (fattr-valid  NFS_ATTR_FATTR_FSID) 
!nfs_fsid_equal(server-fsid, fattr-fsid) 
-   !test_bit(NFS_INO_MOUNTPOINT, nfsi-flags))
+   !IS_AUTOMOUNT(inode))
server-fsid = fattr-fsid;
 
/*
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index e6356b7..66c3dc4 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -245,6 +245,7 @@ extern char *nfs_path(const char *base,
  const struct dentry *droot,
  const struct dentry *dentry,
  char *buffer, ssize_t buflen);
+extern struct vfsmount *nfs_d_automount(struct path *path);
 
 /* getroot.c */
 extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *);
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index 74aaf39..f3fbb1b 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -97,9 +97,8 @@ Elong:
 }
 
 /*
- * nfs_follow_mountpoint - handle crossing a mountpoint on the server
- * @dentry - dentry of mountpoint
- * @nd - nameidata info
+ * nfs_d_automount - Handle crossing a mountpoint on the server
+ * @path - The mountpoint
  *
  * When we encounter a mountpoint on the server, we want to set up
  * a mountpoint on the client too, to prevent inode numbers from
@@ -109,87 +108,81 @@ Elong:
  * situation, and that different filesystems may want to use
  * different security flavours.
  */
-static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata 
*nd)
+struct vfsmount *nfs_d_automount(struct path *path)
 {
struct vfsmount *mnt;
-   struct nfs_server *server = NFS_SERVER(dentry-d_inode);
+   struct nfs_server *server = NFS_SERVER(path-dentry-d_inode);
struct dentry *parent;
struct nfs_fh *fh = NULL;
struct nfs_fattr *fattr = NULL;
int err;
 
-   dprintk(-- nfs_follow_mountpoint()\n);
+   dprintk(-- nfs_d_automount()\n);
 
-   err = -ESTALE;
-   if (IS_ROOT(dentry))
-   goto out_err;
+   mnt = ERR_PTR(-ESTALE);
+   if (IS_ROOT(path-dentry))
+   goto out_nofree;
 
-   err = -ENOMEM;
+   mnt = ERR_PTR(-ENOMEM);
fh = nfs_alloc_fhandle();
fattr = nfs_alloc_fattr();
if (fh == NULL || fattr == NULL)
-   goto out_err;
+   goto out;
 
dprintk(%s: enter\n, __func__);
-   dput(nd-path.dentry);
-   nd-path.dentry = dget(dentry);
 
-   /* Look it up again */
-   parent = dget_parent(nd-path.dentry);
+   /* Look

[autofs] [PATCH 01/18] Add a dentry op to handle automounting rather than abusing follow_link()

2011-01-11 Thread David Howells
Add a dentry op (d_automount) to handle automounting directories rather than
abusing the follow_link() inode operation.  The operation is keyed off a new
inode flag (S_AUTOMOUNT).

This makes it easier to add an AT_ flag to suppress terminal segment automount
during pathwalk.  It should also remove the need for the kludge code in the
pathwalk algorithm to handle directories with follow_link() semantics.

A new pathwalk subroutine, follow_automount() is added to handle mountpoints.
It will return -EREMOTE if the S_AUTOMOUNT was set, but no d_automount() op was
supplied, -ELOOP if we've encountered too many symlinks or mountpoints, -EISDIR
if the walk point should be used without mounting and 0 if successful.  path
will be updated if an automount took place to point to the mounted filesystem.

I've only changed __follow_mount() to handle call follow_automount(), but it
might be necessary to change follow_mount() too.  The latter is only called
from follow_dotdot(), but any automounts on .. should be pinned whilst we're
using a child of it.

I've also extracted the mount/don't-mount logic from autofs4 and included it
here.  It makes the mount go ahead anyway if someone calls open() or creat(),
tries to traverse the directory, tries to chdir/chroot/etc. into the directory,
or sticks a '/' on the end of the pathname.  If they do a stat(), however,
they'll only trigger the automount if they didn't also say O_NOFOLLOW.

Signed-off-by: David Howells dhowe...@redhat.com
Acked-by: Ian Kent ra...@themaw.net
---

 Documentation/filesystems/Locking |2 +
 Documentation/filesystems/vfs.txt |   13 
 fs/namei.c|  120 -
 include/linux/dcache.h|4 +
 include/linux/fs.h|2 +
 5 files changed, 111 insertions(+), 30 deletions(-)

diff --git a/Documentation/filesystems/Locking 
b/Documentation/filesystems/Locking
index 977d891..7ebe42d 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -19,6 +19,7 @@ prototypes:
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen);
+   struct vfsmount *(*d_automount)(struct path *path);
 
 locking rules:
rename_lock -d_lockmay block   rcu-walk
@@ -29,6 +30,7 @@ d_delete: no  yes no  
no
 d_release: no  no  yes no
 d_iput:no  no  yes no
 d_dname:   no  no  no  no
+d_automount:   no  no  no  yes
 
 --- inode_operations --- 
 prototypes:
diff --git a/Documentation/filesystems/vfs.txt 
b/Documentation/filesystems/vfs.txt
index fbb324e..bb8d277 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -864,6 +864,7 @@ struct dentry_operations {
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
+   struct vfsmount *(*d_automount)(struct path *);
 };
 
   d_revalidate: called when the VFS needs to revalidate a dentry. This
@@ -930,6 +931,18 @@ struct dentry_operations {
at the end of the buffer, and returns a pointer to the first char.
dynamic_dname() helper function is provided to take care of this.
 
+  d_automount: called when an automount dentry is to be traversed (optional).
+   This should create a new VFS mount record, mount it on the directory
+   and return the record to the caller.  The caller is supplied with a
+   path parameter giving the automount directory to describe the automount
+   target and the parent VFS mount record to provide inheritable mount
+   parameters.  NULL should be returned if someone else managed to make
+   the automount first.  If the automount failed, then an error code
+   should be returned.
+
+   This function is only used if S_AUTOMOUNT is set on the inode to which
+   the dentry refers.
+
 Example :
 
 static char *pipefs_dname(struct dentry *dent, char *buffer, int buflen)
diff --git a/fs/namei.c b/fs/namei.c
index 24ece10..159da29 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -877,38 +877,84 @@ int follow_up(struct path *path)
 }
 
 /*
- * serialization is taken care of in namespace.c
+ * Perform an automount
+ * - return -EISDIR to tell __follow_mount() to stop and return the path we
+ *   were called with.
  */
-static void __follow_mount_rcu(struct nameidata *nd, struct path *path,
-   struct inode **inode)
+static int follow_automount(struct path *path, unsigned flags,
+   bool *need_mntput)
 {
-   while (d_mountpoint(path-dentry)) {
-   struct

[autofs] [PATCH 08/18] Make follow_down() handle d_manage()

2011-01-11 Thread David Howells
The previous patch (that adds d_manage()) offers autofs the opportunity to
block processes whilst it is rearranging its dentry tree, but only covers cases
where managed_dentry() is called.  Some places call follow_down(), which would
allow processes to bypass autofs's attempts to block them.

Make follow_down() handle managed dentries.  Do this by renaming follow_down()
to follow_down_one() and instituting a new follow_down().  follow_down_one() is
then only used where a call to d_manage() is not needed.

follow_down() then incorporates the loop from its remaining callers to follow
down through all mounted filesystems at that point.  Before each mountpoint is
transited and if requested by the filesystem, d_manage() is called to hold or
reject that transit.  The callers of follow_down() must then handle a possible
error condition.

follow_down() is given a parameter to say whether someone is trying to mount on
that point (and holding namespace_sem).  This is now passed on to d_manage().
The filesystem may reject this request by returning an error from d_manage().

Furthermore, d_manage() may end follow_down() processing early by returning
-EISDIR to indicate it wants the dentry to be dealt with as an ordinary
directory, not a mountpoint.  This permits autofs to let its daemon see the
underlying dentry.

Signed-off-by: David Howells dhowe...@redhat.com
Acked-by: Ian Kent ra...@themaw.net
---

 drivers/staging/autofs/dirhash.c |5 +--
 fs/autofs4/autofs_i.h|   13 -
 fs/autofs4/dev-ioctl.c   |2 +
 fs/autofs4/expire.c  |2 +
 fs/autofs4/root.c|   11 +++
 fs/namei.c   |   58 --
 fs/namespace.c   |   14 +
 fs/nfsd/vfs.c|5 ++-
 include/linux/dcache.h   |7 -
 include/linux/namei.h|3 +-
 10 files changed, 83 insertions(+), 37 deletions(-)

diff --git a/drivers/staging/autofs/dirhash.c b/drivers/staging/autofs/dirhash.c
index d3f42c8..a08bd73 100644
--- a/drivers/staging/autofs/dirhash.c
+++ b/drivers/staging/autofs/dirhash.c
@@ -88,14 +88,13 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb,
}
path.mnt = mnt;
path_get(path);
-   if (!follow_down(path)) {
+   if (!follow_down_one(path)) {
path_put(path);
DPRINTK((autofs: not expirable\
(not a mounted directory): %s\n, ent-name));
continue;
}
-   while (d_mountpoint(path.dentry)  follow_down(path))
-   ;
+   follow_down(path, false);  // TODO: need to check error
umount_ok = may_umount(path.mnt);
path_put(path);
 
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index 0fffe1c..eb67953 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -229,19 +229,6 @@ int autofs4_wait(struct autofs_sb_info *,struct dentry *, 
enum autofs_notify);
 int autofs4_wait_release(struct autofs_sb_info *,autofs_wqt_t,int);
 void autofs4_catatonic_mode(struct autofs_sb_info *);
 
-static inline int autofs4_follow_mount(struct path *path)
-{
-   int res = 0;
-
-   while (d_mountpoint(path-dentry)) {
-   int followed = follow_down(path);
-   if (!followed)
-   break;
-   res = 1;
-   }
-   return res;
-}
-
 static inline u32 autofs4_get_dev(struct autofs_sb_info *sbi)
 {
return new_encode_dev(sbi-sb-s_dev);
diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c
index eff9a41..1442da4 100644
--- a/fs/autofs4/dev-ioctl.c
+++ b/fs/autofs4/dev-ioctl.c
@@ -551,7 +551,7 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp,
 
err = have_submounts(path.dentry);
 
-   if (follow_down(path))
+   if (follow_down_one(path))
magic = path.mnt-mnt_sb-s_magic;
}
 
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index cc1d013..6a930b9 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -56,7 +56,7 @@ static int autofs4_mount_busy(struct vfsmount *mnt, struct 
dentry *dentry)
 
path_get(path);
 
-   if (!follow_down(path))
+   if (!follow_down_one(path))
goto done;
 
if (is_autofs4_dentry(path.dentry)) {
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 651e4ef..2022563 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -234,7 +234,7 @@ static void *autofs4_follow_link(struct dentry *dentry, 
struct nameidata *nd)
nd-flags);
/*
 * For an expire of a covered direct or offset mount we need
-* to break out of follow_down() at the autofs mount trigger
+* to break out of follow_down_one() at the autofs mount trigger
 * (d_mounted--), so

[autofs] [PATCH 02/18] AFS: Use d_automount() rather than abusing follow_link()

2011-01-11 Thread David Howells
Make AFS use the new d_automount() dentry operation rather than abusing
follow_link() on directories.

Signed-off-by: David Howells dhowe...@redhat.com
---

 fs/afs/dir.c  |1 +
 fs/afs/inode.c|3 ++-
 fs/afs/internal.h |1 +
 fs/afs/mntpt.c|   47 +++
 4 files changed, 19 insertions(+), 33 deletions(-)

diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 34a3263..70f07e3 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -66,6 +66,7 @@ static const struct dentry_operations 
afs_fs_dentry_operations = {
.d_revalidate   = afs_d_revalidate,
.d_delete   = afs_d_delete,
.d_release  = afs_d_release,
+   .d_automount= afs_d_automount,
 };
 
 #define AFS_DIR_HASHTBL_SIZE   128
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index 0747339..db66c52 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -184,7 +184,8 @@ struct inode *afs_iget_autocell(struct inode *dir, const 
char *dev_name,
inode-i_generation = 0;
 
set_bit(AFS_VNODE_PSEUDODIR, vnode-flags);
-   inode-i_flags |= S_NOATIME;
+   set_bit(AFS_VNODE_MOUNTPOINT, vnode-flags);
+   inode-i_flags |= S_AUTOMOUNT | S_NOATIME;
unlock_new_inode(inode);
_leave( = %p, inode);
return inode;
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 6d4bc1c..c59bb7c 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -590,6 +590,7 @@ extern const struct inode_operations 
afs_mntpt_inode_operations;
 extern const struct inode_operations afs_autocell_inode_operations;
 extern const struct file_operations afs_mntpt_file_operations;
 
+extern struct vfsmount *afs_d_automount(struct path *);
 extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *);
 extern void afs_mntpt_kill_timer(void);
 
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index 6153417..0f7dd7a 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -24,7 +24,6 @@ static struct dentry *afs_mntpt_lookup(struct inode *dir,
   struct dentry *dentry,
   struct nameidata *nd);
 static int afs_mntpt_open(struct inode *inode, struct file *file);
-static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata 
*nd);
 static void afs_mntpt_expiry_timed_out(struct work_struct *work);
 
 const struct file_operations afs_mntpt_file_operations = {
@@ -34,13 +33,11 @@ const struct file_operations afs_mntpt_file_operations = {
 
 const struct inode_operations afs_mntpt_inode_operations = {
.lookup = afs_mntpt_lookup,
-   .follow_link= afs_mntpt_follow_link,
.readlink   = page_readlink,
.getattr= afs_getattr,
 };
 
 const struct inode_operations afs_autocell_inode_operations = {
-   .follow_link= afs_mntpt_follow_link,
.getattr= afs_getattr,
 };
 
@@ -88,6 +85,7 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct 
key *key)
_debug(symlink is a mountpoint);
spin_lock(vnode-lock);
set_bit(AFS_VNODE_MOUNTPOINT, vnode-flags);
+   vnode-vfs_inode.i_flags |= S_AUTOMOUNT;
spin_unlock(vnode-lock);
}
 
@@ -238,52 +236,37 @@ error_no_devname:
 }
 
 /*
- * follow a link from a mountpoint directory, thus causing it to be mounted
+ * handle an automount point
  */
-static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd)
+struct vfsmount *afs_d_automount(struct path *path)
 {
struct vfsmount *newmnt;
int err;
 
-   _enter(%p{%s},{%s:%p{%s},},
-  dentry,
-  dentry-d_name.name,
-  nd-path.mnt-mnt_devname,
-  dentry,
-  nd-path.dentry-d_name.name);
-
-   dput(nd-path.dentry);
-   nd-path.dentry = dget(dentry);
+   _enter({%s,%s}, path-mnt-mnt_devname, path-dentry-d_name.name);
 
-   newmnt = afs_mntpt_do_automount(nd-path.dentry);
-   if (IS_ERR(newmnt)) {
-   path_put(nd-path);
-   return (void *)newmnt;
-   }
+   newmnt = afs_mntpt_do_automount(path-dentry);
+   if (IS_ERR(newmnt))
+   return newmnt;
 
mntget(newmnt);
-   err = do_add_mount(newmnt, nd-path, MNT_SHRINKABLE, afs_vfsmounts);
+   err = do_add_mount(newmnt, path, MNT_SHRINKABLE, afs_vfsmounts);
switch (err) {
case 0:
-   path_put(nd-path);
-   nd-path.mnt = newmnt;
-   nd-path.dentry = dget(newmnt-mnt_root);
schedule_delayed_work(afs_mntpt_expiry_timer,
  afs_mntpt_expiry_timeout * HZ);
-   break;
+   _leave( = %p {%s}, newmnt, newmnt-mnt_devname);
+   return newmnt;
case -EBUSY:
/* someone else made a mount here whilst we were busy */
-   while (d_mountpoint(nd-path.dentry) 
-  follow_down

[autofs] [PATCH 13/18] autofs4: Clean up dentry operations

2011-01-11 Thread David Howells
From: Ian Kent ra...@themaw.net

There are now two distinct dentry operations uses. One for dentrys
that trigger mounts and one for dentrys that do not.

Rationalize the use of these dentry operations and rename them to
reflect their function.

Signed-off-by: Ian Kent ra...@themaw.net
Signed-off-by: David Howells dhowe...@redhat.com
---

 fs/autofs4/autofs_i.h |7 ++-
 fs/autofs4/inode.c|   12 
 fs/autofs4/root.c |   36 
 3 files changed, 26 insertions(+), 29 deletions(-)

diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index c3b0afe..c28085c 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -206,11 +206,8 @@ extern const struct inode_operations 
autofs4_symlink_inode_operations;
 extern const struct inode_operations autofs4_dir_inode_operations;
 extern const struct file_operations autofs4_dir_operations;
 extern const struct file_operations autofs4_root_operations;
-
-/* Operations methods */
-
-struct vfsmount *autofs4_d_automount(struct path *);
-int autofs4_d_manage(struct path *, bool);
+extern const struct dentry_operations autofs4_dentry_operations;
+extern const struct dentry_operations autofs4_mount_dentry_operations;
 
 /* VFS automount flags management functions */
 
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index dac3dc7..427c357 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -251,12 +251,6 @@ static struct autofs_info *autofs4_mkroot(struct 
autofs_sb_info *sbi)
return ino;
 }
 
-static const struct dentry_operations autofs4_sb_dentry_operations = {
-   .d_automount= autofs4_d_automount,
-   .d_manage   = autofs4_d_manage,
-   .d_release  = autofs4_dentry_release,
-};
-
 int autofs4_fill_super(struct super_block *s, void *data, int silent)
 {
struct inode * root_inode;
@@ -311,7 +305,7 @@ int autofs4_fill_super(struct super_block *s, void *data, 
int silent)
goto fail_iput;
pipe = NULL;
 
-   d_set_d_op(root, autofs4_sb_dentry_operations);
+   d_set_d_op(root, autofs4_dentry_operations);
root-d_fsdata = ino;
 
/* Can this call block? */
@@ -322,8 +316,10 @@ int autofs4_fill_super(struct super_block *s, void *data, 
int silent)
goto fail_dput;
}
 
-   if (autofs_type_trigger(sbi-type))
+   if (autofs_type_trigger(sbi-type)) {
+   d_set_d_op(root, autofs4_mount_dentry_operations);
__managed_dentry_set_managed(root);
+   }
 
root_inode-i_fop = autofs4_root_operations;
root_inode-i_op = autofs4_dir_inode_operations;
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index ab391d4..b3ab9e9 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -35,6 +35,8 @@ static long autofs4_root_compat_ioctl(struct file *,unsigned 
int,unsigned long);
 #endif
 static int autofs4_dir_open(struct inode *inode, struct file *file);
 static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct 
nameidata *);
+static struct vfsmount *autofs4_d_automount(struct path *);
+static int autofs4_d_manage(struct path *, bool);
 
 const struct file_operations autofs4_root_operations = {
.open   = dcache_dir_open,
@@ -64,6 +66,18 @@ const struct inode_operations autofs4_dir_inode_operations = 
{
.rmdir  = autofs4_dir_rmdir,
 };
 
+/* For dentries that don't initiate mounting */
+const struct dentry_operations autofs4_dentry_operations = {
+   .d_release  = autofs4_dentry_release,
+};
+
+/* For dentries that do initiate mounting */
+const struct dentry_operations autofs4_mount_dentry_operations = {
+   .d_automount= autofs4_d_automount,
+   .d_manage   = autofs4_d_manage,
+   .d_release  = autofs4_dentry_release,
+};
+
 static void autofs4_add_active(struct dentry *dentry)
 {
struct autofs_sb_info *sbi = autofs4_sbi(dentry-d_sb);
@@ -158,18 +172,6 @@ void autofs4_dentry_release(struct dentry *de)
}
 }
 
-/* For dentries of directories in the root dir */
-static const struct dentry_operations autofs4_root_dentry_operations = {
-   .d_release  = autofs4_dentry_release,
-};
-
-/* For other dentries */
-static const struct dentry_operations autofs4_dentry_operations = {
-   .d_automount= autofs4_d_automount,
-   .d_manage   = autofs4_d_manage,
-   .d_release  = autofs4_dentry_release,
-};
-
 static struct dentry *autofs4_lookup_active(struct dentry *dentry)
 {
struct autofs_sb_info *sbi = autofs4_sbi(dentry-d_sb);
@@ -337,7 +339,7 @@ static struct dentry *autofs4_mountpoint_changed(struct 
path *path)
return path-dentry;
 }
 
-struct vfsmount *autofs4_d_automount(struct path *path)
+static struct vfsmount *autofs4_d_automount(struct path *path)
 {
struct dentry *dentry = path-dentry;
struct autofs_sb_info *sbi = autofs4_sbi(dentry-d_sb);
@@ -506,7 +508,7 @@ static struct dentry *autofs4_lookup

[autofs] [PATCH 07/18] Add more dentry flags for special function directories

2011-01-11 Thread David Howells
Add more flags to the d_flags in struct dentry for special function directories
such as mountpoints and autofs substructures.  The relevant flags are:

 (*) DCACHE_MOUNTED.

 (Already exists).  Indicates that this dentry has things mounted upon it.

 (*) DCACHE_NEED_AUTOMOUNT.

 This is a reflection of the S_AUTOMOUNT inode flag.  This is reflected by
 d_set_d_op().  follow_automount() is now keyed off of this rather than
 being keyed off S_AUTOMOUNT directly.  Possibly S_AUTOMOUNT should shift
 to the dentry entirely.

 This may also be tweaked live (such as by the autofs4 filesystem) to alter
 the effect.

 (*) DCACHE_MANAGE_TRANSIT.

 This is an indicator that the filesystem that owns the dentry wants to
 manage processes transiting away from that dentry.  If this is set on a
 dentry, then a new dentry op:

int (*d_manage)(struct path *);

 is invoked.  This is allowed to sleep and is allowed to return an error.

 This allows autofs to hold non-Oz-mode processes here without any
 filesystem locks being held.

__follow_mount() is replaced by managed_dentry() which now handles transit to a
mountpoint's root dentry, automount points and points that the filesystem wants
to manage.


==
WHAT THIS MEANS FOR AUTOFS
==

autofs currently uses the lookup() inode op and the d_revalidate() dentry op to
trigger the automounting of indirect mounts, and both of these can be called
with i_mutex held.

autofs knows that the i_mutex will be held by the caller in lookup(), and so
can drop it before invoking the daemon - but this isn't so for d_revalidate(),
since the lock is only held on _some_ of the code paths that call it.  This
means that autofs can't risk dropping i_mutex from its d_revalidate() function
before it calls the daemon.

The bug could manifest itself as, for example, a process that's trying to
validate an automount dentry that gets made to wait because that dentry is
expired and needs cleaning up:

mkdir S 8014e05a 0 32580  24956
Call Trace:
 [885371fd] :autofs4:autofs4_wait+0x674/0x897
 [80127f7d] avc_has_perm+0x46/0x58
 [8009fdcf] autoremove_wake_function+0x0/0x2e
 [88537be6] :autofs4:autofs4_expire_wait+0x41/0x6b
 [88535cfc] :autofs4:autofs4_revalidate+0x91/0x149
 [80036d96] __lookup_hash+0xa0/0x12f
 [80057a2f] lookup_create+0x46/0x80
 [800e6e31] sys_mkdirat+0x56/0xe4

versus the automount daemon which wants to remove that dentry, but can't
because the normal process is holding the i_mutex lock:

automount D 8014e05a 0 32581  1  32561
Call Trace:
 [80063c3f] __mutex_lock_slowpath+0x60/0x9b
 [8000ccf1] do_path_lookup+0x2ca/0x2f1
 [80063c89] .text.lock.mutex+0xf/0x14
 [800e6d55] do_rmdir+0x77/0xde
 [8005d229] tracesys+0x71/0xe0
 [8005d28d] tracesys+0xd5/0xe0

which means that the system is deadlocked.

This patch allows autofs to hold up normal processes whilst the daemon goes
ahead and does things to the dentry tree behind the automouter point without
risking a deadlock as no locks are held in d_manage() or d_automount().

Signed-off-by: David Howells dhowe...@redhat.com
Acked-by: Ian Kent ra...@themaw.net
---

 Documentation/filesystems/vfs.txt |   13 +++
 fs/dcache.c   |2 
 fs/namei.c|  153 ++---
 include/linux/dcache.h|   13 ++-
 4 files changed, 130 insertions(+), 51 deletions(-)

diff --git a/Documentation/filesystems/vfs.txt 
b/Documentation/filesystems/vfs.txt
index bb8d277..99f0127 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -865,6 +865,7 @@ struct dentry_operations {
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
struct vfsmount *(*d_automount)(struct path *);
+   int (*d_manage)(struct path *);
 };
 
   d_revalidate: called when the VFS needs to revalidate a dentry. This
@@ -940,8 +941,16 @@ struct dentry_operations {
the automount first.  If the automount failed, then an error code
should be returned.
 
-   This function is only used if S_AUTOMOUNT is set on the inode to which
-   the dentry refers.
+   This function is only used if DMANAGED_AUTOMOUNT is set on the dentry.
+   This is set by d_add() if S_AUTOMOUNT is set on the inode being added.
+
+  d_manage: called to allow the filesystem to manage the transition from a
+   dentry (optional).  This allows autofs, for example, to hold up clients
+   waiting to explore behind a 'mountpoint', whilst letting the daemon go
+   past and construct the subtree

[autofs] [PATCH 05/18] Remove the automount through follow_link() kludge code from pathwalk

2011-01-11 Thread David Howells
Remove the automount through follow_link() kludge code from pathwalk in favour
of using d_automount().

Signed-off-by: David Howells dhowe...@redhat.com
Acked-by: Ian Kent ra...@themaw.net
---

 fs/namei.c |   17 +++--
 1 files changed, 3 insertions(+), 14 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index 159da29..dfafb97 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1193,17 +1193,6 @@ fail:
 }
 
 /*
- * This is a temporary kludge to deal with automount symlinks; proper
- * solution is to trigger them on follow_mount(), so that do_lookup()
- * would DTRT.  To be killed before 2.6.34-final.
- */
-static inline int follow_on_final(struct inode *inode, unsigned lookup_flags)
-{
-   return inode  unlikely(inode-i_op-follow_link) 
-   ((lookup_flags  LOOKUP_FOLLOW) || S_ISDIR(inode-i_mode));
-}
-
-/*
  * Name resolution.
  * This is the basic name resolution function, turning a pathname into
  * the final dentry. We expect 'base' to be positive and a directory.
@@ -1341,7 +1330,8 @@ last_component:
err = do_lookup(nd, this, next, inode);
if (err)
break;
-   if (follow_on_final(inode, lookup_flags)) {
+   if (inode  unlikely(inode-i_op-follow_link) 
+   (lookup_flags  LOOKUP_FOLLOW)) {
if (nameidata_dentry_drop_rcu_maybe(nd, next.dentry))
return -ECHILD;
BUG_ON(inode != next.dentry-d_inode);
@@ -2390,8 +2380,7 @@ reval:
struct path holder;
void *cookie;
error = -ELOOP;
-   /* S_ISDIR part is a temporary automount kludge */
-   if (!(nd.flags  LOOKUP_FOLLOW)  !S_ISDIR(nd.inode-i_mode))
+   if (!(nd.flags  LOOKUP_FOLLOW))
goto exit_dput;
if (count++ == 32)
goto exit_dput;

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH 04/18] CIFS: Use d_automount() rather than abusing follow_link()

2011-01-11 Thread David Howells
Make CIFS use the new d_automount() dentry operation rather than abusing
follow_link() on directories.

[NOTE: THIS IS UNTESTED!]

Signed-off-by: David Howells dhowe...@redhat.com
Cc: Steve French sfre...@samba.org
---

 fs/cifs/cifs_dfs_ref.c |  134 
 fs/cifs/cifsfs.h   |6 ++
 fs/cifs/dir.c  |2 +
 fs/cifs/inode.c|8 ++-
 4 files changed, 80 insertions(+), 70 deletions(-)

diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
index c68a056..ddd0b3e 100644
--- a/fs/cifs/cifs_dfs_ref.c
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -255,35 +255,6 @@ static struct vfsmount *cifs_dfs_do_refmount(struct 
cifs_sb_info *cifs_sb,
 
 }
 
-static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd,
-   struct list_head *mntlist)
-{
-   /* stolen from afs code */
-   int err;
-
-   mntget(newmnt);
-   err = do_add_mount(newmnt, nd-path, nd-path.mnt-mnt_flags | 
MNT_SHRINKABLE, mntlist);
-   switch (err) {
-   case 0:
-   path_put(nd-path);
-   nd-path.mnt = newmnt;
-   nd-path.dentry = dget(newmnt-mnt_root);
-   schedule_delayed_work(cifs_dfs_automount_task,
- cifs_dfs_mountpoint_expiry_timeout);
-   break;
-   case -EBUSY:
-   /* someone else made a mount here whilst we were busy */
-   while (d_mountpoint(nd-path.dentry) 
-  follow_down(nd-path))
-   ;
-   err = 0;
-   default:
-   mntput(newmnt);
-   break;
-   }
-   return err;
-}
-
 static void dump_referral(const struct dfs_info3_param *ref)
 {
cFYI(1, DFS: ref path: %s, ref-path_name);
@@ -293,45 +264,43 @@ static void dump_referral(const struct dfs_info3_param 
*ref)
ref-path_consumed);
 }
 
-
-static void*
-cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
+/*
+ * Create a vfsmount that we can automount
+ */
+static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
 {
struct dfs_info3_param *referrals = NULL;
unsigned int num_referrals = 0;
struct cifs_sb_info *cifs_sb;
struct cifsSesInfo *ses;
-   char *full_path = NULL;
+   char *full_path;
int xid, i;
-   int rc = 0;
-   struct vfsmount *mnt = ERR_PTR(-ENOENT);
+   int rc;
+   struct vfsmount *mnt;
struct tcon_link *tlink;
 
cFYI(1, in %s, __func__);
-   BUG_ON(IS_ROOT(dentry));
+   BUG_ON(IS_ROOT(mntpt));
 
xid = GetXid();
 
-   dput(nd-path.dentry);
-   nd-path.dentry = dget(dentry);
-
/*
 * The MSDFS spec states that paths in DFS referral requests and
 * responses must be prefixed by a single '\' character instead of
 * the double backslashes usually used in the UNC. This function
 * gives us the latter, so we must adjust the result.
 */
-   full_path = build_path_from_dentry(dentry);
-   if (full_path == NULL) {
-   rc = -ENOMEM;
-   goto out_err;
-   }
+   mnt = ERR_PTR(-ENOMEM);
+   full_path = build_path_from_dentry(mntpt);
+   if (full_path == NULL)
+   goto free_xid;
 
-   cifs_sb = CIFS_SB(dentry-d_inode-i_sb);
+   cifs_sb = CIFS_SB(mntpt-d_inode-i_sb);
tlink = cifs_sb_tlink(cifs_sb);
+   mnt = ERR_PTR(-EINVAL);
if (IS_ERR(tlink)) {
-   rc = PTR_ERR(tlink);
-   goto out_err;
+   mnt = ERR_CAST(tlink);
+   goto free_full_path;
}
ses = tlink_tcon(tlink)-ses;
 
@@ -341,46 +310,77 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct 
nameidata *nd)
 
cifs_put_tlink(tlink);
 
+   mnt = ERR_PTR(-ENOENT);
for (i = 0; i  num_referrals; i++) {
int len;
-   dump_referral(referrals+i);
+   dump_referral(referrals + i);
/* connect to a node */
len = strlen(referrals[i].node_name);
if (len  2) {
cERROR(1, %s: Net Address path too short: %s,
__func__, referrals[i].node_name);
-   rc = -EINVAL;
-   goto out_err;
+   mnt = ERR_PTR(-EINVAL);
+   break;
}
mnt = cifs_dfs_do_refmount(cifs_sb,
full_path, referrals + i);
cFYI(1, %s: cifs_dfs_do_refmount:%s , mnt:%p, __func__,
referrals[i].node_name, mnt);
-
-   /* complete mount procedure if we accured submount */
if (!IS_ERR(mnt))
-   break;
+   goto success;
}
 
-   /* we need it cause for() above

Re: [autofs] [PATCH 00/17] Introduce automounter dentry ops

2010-10-04 Thread David Howells
Stef Bon stef...@gmail.com wrote:

 As I understand it, it gives a framework to allow the fs (cifs, nfs
 afs) do sub-auto-mounting right?

I suppose.  Is there a difference between automounting and sub-automounting?
:-)

David

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH 08/17] Make follow_down() handle d_manage()

2010-09-30 Thread David Howells
The previous patch (that adds d_manage()) offers autofs the opportunity to
block processes whilst it is rearranging its dentry tree, but only covers cases
where managed_dentry() is called.  Some places call follow_down(), which would
allow processes to bypass autofs's attempts to block them.

Make follow_down() handle managed dentries.  Do this by renaming follow_down()
to follow_down_one() and instituting a new follow_down().  follow_down_one() is
then only used where a call to d_manage() is not needed.

follow_down() then incorporates the loop from its remaining callers to follow
down through all mounted filesystems at that point.  Before each mountpoint is
transited and if requested by the filesystem, d_manage() is called to hold or
reject that transit.  The callers of follow_down() must then handle a possible
error condition.

follow_down() is given a parameter to say whether someone is trying to mount on
that point (and holding namespace_sem).  This is now passed on to d_manage().
The filesystem may reject this request by returning an error from d_manage().

Furthermore, d_manage() may end follow_down() processing early by returning
-EISDIR to indicate it wants the dentry to be dealt with as an ordinary
directory, not a mountpoint.  This permits autofs to let its daemon see the
underlying dentry.

Signed-off-by: David Howells dhowe...@redhat.com
Acked-by: Ian Kent ra...@themaw.net
---

 fs/autofs/dirhash.c|5 ++--
 fs/autofs4/autofs_i.h  |   13 ---
 fs/autofs4/dev-ioctl.c |2 +-
 fs/autofs4/expire.c|2 +-
 fs/autofs4/root.c  |   11 -
 fs/namei.c |   57 +---
 fs/namespace.c |   14 +++-
 fs/nfsd/vfs.c  |5 +++-
 include/linux/dcache.h |7 +-
 include/linux/namei.h  |3 ++-
 10 files changed, 82 insertions(+), 37 deletions(-)

diff --git a/fs/autofs/dirhash.c b/fs/autofs/dirhash.c
index e947915..a24092c 100644
--- a/fs/autofs/dirhash.c
+++ b/fs/autofs/dirhash.c
@@ -85,13 +85,12 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb,
}
path.mnt = mnt;
path_get(path);
-   if (!follow_down(path)) {
+   if (!follow_down_one(path)) {
path_put(path);
DPRINTK((autofs: not expirable (not a mounted 
directory): %s\n, ent-name));
continue;
}
-   while (d_mountpoint(path.dentry)  follow_down(path))
-   ;
+   follow_down(path, false);  // TODO: need to check error
umount_ok = may_umount(path.mnt);
path_put(path);
 
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index 3d283ab..08af160 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -226,19 +226,6 @@ int autofs4_wait(struct autofs_sb_info *,struct dentry *, 
enum autofs_notify);
 int autofs4_wait_release(struct autofs_sb_info *,autofs_wqt_t,int);
 void autofs4_catatonic_mode(struct autofs_sb_info *);
 
-static inline int autofs4_follow_mount(struct path *path)
-{
-   int res = 0;
-
-   while (d_mountpoint(path-dentry)) {
-   int followed = follow_down(path);
-   if (!followed)
-   break;
-   res = 1;
-   }
-   return res;
-}
-
 static inline u32 autofs4_get_dev(struct autofs_sb_info *sbi)
 {
return new_encode_dev(sbi-sb-s_dev);
diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c
index ba4a38b..8567abc 100644
--- a/fs/autofs4/dev-ioctl.c
+++ b/fs/autofs4/dev-ioctl.c
@@ -551,7 +551,7 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp,
 
err = have_submounts(path.dentry);
 
-   if (follow_down(path))
+   if (follow_down_one(path))
magic = path.mnt-mnt_sb-s_magic;
}
 
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index 9f5bde2..47feba9 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -56,7 +56,7 @@ static int autofs4_mount_busy(struct vfsmount *mnt, struct 
dentry *dentry)
 
path_get(path);
 
-   if (!follow_down(path))
+   if (!follow_down_one(path))
goto done;
 
if (is_autofs4_dentry(path.dentry)) {
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index cb1bd38..7dd218b 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -227,7 +227,7 @@ static void *autofs4_follow_link(struct dentry *dentry, 
struct nameidata *nd)
nd-flags);
/*
 * For an expire of a covered direct or offset mount we need
-* to break out of follow_down() at the autofs mount trigger
+* to break out of follow_down_one() at the autofs mount trigger
 * (d_mounted--), so we can see the expiring flag, and manage
 * the blocking and following here until the expire is completed.
 */
@@ -236,7 +236,7

[autofs] [PATCH 12/17] autofs4: cleanup inode operations

2010-09-30 Thread David Howells
From: Ian Kent ra...@themaw.net

Since the use of -follow_link() has been eliminated there is no
need to separate the indirect and direct inode operations.

Signed-off-by: Ian Kent ra...@themaw.net
Signed-off-by: David Howells dhowe...@redhat.com
---

 fs/autofs4/autofs_i.h |3 ---
 fs/autofs4/inode.c|4 +---
 fs/autofs4/root.c |   15 ---
 3 files changed, 1 insertions(+), 21 deletions(-)

diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index cb86036..8710878 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -201,9 +201,6 @@ void autofs_dev_ioctl_exit(void);
 
 extern const struct inode_operations autofs4_symlink_inode_operations;
 extern const struct inode_operations autofs4_dir_inode_operations;
-extern const struct inode_operations autofs4_root_inode_operations;
-extern const struct inode_operations autofs4_indirect_root_inode_operations;
-extern const struct inode_operations autofs4_direct_root_inode_operations;
 extern const struct file_operations autofs4_dir_operations;
 extern const struct file_operations autofs4_root_operations;
 
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index c6e75b3..80cdffd 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -326,9 +326,7 @@ int autofs4_fill_super(struct super_block *s, void *data, 
int silent)
__managed_dentry_set_managed(root);
 
root_inode-i_fop = autofs4_root_operations;
-   root_inode-i_op = autofs_type_trigger(sbi-type) ?
-   autofs4_direct_root_inode_operations :
-   autofs4_indirect_root_inode_operations;
+   root_inode-i_op = autofs4_dir_inode_operations;
 
/* Couldn't this be tested earlier? */
if (sbi-max_proto  AUTOFS_MIN_PROTO_VERSION ||
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 77257dd..2856a0c 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -52,21 +52,6 @@ const struct file_operations autofs4_dir_operations = {
.llseek = dcache_dir_lseek,
 };
 
-const struct inode_operations autofs4_indirect_root_inode_operations = {
-   .lookup = autofs4_lookup,
-   .unlink = autofs4_dir_unlink,
-   .symlink= autofs4_dir_symlink,
-   .mkdir  = autofs4_dir_mkdir,
-   .rmdir  = autofs4_dir_rmdir,
-};
-
-const struct inode_operations autofs4_direct_root_inode_operations = {
-   .lookup = autofs4_lookup,
-   .unlink = autofs4_dir_unlink,
-   .mkdir  = autofs4_dir_mkdir,
-   .rmdir  = autofs4_dir_rmdir,
-};
-
 const struct inode_operations autofs4_dir_inode_operations = {
.lookup = autofs4_lookup,
.unlink = autofs4_dir_unlink,

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH 07/17] Make dentry::d_mounted into a more general field for special function dirs

2010-09-30 Thread David Howells
Make the d_mounted field in struct dentry into a more general field for special
function directories such as mountpoints and autofs substructures.

d_mounted is renamed d_managed, and that is split into three fields:

 (*) #define DMANAGED_MOUNTPOINT0x0fff

 This is the mounted-on-this-dentry count as per d_mounted.

 (*) #define DMANAGED_AUTOMOUNT 0x1000

 This is a reflection of the S_AUTOMOUNT inode flag.  This is reflected by
 __d_instantiate().  follow_automount() is now keyed off of this rather
 than being keyed off S_AUTOMOUNT directly.  Possibly S_AUTOMOUNT should
 shift to the dentry entirely.

 (*) #define DMANAGED_TRANSIT   0x2000

 This is an indicator that the filesystem that owns the dentry wants to
 manage processes transiting away from that dentry.  If this is set on a
 dentry, then a new dentry op:

int (*d_manage)(struct path *);

 is invoked.  This is allowed to sleep and is allowed to return an error.

 This allows autofs to hold non-Oz-mode processes here without any
 filesystem locks being held.

Since d_managed is just an integer, all three fields can be tested in one go,
reducing the amount of intrusion into the normal path.  __follow_mount() is
replaced by managed_dentry() which now handles transit to a mountpoint's root
dentry, automount points and points that the filesystem wants to manage.


==
WHAT THIS MEANS FOR AUTOFS
==

autofs currently uses the lookup() inode op and the d_revalidate() dentry op to
trigger the automounting of indirect mounts, and both of these can be called
with i_mutex held.

autofs knows that the i_mutex will be held by the caller in lookup(), and so
can drop it before invoking the daemon - but this isn't so for d_revalidate(),
since the lock is only held on _some_ of the code paths that call it.  This
means that autofs can't risk dropping i_mutex from its d_revalidate() function
before it calls the daemon.

The bug could manifest itself as, for example, a process that's trying to
validate an automount dentry that gets made to wait because that dentry is
expired and needs cleaning up:

mkdir S 8014e05a 0 32580  24956
Call Trace:
 [885371fd] :autofs4:autofs4_wait+0x674/0x897
 [80127f7d] avc_has_perm+0x46/0x58
 [8009fdcf] autoremove_wake_function+0x0/0x2e
 [88537be6] :autofs4:autofs4_expire_wait+0x41/0x6b
 [88535cfc] :autofs4:autofs4_revalidate+0x91/0x149
 [80036d96] __lookup_hash+0xa0/0x12f
 [80057a2f] lookup_create+0x46/0x80
 [800e6e31] sys_mkdirat+0x56/0xe4

versus the automount daemon which wants to remove that dentry, but can't
because the normal process is holding the i_mutex lock:

automount D 8014e05a 0 32581  1  32561
Call Trace:
 [80063c3f] __mutex_lock_slowpath+0x60/0x9b
 [8000ccf1] do_path_lookup+0x2ca/0x2f1
 [80063c89] .text.lock.mutex+0xf/0x14
 [800e6d55] do_rmdir+0x77/0xde
 [8005d229] tracesys+0x71/0xe0
 [8005d28d] tracesys+0xd5/0xe0

which means that the system is deadlocked.

This patch allows autofs to hold up normal processes whilst the daemon goes
ahead and does things to the dentry tree behind the automouter point without
risking a deadlock as no locks are held in d_manage() or d_automount().

Signed-off-by: David Howells dhowe...@redhat.com
Acked-by: Ian Kent ra...@themaw.net
---

 Documentation/filesystems/vfs.txt |   13 +++-
 fs/autofs4/expire.c   |4 +
 fs/dcache.c   |7 ++
 fs/namei.c|  118 +
 fs/namespace.c|6 +-
 include/linux/dcache.h|   15 +++--
 6 files changed, 110 insertions(+), 53 deletions(-)

diff --git a/Documentation/filesystems/vfs.txt 
b/Documentation/filesystems/vfs.txt
index ff4bf82..fc27e43 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -848,6 +848,7 @@ struct dentry_operations {
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
struct vfsmount *(*d_automount)(struct path *);
+   int (*d_manage)(struct path *);
 };
 
   d_revalidate: called when the VFS needs to revalidate a dentry. This
@@ -891,8 +892,16 @@ struct dentry_operations {
the automount first.  If the automount failed, then an error code
should be returned.
 
-   This function is only used if S_AUTOMOUNT is set on the inode to which
-   the dentry refers.
+   This function is only used if DMANAGED_AUTOMOUNT is set on the dentry.
+   This is set by d_add() if S_AUTOMOUNT is set on the inode being added.
+
+  d_manage: called to allow the filesystem

[autofs] [PATCH 14/17] autofs4: cleanup autofs4_free_ino()

2010-09-30 Thread David Howells
From: Ian Kent ra...@themaw.net

When this function is called the local reference count does't need to
be updated since the dentry is going away and dput definitely must
not be called here.

Also the autofs info struct field inode isn't used so remove it.

Signed-off-by: Ian Kent ra...@themaw.net
Signed-off-by: David Howells dhowe...@redhat.com
---

 fs/autofs4/inode.c |   13 -
 fs/autofs4/root.c  |9 -
 2 files changed, 0 insertions(+), 22 deletions(-)

diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 8eaa723..ebc6354 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -45,7 +45,6 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino,
 
if (!reinit) {
ino-flags = 0;
-   ino-inode = NULL;
ino-dentry = NULL;
ino-size = 0;
INIT_LIST_HEAD(ino-active);
@@ -76,19 +75,8 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino,
 
 void autofs4_free_ino(struct autofs_info *ino)
 {
-   struct autofs_info *p_ino;
-
if (ino-dentry) {
ino-dentry-d_fsdata = NULL;
-   if (ino-dentry-d_inode) {
-   struct dentry *parent = ino-dentry-d_parent;
-   if (atomic_dec_and_test(ino-count)) {
-   p_ino = autofs4_dentry_ino(parent);
-   if (p_ino  parent != ino-dentry)
-   atomic_dec(p_ino-count);
-   }
-   dput(ino-dentry);
-   }
ino-dentry = NULL;
}
if (ino-free)
@@ -390,7 +378,6 @@ struct inode *autofs4_get_inode(struct super_block *sb,
if (inode == NULL)
return NULL;
 
-   inf-inode = inode;
inode-i_mode = inf-mode;
if (sb-s_root) {
inode-i_uid = sb-s_root-d_inode-i_uid;
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index cb168ba..3b38794 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -144,11 +144,8 @@ void autofs4_dentry_release(struct dentry *de)
DPRINTK(releasing %p, de);
 
inf = autofs4_dentry_ino(de);
-   de-d_fsdata = NULL;
-
if (inf) {
struct autofs_sb_info *sbi = autofs4_sbi(de-d_sb);
-
if (sbi) {
spin_lock(sbi-lookup_lock);
if (!list_empty(inf-active))
@@ -157,10 +154,6 @@ void autofs4_dentry_release(struct dentry *de)
list_del(inf-expiring);
spin_unlock(sbi-lookup_lock);
}
-
-   inf-dentry = NULL;
-   inf-inode = NULL;
-
autofs4_free_ino(inf);
}
 }
@@ -582,7 +575,6 @@ static int autofs4_dir_symlink(struct inode *dir,
p_ino = autofs4_dentry_ino(dentry-d_parent);
if (p_ino  dentry-d_parent != dentry)
atomic_inc(p_ino-count);
-   ino-inode = inode;
 
ino-u.symlink = cp;
dir-i_mtime = CURRENT_TIME;
@@ -708,7 +700,6 @@ static int autofs4_dir_mkdir(struct inode *dir, struct 
dentry *dentry, int mode)
p_ino = autofs4_dentry_ino(dentry-d_parent);
if (p_ino  dentry-d_parent != dentry)
atomic_inc(p_ino-count);
-   ino-inode = inode;
inc_nlink(dir);
dir-i_mtime = CURRENT_TIME;
 

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH 15/17] autofs4 - fix wait validation

2010-09-30 Thread David Howells
From: Ian Kent ra...@themaw.net

It is possible for the check in wait.c:validate_request() to return
an incorrect result if the dentry that was mounted upon has changed
during the callback.

Signed-off-by: Ian Kent ra...@themaw.net
Signed-off-by: David Howells dhowe...@redhat.com
---

 fs/autofs4/waitq.c |   17 -
 1 files changed, 16 insertions(+), 1 deletions(-)

diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index 2341375..f3792ff 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -296,6 +296,9 @@ static int validate_request(struct autofs_wait_queue **wait,
 * completed while we waited on the mutex ...
 */
if (notify == NFY_MOUNT) {
+   struct dentry *new = NULL;
+   int valid = 1;
+
/*
 * If the dentry was successfully mounted while we slept
 * on the wait queue mutex we can return success. If it
@@ -303,8 +306,20 @@ static int validate_request(struct autofs_wait_queue 
**wait,
 * a multi-mount with no mount at it's base) we can
 * continue on and create a new request.
 */
+   if (!IS_ROOT(dentry)) {
+   if (dentry-d_inode  d_unhashed(dentry)) {
+   struct dentry *parent = dentry-d_parent;
+   new = d_lookup(parent, dentry-d_name);
+   if (new)
+   dentry = new;
+   }
+   }
if (have_submounts(dentry))
-   return 0;
+   valid = 0;
+
+   if (new)
+   dput(new);
+   return valid;
}
 
return 1;

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH 06/17] Add an AT_NO_AUTOMOUNT flag to suppress terminal automount

2010-09-30 Thread David Howells
Add an AT_NO_AUTOMOUNT flag to suppress terminal automounting of directories
with follow_link semantics.  This can be used by fstatat() users to permit the
gathering of attributes on an automount point and also prevent
mass-automounting of a directory of automount points by ls.

Signed-off-by: David Howells dhowe...@redhat.com
Acked-by: Ian Kent ra...@themaw.net
---

 fs/namei.c|6 ++
 fs/stat.c |4 +++-
 include/linux/fcntl.h |1 +
 include/linux/namei.h |2 ++
 4 files changed, 12 insertions(+), 1 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index 86421f9..74bce3a 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -625,6 +625,12 @@ static int follow_automount(struct path *path, unsigned 
flags,
if (!path-dentry-d_op || !path-dentry-d_op-d_automount)
return -EREMOTE;
 
+   /* We don't want to mount if someone supplied AT_NO_AUTOMOUNT
+* and this is the terminal part of the path.
+*/
+   if ((flags  LOOKUP_NO_AUTOMOUNT)  !(flags  LOOKUP_CONTINUE))
+   return -EXDEV; /* we actually want to stop here */
+
/* We want to mount if someone is trying to open/create a file of any
 * type under the mountpoint, wants to traverse through the mountpoint
 * or wants to open the mounted directory.
diff --git a/fs/stat.c b/fs/stat.c
index 12e90e2..d5c61cf 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -75,11 +75,13 @@ int vfs_fstatat(int dfd, const char __user *filename, 
struct kstat *stat,
int error = -EINVAL;
int lookup_flags = 0;
 
-   if ((flag  ~AT_SYMLINK_NOFOLLOW) != 0)
+   if ((flag  ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT)) != 0)
goto out;
 
if (!(flag  AT_SYMLINK_NOFOLLOW))
lookup_flags |= LOOKUP_FOLLOW;
+   if (flag  AT_NO_AUTOMOUNT)
+   lookup_flags |= LOOKUP_NO_AUTOMOUNT;
 
error = user_path_at(dfd, filename, lookup_flags, path);
if (error)
diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h
index afc00af..a562fa5 100644
--- a/include/linux/fcntl.h
+++ b/include/linux/fcntl.h
@@ -45,6 +45,7 @@
 #define AT_REMOVEDIR   0x200   /* Remove directory instead of
unlinking file.  */
 #define AT_SYMLINK_FOLLOW  0x400   /* Follow symbolic links.  */
+#define AT_NO_AUTOMOUNT0x800   /* Suppress terminal automount 
traversal */
 
 #ifdef __KERNEL__
 
diff --git a/include/linux/namei.h b/include/linux/namei.h
index 05b441d..1e1febf 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -43,12 +43,14 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, 
LAST_BIND};
  *  - internal there are more path components flag
  *  - locked when lookup done with dcache_lock held
  *  - dentry cache is untrusted; force a real lookup
+ *  - suppress terminal automount
  */
 #define LOOKUP_FOLLOW   1
 #define LOOKUP_DIRECTORY2
 #define LOOKUP_CONTINUE 4
 #define LOOKUP_PARENT  16
 #define LOOKUP_REVAL   64
+#define LOOKUP_NO_AUTOMOUNT128
 /*
  * Intent data
  */

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH 05/17] Remove the automount through follow_link() kludge code from pathwalk

2010-09-30 Thread David Howells
Remove the automount through follow_link() kludge code from pathwalk in favour
of using d_automount().

Signed-off-by: David Howells dhowe...@redhat.com
Acked-by: Ian Kent ra...@themaw.net
---

 fs/namei.c |   17 +++--
 1 files changed, 3 insertions(+), 14 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index c50b9d7..86421f9 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -861,17 +861,6 @@ fail:
 }
 
 /*
- * This is a temporary kludge to deal with automount symlinks; proper
- * solution is to trigger them on follow_mount(), so that do_lookup()
- * would DTRT.  To be killed before 2.6.34-final.
- */
-static inline int follow_on_final(struct inode *inode, unsigned lookup_flags)
-{
-   return inode  unlikely(inode-i_op-follow_link) 
-   ((lookup_flags  LOOKUP_FOLLOW) || S_ISDIR(inode-i_mode));
-}
-
-/*
  * Name resolution.
  * This is the basic name resolution function, turning a pathname into
  * the final dentry. We expect 'base' to be positive and a directory.
@@ -991,7 +980,8 @@ last_component:
if (err)
break;
inode = next.dentry-d_inode;
-   if (follow_on_final(inode, lookup_flags)) {
+   if (inode  unlikely(inode-i_op-follow_link) 
+   (lookup_flags  LOOKUP_FOLLOW)) {
err = do_follow_link(next, nd);
if (err)
goto return_err;
@@ -1882,8 +1872,7 @@ reval:
struct inode *inode = path.dentry-d_inode;
void *cookie;
error = -ELOOP;
-   /* S_ISDIR part is a temporary automount kludge */
-   if (!(nd.flags  LOOKUP_FOLLOW)  !S_ISDIR(inode-i_mode))
+   if (!(nd.flags  LOOKUP_FOLLOW))
goto exit_dput;
if (count++ == 32)
goto exit_dput;

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH 04/17] CIFS: Use d_automount() rather than abusing follow_link()

2010-09-30 Thread David Howells
Make CIFS use the new d_automount() dentry operation rather than abusing
follow_link() on directories.

[NOTE: THIS IS UNTESTED!]

[Question:  Why does cifs_dfs_do_refmount() when the caller has already done
that and could pass the result through?]

Signed-off-by: David Howells dhowe...@redhat.com
Cc: Steve French sfre...@samba.org
---

 fs/cifs/cifs_dfs_ref.c |  134 +++-
 fs/cifs/cifsfs.h   |6 ++
 fs/cifs/dir.c  |2 +
 fs/cifs/inode.c|8 ++-
 4 files changed, 78 insertions(+), 72 deletions(-)

diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
index d6ced7a..8fc4943 100644
--- a/fs/cifs/cifs_dfs_ref.c
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -256,35 +256,6 @@ static struct vfsmount *cifs_dfs_do_refmount(struct 
cifs_sb_info *cifs_sb,
 
 }
 
-static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd,
-   struct list_head *mntlist)
-{
-   /* stolen from afs code */
-   int err;
-
-   mntget(newmnt);
-   err = do_add_mount(newmnt, nd-path, nd-path.mnt-mnt_flags | 
MNT_SHRINKABLE, mntlist);
-   switch (err) {
-   case 0:
-   path_put(nd-path);
-   nd-path.mnt = newmnt;
-   nd-path.dentry = dget(newmnt-mnt_root);
-   schedule_delayed_work(cifs_dfs_automount_task,
- cifs_dfs_mountpoint_expiry_timeout);
-   break;
-   case -EBUSY:
-   /* someone else made a mount here whilst we were busy */
-   while (d_mountpoint(nd-path.dentry) 
-  follow_down(nd-path))
-   ;
-   err = 0;
-   default:
-   mntput(newmnt);
-   break;
-   }
-   return err;
-}
-
 static void dump_referral(const struct dfs_info3_param *ref)
 {
cFYI(1, DFS: ref path: %s, ref-path_name);
@@ -294,34 +265,30 @@ static void dump_referral(const struct dfs_info3_param 
*ref)
ref-path_consumed);
 }
 
-
-static void*
-cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
+/*
+ * Create a vfsmount that we can automount
+ */
+static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
 {
struct dfs_info3_param *referrals = NULL;
unsigned int num_referrals = 0;
struct cifs_sb_info *cifs_sb;
struct cifsSesInfo *ses;
-   char *full_path = NULL;
+   char *full_path;
int xid, i;
-   int rc = 0;
-   struct vfsmount *mnt = ERR_PTR(-ENOENT);
+   int rc;
+   struct vfsmount *mnt;
 
cFYI(1, in %s, __func__);
-   BUG_ON(IS_ROOT(dentry));
+   BUG_ON(IS_ROOT(mntpt));
 
xid = GetXid();
 
-   dput(nd-path.dentry);
-   nd-path.dentry = dget(dentry);
-
-   cifs_sb = CIFS_SB(dentry-d_inode-i_sb);
+   cifs_sb = CIFS_SB(mntpt-d_inode-i_sb);
+   mnt = ERR_PTR(-EINVAL);
ses = cifs_sb-tcon-ses;
-
-   if (!ses) {
-   rc = -EINVAL;
-   goto out_err;
-   }
+   if (!ses)
+   goto free_xid;
 
/*
 * The MSDFS spec states that paths in DFS referral requests and
@@ -329,56 +296,85 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct 
nameidata *nd)
 * the double backslashes usually used in the UNC. This function
 * gives us the latter, so we must adjust the result.
 */
-   full_path = build_path_from_dentry(dentry);
-   if (full_path == NULL) {
-   rc = -ENOMEM;
-   goto out_err;
-   }
+   mnt = ERR_PTR(-ENOMEM);
+   full_path = build_path_from_dentry(mntpt);
+   if (full_path == NULL)
+   goto free_xid;
 
rc = get_dfs_path(xid, ses , full_path + 1, cifs_sb-local_nls,
num_referrals, referrals,
cifs_sb-mnt_cifs_flags  CIFS_MOUNT_MAP_SPECIAL_CHR);
 
+   mnt = ERR_PTR(-ENOENT);
for (i = 0; i  num_referrals; i++) {
int len;
-   dump_referral(referrals+i);
+   dump_referral(referrals + i);
/* connect to a node */
len = strlen(referrals[i].node_name);
if (len  2) {
cERROR(1, %s: Net Address path too short: %s,
__func__, referrals[i].node_name);
-   rc = -EINVAL;
-   goto out_err;
+   mnt = ERR_PTR(-EINVAL);
+   break;
}
mnt = cifs_dfs_do_refmount(cifs_sb,
full_path, referrals + i);
cFYI(1, %s: cifs_dfs_do_refmount:%s , mnt:%p, __func__,
referrals[i].node_name, mnt);
-
-   /* complete mount procedure if we accured submount */
if (!IS_ERR(mnt))
-   break

[autofs] [PATCH 03/17] NFS: Use d_automount() rather than abusing follow_link()

2010-09-30 Thread David Howells
Make NFS use the new d_automount() dentry operation rather than abusing
follow_link() on directories.

Signed-off-by: David Howells dhowe...@redhat.com
Acked-by: Trond Myklebust trond.mykleb...@netapp.com
Acked-by: Ian Kent ra...@themaw.net
---

 fs/nfs/dir.c   |4 ++
 fs/nfs/inode.c |4 +-
 fs/nfs/internal.h  |1 +
 fs/nfs/namespace.c |   87 ++--
 include/linux/nfs_fs.h |1 -
 5 files changed, 46 insertions(+), 51 deletions(-)

diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index e257172..46f2e12 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -734,7 +734,7 @@ int nfs_lookup_verify_inode(struct inode *inode, struct 
nameidata *nd)
 {
struct nfs_server *server = NFS_SERVER(inode);
 
-   if (test_bit(NFS_INO_MOUNTPOINT, NFS_I(inode)-flags))
+   if (IS_AUTOMOUNT(inode))
return 0;
if (nd != NULL) {
/* VFS wants an on-the-wire revalidation */
@@ -934,6 +934,7 @@ const struct dentry_operations nfs_dentry_operations = {
.d_revalidate   = nfs_lookup_revalidate,
.d_delete   = nfs_dentry_delete,
.d_iput = nfs_dentry_iput,
+   .d_automount= nfs_d_automount,
 };
 
 static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, 
struct nameidata *nd)
@@ -1009,6 +1010,7 @@ const struct dentry_operations nfs4_dentry_operations = {
.d_revalidate   = nfs_open_revalidate,
.d_delete   = nfs_dentry_delete,
.d_iput = nfs_dentry_iput,
+   .d_automount= nfs_d_automount,
 };
 
 /*
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 7d2d6c7..d554949 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -302,7 +302,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct 
nfs_fattr *fattr)
else
inode-i_op = 
nfs_mountpoint_inode_operations;
inode-i_fop = NULL;
-   set_bit(NFS_INO_MOUNTPOINT, nfsi-flags);
+   inode-i_flags |= S_AUTOMOUNT;
}
} else if (S_ISLNK(inode-i_mode))
inode-i_op = nfs_symlink_inode_operations;
@@ -1205,7 +1205,7 @@ static int nfs_update_inode(struct inode *inode, struct 
nfs_fattr *fattr)
/* Update the fsid? */
if (S_ISDIR(inode-i_mode)  (fattr-valid  NFS_ATTR_FATTR_FSID) 
!nfs_fsid_equal(server-fsid, fattr-fsid) 
-   !test_bit(NFS_INO_MOUNTPOINT, nfsi-flags))
+   !IS_AUTOMOUNT(inode))
server-fsid = fattr-fsid;
 
/*
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index c961bc9..45b98e7 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -239,6 +239,7 @@ extern char *nfs_path(const char *base,
  const struct dentry *droot,
  const struct dentry *dentry,
  char *buffer, ssize_t buflen);
+extern struct vfsmount *nfs_d_automount(struct path *path);
 
 /* getroot.c */
 extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *);
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index db6aa36..bf80079 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -88,9 +88,8 @@ Elong:
 }
 
 /*
- * nfs_follow_mountpoint - handle crossing a mountpoint on the server
- * @dentry - dentry of mountpoint
- * @nd - nameidata info
+ * nfs_d_automount - Handle crossing a mountpoint on the server
+ * @path - The mountpoint
  *
  * When we encounter a mountpoint on the server, we want to set up
  * a mountpoint on the client too, to prevent inode numbers from
@@ -100,87 +99,81 @@ Elong:
  * situation, and that different filesystems may want to use
  * different security flavours.
  */
-static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata 
*nd)
+struct vfsmount *nfs_d_automount(struct path *path)
 {
struct vfsmount *mnt;
-   struct nfs_server *server = NFS_SERVER(dentry-d_inode);
+   struct nfs_server *server = NFS_SERVER(path-dentry-d_inode);
struct dentry *parent;
struct nfs_fh *fh = NULL;
struct nfs_fattr *fattr = NULL;
int err;
 
-   dprintk(-- nfs_follow_mountpoint()\n);
+   dprintk(-- nfs_d_automount()\n);
 
-   err = -ESTALE;
-   if (IS_ROOT(dentry))
-   goto out_err;
+   mnt = ERR_PTR(-ESTALE);
+   if (IS_ROOT(path-dentry))
+   goto out_nofree;
 
-   err = -ENOMEM;
+   mnt = ERR_PTR(-ENOMEM);
fh = nfs_alloc_fhandle();
fattr = nfs_alloc_fattr();
if (fh == NULL || fattr == NULL)
-   goto out_err;
+   goto out;
 
dprintk(%s: enter\n, __func__);
-   dput(nd-path.dentry);
-   nd-path.dentry = dget(dentry);
 
-   /* Look it up again */
-   parent = dget_parent(nd-path.dentry);
+   /* Look

[autofs] [PATCH 10/17] autofs4: add d_manage() dentry operation

2010-09-30 Thread David Howells
From: Ian Kent ra...@themaw.net

This patch required a previous patch to add the -d_automount()
dentry operation.

Add a function to use the newly defined -d_manage() dentry operation
for blocking during mount and expire.

Whether the VFS calls the dentry operations d_automount() and d_manage()
is controled by the DMANAGED_AUTOMOUNT and DMANAGED_TRANSIT flags. autofs
uses the d_automount() operation to callback to user space to request
mount operations and the d_manage() operation to block walks into mounts
that are under construction or destruction.

In order to prevent these functions from being called unnecessarily the
DMANAGED_* flags are cleared for cases which would cause this. In the
common case the DMANAGED_AUTOMOUNT and DMANAGED_TRANSIT flags are both
set for dentrys waiting to be mounted. The DMANAGED_TRANSIT flag is
cleared upon successful mount request completion and set during expire
runs, both during the dentry expire check, and if selected for expire,
is left set until a subsequent successful mount request completes.

The exception to this is the so-called rootless multi-mount which has
no actual mount at its base. In this case the DMANAGED_AUTOMOUNT flag
is cleared upon successful mount request completion as well and set
again after a successful expire.

Signed-off-by: Ian Kent ra...@themaw.net
Signed-off-by: David Howells dhowe...@redhat.com
---

 fs/autofs4/autofs_i.h |   50 -
 fs/autofs4/expire.c   |   42 +
 fs/autofs4/inode.c|3 +
 fs/autofs4/root.c |  100 +++--
 4 files changed, 164 insertions(+), 31 deletions(-)

diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index 079206c..48f8248 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -96,7 +96,6 @@ struct autofs_info {
 };
 
 #define AUTOFS_INF_EXPIRING(10) /* dentry is in the process of expiring 
*/
-#define AUTOFS_INF_MOUNTPOINT  (11) /* mountpoint status for direct expire */
 #define AUTOFS_INF_PENDING (12) /* dentry pending mount */
 
 struct autofs_wait_queue {
@@ -218,6 +217,7 @@ extern const struct file_operations autofs4_root_operations;
 /* Operations methods */
 
 struct vfsmount *autofs4_d_automount(struct path *);
+int autofs4_d_manage(struct path *, bool);
 
 /* VFS automount flags management functions */
 
@@ -245,6 +245,54 @@ static inline void managed_dentry_clear_automount(struct 
dentry *dentry)
spin_unlock(dentry-d_lock);
 }
 
+static inline void __managed_dentry_set_transit(struct dentry *dentry)
+{
+   dentry-d_managed |= DMANAGED_TRANSIT;
+}
+
+static inline void managed_dentry_set_transit(struct dentry *dentry)
+{
+   spin_lock(dentry-d_lock);
+   __managed_dentry_set_transit(dentry);
+   spin_unlock(dentry-d_lock);
+}
+
+static inline void __managed_dentry_clear_transit(struct dentry *dentry)
+{
+   dentry-d_managed = ~DMANAGED_TRANSIT;
+}
+
+static inline void managed_dentry_clear_transit(struct dentry *dentry)
+{
+   spin_lock(dentry-d_lock);
+   __managed_dentry_clear_transit(dentry);
+   spin_unlock(dentry-d_lock);
+}
+
+static inline void __managed_dentry_set_managed(struct dentry *dentry)
+{
+   dentry-d_managed |= (DMANAGED_AUTOMOUNT|DMANAGED_TRANSIT);
+}
+
+static inline void managed_dentry_set_managed(struct dentry *dentry)
+{
+   spin_lock(dentry-d_lock);
+   __managed_dentry_set_managed(dentry);
+   spin_unlock(dentry-d_lock);
+}
+
+static inline void __managed_dentry_clear_managed(struct dentry *dentry)
+{
+   dentry-d_managed = ~(DMANAGED_AUTOMOUNT|DMANAGED_TRANSIT);
+}
+
+static inline void managed_dentry_clear_managed(struct dentry *dentry)
+{
+   spin_lock(dentry-d_lock);
+   __managed_dentry_clear_managed(dentry);
+   spin_unlock(dentry-d_lock);
+}
+
 /* Initializing function */
 
 int autofs4_fill_super(struct super_block *, void *, int);
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index c366dac..5901da5 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -26,10 +26,6 @@ static inline int autofs4_can_expire(struct dentry *dentry,
if (ino == NULL)
return 0;
 
-   /* No point expiring a pending mount */
-   if (ino-flags  AUTOFS_INF_PENDING)
-   return 0;
-
if (!do_now) {
/* Too young to die */
if (!timeout || time_after(ino-last_used + timeout, now))
@@ -264,6 +260,7 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
unsigned long timeout;
struct dentry *root = dget(sb-s_root);
int do_now = how  AUTOFS_EXP_IMMEDIATE;
+   struct autofs_info *ino;
 
if (!root)
return NULL;
@@ -272,18 +269,21 @@ struct dentry *autofs4_expire_direct(struct super_block 
*sb,
timeout = sbi-exp_timeout;
 
spin_lock(sbi-fs_lock);
+   ino = autofs4_dentry_ino(root);
+   /* No point expiring a pending mount */
+   if (ino

[autofs] [PATCH 13/17] autofs4: cleanup dentry operations

2010-09-30 Thread David Howells
From: Ian Kent ra...@themaw.net

There are now two distinct dentry operations uses. One for dentrys
that trigger mounts and one for dentrys that do not.

Rationalize the use of these dentry operations and rename them to
reflect their function.

Signed-off-by: Ian Kent ra...@themaw.net
Signed-off-by: David Howells dhowe...@redhat.com
---

 fs/autofs4/autofs_i.h |7 ++-
 fs/autofs4/inode.c|   12 
 fs/autofs4/root.c |   36 
 3 files changed, 26 insertions(+), 29 deletions(-)

diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index 8710878..8b1c0bc 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -203,11 +203,8 @@ extern const struct inode_operations 
autofs4_symlink_inode_operations;
 extern const struct inode_operations autofs4_dir_inode_operations;
 extern const struct file_operations autofs4_dir_operations;
 extern const struct file_operations autofs4_root_operations;
-
-/* Operations methods */
-
-struct vfsmount *autofs4_d_automount(struct path *);
-int autofs4_d_manage(struct path *, bool);
+extern const struct dentry_operations autofs4_dentry_operations;
+extern const struct dentry_operations autofs4_mount_dentry_operations;
 
 /* VFS automount flags management functions */
 
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 80cdffd..8eaa723 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -251,12 +251,6 @@ static struct autofs_info *autofs4_mkroot(struct 
autofs_sb_info *sbi)
return ino;
 }
 
-static const struct dentry_operations autofs4_sb_dentry_operations = {
-   .d_automount= autofs4_d_automount,
-   .d_manage   = autofs4_d_manage,
-   .d_release  = autofs4_dentry_release,
-};
-
 int autofs4_fill_super(struct super_block *s, void *data, int silent)
 {
struct inode * root_inode;
@@ -311,7 +305,7 @@ int autofs4_fill_super(struct super_block *s, void *data, 
int silent)
goto fail_iput;
pipe = NULL;
 
-   root-d_op = autofs4_sb_dentry_operations;
+   root-d_op = autofs4_dentry_operations;
root-d_fsdata = ino;
 
/* Can this call block? */
@@ -322,8 +316,10 @@ int autofs4_fill_super(struct super_block *s, void *data, 
int silent)
goto fail_dput;
}
 
-   if (autofs_type_trigger(sbi-type))
+   if (autofs_type_trigger(sbi-type)) {
+   root-d_op = autofs4_mount_dentry_operations;
__managed_dentry_set_managed(root);
+   }
 
root_inode-i_fop = autofs4_root_operations;
root_inode-i_op = autofs4_dir_inode_operations;
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 2856a0c..cb168ba 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -31,6 +31,8 @@ static long autofs4_root_ioctl(struct file *,unsigned 
int,unsigned long);
 static long autofs4_root_compat_ioctl(struct file *,unsigned int,unsigned 
long);
 static int autofs4_dir_open(struct inode *inode, struct file *file);
 static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct 
nameidata *);
+static struct vfsmount *autofs4_d_automount(struct path *);
+static int autofs4_d_manage(struct path *, bool);
 
 const struct file_operations autofs4_root_operations = {
.open   = dcache_dir_open,
@@ -60,6 +62,18 @@ const struct inode_operations autofs4_dir_inode_operations = 
{
.rmdir  = autofs4_dir_rmdir,
 };
 
+/* For dentries that don't initiate mounting */
+const struct dentry_operations autofs4_dentry_operations = {
+   .d_release  = autofs4_dentry_release,
+};
+
+/* For dentries that do initiate mounting */
+const struct dentry_operations autofs4_mount_dentry_operations = {
+   .d_automount= autofs4_d_automount,
+   .d_manage   = autofs4_d_manage,
+   .d_release  = autofs4_dentry_release,
+};
+
 static void autofs4_add_active(struct dentry *dentry)
 {
struct autofs_sb_info *sbi = autofs4_sbi(dentry-d_sb);
@@ -151,18 +165,6 @@ void autofs4_dentry_release(struct dentry *de)
}
 }
 
-/* For dentries of directories in the root dir */
-static const struct dentry_operations autofs4_root_dentry_operations = {
-   .d_release  = autofs4_dentry_release,
-};
-
-/* For other dentries */
-static const struct dentry_operations autofs4_dentry_operations = {
-   .d_automount= autofs4_d_automount,
-   .d_manage   = autofs4_d_manage,
-   .d_release  = autofs4_dentry_release,
-};
-
 static struct dentry *autofs4_lookup_active(struct dentry *dentry)
 {
struct autofs_sb_info *sbi = autofs4_sbi(dentry-d_sb);
@@ -330,7 +332,7 @@ static struct dentry *autofs4_mountpoint_changed(struct 
path *path)
return path-dentry;
 }
 
-struct vfsmount *autofs4_d_automount(struct path *path)
+static struct vfsmount *autofs4_d_automount(struct path *path)
 {
struct dentry *dentry = path-dentry;
struct autofs_sb_info *sbi = autofs4_sbi(dentry-d_sb

Re: [autofs] [PATCH 1/7] autofs4: Save autofs trigger's vfsmount in super block info

2010-01-15 Thread David Howells
Al Viro v...@zeniv.linux.org.uk wrote:

 AFS can't be arsed and just sets MNT_SHRINKABLE, all flags on parent be
 damned.

Why's that wrong?  This is AFS's automounter, and it seems quite reasonable to
have the outer edges pruned to make space.

David

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


Re: [autofs] [PATCH 1/7] autofs4: Save autofs trigger's vfsmount in super block info

2010-01-15 Thread David Howells
Al Viro v...@zeniv.linux.org.uk wrote:

 Do you want it to inerit e.g. nosuid?

Are you just talking about MNT_SHRINKABLE?  Or all the other flags?

Should I be passing:

nd-path.mnt-mnt_flags | MNT_SHRINKABLE

instead?

David

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH 16/59] CRED: Wrap task credential accesses in the autofs filesystem

2008-08-27 Thread David Howells
Wrap access to task credentials so that they can be separated more easily from
the task_struct during the introduction of COW creds.

Change most current-(|e|s|fs)[ug]id to current_(|e|s|fs)[ug]id().

Change some task-e?[ug]id to task_e?[ug]id().  In some places it makes more
sense to use RCU directly rather than a convenient wrapper; these will be
addressed by later patches.

Signed-off-by: David Howells [EMAIL PROTECTED]
Reviewed-by: James Morris [EMAIL PROTECTED]
Acked-by: Serge Hallyn [EMAIL PROTECTED]
Cc: H. Peter Anvin [EMAIL PROTECTED]
Cc: autofs@linux.kernel.org
---

 fs/autofs/inode.c |4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)


diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
index dda510d..61429c5 100644
--- a/fs/autofs/inode.c
+++ b/fs/autofs/inode.c
@@ -76,8 +76,8 @@ static int parse_options(char *options, int *pipefd, uid_t 
*uid, gid_t *gid,
substring_t args[MAX_OPT_ARGS];
int option;
 
-   *uid = current-uid;
-   *gid = current-gid;
+   *uid = current_uid();
+   *gid = current_gid();
*pgrp = task_pgrp_nr(current);
 
*minproto = *maxproto = AUTOFS_PROTO_VERSION;

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] [PATCH 17/59] CRED: Wrap task credential accesses in the autofs4 filesystem

2008-08-27 Thread David Howells
Wrap access to task credentials so that they can be separated more easily from
the task_struct during the introduction of COW creds.

Change most current-(|e|s|fs)[ug]id to current_(|e|s|fs)[ug]id().

Change some task-e?[ug]id to task_e?[ug]id().  In some places it makes more
sense to use RCU directly rather than a convenient wrapper; these will be
addressed by later patches.

Signed-off-by: David Howells [EMAIL PROTECTED]
Reviewed-by: James Morris [EMAIL PROTECTED]
Acked-by: Serge Hallyn [EMAIL PROTECTED]
Cc: Ian Kent [EMAIL PROTECTED]
Cc: autofs@linux.kernel.org
---

 fs/autofs4/inode.c |4 ++--
 fs/autofs4/waitq.c |4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)


diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 7bb3e5b..8c9cf24 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -233,8 +233,8 @@ static int parse_options(char *options, int *pipefd, uid_t 
*uid, gid_t *gid,
substring_t args[MAX_OPT_ARGS];
int option;
 
-   *uid = current-uid;
-   *gid = current-gid;
+   *uid = current_uid();
+   *gid = current_gid();
*pgrp = task_pgrp_nr(current);
 
*minproto = AUTOFS_MIN_PROTO_VERSION;
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index 35216d1..dc1fa39 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -391,8 +391,8 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry 
*dentry,
memcpy(wq-name, qstr, sizeof(struct qstr));
wq-dev = autofs4_get_dev(sbi);
wq-ino = autofs4_get_ino(sbi);
-   wq-uid = current-uid;
-   wq-gid = current-gid;
+   wq-uid = current_uid();
+   wq-gid = current_gid();
wq-pid = current-pid;
wq-tgid = current-tgid;
wq-status = -EINTR; /* Status return if interrupted */

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs


[autofs] Autofs vs shrink_dcache_for_umount() problem

2006-07-01 Thread David Howells
Andrew Morton [EMAIL PROTECTED] wrote:

 But why was yum (or an RPM script) dinking with loop and
 mounting/unmounting things?

It may have restarted the automounter... this may cause mounts and unmounts...

I've done a bit of probing, and when both ext3 and NFS go into the superblock
squidger with a tree that only has a root dentry, that root dentry has a usage
count of 1:

### Shrink root c629b088{1}
--shrink_dcache_for_umount_subtree(c629b088)
- AT c629b088{0}
  - consume c629b088{0}
### Shrunk


### Shrink root c621d710{1}
--shrink_dcache_for_umount_subtree(c621d710)
- AT c621d710{0}
  - consume c621d710{0}
### Shrunk

But when autofs4 goes in there with a minimal tree:

### Shrink root c6b714b0{2}
--shrink_dcache_for_umount_subtree(c6b714b0)
- AT c6b714b0{1}
  - consume c6b714b0{1}
BUG: Dentry c6b714b0{i=1a80,n=/} still in use (1) [unmount of autofs 
autofs]
[ cut here ]
kernel BUG at fs/dcache.c:618!

It's got a usage count of *2*.  That means the root dentry is still in use
somewhere beyond the superblock s_root reference.

I think this in autofs4_fill_super() is the problem:

/*
 * Take a reference to the root dentry so we get a chance to
 * clean up the dentry tree on umount.
 * See autofs4_force_release.
 */
sbi-root = dget(root);

autofs4 violates the assumptions that I was told I could make.  autofs4
expects to clean up its dentries in autofs4_put_super(), when it should
perhaps really be overloading the kill_sb() op and doing it before calling
kill_anon_super().

I've attached the pair of debugging patches I used to generate the above.

David


diff --git a/fs/dcache.c b/fs/dcache.c
index 4fddd12..ae041da 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -597,7 +597,20 @@ static void shrink_dcache_for_umount_sub
do {
struct inode *inode;
 
-   BUG_ON(atomic_read(dentry-d_count) != 0);
+   if (atomic_read(dentry-d_count) != 0) {
+   printk(KERN_ERR
+  BUG: Dentry %p{i=%lx,n=%s}
+   still in use (%d)
+   [unmount of %s %s]\n,
+  dentry,
+  dentry-d_inode ?
+  dentry-d_inode-i_ino : 0UL,
+  dentry-d_name.name,
+  atomic_read(dentry-d_count),
+  dentry-d_sb-s_type-name,
+  dentry-d_sb-s_id);
+   BUG();
+   }
 
parent = dentry-d_parent;
if (parent == dentry)


diff --git a/fs/dcache.c b/fs/dcache.c
index ae041da..61159d2 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -558,6 +558,8 @@ static void shrink_dcache_for_umount_sub
 
BUG_ON(!IS_ROOT(dentry));
 
+   printk(--shrink_dcache_for_umount_subtree(%p)\n, dentry);
+
/* detach this root from the system */
spin_lock(dcache_lock);
if (!list_empty(dentry-d_lru)) {
@@ -568,6 +570,8 @@ static void shrink_dcache_for_umount_sub
spin_unlock(dcache_lock);
 
for (;;) {
+   printk(- AT %p{%d}\n, dentry, atomic_read(dentry-d_count));
+
/* descend to the first leaf in the current subtree */
while (!list_empty(dentry-d_subdirs)) {
struct dentry *loop;
@@ -590,6 +594,8 @@ static void shrink_dcache_for_umount_sub
/* move to the first child */
dentry = list_entry(dentry-d_subdirs.next,
struct dentry, d_u.d_child);
+
+   printk(- descend %p{%d}\n, dentry, 
atomic_read(dentry-d_count));
}
 
/* consume the dentries from this leaf up through its parents
@@ -643,6 +649,7 @@ #endif
return;
 
dentry = parent;
+   printk(- ascend %p{%d}\n, dentry, 
atomic_read(dentry-d_count));
 
} while (list_empty(dentry-d_subdirs));
 
@@ -671,13 +678,17 @@ void shrink_dcache_for_umount(struct sup
 
dentry = sb-s_root;
sb-s_root = NULL;
+   printk(### Shrink root %p{%d}\n, dentry, 
atomic_read(dentry-d_count));
atomic_dec(dentry-d_count);
shrink_dcache_for_umount_subtree(dentry);
 
while (!hlist_empty(sb-s_anon)) {
+   printk(### Shrink anon\n);
dentry = hlist_entry(sb-s_anon.first, struct dentry, d_hash);
shrink_dcache_for_umount_subtree(dentry);
}
+
+   printk(### Shrunk\n);
 }
 
 /*


[autofs] [PATCH 1/2] VFS: Destroy the dentries contributed by a superblock on unmounting

2006-07-01 Thread David Howells
From: David Howells [EMAIL PROTECTED]

The attached patch destroys all the dentries attached to a superblock in one go
by:

 (1) Destroying the tree rooted at s_root.

 (2) Destroying every entry in the anon list, one at a time.

 (3) Each entry in the anon list has its subtree consumed from the leaves
 inwards.

This reduces the amount of work generic_shutdown_super() does, and avoids
iterating through the dentry_unused list.

Note that locking is almost entirely absent in the shrink_dcache_for_umount*()
functions added by this patch.  This is because:

 (1) at the point the filesystem calls generic_shutdown_super(), it is not
 permitted to further touch the superblock's set of dentries, and nor may
 it remove aliases from inodes;

 (2) the dcache memory shrinker now skips dentries that are being unmounted;
 and

 (3) the superblock no longer has any external references through which the VFS
 can reach it.

Given these points, the only locking we need to do is when we remove dentries
from the unused list and the name hashes, which we do a directory's worth at a
time.

We also don't need to guard against reference counts going to zero unexpectedly
and removing bits of the tree we're working on as nothing else can call dput().

A cut down version of dentry_iput() has been folded into
shrink_dcache_for_umount_subtree() function.  Apart from not needing to unlock
things, it also doesn't need to check for inotify watches.

In this version of the patch, the complaint about a dentry still being in use
has been expanded from a single BUG_ON() and now gives much more information.

Signed-Off-By: David Howells [EMAIL PROTECTED]
Acked-by: NeilBrown [EMAIL PROTECTED]
---

 fs/dcache.c|  133 
 fs/super.c |   12 ++--
 include/linux/dcache.h |1 
 3 files changed, 140 insertions(+), 6 deletions(-)

diff --git a/fs/dcache.c b/fs/dcache.c
index 48b44a7..ae041da 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -548,6 +548,139 @@ repeat:
 }
 
 /*
+ * destroy a single subtree of dentries for unmount
+ * - see the comments on shrink_dcache_for_umount() for a description of the
+ *   locking
+ */
+static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
+{
+   struct dentry *parent;
+
+   BUG_ON(!IS_ROOT(dentry));
+
+   /* detach this root from the system */
+   spin_lock(dcache_lock);
+   if (!list_empty(dentry-d_lru)) {
+   dentry_stat.nr_unused--;
+   list_del_init(dentry-d_lru);
+   }
+   __d_drop(dentry);
+   spin_unlock(dcache_lock);
+
+   for (;;) {
+   /* descend to the first leaf in the current subtree */
+   while (!list_empty(dentry-d_subdirs)) {
+   struct dentry *loop;
+
+   /* this is a branch with children - detach all of them
+* from the system in one go */
+   spin_lock(dcache_lock);
+   list_for_each_entry(loop, dentry-d_subdirs,
+   d_u.d_child) {
+   if (!list_empty(loop-d_lru)) {
+   dentry_stat.nr_unused--;
+   list_del_init(loop-d_lru);
+   }
+
+   __d_drop(loop);
+   cond_resched_lock(dcache_lock);
+   }
+   spin_unlock(dcache_lock);
+
+   /* move to the first child */
+   dentry = list_entry(dentry-d_subdirs.next,
+   struct dentry, d_u.d_child);
+   }
+
+   /* consume the dentries from this leaf up through its parents
+* until we find one with children or run out altogether */
+   do {
+   struct inode *inode;
+
+   if (atomic_read(dentry-d_count) != 0) {
+   printk(KERN_ERR
+  BUG: Dentry %p{i=%lx,n=%s}
+   still in use (%d)
+   [unmount of %s %s]\n,
+  dentry,
+  dentry-d_inode ?
+  dentry-d_inode-i_ino : 0UL,
+  dentry-d_name.name,
+  atomic_read(dentry-d_count),
+  dentry-d_sb-s_type-name,
+  dentry-d_sb-s_id);
+   BUG();
+   }
+
+   parent = dentry-d_parent;
+   if (parent == dentry)
+   parent = NULL;
+   else
+   atomic_dec(parent-d_count

[autofs] [PATCH 2/2] AUTOFS: Make sure all dentries refs are released before calling kill_anon_super()

2006-07-01 Thread David Howells
From: David Howells [EMAIL PROTECTED]

Make sure all dentries refs are released before calling kill_anon_super() so
that the assumption that generic_shutdown_super() can completely destroy the
dentry tree for there will be no external references holds true.

What was being done in the put_super() superblock op, is now done in the
kill_sb() filesystem op instead, prior to calling kill_anon_super().

This makes the struct autofs_sb_info::root member variable redundant (since
sb-s_root is still available), and so that is removed.  The calls to
shrink_dcache_sb() are also removed since they're also redundant as
shrink_dcache_for_umount() will now be called after the cleanup routine.

Signed-Off-By: David Howells [EMAIL PROTECTED]
---

 fs/autofs4/autofs_i.h |3 +--
 fs/autofs4/init.c |2 +-
 fs/autofs4/inode.c|   22 --
 fs/autofs4/waitq.c|1 -
 4 files changed, 6 insertions(+), 22 deletions(-)

diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index d6603d0..47e38f3 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -96,7 +96,6 @@ #define AUTOFS_TYPE_OFFSET   0x0004
 
 struct autofs_sb_info {
u32 magic;
-   struct dentry *root;
int pipefd;
struct file *pipe;
pid_t oz_pgrp;
@@ -231,4 +230,4 @@ out:
 }
 
 void autofs4_dentry_release(struct dentry *);
-
+extern void autofs4_kill_sb(struct super_block *);
diff --git a/fs/autofs4/init.c b/fs/autofs4/init.c
index 5d91933..723a1c5 100644
--- a/fs/autofs4/init.c
+++ b/fs/autofs4/init.c
@@ -24,7 +24,7 @@ static struct file_system_type autofs_fs
.owner  = THIS_MODULE,
.name   = autofs,
.get_sb = autofs_get_sb,
-   .kill_sb= kill_anon_super,
+   .kill_sb= autofs4_kill_sb,
 };
 
 static int __init init_autofs4_fs(void)
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index fde78b1..1bf68c5 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -95,7 +95,7 @@ void autofs4_free_ino(struct autofs_info
  */
 static void autofs4_force_release(struct autofs_sb_info *sbi)
 {
-   struct dentry *this_parent = sbi-root;
+   struct dentry *this_parent = sbi-sb-s_root;
struct list_head *next;
 
spin_lock(dcache_lock);
@@ -126,7 +126,7 @@ resume:
spin_lock(dcache_lock);
}
 
-   if (this_parent != sbi-root) {
+   if (this_parent != sbi-sb-s_root) {
struct dentry *dentry = this_parent;
 
next = this_parent-d_u.d_child.next;
@@ -139,15 +139,9 @@ resume:
goto resume;
}
spin_unlock(dcache_lock);
-
-   dput(sbi-root);
-   sbi-root = NULL;
-   shrink_dcache_sb(sbi-sb);
-
-   return;
 }
 
-static void autofs4_put_super(struct super_block *sb)
+void autofs4_kill_sb(struct super_block *sb)
 {
struct autofs_sb_info *sbi = autofs4_sbi(sb);
 
@@ -162,6 +156,7 @@ static void autofs4_put_super(struct sup
kfree(sbi);
 
DPRINTK(shutting down);
+   kill_anon_super(sb);
 }
 
 static int autofs4_show_options(struct seq_file *m, struct vfsmount *mnt)
@@ -188,7 +183,6 @@ static int autofs4_show_options(struct s
 }
 
 static struct super_operations autofs4_sops = {
-   .put_super  = autofs4_put_super,
.statfs = simple_statfs,
.show_options   = autofs4_show_options,
 };
@@ -314,7 +308,6 @@ int autofs4_fill_super(struct super_bloc
 
s-s_fs_info = sbi;
sbi-magic = AUTOFS_SBI_MAGIC;
-   sbi-root = NULL;
sbi-pipefd = -1;
sbi-catatonic = 0;
sbi-exp_timeout = 0;
@@ -396,13 +389,6 @@ int autofs4_fill_super(struct super_bloc
sbi-pipefd = pipefd;
 
/*
-* Take a reference to the root dentry so we get a chance to
-* clean up the dentry tree on umount.
-* See autofs4_force_release.
-*/
-   sbi-root = dget(root);
-
-   /*
 * Success! Install the root dentry now to indicate completion.
 */
s-s_root = root;
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index ce103e7..c0a6c8d 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -45,7 +45,6 @@ void autofs4_catatonic_mode(struct autof
fput(sbi-pipe);/* Close the pipe */
sbi-pipe = NULL;
}
-   shrink_dcache_sb(sbi-sb);
 }
 
 static int autofs4_write(struct file *file, const void *addr, int bytes)

___
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs