[TCP]: Consider GSO while counting reord in sacktag
[safe/jmp/linux-2.6] / net / netfilter / nf_sockopt.c
index 8b8ece7..2dfac32 100644 (file)
@@ -23,14 +23,13 @@ static inline int overlap(int min1, int max1, int min2, int max2)
 /* Functions to register sockopt ranges (exclusive). */
 int nf_register_sockopt(struct nf_sockopt_ops *reg)
 {
-       struct list_head *i;
+       struct nf_sockopt_ops *ops;
        int ret = 0;
 
        if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0)
                return -EINTR;
 
-       list_for_each(i, &nf_sockopts) {
-               struct nf_sockopt_ops *ops = (struct nf_sockopt_ops *)i;
+       list_for_each_entry(ops, &nf_sockopts, list) {
                if (ops->pf == reg->pf
                    && (overlap(ops->set_optmin, ops->set_optmax,
                                reg->set_optmin, reg->set_optmax)
@@ -55,18 +54,7 @@ EXPORT_SYMBOL(nf_register_sockopt);
 
 void nf_unregister_sockopt(struct nf_sockopt_ops *reg)
 {
-       /* No point being interruptible: we're probably in cleanup_module() */
- restart:
        mutex_lock(&nf_sockopt_mutex);
-       if (reg->use != 0) {
-               /* To be woken by nf_sockopt call... */
-               /* FIXME: Stuart Young's name appears gratuitously. */
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               reg->cleanup_task = current;
-               mutex_unlock(&nf_sockopt_mutex);
-               schedule();
-               goto restart;
-       }
        list_del(&reg->list);
        mutex_unlock(&nf_sockopt_mutex);
 }
@@ -76,20 +64,22 @@ EXPORT_SYMBOL(nf_unregister_sockopt);
 static int nf_sockopt(struct sock *sk, int pf, int val,
                      char __user *opt, int *len, int get)
 {
-       struct list_head *i;
        struct nf_sockopt_ops *ops;
        int ret;
 
+       if (sk->sk_net != &init_net)
+               return -ENOPROTOOPT;
+
        if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0)
                return -EINTR;
 
-       list_for_each(i, &nf_sockopts) {
-               ops = (struct nf_sockopt_ops *)i;
+       list_for_each_entry(ops, &nf_sockopts, list) {
                if (ops->pf == pf) {
+                       if (!try_module_get(ops->owner))
+                               goto out_nosup;
                        if (get) {
                                if (val >= ops->get_optmin
                                    && val < ops->get_optmax) {
-                                       ops->use++;
                                        mutex_unlock(&nf_sockopt_mutex);
                                        ret = ops->get(sk, val, opt, len);
                                        goto out;
@@ -97,23 +87,20 @@ static int nf_sockopt(struct sock *sk, int pf, int val,
                        } else {
                                if (val >= ops->set_optmin
                                    && val < ops->set_optmax) {
-                                       ops->use++;
                                        mutex_unlock(&nf_sockopt_mutex);
                                        ret = ops->set(sk, val, opt, *len);
                                        goto out;
                                }
                        }
+                       module_put(ops->owner);
                }
        }
+ out_nosup:
        mutex_unlock(&nf_sockopt_mutex);
        return -ENOPROTOOPT;
 
  out:
-       mutex_lock(&nf_sockopt_mutex);
-       ops->use--;
-       if (ops->cleanup_task)
-               wake_up_process(ops->cleanup_task);
-       mutex_unlock(&nf_sockopt_mutex);
+       module_put(ops->owner);
        return ret;
 }
 
@@ -134,20 +121,24 @@ EXPORT_SYMBOL(nf_getsockopt);
 static int compat_nf_sockopt(struct sock *sk, int pf, int val,
                             char __user *opt, int *len, int get)
 {
-       struct list_head *i;
        struct nf_sockopt_ops *ops;
        int ret;
 
+       if (sk->sk_net != &init_net)
+               return -ENOPROTOOPT;
+
+
        if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0)
                return -EINTR;
 
-       list_for_each(i, &nf_sockopts) {
-               ops = (struct nf_sockopt_ops *)i;
+       list_for_each_entry(ops, &nf_sockopts, list) {
                if (ops->pf == pf) {
+                       if (!try_module_get(ops->owner))
+                               goto out_nosup;
+
                        if (get) {
                                if (val >= ops->get_optmin
                                    && val < ops->get_optmax) {
-                                       ops->use++;
                                        mutex_unlock(&nf_sockopt_mutex);
                                        if (ops->compat_get)
                                                ret = ops->compat_get(sk,
@@ -160,7 +151,6 @@ static int compat_nf_sockopt(struct sock *sk, int pf, int val,
                        } else {
                                if (val >= ops->set_optmin
                                    && val < ops->set_optmax) {
-                                       ops->use++;
                                        mutex_unlock(&nf_sockopt_mutex);
                                        if (ops->compat_set)
                                                ret = ops->compat_set(sk,
@@ -171,17 +161,15 @@ static int compat_nf_sockopt(struct sock *sk, int pf, int val,
                                        goto out;
                                }
                        }
+                       module_put(ops->owner);
                }
        }
+ out_nosup:
        mutex_unlock(&nf_sockopt_mutex);
        return -ENOPROTOOPT;
 
  out:
-       mutex_lock(&nf_sockopt_mutex);
-       ops->use--;
-       if (ops->cleanup_task)
-               wake_up_process(ops->cleanup_task);
-       mutex_unlock(&nf_sockopt_mutex);
+       module_put(ops->owner);
        return ret;
 }