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