diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp
index 61055f6f586aeed00444e7720c6b228f88bdfac2..26c4865e4c713db352951a8dff75bcdaa8e7c34f 100644
--- a/indra/newview/llcontrolavatar.cpp
+++ b/indra/newview/llcontrolavatar.cpp
@@ -48,15 +48,15 @@ LLControlAvatar::~LLControlAvatar()
 
 void LLControlAvatar::matchVolumeTransform()
 {
-	setPositionAgent(mVolp->getRenderPosition());
+	setPositionAgent(mRootVolp->getRenderPosition());
 	//slamPosition();
 
     LLQuaternion fix_axes_rot(-F_PI_BY_TWO, LLVector3(0,0,1));
-    LLQuaternion obj_rot = mVolp->getRotation();
+    LLQuaternion obj_rot = mRootVolp->getRotation();
     LLQuaternion result_rot = fix_axes_rot * obj_rot;
 	setRotation(result_rot);
     mRoot->setWorldRotation(result_rot);
-    mRoot->setPosition(mVolp->getRenderPosition());
+    mRoot->setPosition(mRootVolp->getRenderPosition());
 }
 
 void LLControlAvatar::setGlobalScale(F32 scale)
@@ -91,18 +91,18 @@ void LLControlAvatar::recursiveScaleJoint(LLJoint* joint, F32 factor)
 // Based on LLViewerJointAttachment::setupDrawable(), without the attaching part.
 void LLControlAvatar::updateVolumeGeom()
 {
-	if (!mVolp->mDrawable)
+	if (!mRootVolp->mDrawable)
 		return;
-	if (mVolp->mDrawable->isActive())
+	if (mRootVolp->mDrawable->isActive())
 	{
-		mVolp->mDrawable->makeStatic(FALSE);
+		mRootVolp->mDrawable->makeStatic(FALSE);
 	}
-	mVolp->mDrawable->makeActive();
-	gPipeline.markMoved(mVolp->mDrawable);
-	gPipeline.markTextured(mVolp->mDrawable); // face may need to change draw pool to/from POOL_HUD
-	mVolp->mDrawable->setState(LLDrawable::USE_BACKLIGHT);
+	mRootVolp->mDrawable->makeActive();
+	gPipeline.markMoved(mRootVolp->mDrawable);
+	gPipeline.markTextured(mRootVolp->mDrawable); // face may need to change draw pool to/from POOL_HUD
+	mRootVolp->mDrawable->setState(LLDrawable::USE_BACKLIGHT);
 
-	LLViewerObject::const_child_list_t& child_list = mVolp->getChildren();
+	LLViewerObject::const_child_list_t& child_list = mRootVolp->getChildren();
 	for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
 		 iter != child_list.end(); ++iter)
 	{
@@ -115,8 +115,8 @@ void LLControlAvatar::updateVolumeGeom()
         }
     }
 
-    gPipeline.markRebuild(mVolp->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
-    mVolp->markForUpdate(TRUE);
+    gPipeline.markRebuild(mRootVolp->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
+    mRootVolp->markForUpdate(TRUE);
 
     // Note that attachment overrides aren't needed here, have already
     // been applied at the time the mControlAvatar was created, in
@@ -148,7 +148,7 @@ LLControlAvatar *LLControlAvatar::createControlAvatar(LLVOVolume *obj)
     // AXON Lifted from LLPreviewAnimation
 	LLControlAvatar *cav = (LLControlAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), CO_FLAG_CONTROL_AVATAR);
 
-    cav->mVolp = obj;
+    cav->mRootVolp = obj;
     
 	cav->createDrawable(&gPipeline);
 	cav->mIsDummy = TRUE;
diff --git a/indra/newview/llcontrolavatar.h b/indra/newview/llcontrolavatar.h
index f29388e035d5f5dec4efa11509d667559c6f5fd4..bb54cc5b2d573c72f5e7ca3f6b8b0a3c70137a49 100644
--- a/indra/newview/llcontrolavatar.h
+++ b/indra/newview/llcontrolavatar.h
@@ -50,7 +50,7 @@ class LLControlAvatar:
 
     F32 mGlobalScale;
 
-    LLVOVolume *mVolp;
+    LLVOVolume *mRootVolp;
 };
 
 #endif //LL_CONTROLAVATAR_H
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index ff33fe79fac86d761d65ca7364446e78ed599c95..f8cdb5bf928fc77e0025cdb236dc9095691aa6ef 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -5097,7 +5097,7 @@ void process_object_animation(LLMessageSystem *mesgsys, void **user_data)
         return;
     }
 
-    LLControlAvatar *avatarp = volp->mControlAvatar;
+    LLControlAvatar *avatarp = volp->getControlAvatar();
     if (!avatarp)
     {
         LL_WARNS() << "AXON no control avatar, ignoring" << LL_ENDL;
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index f1c7cfae0d922a703825b82d6e9ef21330aea2a3..bd0e864f80c15654b2ad911395f0f4f174936849 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -383,11 +383,9 @@ void LLViewerObject::markDead()
 			// This case is needed for indirectly attached mesh objects.
 			av->resetJointsOnDetach(mesh_id);
 		}
-        if (mControlAvatar)
+        if (getControlAvatar())
         {
-            LLControlAvatar *av = mControlAvatar;
-            mControlAvatar = NULL;
-            av->markDead();
+            unlinkControlAvatar();
         }
 
 		// Mark itself as dead
@@ -2917,6 +2915,55 @@ void LLViewerObject::fetchInventoryFromServer()
 	}
 }
 
+LLControlAvatar *LLViewerObject::getControlAvatar()
+{
+    return getRootEdit()->mControlAvatar.get();
+}
+
+LLControlAvatar *LLViewerObject::getControlAvatar() const
+{
+    return getRootEdit()->mControlAvatar.get();
+}
+
+void LLViewerObject::linkControlAvatar()
+{
+    if (!getControlAvatar() && isRootEdit())
+    {
+        LLVOVolume *volp = dynamic_cast<LLVOVolume*>(this);
+        if (!volp)
+        {
+            LL_WARNS() << "called with null or non-volume object" << LL_ENDL;
+            return;
+        }
+        mControlAvatar = LLControlAvatar::createControlAvatar(volp);
+    }
+    if (getControlAvatar())
+    {
+        getControlAvatar()->addAttachmentOverridesForObject(this);
+    }
+    else
+    {
+        LL_WARNS() << "no control avatar found!" << LL_ENDL;
+    }
+}
+
+void LLViewerObject::unlinkControlAvatar()
+{
+    if (getControlAvatar())
+    {
+        getControlAvatar()->resetJointsOnDetach(this);
+    }
+    if (isRootEdit())
+    {
+        // This will remove the entire linkset from the control avatar
+        LLControlAvatar *av = mControlAvatar;
+        mControlAvatar = NULL;
+        av->markDead();
+    }
+    // For non-root prims, removing from the linkset will
+    // automatically remove the control avatar connection.
+}
+
 struct LLFilenameAndTask
 {
 	LLUUID mTaskID;
@@ -3872,7 +3919,7 @@ const LLVector3 LLViewerObject::getRenderPosition() const
 	if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED))
 	{
 		LLVOAvatar* avatar = getAvatar();
-		if (avatar && !mControlAvatar)
+		if (avatar && !getControlAvatar())
 		{
 			return avatar->getPositionAgent();
 		}
@@ -4008,9 +4055,9 @@ void LLViewerObject::setPosition(const LLVector3 &pos, BOOL damped)
 		// position caches need to be up to date on root objects
 		updatePositionCaches();
 	}
-    if (mControlAvatar)
+    if (getControlAvatar() && isRootEdit())
     {
-        mControlAvatar->matchVolumeTransform();
+        getControlAvatar()->matchVolumeTransform();
     }
 }
 
@@ -6377,9 +6424,9 @@ const std::string& LLViewerObject::getAttachmentItemName() const
 //virtual
 LLVOAvatar* LLViewerObject::getAvatar() const
 {
-    if (mControlAvatar)
+    if (getControlAvatar())
     {
-        return mControlAvatar;
+        return getControlAvatar();
     }
 	if (isAttachment())
 	{
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index e727567957a31c4be5f7d387630c0f0ed9dfa393..bef00e2bab8e70c4aaa0889aac1c163bd0f365b4 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -684,6 +684,17 @@ class LLViewerObject
 
 	static			BOOL		sUseSharedDrawables;
 
+public:
+    // Returns mControlAvatar for the edit root prim of this linkset
+    LLControlAvatar *getControlAvatar();
+    LLControlAvatar *getControlAvatar() const;
+
+    // Create or connect to an existing control av as applicable
+    void linkControlAvatar();
+    // Remove any reference to control av for this prim
+    void unlinkControlAvatar();
+    
+private:
     LLPointer<LLControlAvatar> mControlAvatar;
 
 protected:
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index beb6f08899f06eaaeec0b8271a0fda928bc0bf73..c268ab5f3c6bd9454691a074a9fbfea5d4c811b6 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -3433,7 +3433,7 @@ void LLVOAvatar::updateDebugText()
                     {
                         LLControlAvatar *control_av = dynamic_cast<LLControlAvatar*>(this);
                         // Try to get name from inventory of associated object
-                        LLVOVolume *volp = control_av->mVolp;
+                        LLVOVolume *volp = control_av->mRootVolp;
                         if (volp)
                         {
                             volp->requestInventory(); // AXON should be a no-op if already requested or fetched?
@@ -5565,14 +5565,14 @@ void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo)
 {
     bool non_attached_case = false;
     // FIXME AXON - will this work if vo has child objects?
-    if (vo->mControlAvatar)
+    if (vo->getControlAvatar())
     {
         non_attached_case = true;
     }
     LLVOAvatar *av;
     if (non_attached_case)
     {
-        av = vo->mControlAvatar;
+        av = vo->getControlAvatar();
     }
     else
     {
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 150769845b3e16067fa6c7edbfe4c2cbc097035c..da24d9f9c27fa846dfe91110d82607fe533e5348 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -3311,6 +3311,10 @@ void LLVOVolume::setExtendedMeshFlags(U32 flags)
 bool LLVOVolume::canBeAnimatedObject() const
 {
     if (!isMesh())
+    {
+        return false;
+    }
+    if (isAttachment())
     {
         return false;
     }
@@ -4830,20 +4834,24 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
                           vobj->isMesh() && 
 						  gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj);
 
-            bool rigged_non_attachment = !vobj->isAttachment() &&
-                                         vobj->isMesh() && 
-                                         gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj);
-
-            if (rigged_non_attachment)
+            if (vobj->isAnimatedObject())
             {
-                if (!vobj->mControlAvatar)
+                if (!vobj->getControlAvatar())
                 {
-                    vobj->mControlAvatar = LLControlAvatar::createControlAvatar(vobj);
-                    vobj->mControlAvatar->addAttachmentOverridesForObject(vobj);
+                    vobj->linkControlAvatar();
                 }
-                if (vobj->mControlAvatar)
+                if (vobj->getControlAvatar())
+                {
+                    pAvatarVO = vobj->getControlAvatar();
+                }
+            }
+            else
+            {
+                // Not animated but has a control avatar - probably
+                // the checkbox has changed since the last rebuild.
+                if (vobj->getControlAvatar())
                 {
-                    pAvatarVO = vobj->mControlAvatar;
+                    vobj->unlinkControlAvatar();
                 }
             }
 
@@ -4880,7 +4888,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 				//sum up face verts and indices
 				drawablep->updateFaceSize(i);
 			
-				if (rigged || (vobj->mControlAvatar && vobj->mControlAvatar->mPlaying))
+				if (rigged || (vobj->getControlAvatar() && vobj->getControlAvatar()->mPlaying))
 				{
 					if (!facep->isState(LLFace::RIGGED))
 					{ //completely reset vertex buffer