struct kiocb;
struct sockaddr;
struct msghdr;
+struct module;
struct proto_ops {
int family;
+ struct module *owner;
int (*release) (struct socket *sock);
int (*bind) (struct socket *sock,
struct sockaddr *umyaddr,
int offset, size_t size, int flags);
};
-struct module;
-
struct net_proto_family {
int family;
int (*create)(struct socket *sock, int protocol);
struct module *owner;
};
-extern int net_family_get(int family);
-extern void net_family_put(int family);
-
struct iovec;
extern int sock_wake_async(struct socket *sk, int how, int band);
\
static struct proto_ops name##_ops = { \
.family = fam, \
- \
+ .owner = THIS_MODULE, \
.release = __lock_##name##_release, \
.bind = __lock_##name##_bind, \
.connect = __lock_##name##_connect, \
#include <linux/config.h>
#include <linux/timer.h>
#include <linux/cache.h>
-
+#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h> /* struct sk_buff */
#include <linux/security.h>
void *user_data;
/* Callbacks */
+ struct module *owner;
void (*state_change)(struct sock *sk);
void (*data_ready)(struct sock *sk,int bytes);
void (*write_space)(struct sock *sk);
} stats[NR_CPUS];
};
+static __inline__ void sk_set_owner(struct sock *sk, struct module *owner)
+{
+ /*
+ * One should use sk_set_owner just once, after struct sock creation,
+ * be it shortly after sk_alloc or after a function that returns a new
+ * struct sock (and that down the call chain called sk_alloc), e.g. the
+ * IPv4 and IPv6 modules share tcp_create_openreq_child, so if
+ * tcp_create_openreq_child called sk_set_owner IPv6 would have to
+ * change the ownership of this struct sock, with one not needed
+ * transient sk_set_owner call.
+ */
+ if (unlikely(sk->owner != NULL))
+ BUG();
+ sk->owner = owner;
+ __module_get(owner);
+}
+
/* Called with local bh disabled */
static __inline__ void sock_prot_inc_use(struct proto *prot)
{
{
struct sock *sk = NULL;
- if (!net_family_get(family))
- goto out;
if (!slab)
slab = sk_cachep;
sk = kmem_cache_alloc(slab, priority);
sock_lock_init(sk);
}
sk->slab = slab;
- } else
- net_family_put(family);
-out:
+ }
return sk;
}
void sk_free(struct sock *sk)
{
struct sk_filter *filter;
- const int family = sk->family;
+ struct module *owner = sk->owner;
if (sk->destruct)
sk->destruct(sk);
printk(KERN_DEBUG "sk_free: optmem leakage (%d bytes) detected.\n", atomic_read(&sk->omem_alloc));
kmem_cache_free(sk->slab, sk);
- net_family_put(family);
+ module_put(owner);
}
void __init sk_init(void)
sk->rcvlowat = 1;
sk->rcvtimeo = MAX_SCHEDULE_TIMEOUT;
sk->sndtimeo = MAX_SCHEDULE_TIMEOUT;
+ sk->owner = NULL;
atomic_set(&sk->refcnt, 1);
}
static struct net_proto_family *net_families[NPROTO];
-static __inline__ void net_family_bug(int family)
-{
- printk(KERN_ERR "%d is not yet sock_registered!\n", family);
- BUG();
-}
-
-int net_family_get(int family)
-{
- struct net_proto_family *prot = net_families[family];
- int rc = 1;
-
- barrier();
- if (likely(prot != NULL))
- rc = try_module_get(prot->owner);
- else
- net_family_bug(family);
- return rc;
-}
-
-void net_family_put(int family)
-{
- struct net_proto_family *prot = net_families[family];
-
- barrier();
- if (likely(prot != NULL))
- module_put(prot->owner);
- else
- net_family_bug(family);
-}
-
#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
static atomic_t net_family_lockct = ATOMIC_INIT(0);
static spinlock_t net_family_lock = SPIN_LOCK_UNLOCKED;
void sock_release(struct socket *sock)
{
if (sock->ops) {
- const int family = sock->ops->family;
+ struct module *owner = sock->ops->owner;
sock->ops->release(sock);
sock->ops = NULL;
- net_family_put(family);
+ module_put(owner);
}
if (sock->fasync_list)
sock->type = type;
+ /*
+ * We will call the ->create function, that possibly is in a loadable
+ * module, so we have to bump that loadable module refcnt first.
+ */
i = -EAFNOSUPPORT;
- if (!net_family_get(family))
- goto out_release;
-
- if ((i = net_families[family]->create(sock, protocol)) < 0)
+ if (!try_module_get(net_families[family]->owner))
goto out_release;
+ if ((i = net_families[family]->create(sock, protocol)) < 0)
+ goto out_module_put;
+ /*
+ * Now to bump the refcnt of the [loadable] module that owns this
+ * socket at sock_release time we decrement its refcnt.
+ */
+ if (!try_module_get(sock->ops->owner)) {
+ sock->ops = NULL;
+ goto out_module_put;
+ }
+ /*
+ * Now that we're done with the ->create function, the [loadable]
+ * module can have its refcnt decremented
+ */
+ module_put(net_families[family]->owner);
*res = sock;
security_socket_post_create(sock, family, type, protocol);
out:
net_family_read_unlock();
return i;
+out_module_put:
+ module_put(net_families[family]->owner);
out_release:
sock_release(sock);
goto out;
if (err)
goto out_release;
- err = -EAFNOSUPPORT;
- if (!net_family_get(sock->ops->family))
- goto out_release;
+ /*
+ * We don't need try_module_get here, as the listening socket (sock)
+ * has the protocol module (sock->ops->owner) held.
+ */
+ __module_get(sock->ops->owner);
err = sock->ops->accept(sock, newsock, sock->file->f_flags);
if (err < 0)
- goto out_family_put;
+ goto out_module_put;
if (upeer_sockaddr) {
if(newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 2)<0) {
err = -ECONNABORTED;
- goto out_family_put;
+ goto out_module_put;
}
err = move_addr_to_user(address, len, upeer_sockaddr, upeer_addrlen);
if (err < 0)
- goto out_family_put;
+ goto out_module_put;
}
/* File flags are not inherited via accept() unlike another OSes. */
if ((err = sock_map_fd(newsock)) < 0)
- goto out_family_put;
+ goto out_module_put;
security_socket_post_accept(sock, newsock);
sockfd_put(sock);
out:
return err;
-out_family_put:
- net_family_put(sock->ops->family);
+out_module_put:
+ module_put(sock->ops->owner);
out_release:
sock_release(newsock);
goto out_put;