cifs: refactor new_inode() calls and inode initialization
[safe/jmp/linux-2.6] / fs / afs / cell.c
index 733c602..5e1df14 100644 (file)
 
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/key.h>
+#include <linux/ctype.h>
+#include <linux/sched.h>
+#include <keys/rxrpc-type.h>
 #include "internal.h"
 
 DECLARE_RWSEM(afs_proc_cells_sem);
 LIST_HEAD(afs_proc_cells);
 
-static struct list_head afs_cells = LIST_HEAD_INIT(afs_cells);
+static LIST_HEAD(afs_cells);
 static DEFINE_RWLOCK(afs_cells_lock);
 static DECLARE_RWSEM(afs_cells_sem); /* add/remove serialisation */
 static DECLARE_WAIT_QUEUE_HEAD(afs_cells_freeable_wq);
 static struct afs_cell *afs_cell_root;
 
 /*
- * create a cell record
- * - "name" is the name of the cell
- * - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format
+ * allocate a cell record and fill in its name, VL server address list and
+ * allocate an anonymous key
  */
-struct afs_cell *afs_cell_create(const char *name, char *vllist)
+static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
 {
        struct afs_cell *cell;
-       char *next;
+       struct key *key;
+       size_t namelen;
+       char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next;
        int ret;
 
        _enter("%s,%s", name, vllist);
 
        BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */
 
+       namelen = strlen(name);
+       if (namelen > AFS_MAXCELLNAME)
+               return ERR_PTR(-ENAMETOOLONG);
+
        /* allocate and initialise a cell record */
-       cell = kmalloc(sizeof(struct afs_cell) + strlen(name) + 1, GFP_KERNEL);
+       cell = kzalloc(sizeof(struct afs_cell) + namelen + 1, GFP_KERNEL);
        if (!cell) {
                _leave(" = -ENOMEM");
                return ERR_PTR(-ENOMEM);
        }
 
-       down_write(&afs_cells_sem);
+       memcpy(cell->name, name, namelen);
+       cell->name[namelen] = 0;
 
-       memset(cell, 0, sizeof(struct afs_cell));
        atomic_set(&cell->usage, 1);
-
        INIT_LIST_HEAD(&cell->link);
-
        rwlock_init(&cell->servers_lock);
        INIT_LIST_HEAD(&cell->servers);
-
        init_rwsem(&cell->vl_sem);
        INIT_LIST_HEAD(&cell->vl_list);
        spin_lock_init(&cell->vl_lock);
 
-       strcpy(cell->name, name);
-
        /* fill in the VL server list from the rest of the string */
-       ret = -EINVAL;
        do {
                unsigned a, b, c, d;
 
@@ -70,18 +73,74 @@ struct afs_cell *afs_cell_create(const char *name, char *vllist)
                        *next++ = 0;
 
                if (sscanf(vllist, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
-                       goto badaddr;
+                       goto bad_address;
 
                if (a > 255 || b > 255 || c > 255 || d > 255)
-                       goto badaddr;
+                       goto bad_address;
 
                cell->vl_addrs[cell->vl_naddrs++].s_addr =
                        htonl((a << 24) | (b << 16) | (c << 8) | d);
 
-               if (cell->vl_naddrs >= AFS_CELL_MAX_ADDRS)
-                       break;
+       } while (cell->vl_naddrs < AFS_CELL_MAX_ADDRS && (vllist = next));
+
+       /* create a key to represent an anonymous user */
+       memcpy(keyname, "afs@", 4);
+       dp = keyname + 4;
+       cp = cell->name;
+       do {
+               *dp++ = toupper(*cp);
+       } while (*cp++);
+
+       key = rxrpc_get_null_key(keyname);
+       if (IS_ERR(key)) {
+               _debug("no key");
+               ret = PTR_ERR(key);
+               goto error;
+       }
+       cell->anonymous_key = key;
+
+       _debug("anon key %p{%x}",
+              cell->anonymous_key, key_serial(cell->anonymous_key));
+
+       _leave(" = %p", cell);
+       return cell;
+
+bad_address:
+       printk(KERN_ERR "kAFS: bad VL server IP address\n");
+       ret = -EINVAL;
+error:
+       key_put(cell->anonymous_key);
+       kfree(cell);
+       _leave(" = %d", ret);
+       return ERR_PTR(ret);
+}
+
+/*
+ * create a cell record
+ * - "name" is the name of the cell
+ * - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format
+ */
+struct afs_cell *afs_cell_create(const char *name, char *vllist)
+{
+       struct afs_cell *cell;
+       int ret;
 
-       } while ((vllist = next));
+       _enter("%s,%s", name, vllist);
+
+       down_write(&afs_cells_sem);
+       read_lock(&afs_cells_lock);
+       list_for_each_entry(cell, &afs_cells, link) {
+               if (strcasecmp(cell->name, name) == 0)
+                       goto duplicate_name;
+       }
+       read_unlock(&afs_cells_lock);
+
+       cell = afs_cell_alloc(name, vllist);
+       if (IS_ERR(cell)) {
+               _leave(" = %ld", PTR_ERR(cell));
+               up_write(&afs_cells_sem);
+               return cell;
+       }
 
        /* add a proc directory for this cell */
        ret = afs_proc_cell_setup(cell);
@@ -109,13 +168,17 @@ struct afs_cell *afs_cell_create(const char *name, char *vllist)
        _leave(" = %p", cell);
        return cell;
 
-badaddr:
-       printk(KERN_ERR "kAFS: bad VL server IP address\n");
 error:
        up_write(&afs_cells_sem);
+       key_put(cell->anonymous_key);
        kfree(cell);
        _leave(" = %d", ret);
        return ERR_PTR(ret);
+
+duplicate_name:
+       read_unlock(&afs_cells_lock);
+       up_write(&afs_cells_sem);
+       return ERR_PTR(-EEXIST);
 }
 
 /*
@@ -209,6 +272,7 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz)
        return cell;
 }
 
+#if 0
 /*
  * try and get a cell record
  */
@@ -224,6 +288,7 @@ struct afs_cell *afs_get_cell_maybe(struct afs_cell *cell)
        write_unlock(&afs_cells_lock);
        return cell;
 }
+#endif  /*  0  */
 
 /*
  * destroy a cell record
@@ -301,6 +366,7 @@ static void afs_cell_destroy(struct afs_cell *cell)
        cachefs_relinquish_cookie(cell->cache, 0);
 #endif
 
+       key_put(cell->anonymous_key);
        kfree(cell);
 
        _leave(" [destroyed]");