vserver 2.0-rc4
[linux-2.6.git] / kernel / vserver / network.c
index 4c3eb43..3212ff6 100644 (file)
@@ -9,6 +9,7 @@
  *  V0.02  cleaned up implementation
  *  V0.03  added equiv nx commands
  *  V0.04  switch to RCU based hash
+ *  V0.05  and back to locking again
  *
  */
 
@@ -39,15 +40,17 @@ static struct nx_info *__alloc_nx_info(nid_t nid)
 
        memset (new, 0, sizeof(struct nx_info));
        new->nx_id = nid;
-       INIT_RCU_HEAD(&new->nx_rcu);
        INIT_HLIST_NODE(&new->nx_hlist);
-       atomic_set(&new->nx_refcnt, 0);
        atomic_set(&new->nx_usecnt, 0);
+       atomic_set(&new->nx_tasks, 0);
+       new->nx_state = 0;
+
+       new->nx_flags = NXF_INIT_SET;
 
        /* rest of init goes here */
 
        vxdprintk(VXD_CBIT(nid, 0),
-               "alloc_nx_info() = %p", new);
+               "alloc_nx_info(%d) = %p", nid, new);
        return new;
 }
 
@@ -64,26 +67,16 @@ static void __dealloc_nx_info(struct nx_info *nxi)
        nxi->nx_id = -1;
 
        BUG_ON(atomic_read(&nxi->nx_usecnt));
-       BUG_ON(atomic_read(&nxi->nx_refcnt));
+       BUG_ON(atomic_read(&nxi->nx_tasks));
 
+       nxi->nx_state |= NXS_RELEASED;
        kfree(nxi);
 }
 
-static inline int __free_nx_info(struct nx_info *nxi)
+static void __shutdown_nx_info(struct nx_info *nxi)
 {
-       int usecnt, refcnt;
-
-       BUG_ON(!nxi);
-
-       usecnt = atomic_read(&nxi->nx_usecnt);
-       BUG_ON(usecnt < 0);
-
-       refcnt = atomic_read(&nxi->nx_refcnt);
-       BUG_ON(refcnt < 0);
-
-       if (!usecnt)
-               __dealloc_nx_info(nxi);
-       return usecnt;
+       nxi->nx_state |= NXS_SHUTDOWN;
+       vs_net_change(nxi, VSC_NETDOWN);
 }
 
 /*     exported stuff                                          */
@@ -91,11 +84,15 @@ static inline int __free_nx_info(struct nx_info *nxi)
 void free_nx_info(struct nx_info *nxi)
 {
        /* context shutdown is mandatory */
-       // BUG_ON(nxi->nx_state != NXS_SHUTDOWN);
+       BUG_ON(nxi->nx_state != NXS_SHUTDOWN);
 
-       // BUG_ON(nxi->nx_state & NXS_HASHED);
+       /* context must not be hashed */
+       BUG_ON(nxi->nx_state & NXS_HASHED);
 
-       BUG_ON(__free_nx_info(nxi));
+       BUG_ON(atomic_read(&nxi->nx_usecnt));
+       BUG_ON(atomic_read(&nxi->nx_tasks));
+
+       __dealloc_nx_info(nxi);
 }
 
 
@@ -124,9 +121,14 @@ static inline void __hash_nx_info(struct nx_info *nxi)
 {
        struct hlist_head *head;
 
+       vxd_assert_lock(&nx_info_hash_lock);
        vxdprintk(VXD_CBIT(nid, 4),
                "__hash_nx_info: %p[#%d]", nxi, nxi->nx_id);
-       get_nx_info(nxi);
+
+       /* context must not be hashed */
+       BUG_ON(nx_info_state(nxi, NXS_HASHED));
+
+       nxi->nx_state |= NXS_HASHED;
        head = &nx_info_hash[__hashval(nxi->nx_id)];
        hlist_add_head(&nxi->nx_hlist, head);
 }
@@ -141,8 +143,12 @@ static inline void __unhash_nx_info(struct nx_info *nxi)
        vxd_assert_lock(&nx_info_hash_lock);
        vxdprintk(VXD_CBIT(nid, 4),
                "__unhash_nx_info: %p[#%d]", nxi, nxi->nx_id);
+
+       /* context must be hashed */
+       BUG_ON(!nx_info_state(nxi, NXS_HASHED));
+
+       nxi->nx_state &= ~NXS_HASHED;
        hlist_del(&nxi->nx_hlist);
-       put_nx_info(nxi);
 }
 
 
@@ -155,17 +161,21 @@ static inline struct nx_info *__lookup_nx_info(nid_t nid)
 {
        struct hlist_head *head = &nx_info_hash[__hashval(nid)];
        struct hlist_node *pos;
+       struct nx_info *nxi;
 
        vxd_assert_lock(&nx_info_hash_lock);
        hlist_for_each(pos, head) {
-               struct nx_info *nxi =
-                       hlist_entry(pos, struct nx_info, nx_hlist);
+               nxi = hlist_entry(pos, struct nx_info, nx_hlist);
 
-               if (nxi->nx_id == nid) {
-                       return nxi;
-               }
+               if (nxi->nx_id == nid)
+                       goto found;
        }
-       return NULL;
+       nxi = NULL;
+found:
+       vxdprintk(VXD_CBIT(nid, 0),
+               "__lookup_nx_info(#%u): %p[#%u]",
+               nid, nxi, nxi?nxi->nx_id:0);
+       return nxi;
 }
 
 
@@ -192,21 +202,19 @@ static inline nid_t __nx_dynamic_id(void)
        return 0;
 }
 
-/*     __loc_nx_info()
+/*     __create_nx_info()
 
-       * locate or create the requested context
-       * get() it and if new hash it                           */
+       * create the requested context
+       * get() and hash it                             */
 
-static struct nx_info * __loc_nx_info(int id, int *err)
+static struct nx_info * __create_nx_info(int id)
 {
        struct nx_info *new, *nxi = NULL;
 
-       vxdprintk(VXD_CBIT(nid, 1), "loc_nx_info(%d)*", id);
+       vxdprintk(VXD_CBIT(nid, 1), "create_nx_info(%d)*", id);
 
-       if (!(new = __alloc_nx_info(id))) {
-               *err = -ENOMEM;
-               return NULL;
-       }
+       if (!(new = __alloc_nx_info(id)))
+               return ERR_PTR(-ENOMEM);
 
        /* required to make dynamic xids unique */
        spin_lock(&nx_info_hash_lock);
@@ -216,33 +224,34 @@ static struct nx_info * __loc_nx_info(int id, int *err)
                id = __nx_dynamic_id();
                if (!id) {
                        printk(KERN_ERR "no dynamic context available.\n");
+                       nxi = ERR_PTR(-EAGAIN);
                        goto out_unlock;
                }
                new->nx_id = id;
        }
-       /* existing context requested */
+       /* static context requested */
        else if ((nxi = __lookup_nx_info(id))) {
-               /* context in setup is not available */
-               if (nxi->nx_flags & VXF_STATE_SETUP) {
-                       vxdprintk(VXD_CBIT(nid, 0),
-                               "loc_nx_info(%d) = %p (not available)", id, nxi);
-                       nxi = NULL;
-                       *err = -EBUSY;
-               } else {
-                       vxdprintk(VXD_CBIT(nid, 0),
-                               "loc_nx_info(%d) = %p (found)", id, nxi);
-                       get_nx_info(nxi);
-                       *err = 0;
-               }
+               vxdprintk(VXD_CBIT(nid, 0),
+                       "create_nx_info(%d) = %p (already there)", id, nxi);
+               if (nx_info_flags(nxi, NXF_STATE_SETUP, 0))
+                       nxi = ERR_PTR(-EBUSY);
+               else
+                       nxi = ERR_PTR(-EEXIST);
+               goto out_unlock;
+       }
+       /* dynamic nid creation blocker */
+       else if (id >= MIN_D_CONTEXT) {
+               vxdprintk(VXD_CBIT(nid, 0),
+                       "create_nx_info(%d) (dynamic rejected)", id);
+               nxi = ERR_PTR(-EINVAL);
                goto out_unlock;
        }
 
-       /* new context requested */
+       /* new context */
        vxdprintk(VXD_CBIT(nid, 0),
-               "loc_nx_info(%d) = %p (new)", id, new);
+               "create_nx_info(%d) = %p (new)", id, new);
        __hash_nx_info(get_nx_info(new));
        nxi = new, new = NULL;
-       *err = 1;
 
 out_unlock:
        spin_unlock(&nx_info_hash_lock);
@@ -258,11 +267,21 @@ out_unlock:
 
 void unhash_nx_info(struct nx_info *nxi)
 {
+       __shutdown_nx_info(nxi);
        spin_lock(&nx_info_hash_lock);
        __unhash_nx_info(nxi);
        spin_unlock(&nx_info_hash_lock);
 }
 
+#ifdef  CONFIG_VSERVER_LEGACYNET
+
+struct nx_info *create_nx_info(void)
+{
+       return __create_nx_info(NX_DYNAMIC_ID);
+}
+
+#endif
+
 /*     locate_nx_info()
 
        * search for a nx_info and get() it
@@ -270,11 +289,11 @@ void unhash_nx_info(struct nx_info *nxi)
 
 struct nx_info *locate_nx_info(int id)
 {
-       struct nx_info *nxi;
+       struct nx_info *nxi = NULL;
 
        if (id < 0) {
                nxi = get_nx_info(current->nx_info);
-       } else {
+       } else if (id > 1) {
                spin_lock(&nx_info_hash_lock);
                nxi = get_nx_info(__lookup_nx_info(id));
                spin_unlock(&nx_info_hash_lock);
@@ -296,28 +315,6 @@ int nid_is_hashed(nid_t nid)
        return hashed;
 }
 
-#ifdef CONFIG_VSERVER_LEGACYNET
-
-struct nx_info *locate_or_create_nx_info(int id)
-{
-       int err;
-
-       return __loc_nx_info(id, &err);
-}
-
-struct nx_info *create_nx_info(void)
-{
-       struct nx_info *new;
-       int err;
-
-       vxdprintk(VXD_CBIT(nid, 5), "create_nx_info(%s)", "void");
-       if (!(new = __loc_nx_info(NX_DYNAMIC_ID, &err)))
-               return NULL;
-       return new;
-}
-
-
-#endif
 
 #ifdef CONFIG_PROC_FS
 
@@ -354,6 +351,7 @@ out:
 
 /*
  *     migrate task to new network
+ *     gets nxi, puts old_nxi on change
  */
 
 int nx_migrate_task(struct task_struct *p, struct nx_info *nxi)
@@ -368,22 +366,27 @@ int nx_migrate_task(struct task_struct *p, struct nx_info *nxi)
                "nx_migrate_task(%p,%p[#%d.%d.%d])",
                p, nxi, nxi->nx_id,
                atomic_read(&nxi->nx_usecnt),
-               atomic_read(&nxi->nx_refcnt));
+               atomic_read(&nxi->nx_tasks));
 
+       /* maybe disallow this completely? */
        old_nxi = task_get_nx_info(p);
        if (old_nxi == nxi)
                goto out;
 
        task_lock(p);
-       /* should be handled in set_nx_info !! */
        if (old_nxi)
                clr_nx_info(&p->nx_info);
+       claim_nx_info(nxi, p);
        set_nx_info(&p->nx_info, nxi);
        p->nid = nxi->nx_id;
        task_unlock(p);
 
-       /* obsoleted by clr/set */
-       // put_nx_info(old_nxi);
+       vxdprintk(VXD_CBIT(nid, 5),
+               "moved task %p into nxi:%p[#%d]",
+               p, nxi, nxi->nx_id);
+
+       if (old_nxi)
+               release_nx_info(old_nxi, p);
 out:
        put_nx_info(old_nxi);
        return ret;
@@ -530,30 +533,31 @@ int vc_nx_info(uint32_t id, void __user *data)
 
 int vc_net_create(uint32_t nid, void __user *data)
 {
-       // int ret = -ENOMEM;
+       struct vcmd_net_create vc_data = { .flagword = NXF_INIT_SET };
        struct nx_info *new_nxi;
        int ret;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
+       if (data && copy_from_user (&vc_data, data, sizeof(vc_data)))
+               return -EFAULT;
 
-       if ((nid >= MIN_D_CONTEXT) && (nid != VX_DYNAMIC_ID))
+       if ((nid > MAX_S_CONTEXT) && (nid != VX_DYNAMIC_ID))
                return -EINVAL;
-
-       if (nid < 1)
+       if (nid < 2)
                return -EINVAL;
 
-       new_nxi = __loc_nx_info(nid, &ret);
-       if (!new_nxi)
-               return ret;
-       if (!(new_nxi->nx_flags & VXF_STATE_SETUP)) {
-               ret = -EEXIST;
-               goto out_put;
-       }
+       new_nxi = __create_nx_info(nid);
+       if (IS_ERR(new_nxi))
+               return PTR_ERR(new_nxi);
+
+       /* initial flags */
+       new_nxi->nx_flags = vc_data.flagword;
 
+       vs_net_change(new_nxi, VSC_NETUP);
        ret = new_nxi->nx_id;
        nx_migrate_task(current, new_nxi);
-out_put:
+       /* if this fails, we might end up with a hashed nx_info */
        put_nx_info(new_nxi);
        return ret;
 }
@@ -574,45 +578,6 @@ int vc_net_migrate(uint32_t id, void __user *data)
        return 0;
 }
 
-int vc_net_add(uint32_t id, void __user *data)
-{
-       struct nx_info *nxi;
-       struct vcmd_net_nx_v0 vc_data;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       if (copy_from_user (&vc_data, data, sizeof(vc_data)))
-               return -EFAULT;
-
-       nxi = locate_nx_info(id);
-       if (!nxi)
-               return -ESRCH;
-
-       // add ip to net context here
-       put_nx_info(nxi);
-       return 0;
-}
-
-int vc_net_remove(uint32_t id, void __user *data)
-{
-       struct nx_info *nxi;
-       struct vcmd_net_nx_v0 vc_data;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       if (copy_from_user (&vc_data, data, sizeof(vc_data)))
-               return -EFAULT;
-
-       nxi = locate_nx_info(id);
-       if (!nxi)
-               return -ESRCH;
-
-       // rem ip from net context here
-       put_nx_info(nxi);
-       return 0;
-}
-
-
 
 int vc_get_nflags(uint32_t id, void __user *data)
 {
@@ -656,7 +621,6 @@ int vc_set_nflags(uint32_t id, void __user *data)
        /* special STATE flag handling */
        mask = vx_mask_mask(vc_data.mask, nxi->nx_flags, IPF_ONE_TIME);
        trigger = (mask & nxi->nx_flags) ^ (mask & vc_data.flagword);
-       // if (trigger & IPF_STATE_SETUP)
 
        nxi->nx_flags = vx_mask_flags(nxi->nx_flags,
                vc_data.flagword, mask);