Skip to content

Commit e298492

Browse files
committed
Collect nropen for each process to monitor if fd leaks
This patch collects and displays the current number of opened file descriptors for each process to monitor if fd leaks. As each thread has the same fds with its process, there is no need to collect each thread's fd numbers then. Considering users may set the nr_open limit to a very large number, we use getdents[64] SYSCALL directly to get fd numbers instead of glibc's readdir() for performance consideration. Also, define MAX_OPEN to be 1024 * 1024 for display even if the fd numbers may exceed 1024 * 1024. Signed-off-by: Fei Li <[email protected]>
1 parent 416e955 commit e298492

File tree

9 files changed

+100
-3
lines changed

9 files changed

+100
-3
lines changed

deviate.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,7 @@ calcdiff(struct tstat *devstat, const struct tstat *curstat,
455455
devstat->cpu.cgcpuweight = curstat->cpu.cgcpuweight;
456456
devstat->cpu.cgcpumax = curstat->cpu.cgcpumax;
457457
devstat->cpu.cgcpumaxr = curstat->cpu.cgcpumaxr;
458+
devstat->cpu.nropen = curstat->cpu.nropen;
458459

459460
if (curstat->cpu.wchan[0])
460461
strcpy(devstat->cpu.wchan, curstat->cpu.wchan);

json.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,7 @@ static void json_print_PRC(char *hp, struct sstat *ss, struct tstat *ps, int nac
10281028
"\"isproc\": %d, "
10291029
"\"rundelay\": %lld, "
10301030
"\"blkdelay\": %lld, "
1031+
"\"nropen\": %d, "
10311032
"\"sleepavg\": %d}",
10321033
ps->gen.pid,
10331034
ps->cpu.utime,
@@ -1039,6 +1040,7 @@ static void json_print_PRC(char *hp, struct sstat *ss, struct tstat *ps, int nac
10391040
!!ps->gen.isproc,
10401041
ps->cpu.rundelay/1000000,
10411042
ps->cpu.blkdelay*1000/hertz,
1043+
ps->cpu.nropen,
10421044
ps->cpu.sleepavg);
10431045
}
10441046

man/atop.1

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1661,6 +1661,11 @@ Time that the process has been finished. If the process is still running,
16611661
this field shows `active'.
16621662
.PP
16631663
.TP 9
1664+
.B NROPEN
1665+
Current number of opened file descriptors (fds) for each process, at least 0.
1666+
As each thread has the same fds with its process, this filed shows `-`.
1667+
.PP
1668+
.TP 9
16641669
.B ENVID
16651670
Virtual environment identified (OpenVZ only).
16661671
.PP

parseable.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -783,7 +783,7 @@ print_PRC(char *hp, struct sstat *ss, struct tstat *ps, int nact)
783783
for (i=0; i < nact; i++, ps++)
784784
{
785785
printf("%s %d %s %c %u %lld %lld %d %d %d %d %d %d %d %c "
786-
"%llu %s %llu %d %d\n",
786+
"%llu %s %llu %d %d %d\n",
787787
hp,
788788
ps->gen.pid,
789789
spaceformat(ps->gen.name, namout),
@@ -802,6 +802,7 @@ print_PRC(char *hp, struct sstat *ss, struct tstat *ps, int nact)
802802
ps->cpu.rundelay,
803803
spaceformat(ps->cpu.wchan, wchanout),
804804
ps->cpu.blkdelay,
805+
ps->cpu.nropen,
805806
cgroupv2max(ps->gen.isproc, ps->cpu.cgcpumax),
806807
cgroupv2max(ps->gen.isproc, ps->cpu.cgcpumaxr));
807808
}

photoproc.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,14 @@
3131
** --------------------------------------------------------------------------
3232
*/
3333

34+
#define _GNU_SOURCE
3435
#include <sys/types.h>
3536
#include <sys/param.h>
37+
#include <sys/syscall.h>
3638
#include <dirent.h>
3739
#include <stdio.h>
3840
#include <string.h>
41+
#include <fcntl.h>
3942
#include <unistd.h>
4043
#include <ctype.h>
4144
#include <time.h>
@@ -63,6 +66,7 @@ static int proccont(struct tstat *);
6366
static void proccmd(struct tstat *);
6467
static void procsmaps(struct tstat *);
6568
static void procwchan(struct tstat *);
69+
static void procfd(struct tstat *);
6670
static count_t procschedstat(struct tstat *);
6771
static int proccgroupv2(struct tstat *);
6872
static struct cgroupv2vals *
@@ -218,6 +222,8 @@ photoproc(struct tstat *tasklist, int maxtask)
218222
if (getwchan)
219223
procwchan(curtask);
220224

225+
procfd(curtask);
226+
221227
// read network stats from netatop
222228
netatop_gettask(curtask->gen.tgid, 'g', curtask);
223229

@@ -959,6 +965,57 @@ procschedstat(struct tstat *curtask)
959965
return curtask->cpu.rundelay;
960966
}
961967

968+
/*
969+
** get current number of opened file descriptors for process
970+
** to monitor if fd leaks.
971+
** Considering users may set the max number of open files to
972+
** a very large number, we use getdents[64] SYSCALL directly
973+
** instead of glibc's readdir() for performance consideration.
974+
** Also, define MAX_OPEN to be 1024 * 1024 for display.
975+
*/
976+
struct linux_dirent64 {
977+
unsigned long d_ino;
978+
off_t d_off;
979+
unsigned short d_reclen;
980+
unsigned char d_type;
981+
char d_name[];
982+
};
983+
984+
#define MAX_OPEN 1024 * 1024
985+
986+
static void
987+
procfd(struct tstat *curtask)
988+
{
989+
int fd, nread, fd_num = 0;
990+
struct linux_dirent64 *buf, *d;
991+
unsigned int count = 0;
992+
993+
if ( (fd = open("fd", O_RDONLY | O_DIRECTORY)) != -1) {
994+
count = MAX_OPEN * sizeof(struct linux_dirent64);
995+
buf = malloc(count);
996+
ptrverify(buf, "Malloc failed for process's opened files\n");
997+
998+
nread = syscall(SYS_getdents64, fd, buf, count);
999+
if (nread == -1) {
1000+
curtask->cpu.nropen = -1;
1001+
} else if (nread == 0) {
1002+
curtask->cpu.nropen = 0;
1003+
} else if (nread > 0) {
1004+
for (int bops = 0; bops < nread;) {
1005+
d = (struct linux_dirent64 *)((char *)buf + bops);
1006+
bops += d->d_reclen;
1007+
fd_num++;
1008+
}
1009+
curtask->cpu.nropen = fd_num - 2;
1010+
}
1011+
1012+
close(fd);
1013+
free(buf);
1014+
} else {
1015+
curtask->cpu.nropen = 0;
1016+
}
1017+
}
1018+
9621019
/*
9631020
** CGROUP V2 specific items
9641021
*/

photoproc.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ struct tstat {
7979
int cgcpuweight; /* cgroup cpu.weight */
8080
int cgcpumax; /* cgroup cpu.max percentage */
8181
int cgcpumaxr; /* restrictive percentage */
82-
int ifuture[3]; /* reserved for future use */
82+
int nropen; /* number of opened files */
83+
int ifuture[2]; /* reserved for future use */
8384
char wchan[16]; /* wait channel string */
8485
count_t rundelay; /* schedstat rundelay (nanosec) */
8586
count_t blkdelay; /* blkio delay (ticks) */

showlinux.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,7 @@ proc_printdef *allprocpdefs[]=
421421
&procprt_STTIME,
422422
&procprt_ENDATE,
423423
&procprt_ENTIME,
424+
&procprt_NROPEN,
424425
&procprt_THR,
425426
&procprt_TRUN,
426427
&procprt_TSLPI,
@@ -1297,7 +1298,7 @@ priphead(int curlist, int totlist, char *showtype, char *showorder,
12971298
"RUID:8 RGID:8 EUID:5 EGID:4 "
12981299
"SUID:3 SGID:2 FSUID:3 FSGID:2 "
12991300
"STDATE:7 STTIME:7 ENDATE:5 ENTIME:5 "
1300-
"ST:6 EXC:6 S:6 SORTITEM:10 CMD:10",
1301+
"NROPEN:5 ST:6 EXC:6 S:6 SORTITEM:10 CMD:10",
13011302
"built-in varprocs");
13021303

13031304
make_proc_prints(cmdprocs, MAXITEMS,

showlinux.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,7 @@ extern proc_printdef procprt_STDATE;
416416
extern proc_printdef procprt_STTIME;
417417
extern proc_printdef procprt_ENDATE;
418418
extern proc_printdef procprt_ENTIME;
419+
extern proc_printdef procprt_NROPEN;
419420
extern proc_printdef procprt_THR;
420421
extern proc_printdef procprt_TRUN;
421422
extern proc_printdef procprt_TSLPI;

showprocs.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ char *procprt_ENDATE_a(struct tstat *, int, int);
115115
char *procprt_ENDATE_e(struct tstat *, int, int);
116116
char *procprt_ENTIME_a(struct tstat *, int, int);
117117
char *procprt_ENTIME_e(struct tstat *, int, int);
118+
char *procprt_NROPEN_a(struct tstat *, int, int);
119+
char *procprt_NROPEN_e(struct tstat *, int, int);
118120
char *procprt_THR_a(struct tstat *, int, int);
119121
char *procprt_THR_e(struct tstat *, int, int);
120122
char *procprt_TRUN_a(struct tstat *, int, int);
@@ -1231,6 +1233,32 @@ proc_printdef procprt_ENTIME =
12311233
{ " ENTIME ", "ENTIME", procprt_ENTIME_a, procprt_ENTIME_e, 8 };
12321234
/***************************************************************/
12331235
char *
1236+
procprt_NROPEN_a(struct tstat *curstat, int avgval, int nsecs)
1237+
{
1238+
static char buf[64];
1239+
1240+
if (curstat->gen.isproc)
1241+
sprintf(buf, "%*d", procprt_NROPEN.width, curstat->cpu.nropen);
1242+
else
1243+
sprintf(buf, "%*s", procprt_NROPEN.width, "-");
1244+
1245+
return buf;
1246+
}
1247+
1248+
char *
1249+
procprt_NROPEN_e(struct tstat *curstat, int avgval, int nsecs)
1250+
{
1251+
static char buf[64];
1252+
1253+
sprintf(buf, "%*s", procprt_NROPEN.width, "-");
1254+
1255+
return buf;
1256+
}
1257+
1258+
proc_printdef procprt_NROPEN =
1259+
{ " NROPEN", "NROPEN", procprt_NROPEN_a, procprt_NROPEN_e, 7 };
1260+
/***************************************************************/
1261+
char *
12341262
procprt_THR_a(struct tstat *curstat, int avgval, int nsecs)
12351263
{
12361264
static char buf[15];

0 commit comments

Comments
 (0)