1 /* AFS volume management
3 * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/slab.h>
17 #include <linux/pagemap.h>
18 #include <linux/sched.h>
21 static const char *afs_voltypes
[] = { "R/W", "R/O", "BAK" };
24 * lookup a volume by name
25 * - this can be one of the following:
26 * "%[cell:]volume[.]" R/W volume
27 * "#[cell:]volume[.]" R/O or R/W volume (rwparent=0),
28 * or R/W (rwparent=1) volume
29 * "%[cell:]volume.readonly" R/O volume
30 * "#[cell:]volume.readonly" R/O volume
31 * "%[cell:]volume.backup" Backup volume
32 * "#[cell:]volume.backup" Backup volume
34 * The cell name is optional, and defaults to the current cell.
36 * See "The Rules of Mount Point Traversal" in Chapter 5 of the AFS SysAdmin
38 * - Rule 1: Explicit type suffix forces access of that type or nothing
39 * (no suffix, then use Rule 2 & 3)
40 * - Rule 2: If parent volume is R/O, then mount R/O volume by preference, R/W
42 * - Rule 3: If parent volume is R/W, then only mount R/W volume unless
43 * explicitly told otherwise
45 struct afs_volume
*afs_volume_lookup(struct afs_mount_params
*params
)
47 struct afs_vlocation
*vlocation
= NULL
;
48 struct afs_volume
*volume
= NULL
;
49 struct afs_server
*server
= NULL
;
54 params
->volnamesz
, params
->volnamesz
, params
->volname
, params
->rwpath
);
56 /* lookup the volume location record */
57 vlocation
= afs_vlocation_lookup(params
->cell
, params
->key
,
58 params
->volname
, params
->volnamesz
);
59 if (IS_ERR(vlocation
)) {
60 ret
= PTR_ERR(vlocation
);
65 /* make the final decision on the type we want */
67 if (params
->force
&& !(vlocation
->vldb
.vidmask
& (1 << params
->type
)))
71 for (loop
= 0; loop
< vlocation
->vldb
.nservers
; loop
++)
72 srvtmask
|= vlocation
->vldb
.srvtmask
[loop
];
75 if (!(srvtmask
& (1 << params
->type
)))
77 } else if (srvtmask
& AFS_VOL_VTM_RO
) {
78 params
->type
= AFSVL_ROVOL
;
79 } else if (srvtmask
& AFS_VOL_VTM_RW
) {
80 params
->type
= AFSVL_RWVOL
;
85 down_write(¶ms
->cell
->vl_sem
);
87 /* is the volume already active? */
88 if (vlocation
->vols
[params
->type
]) {
90 volume
= vlocation
->vols
[params
->type
];
91 afs_get_volume(volume
);
95 /* create a new volume record */
96 _debug("creating new volume record");
99 volume
= kzalloc(sizeof(struct afs_volume
), GFP_KERNEL
);
103 atomic_set(&volume
->usage
, 1);
104 volume
->type
= params
->type
;
105 volume
->type_force
= params
->force
;
106 volume
->cell
= params
->cell
;
107 volume
->vid
= vlocation
->vldb
.vid
[params
->type
];
109 ret
= bdi_setup_and_register(&volume
->bdi
, "afs", BDI_CAP_MAP_COPY
);
113 init_rwsem(&volume
->server_sem
);
115 /* look up all the applicable server records */
116 for (loop
= 0; loop
< 8; loop
++) {
117 if (vlocation
->vldb
.srvtmask
[loop
] & (1 << volume
->type
)) {
118 server
= afs_lookup_server(
119 volume
->cell
, &vlocation
->vldb
.servers
[loop
]);
120 if (IS_ERR(server
)) {
121 ret
= PTR_ERR(server
);
125 volume
->servers
[volume
->nservers
] = server
;
130 /* attach the cache and volume location */
131 #ifdef CONFIG_AFS_FSCACHE
132 volume
->cache
= fscache_acquire_cookie(vlocation
->cache
,
133 &afs_volume_cache_index_def
,
136 afs_get_vlocation(vlocation
);
137 volume
->vlocation
= vlocation
;
139 vlocation
->vols
[volume
->type
] = volume
;
142 _debug("kAFS selected %s volume %08x",
143 afs_voltypes
[volume
->type
], volume
->vid
);
144 up_write(¶ms
->cell
->vl_sem
);
145 afs_put_vlocation(vlocation
);
146 _leave(" = %p", volume
);
151 up_write(¶ms
->cell
->vl_sem
);
153 afs_put_vlocation(vlocation
);
154 _leave(" = %d", ret
);
158 bdi_destroy(&volume
->bdi
);
160 up_write(¶ms
->cell
->vl_sem
);
162 for (loop
= volume
->nservers
- 1; loop
>= 0; loop
--)
163 afs_put_server(volume
->servers
[loop
]);
170 * destroy a volume record
172 void afs_put_volume(struct afs_volume
*volume
)
174 struct afs_vlocation
*vlocation
;
180 _enter("%p", volume
);
182 ASSERTCMP(atomic_read(&volume
->usage
), >, 0);
184 vlocation
= volume
->vlocation
;
186 /* to prevent a race, the decrement and the dequeue must be effectively
188 down_write(&vlocation
->cell
->vl_sem
);
190 if (likely(!atomic_dec_and_test(&volume
->usage
))) {
191 up_write(&vlocation
->cell
->vl_sem
);
196 vlocation
->vols
[volume
->type
] = NULL
;
198 up_write(&vlocation
->cell
->vl_sem
);
200 /* finish cleaning up the volume */
201 #ifdef CONFIG_AFS_FSCACHE
202 fscache_relinquish_cookie(volume
->cache
, 0);
204 afs_put_vlocation(vlocation
);
206 for (loop
= volume
->nservers
- 1; loop
>= 0; loop
--)
207 afs_put_server(volume
->servers
[loop
]);
209 bdi_destroy(&volume
->bdi
);
212 _leave(" [destroyed]");
216 * pick a server to use to try accessing this volume
217 * - returns with an elevated usage count on the server chosen
219 struct afs_server
*afs_volume_pick_fileserver(struct afs_vnode
*vnode
)
221 struct afs_volume
*volume
= vnode
->volume
;
222 struct afs_server
*server
;
223 int ret
, state
, loop
;
225 _enter("%s", volume
->vlocation
->vldb
.name
);
227 /* stick with the server we're already using if we can */
228 if (vnode
->server
&& vnode
->server
->fs_state
== 0) {
229 afs_get_server(vnode
->server
);
230 _leave(" = %p [current]", vnode
->server
);
231 return vnode
->server
;
234 down_read(&volume
->server_sem
);
236 /* handle the no-server case */
237 if (volume
->nservers
== 0) {
238 ret
= volume
->rjservers
? -ENOMEDIUM
: -ESTALE
;
239 up_read(&volume
->server_sem
);
240 _leave(" = %d [no servers]", ret
);
244 /* basically, just search the list for the first live server and use
247 for (loop
= 0; loop
< volume
->nservers
; loop
++) {
248 server
= volume
->servers
[loop
];
249 state
= server
->fs_state
;
251 _debug("consider %d [%d]", loop
, state
);
254 /* found an apparently healthy server */
256 afs_get_server(server
);
257 up_read(&volume
->server_sem
);
258 _leave(" = %p (picked %08x)",
259 server
, ntohl(server
->addr
.s_addr
));
275 ret
== -ENETUNREACH
||
276 ret
== -EHOSTUNREACH
)
283 ret
== -ENETUNREACH
||
284 ret
== -EHOSTUNREACH
||
285 ret
== -ECONNREFUSED
)
291 /* no available servers
292 * - TODO: handle the no active servers case better
294 up_read(&volume
->server_sem
);
295 _leave(" = %d", ret
);
300 * release a server after use
301 * - releases the ref on the server struct that was acquired by picking
302 * - records result of using a particular server to access a volume
303 * - return 0 to try again, 1 if okay or to issue error
304 * - the caller must release the server struct if result was 0
306 int afs_volume_release_fileserver(struct afs_vnode
*vnode
,
307 struct afs_server
*server
,
310 struct afs_volume
*volume
= vnode
->volume
;
314 volume
->vlocation
->vldb
.name
, ntohl(server
->addr
.s_addr
),
320 server
->fs_act_jif
= jiffies
;
321 server
->fs_state
= 0;
325 /* the fileserver denied all knowledge of the volume */
327 server
->fs_act_jif
= jiffies
;
328 down_write(&volume
->server_sem
);
330 /* firstly, find where the server is in the active list (if it
332 for (loop
= 0; loop
< volume
->nservers
; loop
++)
333 if (volume
->servers
[loop
] == server
)
336 /* no longer there - may have been discarded by another op */
337 goto try_next_server_upw
;
341 memmove(&volume
->servers
[loop
],
342 &volume
->servers
[loop
+ 1],
343 sizeof(volume
->servers
[loop
]) *
344 (volume
->nservers
- loop
));
345 volume
->servers
[volume
->nservers
] = NULL
;
346 afs_put_server(server
);
349 if (volume
->nservers
> 0)
350 /* another server might acknowledge its existence */
351 goto try_next_server_upw
;
353 /* handle the case where all the fileservers have rejected the
355 * - TODO: try asking the fileservers for volume information
356 * - TODO: contact the VL server again to see if the volume is
357 * no longer registered
359 up_write(&volume
->server_sem
);
360 afs_put_server(server
);
361 _leave(" [completely rejected]");
364 /* problem reaching the server */
371 /* mark the server as dead
372 * TODO: vary dead timeout depending on error
374 spin_lock(&server
->fs_lock
);
375 if (!server
->fs_state
) {
376 server
->fs_dead_jif
= jiffies
+ HZ
* 10;
377 server
->fs_state
= result
;
378 printk("kAFS: SERVER DEAD state=%d\n", result
);
380 spin_unlock(&server
->fs_lock
);
381 goto try_next_server
;
383 /* miscellaneous error */
385 server
->fs_act_jif
= jiffies
;
388 /* tell the caller to accept the result */
389 afs_put_server(server
);
390 _leave(" [local failure]");
394 /* tell the caller to loop around and try the next server */
396 up_write(&volume
->server_sem
);
398 afs_put_server(server
);
399 _leave(" [try next server]");