Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
[pandora-kernel.git] / fs / afs / cell.c
index ffea35c..0d5eead 100644 (file)
@@ -31,21 +31,20 @@ static struct afs_cell *afs_cell_root;
  * allocate a cell record and fill in its name, VL server address list and
  * allocate an anonymous key
  */
-static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
+static struct afs_cell *afs_cell_alloc(const char *name, unsigned namelen,
+                                      char *vllist)
 {
        struct afs_cell *cell;
        struct key *key;
-       size_t namelen;
        char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next;
        char  *dvllist = NULL, *_vllist = NULL;
        char  delimiter = ':';
        int ret;
 
-       _enter("%s,%s", name, vllist);
+       _enter("%*.*s,%s", namelen, namelen, name ?: "", vllist);
 
        BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */
 
-       namelen = strlen(name);
        if (namelen > AFS_MAXCELLNAME) {
                _leave(" = -ENAMETOOLONG");
                return ERR_PTR(-ENAMETOOLONG);
@@ -73,6 +72,10 @@ static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
        if (!vllist || strlen(vllist) < 7) {
                ret = dns_query("afsdb", name, namelen, "ipv4", &dvllist, NULL);
                if (ret < 0) {
+                       if (ret == -ENODATA || ret == -EAGAIN || ret == -ENOKEY)
+                               /* translate these errors into something
+                                * userspace might understand */
+                               ret = -EDESTADDRREQ;
                        _leave(" = %d", ret);
                        return ERR_PTR(ret);
                }
@@ -138,26 +141,29 @@ error:
 }
 
 /*
- * 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
+ * afs_cell_crate() - create a cell record
+ * @name:      is the name of the cell.
+ * @namsesz:   is the strlen of the cell name.
+ * @vllist:    is a colon separated list of IP addresses in "a.b.c.d" format.
+ * @retref:    is T to return the cell reference when the cell exists.
  */
-struct afs_cell *afs_cell_create(const char *name, char *vllist)
+struct afs_cell *afs_cell_create(const char *name, unsigned namesz,
+                                char *vllist, bool retref)
 {
        struct afs_cell *cell;
        int ret;
 
-       _enter("%s,%s", name, vllist);
+       _enter("%*.*s,%s", namesz, namesz, 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)
+               if (strncasecmp(cell->name, name, namesz) == 0)
                        goto duplicate_name;
        }
        read_unlock(&afs_cells_lock);
 
-       cell = afs_cell_alloc(name, vllist);
+       cell = afs_cell_alloc(name, namesz, vllist);
        if (IS_ERR(cell)) {
                _leave(" = %ld", PTR_ERR(cell));
                up_write(&afs_cells_sem);
@@ -197,8 +203,18 @@ error:
        return ERR_PTR(ret);
 
 duplicate_name:
+       if (retref && !IS_ERR(cell))
+               afs_get_cell(cell);
+
        read_unlock(&afs_cells_lock);
        up_write(&afs_cells_sem);
+
+       if (retref) {
+               _leave(" = %p", cell);
+               return cell;
+       }
+
+       _leave(" = -EEXIST");
        return ERR_PTR(-EEXIST);
 }
 
@@ -229,7 +245,7 @@ int afs_cell_init(char *rootcell)
                *cp++ = 0;
 
        /* allocate a cell record for the root cell */
-       new_root = afs_cell_create(rootcell, cp);
+       new_root = afs_cell_create(rootcell, strlen(rootcell), cp, false);
        if (IS_ERR(new_root)) {
                _leave(" = %ld", PTR_ERR(new_root));
                return PTR_ERR(new_root);
@@ -249,11 +265,12 @@ int afs_cell_init(char *rootcell)
 /*
  * lookup a cell record
  */
-struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz)
+struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz,
+                                bool dns_cell)
 {
        struct afs_cell *cell;
 
-       _enter("\"%*.*s\",", namesz, namesz, name ? name : "");
+       _enter("\"%*.*s\",", namesz, namesz, name ?: "");
 
        down_read(&afs_cells_sem);
        read_lock(&afs_cells_lock);
@@ -267,6 +284,8 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz)
                        }
                }
                cell = ERR_PTR(-ENOENT);
+               if (dns_cell)
+                       goto create_cell;
        found:
                ;
        } else {
@@ -289,6 +308,15 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz)
        up_read(&afs_cells_sem);
        _leave(" = %p", cell);
        return cell;
+
+create_cell:
+       read_unlock(&afs_cells_lock);
+       up_read(&afs_cells_sem);
+
+       cell = afs_cell_create(name, namesz, NULL, true);
+
+       _leave(" = %p", cell);
+       return cell;
 }
 
 #if 0