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

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