Blame SOURCES/autofs-5.0.7-fix-file-descriptor-leak-when-reloading-the-daemon.patch

304803
autofs-5.0.7 - fix file descriptor leak when reloading the daemon
304803
304803
From: Leonardo Chiquitto <leonardo.lists@gmail.com>
304803
304803
A customer reported that AutoFS may leak file descriptors when some
304803
maps are modified and the daemon reloaded. I'm able to reproduce the
304803
problem on 5.0.7 by following these steps:
304803
304803
1. Configure a simple direct mount:
304803
304803
# cat /etc/auto.master
304803
/-	/etc/auto.direct
304803
304803
# cat /etc/auto.direct
304803
/nfs   server:/nfs
304803
304803
2. Start the automounter and do NOT trigger the mount
304803
304803
3. Replace /etc/auto.direct with:
304803
304803
# cat /etc/auto.direct
304803
/nfs/1  server:/nfs
304803
/nfs/2  server:/nfs
304803
304803
4. Reload:
304803
304803
# kill -HUP $(pidof automount)
304803
304803
>From now on, every reload will leak a file descriptor:
304803
304803
# ls -la /proc/$(pidof automount)/fd | grep /nfs
304803
lr-x------ 1 root root 64 Aug 14 22:08 11 -> /nfs
304803
lr-x------ 1 root root 64 Aug 14 22:08 12 -> /nfs
304803
lr-x------ 1 root root 64 Aug 14 22:08 13 -> /nfs
304803
lr-x------ 1 root root 64 Aug 14 22:08 14 -> /nfs
304803
lr-x------ 1 root root 64 Aug 14 22:08 5 -> /nfs
304803
304803
I've investigated the problem and discovered that the leak happens in
304803
do_umount_autofs_direct():
304803
304803
- edit imk
304803
The same leak is present in umount_autofs_offset() also.
304803
Updated patch to cover that too.
304803
- end edit
304803
304803
int do_umount_autofs_direct(struct autofs_point *ap, struct mnt_list
304803
*mnts, struct mapent *me)
304803
{
304803
(...)
304803
	if (me->ioctlfd != -1) {
304803
		if (tree_is_mounted(mnts, me->key, MNTS_REAL)) {
304803
			error(ap->logopt,
304803
			      "attempt to umount busy direct mount %s",
304803
			      me->key);
304803
			return 1;
304803
		}
304803
		ioctlfd = me->ioctlfd;
304803
	} else	// ioctlfd == -1
304803
		ops->open(ap->logopt, &ioctlfd, me->dev, me->key);  <= we open it here
304803
304803
	if (ioctlfd >= 0) {
304803
		unsigned int status = 1;
304803
304803
		rv = ops->askumount(ap->logopt, ioctlfd, &status);
304803
				/// at this point, rv == 0 and status == 0
304803
		if (rv) {
304803
			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
304803
			error(ap->logopt, "ioctl failed: %s", estr);
304803
			return 1;
304803
		} else if (!status) {
304803
				/// at this point, ap->state == ST_READMAP
304803
			if (ap->state != ST_SHUTDOWN_FORCE) {
304803
				error(ap->logopt,
304803
				      "ask umount returned busy for %s",
304803
				      me->key);
304803
				return 1;			<= we return here, without closing the fd
304803
			} else {
304803
				me->ioctlfd = -1;
304803
				ops->catatonic(ap->logopt, ioctlfd);
304803
				ops->close(ap->logopt, ioctlfd);
304803
				goto force_umount;
304803
			}
304803
(...)
304803
---
304803
 CHANGELOG       |    1 +
304803
 daemon/direct.c |   19 ++++++++++++++++---
304803
 2 files changed, 17 insertions(+), 3 deletions(-)
304803
304803
diff --git a/CHANGELOG b/CHANGELOG
304803
index 46ef335..a7ed212 100644
304803
--- a/CHANGELOG
304803
+++ b/CHANGELOG
304803
@@ -30,6 +30,7 @@
304803
 - workaround missing GNU versionsort extension.
304803
 - dont fail on master map self include.
304803
 - fix wildcard multi map regression.
304803
+- fix file descriptor leak when reloading the daemon.
304803
 
304803
 25/07/2012 autofs-5.0.7
304803
 =======================
304803
diff --git a/daemon/direct.c b/daemon/direct.c
304803
index 3e09c5d..228a666 100644
304803
--- a/daemon/direct.c
304803
+++ b/daemon/direct.c
304803
@@ -86,7 +86,8 @@ int do_umount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, stru
304803
 {
304803
 	struct ioctl_ops *ops = get_ioctl_ops();
304803
 	char buf[MAX_ERR_BUF];
304803
-	int ioctlfd, rv, left, retries;
304803
+	int ioctlfd = -1, rv, left, retries;
304803
+	int opened = 0;
304803
 
304803
 	left = umount_multi(ap, me->key, 0);
304803
 	if (left) {
304803
@@ -103,8 +104,10 @@ int do_umount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, stru
304803
 			return 1;
304803
 		}
304803
 		ioctlfd = me->ioctlfd;
304803
-	} else
304803
+	} else {
304803
 		ops->open(ap->logopt, &ioctlfd, me->dev, me->key);
304803
+		opened = 1;
304803
+	}
304803
 
304803
 	if (ioctlfd >= 0) {
304803
 		unsigned int status = 1;
304803
@@ -113,12 +116,16 @@ int do_umount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, stru
304803
 		if (rv) {
304803
 			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
304803
 			error(ap->logopt, "ioctl failed: %s", estr);
304803
+			if (opened && ioctlfd != -1)
304803
+				ops->close(ap->logopt, ioctlfd);
304803
 			return 1;
304803
 		} else if (!status) {
304803
 			if (ap->state != ST_SHUTDOWN_FORCE) {
304803
 				error(ap->logopt,
304803
 				      "ask umount returned busy for %s",
304803
 				      me->key);
304803
+				if (opened && ioctlfd != -1)
304803
+					ops->close(ap->logopt, ioctlfd);
304803
 				return 1;
304803
 			} else {
304803
 				me->ioctlfd = -1;
304803
@@ -536,7 +543,8 @@ int umount_autofs_offset(struct autofs_point *ap, struct mapent *me)
304803
 {
304803
 	struct ioctl_ops *ops = get_ioctl_ops();
304803
 	char buf[MAX_ERR_BUF];
304803
-	int ioctlfd, rv = 1, retries;
304803
+	int ioctlfd = -1, rv = 1, retries;
304803
+	int opened = 0;
304803
 
304803
 	if (me->ioctlfd != -1) {
304803
 		if (is_mounted(_PATH_MOUNTED, me->key, MNTS_REAL)) {
304803
@@ -554,6 +562,7 @@ int umount_autofs_offset(struct autofs_point *ap, struct mapent *me)
304803
 			return 0;
304803
 		}
304803
 		ops->open(ap->logopt, &ioctlfd, me->dev, me->key);
304803
+		opened = 1;
304803
 	}
304803
 
304803
 	if (ioctlfd >= 0) {
304803
@@ -563,6 +572,8 @@ int umount_autofs_offset(struct autofs_point *ap, struct mapent *me)
304803
 		if (rv) {
304803
 			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
304803
 			logerr("ioctl failed: %s", estr);
304803
+			if (opened && ioctlfd != -1)
304803
+				ops->close(ap->logopt, ioctlfd);
304803
 			return 1;
304803
 		} else if (!status) {
304803
 			if (ap->state != ST_SHUTDOWN_FORCE) {
304803
@@ -570,6 +581,8 @@ int umount_autofs_offset(struct autofs_point *ap, struct mapent *me)
304803
 					error(ap->logopt,
304803
 					     "ask umount returned busy for %s",
304803
 					     me->key);
304803
+				if (opened && ioctlfd != -1)
304803
+					ops->close(ap->logopt, ioctlfd);
304803
 				return 1;
304803
 			} else {
304803
 				me->ioctlfd = -1;