code: private void doUpgrade(List<StorageDirectory> sds,
                   List<StorageInfo> sdsInfo,
                   final NamespaceInfo nsInfo
                   ) throws IOException {
      assert sds.size() == sdsInfo.size();
      UpgradeThread[] upgradeThreads = new UpgradeThread[sds.size()];
      // start to upgrade
      for (int i=0; i<upgradeThreads.length; i++) {
        final StorageDirectory sd = sds.get(i);
        final StorageInfo si = sdsInfo.get(i);
        UpgradeThread thread = new UpgradeThread(sd, si, nsInfo);
        thread.start();
        upgradeThreads[i] = thread;
      }
      // wait for upgrade to be done
      for (UpgradeThread thread : upgradeThreads) {
        try {
          thread.join();
        } catch (InterruptedException e) {
          throw (InterruptedIOException)new InterruptedIOException().initCause(e);
        }
      }
      // check for errors
      for (UpgradeThread thread : upgradeThreads) {
        if (thread.error != null)
          throw new IOException(thread.error);
      }
  
      // write version file
      this.layoutVersion = FSConstants.LAYOUT_VERSION;
      assert this.namespaceID == nsInfo.getNamespaceID() :
        "Data-node and name-node layout versions must be the same.";
      this.cTime = nsInfo.getCTime();
      for (StorageDirectory sd :sds) {
        sd.write();
        File prevDir = sd.getPreviousDir();
        File tmpDir = sd.getPreviousTmp();
        // rename tmp to previous
        rename(tmpDir, prevDir);
        LOG.info("Upgrade of " + sd.getRoot()+ " is complete.");
      }
    }
docs: Move current storage into a backup directory,
  and hardlink all its blocks into the new current directory.