File descriptor leak when reloading the daemon

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

 



Hello,

A customer reported that AutoFS may leak file descriptors when some
maps are modified and the daemon reloaded. I'm able to reproduce the
problem on 5.0.7 by following these steps:

1. Configure a simple direct mount:

# cat /etc/auto.master
/-	/etc/auto.direct

# cat /etc/auto.direct
/nfs   server:/nfs

2. Start the automounter and do NOT trigger the mount

3. Replace /etc/auto.direct with:

# cat /etc/auto.direct
/nfs/1  server:/nfs
/nfs/2  server:/nfs

4. Reload:

# kill -HUP $(pidof automount)

>From now on, every reload will leak a file descriptor:

# ls -la /proc/$(pidof automount)/fd | grep /nfs
lr-x------ 1 root root 64 Aug 14 22:08 11 -> /nfs
lr-x------ 1 root root 64 Aug 14 22:08 12 -> /nfs
lr-x------ 1 root root 64 Aug 14 22:08 13 -> /nfs
lr-x------ 1 root root 64 Aug 14 22:08 14 -> /nfs
lr-x------ 1 root root 64 Aug 14 22:08 5 -> /nfs

I've investigated the problem and discovered that the leak happens in
do_umount_autofs_direct():

int do_umount_autofs_direct(struct autofs_point *ap, struct mnt_list
*mnts, struct mapent *me)
{
(...)
	if (me->ioctlfd != -1) {
		if (tree_is_mounted(mnts, me->key, MNTS_REAL)) {
			error(ap->logopt,
			      "attempt to umount busy direct mount %s",
			      me->key);
			return 1;
		}
		ioctlfd = me->ioctlfd;
	} else	// ioctlfd == -1
		ops->open(ap->logopt, &ioctlfd, me->dev, me->key);  <= we open it here

	if (ioctlfd >= 0) {
		unsigned int status = 1;

		rv = ops->askumount(ap->logopt, ioctlfd, &status);
				/// at this point, rv == 0 and status == 0
		if (rv) {
			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
			error(ap->logopt, "ioctl failed: %s", estr);
			return 1;
		} else if (!status) {
				/// at this point, ap->state == ST_READMAP
			if (ap->state != ST_SHUTDOWN_FORCE) {
				error(ap->logopt,
				      "ask umount returned busy for %s",
				      me->key);
				return 1;			<= we return here, without closing the fd
			} else {
				me->ioctlfd = -1;
				ops->catatonic(ap->logopt, ioctlfd);
				ops->close(ap->logopt, ioctlfd);
				goto force_umount;
			}
(...)

I wrote a patch to workaround the leak because I still don't know how
to fix the root cause, which I believe is to remove all references to the
old map entry and unmount everything before creating the new entries.

There's also some open points in the workaround:
- should we call ops->catatonic() on the ioctlfd like it's done in the other
  error paths?
- I've opted to close ioctlfd only if it was opened in this function. Is
  this correct or should we close it regardless if it was opened before
  the call?

Thanks,
Leonardo

Index: autofs-5.0.7/daemon/direct.c
===================================================================
--- autofs-5.0.7.orig/daemon/direct.c
+++ autofs-5.0.7/daemon/direct.c
@@ -87,6 +87,7 @@ int do_umount_autofs_direct(struct autof
 	struct ioctl_ops *ops = get_ioctl_ops();
 	char buf[MAX_ERR_BUF];
 	int ioctlfd, rv, left, retries;
+	int opened = 0;

 	left = umount_multi(ap, me->key, 0);
 	if (left) {
@@ -103,8 +104,10 @@ int do_umount_autofs_direct(struct autof
 			return 1;
 		}
 		ioctlfd = me->ioctlfd;
-	} else
+	} else {
 		ops->open(ap->logopt, &ioctlfd, me->dev, me->key);
+		opened = 1;
+	}

 	if (ioctlfd >= 0) {
 		unsigned int status = 1;
@@ -119,6 +122,8 @@ int do_umount_autofs_direct(struct autof
 				error(ap->logopt,
 				      "ask umount returned busy for %s",
 				      me->key);
+				if (opened)
+					ops->close(ap->logopt, ioctlfd);
 				return 1;
 			} else {
 				me->ioctlfd = -1;
--
To unsubscribe from this list: send the line "unsubscribe autofs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Filesystem Development]     [Linux Ext4]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux