diff options
Diffstat (limited to 'fs/afs/cell.c')
-rw-r--r-- | fs/afs/cell.c | 96 |
1 files changed, 72 insertions, 24 deletions
diff --git a/fs/afs/cell.c b/fs/afs/cell.c index e19c13f059ed..0d5eeadf6121 100644 --- a/fs/afs/cell.c +++ b/fs/afs/cell.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | #include <linux/key.h> | 14 | #include <linux/key.h> |
15 | #include <linux/ctype.h> | 15 | #include <linux/ctype.h> |
16 | #include <linux/dns_resolver.h> | ||
16 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
17 | #include <keys/rxrpc-type.h> | 18 | #include <keys/rxrpc-type.h> |
18 | #include "internal.h" | 19 | #include "internal.h" |
@@ -30,21 +31,24 @@ static struct afs_cell *afs_cell_root; | |||
30 | * allocate a cell record and fill in its name, VL server address list and | 31 | * allocate a cell record and fill in its name, VL server address list and |
31 | * allocate an anonymous key | 32 | * allocate an anonymous key |
32 | */ | 33 | */ |
33 | static struct afs_cell *afs_cell_alloc(const char *name, char *vllist) | 34 | static struct afs_cell *afs_cell_alloc(const char *name, unsigned namelen, |
35 | char *vllist) | ||
34 | { | 36 | { |
35 | struct afs_cell *cell; | 37 | struct afs_cell *cell; |
36 | struct key *key; | 38 | struct key *key; |
37 | size_t namelen; | ||
38 | char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next; | 39 | char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next; |
40 | char *dvllist = NULL, *_vllist = NULL; | ||
41 | char delimiter = ':'; | ||
39 | int ret; | 42 | int ret; |
40 | 43 | ||
41 | _enter("%s,%s", name, vllist); | 44 | _enter("%*.*s,%s", namelen, namelen, name ?: "", vllist); |
42 | 45 | ||
43 | BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */ | 46 | BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */ |
44 | 47 | ||
45 | namelen = strlen(name); | 48 | if (namelen > AFS_MAXCELLNAME) { |
46 | if (namelen > AFS_MAXCELLNAME) | 49 | _leave(" = -ENAMETOOLONG"); |
47 | return ERR_PTR(-ENAMETOOLONG); | 50 | return ERR_PTR(-ENAMETOOLONG); |
51 | } | ||
48 | 52 | ||
49 | /* allocate and initialise a cell record */ | 53 | /* allocate and initialise a cell record */ |
50 | cell = kzalloc(sizeof(struct afs_cell) + namelen + 1, GFP_KERNEL); | 54 | cell = kzalloc(sizeof(struct afs_cell) + namelen + 1, GFP_KERNEL); |
@@ -64,15 +68,35 @@ static struct afs_cell *afs_cell_alloc(const char *name, char *vllist) | |||
64 | INIT_LIST_HEAD(&cell->vl_list); | 68 | INIT_LIST_HEAD(&cell->vl_list); |
65 | spin_lock_init(&cell->vl_lock); | 69 | spin_lock_init(&cell->vl_lock); |
66 | 70 | ||
71 | /* if the ip address is invalid, try dns query */ | ||
72 | if (!vllist || strlen(vllist) < 7) { | ||
73 | ret = dns_query("afsdb", name, namelen, "ipv4", &dvllist, NULL); | ||
74 | if (ret < 0) { | ||
75 | if (ret == -ENODATA || ret == -EAGAIN || ret == -ENOKEY) | ||
76 | /* translate these errors into something | ||
77 | * userspace might understand */ | ||
78 | ret = -EDESTADDRREQ; | ||
79 | _leave(" = %d", ret); | ||
80 | return ERR_PTR(ret); | ||
81 | } | ||
82 | _vllist = dvllist; | ||
83 | |||
84 | /* change the delimiter for user-space reply */ | ||
85 | delimiter = ','; | ||
86 | |||
87 | } else { | ||
88 | _vllist = vllist; | ||
89 | } | ||
90 | |||
67 | /* fill in the VL server list from the rest of the string */ | 91 | /* fill in the VL server list from the rest of the string */ |
68 | do { | 92 | do { |
69 | unsigned a, b, c, d; | 93 | unsigned a, b, c, d; |
70 | 94 | ||
71 | next = strchr(vllist, ':'); | 95 | next = strchr(_vllist, delimiter); |
72 | if (next) | 96 | if (next) |
73 | *next++ = 0; | 97 | *next++ = 0; |
74 | 98 | ||
75 | if (sscanf(vllist, "%u.%u.%u.%u", &a, &b, &c, &d) != 4) | 99 | if (sscanf(_vllist, "%u.%u.%u.%u", &a, &b, &c, &d) != 4) |
76 | goto bad_address; | 100 | goto bad_address; |
77 | 101 | ||
78 | if (a > 255 || b > 255 || c > 255 || d > 255) | 102 | if (a > 255 || b > 255 || c > 255 || d > 255) |
@@ -81,7 +105,7 @@ static struct afs_cell *afs_cell_alloc(const char *name, char *vllist) | |||
81 | cell->vl_addrs[cell->vl_naddrs++].s_addr = | 105 | cell->vl_addrs[cell->vl_naddrs++].s_addr = |
82 | htonl((a << 24) | (b << 16) | (c << 8) | d); | 106 | htonl((a << 24) | (b << 16) | (c << 8) | d); |
83 | 107 | ||
84 | } while (cell->vl_naddrs < AFS_CELL_MAX_ADDRS && (vllist = next)); | 108 | } while (cell->vl_naddrs < AFS_CELL_MAX_ADDRS && (_vllist = next)); |
85 | 109 | ||
86 | /* create a key to represent an anonymous user */ | 110 | /* create a key to represent an anonymous user */ |
87 | memcpy(keyname, "afs@", 4); | 111 | memcpy(keyname, "afs@", 4); |
@@ -110,32 +134,36 @@ bad_address: | |||
110 | ret = -EINVAL; | 134 | ret = -EINVAL; |
111 | error: | 135 | error: |
112 | key_put(cell->anonymous_key); | 136 | key_put(cell->anonymous_key); |
137 | kfree(dvllist); | ||
113 | kfree(cell); | 138 | kfree(cell); |
114 | _leave(" = %d", ret); | 139 | _leave(" = %d", ret); |
115 | return ERR_PTR(ret); | 140 | return ERR_PTR(ret); |
116 | } | 141 | } |
117 | 142 | ||
118 | /* | 143 | /* |
119 | * create a cell record | 144 | * afs_cell_crate() - create a cell record |
120 | * - "name" is the name of the cell | 145 | * @name: is the name of the cell. |
121 | * - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format | 146 | * @namsesz: is the strlen of the cell name. |
147 | * @vllist: is a colon separated list of IP addresses in "a.b.c.d" format. | ||
148 | * @retref: is T to return the cell reference when the cell exists. | ||
122 | */ | 149 | */ |
123 | struct afs_cell *afs_cell_create(const char *name, char *vllist) | 150 | struct afs_cell *afs_cell_create(const char *name, unsigned namesz, |
151 | char *vllist, bool retref) | ||
124 | { | 152 | { |
125 | struct afs_cell *cell; | 153 | struct afs_cell *cell; |
126 | int ret; | 154 | int ret; |
127 | 155 | ||
128 | _enter("%s,%s", name, vllist); | 156 | _enter("%*.*s,%s", namesz, namesz, name ?: "", vllist); |
129 | 157 | ||
130 | down_write(&afs_cells_sem); | 158 | down_write(&afs_cells_sem); |
131 | read_lock(&afs_cells_lock); | 159 | read_lock(&afs_cells_lock); |
132 | list_for_each_entry(cell, &afs_cells, link) { | 160 | list_for_each_entry(cell, &afs_cells, link) { |
133 | if (strcasecmp(cell->name, name) == 0) | 161 | if (strncasecmp(cell->name, name, namesz) == 0) |
134 | goto duplicate_name; | 162 | goto duplicate_name; |
135 | } | 163 | } |
136 | read_unlock(&afs_cells_lock); | 164 | read_unlock(&afs_cells_lock); |
137 | 165 | ||
138 | cell = afs_cell_alloc(name, vllist); | 166 | cell = afs_cell_alloc(name, namesz, vllist); |
139 | if (IS_ERR(cell)) { | 167 | if (IS_ERR(cell)) { |
140 | _leave(" = %ld", PTR_ERR(cell)); | 168 | _leave(" = %ld", PTR_ERR(cell)); |
141 | up_write(&afs_cells_sem); | 169 | up_write(&afs_cells_sem); |
@@ -175,8 +203,18 @@ error: | |||
175 | return ERR_PTR(ret); | 203 | return ERR_PTR(ret); |
176 | 204 | ||
177 | duplicate_name: | 205 | duplicate_name: |
206 | if (retref && !IS_ERR(cell)) | ||
207 | afs_get_cell(cell); | ||
208 | |||
178 | read_unlock(&afs_cells_lock); | 209 | read_unlock(&afs_cells_lock); |
179 | up_write(&afs_cells_sem); | 210 | up_write(&afs_cells_sem); |
211 | |||
212 | if (retref) { | ||
213 | _leave(" = %p", cell); | ||
214 | return cell; | ||
215 | } | ||
216 | |||
217 | _leave(" = -EEXIST"); | ||
180 | return ERR_PTR(-EEXIST); | 218 | return ERR_PTR(-EEXIST); |
181 | } | 219 | } |
182 | 220 | ||
@@ -201,15 +239,13 @@ int afs_cell_init(char *rootcell) | |||
201 | } | 239 | } |
202 | 240 | ||
203 | cp = strchr(rootcell, ':'); | 241 | cp = strchr(rootcell, ':'); |
204 | if (!cp) { | 242 | if (!cp) |
205 | printk(KERN_ERR "kAFS: no VL server IP addresses specified\n"); | 243 | _debug("kAFS: no VL server IP addresses specified"); |
206 | _leave(" = -EINVAL"); | 244 | else |
207 | return -EINVAL; | 245 | *cp++ = 0; |
208 | } | ||
209 | 246 | ||
210 | /* allocate a cell record for the root cell */ | 247 | /* allocate a cell record for the root cell */ |
211 | *cp++ = 0; | 248 | new_root = afs_cell_create(rootcell, strlen(rootcell), cp, false); |
212 | new_root = afs_cell_create(rootcell, cp); | ||
213 | if (IS_ERR(new_root)) { | 249 | if (IS_ERR(new_root)) { |
214 | _leave(" = %ld", PTR_ERR(new_root)); | 250 | _leave(" = %ld", PTR_ERR(new_root)); |
215 | return PTR_ERR(new_root); | 251 | return PTR_ERR(new_root); |
@@ -229,11 +265,12 @@ int afs_cell_init(char *rootcell) | |||
229 | /* | 265 | /* |
230 | * lookup a cell record | 266 | * lookup a cell record |
231 | */ | 267 | */ |
232 | struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz) | 268 | struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz, |
269 | bool dns_cell) | ||
233 | { | 270 | { |
234 | struct afs_cell *cell; | 271 | struct afs_cell *cell; |
235 | 272 | ||
236 | _enter("\"%*.*s\",", namesz, namesz, name ? name : ""); | 273 | _enter("\"%*.*s\",", namesz, namesz, name ?: ""); |
237 | 274 | ||
238 | down_read(&afs_cells_sem); | 275 | down_read(&afs_cells_sem); |
239 | read_lock(&afs_cells_lock); | 276 | read_lock(&afs_cells_lock); |
@@ -247,6 +284,8 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz) | |||
247 | } | 284 | } |
248 | } | 285 | } |
249 | cell = ERR_PTR(-ENOENT); | 286 | cell = ERR_PTR(-ENOENT); |
287 | if (dns_cell) | ||
288 | goto create_cell; | ||
250 | found: | 289 | found: |
251 | ; | 290 | ; |
252 | } else { | 291 | } else { |
@@ -269,6 +308,15 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz) | |||
269 | up_read(&afs_cells_sem); | 308 | up_read(&afs_cells_sem); |
270 | _leave(" = %p", cell); | 309 | _leave(" = %p", cell); |
271 | return cell; | 310 | return cell; |
311 | |||
312 | create_cell: | ||
313 | read_unlock(&afs_cells_lock); | ||
314 | up_read(&afs_cells_sem); | ||
315 | |||
316 | cell = afs_cell_create(name, namesz, NULL, true); | ||
317 | |||
318 | _leave(" = %p", cell); | ||
319 | return cell; | ||
272 | } | 320 | } |
273 | 321 | ||
274 | #if 0 | 322 | #if 0 |