extern rwlock_t                                dev_base_lock;          /* Device list lock */
 
+extern seqlock_t       devnet_rename_seq;      /* Device rename lock */
+
 
 #define for_each_netdev(net, d)                \
                list_for_each_entry(d, &(net)->dev_base_head, dev_list)
 
 DEFINE_RWLOCK(dev_base_lock);
 EXPORT_SYMBOL(dev_base_lock);
 
+DEFINE_SEQLOCK(devnet_rename_seq);
+
 static inline void dev_base_seq_inc(struct net *net)
 {
        while (++net->dev_base_seq == 0);
        if (dev->flags & IFF_UP)
                return -EBUSY;
 
-       if (strncmp(newname, dev->name, IFNAMSIZ) == 0)
+       write_seqlock(&devnet_rename_seq);
+
+       if (strncmp(newname, dev->name, IFNAMSIZ) == 0) {
+               write_sequnlock(&devnet_rename_seq);
                return 0;
+       }
 
        memcpy(oldname, dev->name, IFNAMSIZ);
 
        err = dev_get_valid_name(net, dev, newname);
-       if (err < 0)
+       if (err < 0) {
+               write_sequnlock(&devnet_rename_seq);
                return err;
+       }
 
 rollback:
        ret = device_rename(&dev->dev, dev->name);
        if (ret) {
                memcpy(dev->name, oldname, IFNAMSIZ);
+               write_sequnlock(&devnet_rename_seq);
                return ret;
        }
 
+       write_sequnlock(&devnet_rename_seq);
+
        write_lock_bh(&dev_base_lock);
        hlist_del_rcu(&dev->name_hlist);
        write_unlock_bh(&dev_base_lock);
                /* err >= 0 after dev_alloc_name() or stores the first errno */
                if (err >= 0) {
                        err = ret;
+                       write_seqlock(&devnet_rename_seq);
                        memcpy(dev->name, oldname, IFNAMSIZ);
                        goto rollback;
                } else {
 {
        struct net_device *dev;
        struct ifreq ifr;
+       unsigned seq;
 
        /*
         *      Fetch the caller's info block.
        if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
                return -EFAULT;
 
+retry:
+       seq = read_seqbegin(&devnet_rename_seq);
        rcu_read_lock();
        dev = dev_get_by_index_rcu(net, ifr.ifr_ifindex);
        if (!dev) {
 
        strcpy(ifr.ifr_name, dev->name);
        rcu_read_unlock();
+       if (read_seqretry(&devnet_rename_seq, seq))
+               goto retry;
 
        if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
                return -EFAULT;
 
 }
 EXPORT_SYMBOL(sk_dst_check);
 
-static int sock_bindtodevice(struct sock *sk, char __user *optval, int optlen)
+static int sock_setbindtodevice(struct sock *sk, char __user *optval,
+                               int optlen)
 {
        int ret = -ENOPROTOOPT;
 #ifdef CONFIG_NETDEVICES
        return ret;
 }
 
+static int sock_getbindtodevice(struct sock *sk, char __user *optval,
+                               int __user *optlen, int len)
+{
+       int ret = -ENOPROTOOPT;
+#ifdef CONFIG_NETDEVICES
+       struct net *net = sock_net(sk);
+       struct net_device *dev;
+       char devname[IFNAMSIZ];
+       unsigned seq;
+
+       if (sk->sk_bound_dev_if == 0) {
+               len = 0;
+               goto zero;
+       }
+
+       ret = -EINVAL;
+       if (len < IFNAMSIZ)
+               goto out;
+
+retry:
+       seq = read_seqbegin(&devnet_rename_seq);
+       rcu_read_lock();
+       dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if);
+       ret = -ENODEV;
+       if (!dev) {
+               rcu_read_unlock();
+               goto out;
+       }
+
+       strcpy(devname, dev->name);
+       rcu_read_unlock();
+       if (read_seqretry(&devnet_rename_seq, seq))
+               goto retry;
+
+       len = strlen(devname) + 1;
+
+       ret = -EFAULT;
+       if (copy_to_user(optval, devname, len))
+               goto out;
+
+zero:
+       ret = -EFAULT;
+       if (put_user(len, optlen))
+               goto out;
+
+       ret = 0;
+
+out:
+#endif
+
+       return ret;
+}
+
 static inline void sock_valbool_flag(struct sock *sk, int bit, int valbool)
 {
        if (valbool)
         */
 
        if (optname == SO_BINDTODEVICE)
-               return sock_bindtodevice(sk, optval, optlen);
+               return sock_setbindtodevice(sk, optval, optlen);
 
        if (optlen < sizeof(int))
                return -EINVAL;
        case SO_NOFCS:
                v.val = sock_flag(sk, SOCK_NOFCS);
                break;
+
        case SO_BINDTODEVICE:
-               v.val = sk->sk_bound_dev_if;
-               break;
+               return sock_getbindtodevice(sk, optval, optlen, len);
+
        case SO_GET_FILTER:
                len = sk_get_filter(sk, (struct sock_filter __user *)optval, len);
                if (len < 0)
                        return len;
 
                goto lenout;
+
        default:
                return -ENOPROTOOPT;
        }