|
|
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;
|