alpha: Convert alpha to use read/update_persistent_clock
[pandora-kernel.git] / net / core / rtnetlink.c
index 42da96a..4568120 100644 (file)
@@ -90,6 +90,14 @@ int rtnl_is_locked(void)
 }
 EXPORT_SYMBOL(rtnl_is_locked);
 
+#ifdef CONFIG_PROVE_LOCKING
+int lockdep_rtnl_is_held(void)
+{
+       return lockdep_is_held(&rtnl_mutex);
+}
+EXPORT_SYMBOL(lockdep_rtnl_is_held);
+#endif /* #ifdef CONFIG_PROVE_LOCKING */
+
 static struct rtnl_link *rtnl_msg_handlers[NPROTO];
 
 static inline int rtm_msgindex(int msgtype)
@@ -549,6 +557,19 @@ static void set_operstate(struct net_device *dev, unsigned char transition)
        }
 }
 
+static unsigned int rtnl_dev_combine_flags(const struct net_device *dev,
+                                          const struct ifinfomsg *ifm)
+{
+       unsigned int flags = ifm->ifi_flags;
+
+       /* bugwards compatibility: ifi_change == 0 is treated as ~0 */
+       if (ifm->ifi_change)
+               flags = (flags & ifm->ifi_change) |
+                       (dev->flags & ~ifm->ifi_change);
+
+       return flags;
+}
+
 static void copy_rtnl_link_stats(struct rtnl_link_stats *a,
                                 const struct net_device_stats *b)
 {
@@ -904,13 +925,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
        }
 
        if (ifm->ifi_flags || ifm->ifi_change) {
-               unsigned int flags = ifm->ifi_flags;
-
-               /* bugwards compatibility: ifi_change == 0 is treated as ~0 */
-               if (ifm->ifi_change)
-                       flags = (flags & ifm->ifi_change) |
-                               (dev->flags & ~ifm->ifi_change);
-               err = dev_change_flags(dev, flags);
+               err = dev_change_flags(dev, rtnl_dev_combine_flags(dev, ifm));
                if (err < 0)
                        goto errout;
        }
@@ -930,10 +945,9 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
        if (tb[IFLA_VF_MAC]) {
                struct ifla_vf_mac *ivm;
                ivm = nla_data(tb[IFLA_VF_MAC]);
-               write_lock_bh(&dev_base_lock);
+               err = -EOPNOTSUPP;
                if (ops->ndo_set_vf_mac)
                        err = ops->ndo_set_vf_mac(dev, ivm->vf, ivm->mac);
-               write_unlock_bh(&dev_base_lock);
                if (err < 0)
                        goto errout;
                modified = 1;
@@ -942,12 +956,11 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
        if (tb[IFLA_VF_VLAN]) {
                struct ifla_vf_vlan *ivv;
                ivv = nla_data(tb[IFLA_VF_VLAN]);
-               write_lock_bh(&dev_base_lock);
+               err = -EOPNOTSUPP;
                if (ops->ndo_set_vf_vlan)
                        err = ops->ndo_set_vf_vlan(dev, ivv->vf,
-                                                  (u16)ivv->vlan,
-                                                  (u8)ivv->qos);
-               write_unlock_bh(&dev_base_lock);
+                                                  ivv->vlan,
+                                                  ivv->qos);
                if (err < 0)
                        goto errout;
                modified = 1;
@@ -957,10 +970,9 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
        if (tb[IFLA_VF_TX_RATE]) {
                struct ifla_vf_tx_rate *ivt;
                ivt = nla_data(tb[IFLA_VF_TX_RATE]);
-               write_lock_bh(&dev_base_lock);
+               err = -EOPNOTSUPP;
                if (ops->ndo_set_vf_tx_rate)
                        err = ops->ndo_set_vf_tx_rate(dev, ivt->vf, ivt->rate);
-               write_unlock_bh(&dev_base_lock);
                if (err < 0)
                        goto errout;
                modified = 1;
@@ -1056,6 +1068,26 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
        return 0;
 }
 
+int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm)
+{
+       unsigned int old_flags;
+       int err;
+
+       old_flags = dev->flags;
+       if (ifm && (ifm->ifi_flags || ifm->ifi_change)) {
+               err = __dev_change_flags(dev, rtnl_dev_combine_flags(dev, ifm));
+               if (err < 0)
+                       return err;
+       }
+
+       dev->rtnl_link_state = RTNL_LINK_INITIALIZED;
+       rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U);
+
+       __dev_notify_flags(dev, old_flags);
+       return 0;
+}
+EXPORT_SYMBOL(rtnl_configure_link);
+
 struct net_device *rtnl_create_link(struct net *src_net, struct net *net,
        char *ifname, const struct rtnl_link_ops *ops, struct nlattr *tb[])
 {
@@ -1077,6 +1109,7 @@ struct net_device *rtnl_create_link(struct net *src_net, struct net *net,
 
        dev_net_set(dev, net);
        dev->rtnl_link_ops = ops;
+       dev->rtnl_link_state = RTNL_LINK_INITIALIZING;
        dev->real_num_tx_queues = real_num_queues;
 
        if (strchr(dev->name, '%')) {
@@ -1206,7 +1239,7 @@ replay:
                if (!(nlh->nlmsg_flags & NLM_F_CREATE))
                        return -ENODEV;
 
-               if (ifm->ifi_index || ifm->ifi_flags || ifm->ifi_change)
+               if (ifm->ifi_index)
                        return -EOPNOTSUPP;
                if (tb[IFLA_MAP] || tb[IFLA_MASTER] || tb[IFLA_PROTINFO])
                        return -EOPNOTSUPP;
@@ -1237,9 +1270,15 @@ replay:
                        err = ops->newlink(net, dev, tb, data);
                else
                        err = register_netdevice(dev);
-               if (err < 0 && !IS_ERR(dev))
+               if (err < 0 && !IS_ERR(dev)) {
                        free_netdev(dev);
+                       goto out;
+               }
 
+               err = rtnl_configure_link(dev, ifm);
+               if (err < 0)
+                       unregister_netdevice(dev);
+out:
                put_net(dest_net);
                return err;
        }
@@ -1428,17 +1467,14 @@ static int rtnetlink_event(struct notifier_block *this, unsigned long event, voi
        struct net_device *dev = ptr;
 
        switch (event) {
-       case NETDEV_UNREGISTER:
-               rtmsg_ifinfo(RTM_DELLINK, dev, ~0U);
-               break;
        case NETDEV_UP:
        case NETDEV_DOWN:
-               rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING);
-               break;
+       case NETDEV_PRE_UP:
        case NETDEV_POST_INIT:
        case NETDEV_REGISTER:
        case NETDEV_CHANGE:
        case NETDEV_GOING_DOWN:
+       case NETDEV_UNREGISTER:
        case NETDEV_UNREGISTER_BATCH:
                break;
        default: