diff --git a/man/gnt-node.sgml b/man/gnt-node.sgml
index ea02f1944c46e1501f3e690de9508d0da19bf555..d7d9f852c9cd253c4ede1df01fc77fd2eb9ae3eb 100644
--- a/man/gnt-node.sgml
+++ b/man/gnt-node.sgml
@@ -721,6 +721,94 @@ node1.example.com /dev/hdc1 xenvg instance1.example.com-sda_11001.data 256  inst
       </para>
     </refsect2>
 
+    <refsect2>
+      <title>VOLUMES</title>
+
+      <cmdsynopsis>
+        <command>physical-volumes</command>
+        <arg>--no-headers</arg>
+        <arg>--human-readable</arg>
+        <arg>--separator=<replaceable>SEPARATOR</replaceable></arg>
+        <arg>--output=<replaceable>FIELDS</replaceable></arg>
+        <sbr>
+        <arg rep="repeat"><replaceable>node</replaceable></arg>
+      </cmdsynopsis>
+
+      <para>
+        Lists all physical volumes and their details from the node(s) provided.
+      </para>
+
+      <para>
+        The <option>--no-headers</option> option will skip the initial header
+        line. The <option>--separator</option> option takes an argument which
+        denotes what will be used between the output fields. Both these options
+        are to help scripting.
+      </para>
+
+      <para>
+        The units used to display the numeric values in the output varies,
+        depending on the options given. By default, the values will be
+        formatted in the most appropriate unit. If the
+        <option>--separator</option> option is given, then the values are shown
+        in mebibytes to allow parsing by scripts. In both cases, the
+        <option>--units</option> option can be used to enforce a given output
+        unit.
+      </para>
+
+      <para>
+        The <option>-o</option> option takes a comma-separated list of
+        output fields. The available fields and their meaning are:
+        <variablelist>
+          <varlistentry>
+            <term>node</term>
+            <listitem>
+              <simpara>the node name on which the volume exists</simpara>
+            </listitem>
+          </varlistentry>
+          <varlistentry>
+            <term>name</term>
+            <listitem>
+              <simpara>the physical drive name</simpara>
+            </listitem>
+          </varlistentry>
+          <varlistentry>
+            <term>size</term>
+            <listitem>
+              <simpara>the physical drive size</simpara>
+            </listitem>
+          </varlistentry>
+          <varlistentry>
+            <term>used</term>
+            <listitem>
+              <simpara>used disk space</simpara>
+            </listitem>
+          </varlistentry>
+          <varlistentry>
+            <term>free</term>
+            <listitem>
+              <simpara>available disk space</simpara>
+            </listitem>
+          </varlistentry>
+          <varlistentry>
+            <term>allocatable</term>
+            <listitem>
+              <simpara>whether physical volume is allocatable</simpara>
+            </listitem>
+          </varlistentry>
+        </variablelist>
+      </para>
+
+      <para>
+        Example:
+        <screen>
+# gnt-node physical-volumes node5.example.com
+Node              Name        Size Used   Free
+node5.example.com /dev/sda7 673.8G   0M 673.8G
+node5.example.com /dev/sdb1 698.6G 1.3G 697.4G
+        </screen>
+      </para>
+    </refsect2>
+
     <refsect2>
       <title>POWERCYCLE</title>
 
diff --git a/scripts/gnt-node b/scripts/gnt-node
index 10cddd79c92e4b1716bab623b4c986bbc89326e2..6141e50272dd4b11869ead2df651d69c0d038fdd 100755
--- a/scripts/gnt-node
+++ b/scripts/gnt-node
@@ -425,6 +425,54 @@ def ListVolumes(opts, args):
   return 0
 
 
+def ListPhysicalVolumes(opts, args):
+  """List physical volumes on node(s).
+
+  @param opts: the command line options selected by the user
+  @type args: list
+  @param args: should either be an empty list, in which case
+      we list data for all nodes, or contain a list of nodes
+      to display data only for those
+  @rtype: int
+  @return: the desired exit code
+
+  """
+  if opts.output is None:
+    selected_fields = ["node", constants.SF_NAME, constants.SF_SIZE,
+                       constants.SF_USED, constants.SF_FREE]
+  else:
+    selected_fields = opts.output.split(",")
+
+  op = opcodes.OpQueryNodeStorage(nodes=args,
+                                  storage_type=constants.ST_LVM_PV,
+                                  output_fields=selected_fields)
+  output = SubmitOpCode(op)
+
+  if not opts.no_headers:
+    headers = {
+      "node": "Node",
+      constants.SF_NAME: "Name",
+      constants.SF_SIZE: "Size",
+      constants.SF_USED: "Used",
+      constants.SF_FREE: "Free",
+      constants.SF_ALLOCATABLE: "Allocatable",
+      }
+  else:
+    headers = None
+
+  unitfields = [constants.SF_SIZE, constants.SF_USED, constants.SF_FREE]
+  numfields = [constants.SF_SIZE, constants.SF_USED, constants.SF_FREE]
+
+  data = GenerateTable(separator=opts.separator, headers=headers,
+                       fields=selected_fields, unitfields=unitfields,
+                       numfields=numfields, data=output, units=opts.units)
+
+  for line in data:
+    ToStdout(line)
+
+  return 0
+
+
 def SetNodeParams(opts, args):
   """Modifies a node.
 
@@ -551,6 +599,11 @@ commands = {
   'volumes': (ListVolumes, ARGS_ANY,
               [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT],
               "[<node_name>...]", "List logical volumes on node(s)"),
+  'physical-volumes': (ListPhysicalVolumes, ARGS_ANY,
+                       [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT,
+                        FIELDS_OPT],
+                       "[<node_name>...]",
+                       "List physical volumes on node(s)"),
   'list-tags': (ListTags, ARGS_ONE, [DEBUG_OPT],
                 "<node_name>", "List the tags of the given node"),
   'add-tags': (AddTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],