drm/drm_crtc: return -EFAULT on copy_to_user errors
[safe/jmp/linux-2.6] / net / llc / llc_proc.c
index 36e8db3..7af1ff2 100644 (file)
  * See the GNU General Public License for more details.
  */
 
-#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/proc_fs.h>
 #include <linux/errno.h>
 #include <linux/seq_file.h>
+#include <net/net_namespace.h>
 #include <net/sock.h>
 #include <net/llc.h>
 #include <net/llc_c_ac.h>
 #include <net/llc_c_st.h>
 #include <net/llc_conn.h>
 
-static void llc_ui_format_mac(struct seq_file *seq, unsigned char *mac)
+static void llc_ui_format_mac(struct seq_file *seq, u8 *addr)
 {
-       seq_printf(seq, "%02X:%02X:%02X:%02X:%02X:%02X",
-                  mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+       seq_printf(seq, "%pM", addr);
 }
 
 static struct sock *llc_get_sk_idx(loff_t pos)
 {
-       struct list_head *sap_entry;
        struct llc_sap *sap;
-       struct hlist_node *node;
        struct sock *sk = NULL;
-
-       list_for_each(sap_entry, &llc_sap_list) {
-               sap = list_entry(sap_entry, struct llc_sap, node);
-
-               read_lock_bh(&sap->sk_list.lock);
-               sk_for_each(sk, node, &sap->sk_list.list) {
-                       if (!pos)
-                               goto found;
-                       --pos;
+       int i;
+
+       list_for_each_entry_rcu(sap, &llc_sap_list, node) {
+               spin_lock_bh(&sap->sk_lock);
+               for (i = 0; i < LLC_SK_LADDR_HASH_ENTRIES; i++) {
+                       struct hlist_nulls_head *head = &sap->sk_laddr_hash[i];
+                       struct hlist_nulls_node *node;
+
+                       sk_nulls_for_each(sk, node, head) {
+                               if (!pos)
+                                       goto found; /* keep the lock */
+                               --pos;
+                       }
                }
-               read_unlock_bh(&sap->sk_list.lock);
+               spin_unlock_bh(&sap->sk_lock);
        }
        sk = NULL;
 found:
@@ -58,10 +59,23 @@ static void *llc_seq_start(struct seq_file *seq, loff_t *pos)
 {
        loff_t l = *pos;
 
-       read_lock_bh(&llc_sap_list_lock);
+       rcu_read_lock_bh();
        return l ? llc_get_sk_idx(--l) : SEQ_START_TOKEN;
 }
 
+static struct sock *laddr_hash_next(struct llc_sap *sap, int bucket)
+{
+       struct hlist_nulls_node *node;
+       struct sock *sk = NULL;
+
+       while (++bucket < LLC_SK_LADDR_HASH_ENTRIES)
+               sk_nulls_for_each(sk, node, &sap->sk_laddr_hash[bucket])
+                       goto out;
+
+out:
+       return sk;
+}
+
 static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
        struct sock* sk, *next;
@@ -74,25 +88,23 @@ static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
                goto out;
        }
        sk = v;
-       next = sk_next(sk);
+       next = sk_nulls_next(sk);
        if (next) {
                sk = next;
                goto out;
        }
        llc = llc_sk(sk);
        sap = llc->sap;
-       read_unlock_bh(&sap->sk_list.lock);
-       sk = NULL;
-       for (;;) {
-               if (sap->node.next == &llc_sap_list)
-                       break;
-               sap = list_entry(sap->node.next, struct llc_sap, node);
-               read_lock_bh(&sap->sk_list.lock);
-               if (!hlist_empty(&sap->sk_list.list)) {
-                       sk = sk_head(&sap->sk_list.list);
-                       break;
-               }
-               read_unlock_bh(&sap->sk_list.lock);
+       sk = laddr_hash_next(sap, llc_sk_laddr_hashfn(sap, &llc->laddr));
+       if (sk)
+               goto out;
+       spin_unlock_bh(&sap->sk_lock);
+       list_for_each_entry_continue_rcu(sap, &llc_sap_list, node) {
+               spin_lock_bh(&sap->sk_lock);
+               sk = laddr_hash_next(sap, -1);
+               if (sk)
+                       break; /* keep the lock */
+               spin_unlock_bh(&sap->sk_lock);
        }
 out:
        return sk;
@@ -105,9 +117,9 @@ static void llc_seq_stop(struct seq_file *seq, void *v)
                struct llc_sock *llc = llc_sk(sk);
                struct llc_sap *sap = llc->sap;
 
-               read_unlock_bh(&sap->sk_list.lock);
+               spin_unlock_bh(&sap->sk_lock);
        }
-       read_unlock_bh(&llc_sap_list_lock);
+       rcu_read_unlock_bh();
 }
 
 static int llc_seq_socket_show(struct seq_file *seq, void *v)
@@ -128,13 +140,15 @@ static int llc_seq_socket_show(struct seq_file *seq, void *v)
 
        if (llc->dev)
                llc_ui_format_mac(seq, llc->dev->dev_addr);
-       else
-               seq_printf(seq, "00:00:00:00:00:00");
+       else {
+               u8 addr[6] = {0,0,0,0,0,0};
+               llc_ui_format_mac(seq, addr);
+       }
        seq_printf(seq, "@%02X ", llc->sap->laddr.lsap);
        llc_ui_format_mac(seq, llc->daddr.mac);
        seq_printf(seq, "@%02X %8d %8d %2d %3d %4d\n", llc->daddr.lsap,
-                  atomic_read(&sk->sk_wmem_alloc),
-                  atomic_read(&sk->sk_rmem_alloc),
+                  sk_wmem_alloc_get(sk),
+                  sk_rmem_alloc_get(sk) - llc->copied_seq,
                   sk->sk_state,
                   sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_uid : -1,
                   llc->link);
@@ -142,19 +156,19 @@ out:
        return 0;
 }
 
-static char *llc_conn_state_names[] = {
-       [LLC_CONN_STATE_ADM] =        "adm", 
-       [LLC_CONN_STATE_SETUP] =      "setup", 
+static const char *const llc_conn_state_names[] = {
+       [LLC_CONN_STATE_ADM] =        "adm",
+       [LLC_CONN_STATE_SETUP] =      "setup",
        [LLC_CONN_STATE_NORMAL] =     "normal",
-       [LLC_CONN_STATE_BUSY] =       "busy", 
-       [LLC_CONN_STATE_REJ] =        "rej", 
-       [LLC_CONN_STATE_AWAIT] =      "await", 
+       [LLC_CONN_STATE_BUSY] =       "busy",
+       [LLC_CONN_STATE_REJ] =        "rej",
+       [LLC_CONN_STATE_AWAIT] =      "await",
        [LLC_CONN_STATE_AWAIT_BUSY] = "await_busy",
        [LLC_CONN_STATE_AWAIT_REJ] =  "await_rej",
        [LLC_CONN_STATE_D_CONN] =     "d_conn",
-       [LLC_CONN_STATE_RESET] =      "reset", 
-       [LLC_CONN_STATE_ERROR] =      "error", 
-       [LLC_CONN_STATE_TEMP] =       "temp", 
+       [LLC_CONN_STATE_RESET] =      "reset",
+       [LLC_CONN_STATE_ERROR] =      "error",
+       [LLC_CONN_STATE_TEMP] =       "temp",
 };
 
 static int llc_seq_core_show(struct seq_file *seq, void *v)
@@ -185,14 +199,14 @@ out:
        return 0;
 }
 
-static struct seq_operations llc_seq_socket_ops = {
+static const struct seq_operations llc_seq_socket_ops = {
        .start  = llc_seq_start,
        .next   = llc_seq_next,
        .stop   = llc_seq_stop,
        .show   = llc_seq_socket_show,
 };
 
-static struct seq_operations llc_seq_core_ops = {
+static const struct seq_operations llc_seq_core_ops = {
        .start  = llc_seq_start,
        .next   = llc_seq_next,
        .stop   = llc_seq_stop,
@@ -209,7 +223,7 @@ static int llc_seq_core_open(struct inode *inode, struct file *file)
        return seq_open(file, &llc_seq_core_ops);
 }
 
-static struct file_operations llc_seq_socket_fops = {
+static const struct file_operations llc_seq_socket_fops = {
        .owner          = THIS_MODULE,
        .open           = llc_seq_socket_open,
        .read           = seq_read,
@@ -217,7 +231,7 @@ static struct file_operations llc_seq_socket_fops = {
        .release        = seq_release,
 };
 
-static struct file_operations llc_seq_core_fops = {
+static const struct file_operations llc_seq_core_fops = {
        .owner          = THIS_MODULE,
        .open           = llc_seq_core_open,
        .read           = seq_read,
@@ -232,30 +246,25 @@ int __init llc_proc_init(void)
        int rc = -ENOMEM;
        struct proc_dir_entry *p;
 
-       llc_proc_dir = proc_mkdir("llc", proc_net);
+       llc_proc_dir = proc_mkdir("llc", init_net.proc_net);
        if (!llc_proc_dir)
                goto out;
-       llc_proc_dir->owner = THIS_MODULE;
 
-       p = create_proc_entry("socket", S_IRUGO, llc_proc_dir);
+       p = proc_create("socket", S_IRUGO, llc_proc_dir, &llc_seq_socket_fops);
        if (!p)
                goto out_socket;
 
-       p->proc_fops = &llc_seq_socket_fops;
-
-       p = create_proc_entry("core", S_IRUGO, llc_proc_dir);
+       p = proc_create("core", S_IRUGO, llc_proc_dir, &llc_seq_core_fops);
        if (!p)
                goto out_core;
 
-       p->proc_fops = &llc_seq_core_fops;
-
        rc = 0;
 out:
        return rc;
 out_core:
        remove_proc_entry("socket", llc_proc_dir);
 out_socket:
-       remove_proc_entry("llc", proc_net);
+       remove_proc_entry("llc", init_net.proc_net);
        goto out;
 }
 
@@ -263,5 +272,5 @@ void llc_proc_exit(void)
 {
        remove_proc_entry("socket", llc_proc_dir);
        remove_proc_entry("core", llc_proc_dir);
-       remove_proc_entry("llc", proc_net);
+       remove_proc_entry("llc", init_net.proc_net);
 }