Skip to content

Commit

Permalink
List open FDs through reading /proc/self/fd
Browse files Browse the repository at this point in the history
Reviewed-by: akozlov
  • Loading branch information
rvansa authored and AntonKozlov committed May 26, 2023
1 parent e80da08 commit ab3c512
Showing 1 changed file with 79 additions and 75 deletions.
154 changes: 79 additions & 75 deletions src/hotspot/os/linux/os_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,78 +183,67 @@ class FdsInfo {

private:
struct fdinfo {
int fd;
struct stat stat;
state_t state;
unsigned mark;

int flags;
};

bool same_fd(int fd1, int fd2);
// params are indices into _fdinfos
bool same_fd(int i1, int i2);

fdinfo *_fdinfos;
int _len;
bool _inited;
GrowableArray<fdinfo> _fdinfos;

void assert_mark(int i) {
assert(inited(), "");
assert(i < len(), "");
assert(_fdinfos[i].state != CLOSED, "");
assert(_inited, "");
assert(i < _fdinfos.length(), "");
assert(_fdinfos.at(i).state != CLOSED, "");
}

public:
void initialize();

bool inited() { return _fdinfos != NULL; }
int len() { return _len; }
int len() { return _fdinfos.length(); }

state_t get_state(int i, state_t orstate = INVALID) {
assert(inited(), "");
if (i < len()) {
return _fdinfos[i].state;
state_t get_state(int i) {
assert(_inited, "");
assert(i < _fdinfos.length(), "");
return _fdinfos.at(i).state;
}

state_t find_state(int fd, state_t orstate) {
for (int i = 0; i < _fdinfos.length(); ++i) {
fdinfo *info = _fdinfos.adr_at(i);
if (info->fd == fd) {
return info->state;
}
}
guarantee(orstate != INVALID, "can't use default orstate");
return orstate;
}

void set_state(int i, state_t newst) {
assert(inited(), "");
assert(i < len(), "");
_fdinfos[i].state = newst;
}

void mark(int i, mark_t m) {
assert_mark(i);
_fdinfos[i].mark |= (unsigned)m;
}
void clear(int i, mark_t m) {
assert_mark(i);
_fdinfos[i].mark &= ~(unsigned)m;
}
bool check(int i, mark_t m) {
assert_mark(i);
return 0 != (_fdinfos[i].mark & (unsigned)m);
int get_fd(int i) {
assert(_inited, "");
assert(i < _fdinfos.length(), "");
return _fdinfos.at(i).fd;
}

struct stat* get_stat(int i) {
assert(inited(), "");
assert(i < len(), "");
return &_fdinfos[i].stat;
assert(_inited, "");
assert(i < _fdinfos.length(), "");
return &_fdinfos.at(i).stat;
}

FdsInfo(bool do_init = true) :
_fdinfos(NULL),
_len(-1)
_inited(false),
_fdinfos(16, mtInternal)
{
if (do_init) {
initialize();
}
}

~FdsInfo() {
if (_fdinfos) {
FREE_C_HEAP_ARRAY(fdinfo, _fdinfos);
}
}
};

struct CracFailDep {
Expand Down Expand Up @@ -5787,71 +5776,85 @@ static bool same_stat(struct stat* st1, struct stat* st2) {
st1->st_ino == st2->st_ino;
}

bool FdsInfo::same_fd(int fd1, int fd2) {
if (!same_stat(get_stat(fd1), get_stat(fd2))) {
bool FdsInfo::same_fd(int i1, int i2) {
assert(i1 < _fdinfos.length(), "");
assert(i2 < _fdinfos.length(), "");
fdinfo *fi1 = _fdinfos.adr_at(i1);
fdinfo *fi2 = _fdinfos.adr_at(i2);
if (!same_stat(&fi1->stat, &fi2->stat)) {
return false;
}

int flags1 = fcntl(fd1, F_GETFL);
int flags2 = fcntl(fd2, F_GETFL);
int flags1 = fcntl(fi1->fd, F_GETFL);
int flags2 = fcntl(fi2->fd, F_GETFL);
if (flags1 != flags2) {
return false;
}

const int test_flag = O_NONBLOCK;
const int new_flags1 = flags1 ^ test_flag;
fcntl(fd1, F_SETFL, new_flags1);
if (fcntl(fd1, F_GETFL) != new_flags1) {
fcntl(fi1->fd, F_SETFL, new_flags1);
if (fcntl(fi1->fd, F_GETFL) != new_flags1) {
// flag write ignored or handled differently,
// don't know what to do
return false;
}

const int new_flags2 = fcntl(fd2, F_GETFL);
const int new_flags2 = fcntl(fi2->fd, F_GETFL);
const bool are_same = new_flags1 == new_flags2;

fcntl(fd1, flags1);
fcntl(fi2->fd, flags1);

return are_same;
}

void FdsInfo::initialize() {
assert(!inited(), "should be called only once");
assert(!_inited, "should be called only once");

const int max_fd = sysconf(_SC_OPEN_MAX);
_fdinfos = NEW_C_HEAP_ARRAY(fdinfo, max_fd, mtInternal);
int last_fd = -1;
char path[PATH_MAX];
struct dirent *dp;

for (int i = 0; i < max_fd; ++i) {
fdinfo* info = _fdinfos + i;
int r = fstat(i, &info->stat);
DIR *dir = opendir("/proc/self/fd");
int dfd = dirfd(dir);
while (dp = readdir(dir)) {
if (dp->d_name[0] == '.') {
// skip "." and ".."
continue;
}
fdinfo info;
info.fd = atoi(dp->d_name);
if (info.fd == dfd) {
continue;
}
int r = fstat(info.fd, &info.stat);
if (r == -1) {
info->state = CLOSED;
info.state = CLOSED;
continue;
}
info->state = ROOT; // can be changed to DUP_OF_0 + N below
info->mark = 0;
last_fd = i;
info.state = ROOT; // can be changed to DUP_OF_0 + N below
info.mark = 0;
_fdinfos.append(info);
}
_len = last_fd + 1;
_fdinfos = REALLOC_C_HEAP_ARRAY(fdinfo, _fdinfos, _len, mtInternal);
closedir(dir);
_inited = true;

for (int i = 0; i < _len; ++i) {
for (int i = 0; i < _fdinfos.length(); ++i) {
fdinfo *info = _fdinfos.adr_at(i);
for (int j = 0; j < i; ++j) {
if (get_state(j) == ROOT && same_fd(i, j)) {
_fdinfos[i].state = (state_t)(DUP_OF_0 + j);
info->state = (state_t)(DUP_OF_0 + j);
break;
}
}

if (get_state(i) == ROOT) {
if (info->state == ROOT) {
char fdpath[PATH_MAX];
int r = readfdlink(i, fdpath, sizeof(fdpath));
int r = readfdlink(info->fd, fdpath, sizeof(fdpath));
guarantee(-1 != r, "can't stat fd");
if (get_stat(i)->st_nlink == 0 ||
if (info->stat.st_nlink == 0 ||
strstr(fdpath, "(deleted)") ||
nfs_silly_rename(fdpath)) {
mark(i, FdsInfo::M_CANT_RESTORE);
info->mark |= FdsInfo::M_CANT_RESTORE;
}
}
}
Expand Down Expand Up @@ -6067,26 +6070,27 @@ void VM_Crac::doit() {
if (fds.get_state(i) == FdsInfo::CLOSED) {
continue;
}
int fd = fds.get_fd(i);

char detailsbuf[PATH_MAX];
const char* type = stat2strtype(fds.get_stat(i)->st_mode);
int linkret = readfdlink(i, detailsbuf, sizeof(detailsbuf));
struct stat* st = fds.get_stat(i);
const char* type = stat2strtype(st->st_mode);
int linkret = readfdlink(fd, detailsbuf, sizeof(detailsbuf));
const char* details = 0 < linkret ? detailsbuf : "";
print_resources("JVM: FD fd=%d type=%s path=\"%s\"", i, type, details);
print_resources("JVM: FD fd=%d type=%s path=\"%s\"", fd, type, details);

if (is_claimed_fd(i)) {
if (is_claimed_fd(fd)) {
print_resources("OK: claimed by java code\n");
continue;
}

if (_vm_inited_fds.get_state(i, FdsInfo::CLOSED) != FdsInfo::CLOSED) {
if (_vm_inited_fds.find_state(fd, FdsInfo::CLOSED) != FdsInfo::CLOSED) {
print_resources("OK: inherited from process env\n");
continue;
}

struct stat* st = fds.get_stat(i);
if (S_ISSOCK(st->st_mode)) {
if (is_socket_from_jcmd(i)){
if (is_socket_from_jcmd(fd)){
print_resources("OK: jcmd socket\n");
continue;
}
Expand Down

0 comments on commit ab3c512

Please sign in to comment.