Namespace: Add Delete method.

MultiPart: 2/2
Change-Id: Icb40ce084cc8461a5e4795a221e63127808e9b1a
diff --git a/profiles/internal/naming/namespace/mount.go b/profiles/internal/naming/namespace/mount.go
index 029004f..e3b2612 100644
--- a/profiles/internal/naming/namespace/mount.go
+++ b/profiles/internal/naming/namespace/mount.go
@@ -26,19 +26,7 @@
 	return
 }
 
-// unmountFromMountTable removes a single mounted server from a single mount table.
-func unmountFromMountTable(ctx *context.T, client ipc.Client, name, server string, id string) (s status) {
-	s.id = id
-	ctx, _ = context.WithTimeout(ctx, callTimeout)
-	call, err := client.StartCall(ctx, name, "Unmount", []interface{}{server}, options.NoResolve{})
-	s.err = err
-	if err != nil {
-		return
-	}
-	s.err = call.Finish()
-	return
-}
-
+// Mount implements Namespace.Mount.
 func (ns *namespace) Mount(ctx *context.T, name, server string, ttl time.Duration, opts ...naming.MountOpt) error {
 	defer vlog.LogCall()()
 
@@ -84,6 +72,20 @@
 	return err
 }
 
+// unmountFromMountTable removes a single mounted server from a single mount table.
+func unmountFromMountTable(ctx *context.T, client ipc.Client, name, server string, id string) (s status) {
+	s.id = id
+	ctx, _ = context.WithTimeout(ctx, callTimeout)
+	call, err := client.StartCall(ctx, name, "Unmount", []interface{}{server}, options.NoResolve{})
+	s.err = err
+	if err != nil {
+		return
+	}
+	s.err = call.Finish()
+	return
+}
+
+// Unmount implements Namespace.Unmount.
 func (ns *namespace) Unmount(ctx *context.T, name, server string) error {
 	defer vlog.LogCall()()
 	// Unmount the server from all the mount tables.
@@ -96,6 +98,32 @@
 	return err
 }
 
+// removeFromMountTable removes a name (and possibly its subtree) from a single mount table.
+func removeFromMountTable(ctx *context.T, client ipc.Client, name string, removeSubtree bool, id string) (s status) {
+	s.id = id
+	ctx, _ = context.WithTimeout(ctx, callTimeout)
+	call, err := client.StartCall(ctx, name, "Remove", []interface{}{removeSubtree}, options.NoResolve{})
+	s.err = err
+	if err != nil {
+		return
+	}
+	s.err = call.Finish()
+	return
+}
+
+// Remove implements Namespace.Remove.
+func (ns *namespace) Remove(ctx *context.T, name string, removeSubtree bool) error {
+	defer vlog.LogCall()()
+	// Remove from all the mount tables.
+	client := v23.GetClient(ctx)
+	f := func(ctx *context.T, mt, id string) status {
+		return removeFromMountTable(ctx, client, mt, removeSubtree, id)
+	}
+	err := ns.dispatch(ctx, name, f)
+	vlog.VI(1).Infof("Remove(%s, %v) -> %v", name, removeSubtree, err)
+	return err
+}
+
 func str2pattern(strs []string) (ret []security.BlessingPattern) {
 	ret = make([]security.BlessingPattern, len(strs))
 	for i, s := range strs {
diff --git a/profiles/internal/testing/mocks/naming/namespace.go b/profiles/internal/testing/mocks/naming/namespace.go
index 37a3e8c..a052949 100644
--- a/profiles/internal/testing/mocks/naming/namespace.go
+++ b/profiles/internal/testing/mocks/naming/namespace.go
@@ -92,6 +92,26 @@
 	return nil
 }
 
+func (ns *namespace) Remove(ctx *context.T, name string, removeSubtree bool) error {
+	defer vlog.LogCall()()
+	ns.Lock()
+	defer ns.Unlock()
+	e := ns.mounts[name]
+	if e == nil {
+		return nil
+	}
+	delete(ns.mounts, name)
+	if !removeSubtree {
+		return nil
+	}
+	for k := range ns.mounts {
+		if strings.HasPrefix(k, name+"/") {
+			delete(ns.mounts, k)
+		}
+	}
+	return nil
+}
+
 func (ns *namespace) Resolve(ctx *context.T, name string, opts ...naming.ResolveOpt) (*naming.MountEntry, error) {
 	defer vlog.LogCall()()
 	p, n := vnamespace.InternalSplitObjectName(name)