diff options
Diffstat (limited to 'fs/afs/cell.c')
-rw-r--r-- | fs/afs/cell.c | 52 |
1 files changed, 38 insertions, 14 deletions
diff --git a/fs/afs/cell.c b/fs/afs/cell.c index d0765883430e..0d5eeadf6121 100644 --- a/fs/afs/cell.c +++ b/fs/afs/cell.c @@ -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); @@ -142,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); @@ -201,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); } @@ -233,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); @@ -253,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); @@ -271,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 { @@ -293,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 |