Merge
This commit is contained in:
commit
0ceb0316d6
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -32,6 +32,10 @@ import com.sun.tools.attach.spi.AttachProvider;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.Files;
|
||||
|
||||
/*
|
||||
* Linux implementation of HotSpotVirtualMachine
|
||||
@ -63,12 +67,15 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
|
||||
throw new AttachNotSupportedException("Invalid process identifier");
|
||||
}
|
||||
|
||||
// Try to resolve to the "inner most" pid namespace
|
||||
int ns_pid = getNamespacePid(pid);
|
||||
|
||||
// Find the socket file. If not found then we attempt to start the
|
||||
// attach mechanism in the target VM by sending it a QUIT signal.
|
||||
// Then we attempt to find the socket file again.
|
||||
path = findSocketFile(pid);
|
||||
path = findSocketFile(pid, ns_pid);
|
||||
if (path == null) {
|
||||
File f = createAttachFile(pid);
|
||||
File f = createAttachFile(pid, ns_pid);
|
||||
try {
|
||||
sendQuitTo(pid);
|
||||
|
||||
@ -83,7 +90,7 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
|
||||
try {
|
||||
Thread.sleep(delay);
|
||||
} catch (InterruptedException x) { }
|
||||
path = findSocketFile(pid);
|
||||
path = findSocketFile(pid, ns_pid);
|
||||
|
||||
time_spend += delay;
|
||||
if (time_spend > timeout/2 && path == null) {
|
||||
@ -262,8 +269,12 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
|
||||
}
|
||||
|
||||
// Return the socket file for the given process.
|
||||
private String findSocketFile(int pid) {
|
||||
File f = new File(tmpdir, ".java_pid" + pid);
|
||||
private String findSocketFile(int pid, int ns_pid) {
|
||||
// A process may not exist in the same mount namespace as the caller.
|
||||
// Instead, attach relative to the target root filesystem as exposed by
|
||||
// procfs regardless of namespaces.
|
||||
String root = "/proc/" + pid + "/root/" + tmpdir;
|
||||
File f = new File(root, ".java_pid" + ns_pid);
|
||||
if (!f.exists()) {
|
||||
return null;
|
||||
}
|
||||
@ -274,14 +285,23 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
|
||||
// if not already started. The client creates a .attach_pid<pid> file in the
|
||||
// target VM's working directory (or temp directory), and the SIGQUIT handler
|
||||
// checks for the file.
|
||||
private File createAttachFile(int pid) throws IOException {
|
||||
String fn = ".attach_pid" + pid;
|
||||
private File createAttachFile(int pid, int ns_pid) throws IOException {
|
||||
String fn = ".attach_pid" + ns_pid;
|
||||
String path = "/proc/" + pid + "/cwd/" + fn;
|
||||
File f = new File(path);
|
||||
try {
|
||||
f.createNewFile();
|
||||
} catch (IOException x) {
|
||||
f = new File(tmpdir, fn);
|
||||
String root;
|
||||
if (pid != ns_pid) {
|
||||
// A process may not exist in the same mount namespace as the caller.
|
||||
// Instead, attach relative to the target root filesystem as exposed by
|
||||
// procfs regardless of namespaces.
|
||||
root = "/proc/" + pid + "/root/" + tmpdir;
|
||||
} else {
|
||||
root = tmpdir;
|
||||
}
|
||||
f = new File(root, fn);
|
||||
f.createNewFile();
|
||||
}
|
||||
return f;
|
||||
@ -307,6 +327,40 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
|
||||
}
|
||||
|
||||
|
||||
// Return the inner most namespaced PID if there is one,
|
||||
// otherwise return the original PID.
|
||||
private int getNamespacePid(int pid) throws AttachNotSupportedException, IOException {
|
||||
// Assuming a real procfs sits beneath, reading this doesn't block
|
||||
// nor will it consume a lot of memory.
|
||||
String statusFile = "/proc/" + pid + "/status";
|
||||
File f = new File(statusFile);
|
||||
if (!f.exists()) {
|
||||
return pid; // Likely a bad pid, but this is properly handled later.
|
||||
}
|
||||
|
||||
Path statusPath = Paths.get(statusFile);
|
||||
|
||||
try {
|
||||
for (String line : Files.readAllLines(statusPath, StandardCharsets.UTF_8)) {
|
||||
String[] parts = line.split(":");
|
||||
if (parts.length == 2 && parts[0].trim().equals("NSpid")) {
|
||||
parts = parts[1].trim().split("\\s+");
|
||||
// The last entry represents the PID the JVM "thinks" it is.
|
||||
// Even in non-namespaced pids these entries should be
|
||||
// valid. You could refer to it as the inner most pid.
|
||||
int ns_pid = Integer.parseInt(parts[parts.length - 1]);
|
||||
return ns_pid;
|
||||
}
|
||||
}
|
||||
// Old kernels may not have NSpid field (i.e. 3.10).
|
||||
// Fallback to original pid in the event we cannot deduce.
|
||||
return pid;
|
||||
} catch (NumberFormatException | IOException x) {
|
||||
throw new AttachNotSupportedException("Unable to parse namespace");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-- native methods
|
||||
|
||||
static native void sendQuitToChildrenOf(int pid) throws IOException;
|
||||
|
Loading…
Reference in New Issue
Block a user