diff --git a/NEWS b/NEWS
index 6709d3fa226d38a03e182369a338da5ffdecc222..cbbf76a78c842add206e4ed73dc8dd07847c047d 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,33 @@
+Version 2.0.2
+  - Added experimental support for stripped logical volumes; this should
+    enhance performance but comes with a higher complexity in the block
+    device handling; stripping is only enabled when passing
+    --with-lvm-stripecount=N to configure, but codepaths are affected
+    even in the non-stripped mode
+  - Improved resiliency against transient failures at the end of DRBD
+    resyncs, and in general of DRBD resync checks
+  - Fixed a couple of issues with exports and snapshot errors
+  - Fixed a couple of issues in instance listing
+  - Added display of the disk size in β€œgnt-instance info”
+  - Fixed checking for valid OSes in instance creation
+  - Fixed handling of the β€˜vcpus’ parameter in instance listing and in
+    general of invalid parameters
+  - Fixed http server library, and thus RAPI, to handle invalid
+    username/password combinations correctly; this means that now they
+    report unauthorized for queries too, not only for modifications,
+    allowing earlier detect of configuration problems
+  - Added a new β€˜role’ node list field, equivalent to the master/master
+    candidate/drained/offline flags combinations
+  - Fixed cluster modify and changes of candidate pool size
+  - Fixed cluster verify error messages for wrong files on regular nodes
+  - Fixed a couple of issues with node demotion from master candidate
+    role
+  - Fixed node readd issues
+  - Added non-interactive mode for β€œganeti-masterd --no-voting” startup
+  - Added a new β€˜--no-voting’ option for masterfailover to fix failover
+    on two-nodes clusters when the former master node is unreachable
+  - Added instance reinstall over RAPI
+
 Version 2.0.1
   - added -H/-B startup parameters to gnt-instance, which will allow
     re-adding the start in single-user option (regression from 1.2)
diff --git a/configure.ac b/configure.ac
index 76eeb36df835110bb86c12e4fd33e85e8a60282c..12ba06df08c9a98d679eb62c99f6bb6c5bb2166b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
 # Configure script for Ganeti
 m4_define([gnt_version_major], [2])
 m4_define([gnt_version_minor], [0])
-m4_define([gnt_version_revision], [1])
+m4_define([gnt_version_revision], [2])
 m4_define([gnt_version_suffix], [])
 m4_define([gnt_version_full],
           m4_format([%d.%d.%d%s],
@@ -123,10 +123,10 @@ AC_SUBST(SOCAT_PATH, $socat_path)
 AC_ARG_WITH([lvm-stripecount],
   [AS_HELP_STRING([--with-lvm-stripecount=NUM],
     [the number of stripes to use for LVM volumes]
-    [ (default is 3)]
+    [ (default is 1)]
   )],
   [lvm_stripecount="$withval"],
-  [lvm_stripecount="3"])
+  [lvm_stripecount="1"])
 AC_SUBST(LVM_STRIPECOUNT, $lvm_stripecount)
 
 # Check common programs
diff --git a/lib/bdev.py b/lib/bdev.py
index 4971b53b1e33d1a9164c811f4aae5f62c2d0b0fe..9ac41e50e6db08d3b7d99c5bf0d2ed185f5825cc 100644
--- a/lib/bdev.py
+++ b/lib/bdev.py
@@ -299,7 +299,7 @@ class LogicalVolume(BlockDev):
     self._vg_name, self._lv_name = unique_id
     self.dev_path = "/dev/%s/%s" % (self._vg_name, self._lv_name)
     self._degraded = True
-    self.major = self.minor = None
+    self.major = self.minor = self.pe_size = self.stripe_count = None
     self.Attach()
 
   @classmethod
@@ -411,19 +411,30 @@ class LogicalVolume(BlockDev):
     """
     self.attached = False
     result = utils.RunCmd(["lvs", "--noheadings", "--separator=,",
-                           "-olv_attr,lv_kernel_major,lv_kernel_minor",
-                           self.dev_path])
+                           "--units=m", "--nosuffix",
+                           "-olv_attr,lv_kernel_major,lv_kernel_minor,"
+                           "vg_extent_size,stripes", self.dev_path])
     if result.failed:
       logging.error("Can't find LV %s: %s, %s",
                     self.dev_path, result.fail_reason, result.output)
       return False
-    out = result.stdout.strip().rstrip(',')
+    # the output can (and will) have multiple lines for multi-segment
+    # LVs, as the 'stripes' parameter is a segment one, so we take
+    # only the last entry, which is the one we're interested in; note
+    # that with LVM2 anyway the 'stripes' value must be constant
+    # across segments, so this is a no-op actually
+    out = result.stdout.splitlines()
+    if not out: # totally empty result? splitlines() returns at least
+                # one line for any non-empty string
+      logging.error("Can't parse LVS output, no lines? Got '%s'", str(out))
+      return False
+    out = out[-1].strip().rstrip(',')
     out = out.split(",")
-    if len(out) != 3:
-      logging.error("Can't parse LVS output, len(%s) != 3", str(out))
+    if len(out) != 5:
+      logging.error("Can't parse LVS output, len(%s) != 5", str(out))
       return False
 
-    status, major, minor = out[:3]
+    status, major, minor, pe_size, stripes = out
     if len(status) != 6:
       logging.error("lvs lv_attr is not 6 characters (%s)", status)
       return False
@@ -434,8 +445,22 @@ class LogicalVolume(BlockDev):
     except ValueError, err:
       logging.error("lvs major/minor cannot be parsed: %s", str(err))
 
+    try:
+      pe_size = int(float(pe_size))
+    except (TypeError, ValueError), err:
+      logging.error("Can't parse vg extent size: %s", err)
+      return False
+
+    try:
+      stripes = int(stripes)
+    except (TypeError, ValueError), err:
+      logging.error("Can't parse the number of stripes: %s", err)
+      return False
+
     self.major = major
     self.minor = minor
+    self.pe_size = pe_size
+    self.stripe_count = stripes
     self._degraded = status[0] == 'v' # virtual volume, i.e. doesn't backing
                                       # storage
     self.attached = True
@@ -554,6 +579,13 @@ class LogicalVolume(BlockDev):
     """Grow the logical volume.
 
     """
+    if self.pe_size is None or self.stripe_count is None:
+      if not self.Attach():
+        _ThrowError("Can't attach to LV during Grow()")
+    full_stripe_size = self.pe_size * self.stripe_count
+    rest = amount % full_stripe_size
+    if rest != 0:
+      amount += full_stripe_size - rest
     # we try multiple algorithms since the 'best' ones might not have
     # space available in the right place, but later ones might (since
     # they have less constraints); also note that only recent LVM
@@ -1609,7 +1641,8 @@ class DRBD8(BaseDRBD):
     if len(self._children) != 2 or None in self._children:
       _ThrowError("drbd%d: cannot grow diskless device", self.minor)
     self._children[0].Grow(amount)
-    result = utils.RunCmd(["drbdsetup", self.dev_path, "resize"])
+    result = utils.RunCmd(["drbdsetup", self.dev_path, "resize", "-s",
+                           "%dm" % (self.size + amount)])
     if result.failed:
       _ThrowError("drbd%d: resize failed: %s", self.minor, result.output)
 
diff --git a/lib/rapi/baserlib.py b/lib/rapi/baserlib.py
index 270d61ab7ecd0ab06d5af40ff2dd16cacfc0ab3d..77a7e625d5c0f95e4b6076325c2a1db1cd18881f 100644
--- a/lib/rapi/baserlib.py
+++ b/lib/rapi/baserlib.py
@@ -250,6 +250,18 @@ class R_Generic(object):
                                 " '%s' parameter" % (name,))
     return val
 
+  def _checkStringVariable(self, name, default=None):
+    """Return the parsed value of an int argument.
+
+    """
+    val = self.queryargs.get(name, default)
+    if isinstance(val, list):
+      if val:
+        val = val[0]
+      else:
+        val = default
+    return val
+
   def getBodyParameter(self, name, *args):
     """Check and return the value for a given parameter.
 
diff --git a/lib/rapi/connector.py b/lib/rapi/connector.py
index fcc4f2d4e115c0e902d0170a7f3d62d904c47295..c6270abed1b24a1656366e8cc9b7bef03b6cb184 100644
--- a/lib/rapi/connector.py
+++ b/lib/rapi/connector.py
@@ -163,6 +163,8 @@ CONNECTOR.update({
   re.compile(r'^/2/instances/([\w\._-]+)/tags$'): rlib2.R_2_instances_name_tags,
   re.compile(r'^/2/instances/([\w\._-]+)/reboot$'):
       rlib2.R_2_instances_name_reboot,
+  re.compile(r'^/2/instances/([\w\._-]+)/reinstall$'):
+      rlib2.R_2_instances_name_reinstall,
   re.compile(r'^/2/instances/([\w\._-]+)/shutdown$'):
       rlib2.R_2_instances_name_shutdown,
   re.compile(r'^/2/instances/([\w\._-]+)/startup$'):
diff --git a/lib/rapi/rlib2.py b/lib/rapi/rlib2.py
index 738f86f029f1a34e9da41e2f1256529de0f7674c..45f649bea6611f3eda98395d9043a500095fdcd1 100644
--- a/lib/rapi/rlib2.py
+++ b/lib/rapi/rlib2.py
@@ -493,6 +493,36 @@ class R_2_instances_name_shutdown(baserlib.R_Generic):
     return baserlib.SubmitJob([op])
 
 
+class R_2_instances_name_reinstall(baserlib.R_Generic):
+  """/2/instances/[instance_name]/reinstall resource.
+
+  Implements an instance reinstall.
+
+  """
+
+  DOC_URI = "/2/instances/[instance_name]/reinstall"
+
+  def POST(self):
+    """Reinstall an instance.
+
+    The URI takes os=name and nostartup=[0|1] optional
+    parameters. By default, the instance will be started
+    automatically.
+
+    """
+    instance_name = self.items[0]
+    ostype = self._checkStringVariable('os')
+    nostartup = self._checkIntVariable('nostartup')
+    ops = [
+      opcodes.OpShutdownInstance(instance_name=instance_name),
+      opcodes.OpReinstallInstance(instance_name=instance_name, os_type=ostype),
+      ]
+    if not nostartup:
+      ops.append(opcodes.OpStartupInstance(instance_name=instance_name,
+                                           force=False))
+    return baserlib.SubmitJob(ops)
+
+
 class _R_Tags(baserlib.R_Generic):
   """ Quasiclass for tagging resources
 
diff --git a/man/gnt-node.sgml b/man/gnt-node.sgml
index 5071e5a5e8ca3c2622b46b813f5fe1d7b55f131d..278a6335d80504938c7b22241500427dc0707e53 100644
--- a/man/gnt-node.sgml
+++ b/man/gnt-node.sgml
@@ -414,13 +414,18 @@
           <varlistentry>
             <term>drained</term>
             <listitem>
-              <simpara>whether the node is drained or not</simpara>
+              <simpara>whether the node is drained or not; the cluster
+              still communicates with drained nodes but excludes them
+              from allocation operations</simpara>
             </listitem>
           </varlistentry>
           <varlistentry>
             <term>offline</term>
             <listitem>
-              <simpara>whether the node is offline or not</simpara>
+              <simpara>whether the node is offline or not; if offline,
+              the cluster does not communicate with offline nodes;
+              useful for nodes that are not reachable in order to
+              avoid delays</simpara>
             </listitem>
           </varlistentry>
           <varlistentry>