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

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