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

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