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 init_rwsem(&volume
->server_sem
);
111 /* look up all the applicable server records */
112 for (loop
= 0; loop
< 8; loop
++) {
113 if (vlocation
->vldb
.srvtmask
[loop
] & (1 << volume
->type
)) {
114 server
= afs_lookup_server(
115 volume
->cell
, &vlocation
->vldb
.servers
[loop
]);
116 if (IS_ERR(server
)) {
117 ret
= PTR_ERR(server
);
121 volume
->servers
[volume
->nservers
] = server
;
126 /* attach the cache and volume location */
127 #ifdef AFS_CACHING_SUPPORT
128 cachefs_acquire_cookie(vlocation
->cache
,
129 &afs_vnode_cache_index_def
,
134 afs_get_vlocation(vlocation
);
135 volume
->vlocation
= vlocation
;
137 vlocation
->vols
[volume
->type
] = volume
;
140 _debug("kAFS selected %s volume %08x",
141 afs_voltypes
[volume
->type
], volume
->vid
);
142 up_write(¶ms
->cell
->vl_sem
);
143 afs_put_vlocation(vlocation
);
144 _leave(" = %p", volume
);
149 up_write(¶ms
->cell
->vl_sem
);
151 afs_put_vlocation(vlocation
);
152 _leave(" = %d", ret
);
156 up_write(¶ms
->cell
->vl_sem
);
158 for (loop
= volume
->nservers
- 1; loop
>= 0; loop
--)
159 afs_put_server(volume
->servers
[loop
]);
166 * destroy a volume record
168 void afs_put_volume(struct afs_volume
*volume
)
170 struct afs_vlocation
*vlocation
;
176 _enter("%p", volume
);
178 ASSERTCMP(atomic_read(&volume
->usage
), >, 0);
180 vlocation
= volume
->vlocation
;
182 /* to prevent a race, the decrement and the dequeue must be effectively
184 down_write(&vlocation
->cell
->vl_sem
);
186 if (likely(!atomic_dec_and_test(&volume
->usage
))) {
187 up_write(&vlocation
->cell
->vl_sem
);
192 vlocation
->vols
[volume
->type
] = NULL
;
194 up_write(&vlocation
->cell
->vl_sem
);
196 /* finish cleaning up the volume */
197 #ifdef AFS_CACHING_SUPPORT
198 cachefs_relinquish_cookie(volume
->cache
, 0);
200 afs_put_vlocation(vlocation
);
202 for (loop
= volume
->nservers
- 1; loop
>= 0; loop
--)
203 afs_put_server(volume
->servers
[loop
]);
207 _leave(" [destroyed]");
211 * pick a server to use to try accessing this volume
212 * - returns with an elevated usage count on the server chosen
214 struct afs_server
*afs_volume_pick_fileserver(struct afs_vnode
*vnode
)
216 struct afs_volume
*volume
= vnode
->volume
;
217 struct afs_server
*server
;
218 int ret
, state
, loop
;
220 _enter("%s", volume
->vlocation
->vldb
.name
);
222 /* stick with the server we're already using if we can */
223 if (vnode
->server
&& vnode
->server
->fs_state
== 0) {
224 afs_get_server(vnode
->server
);
225 _leave(" = %p [current]", vnode
->server
);
226 return vnode
->server
;
229 down_read(&volume
->server_sem
);
231 /* handle the no-server case */
232 if (volume
->nservers
== 0) {
233 ret
= volume
->rjservers
? -ENOMEDIUM
: -ESTALE
;
234 up_read(&volume
->server_sem
);
235 _leave(" = %d [no servers]", ret
);
239 /* basically, just search the list for the first live server and use
242 for (loop
= 0; loop
< volume
->nservers
; loop
++) {
243 server
= volume
->servers
[loop
];
244 state
= server
->fs_state
;
246 _debug("consider %d [%d]", loop
, state
);
249 /* found an apparently healthy server */
251 afs_get_server(server
);
252 up_read(&volume
->server_sem
);
253 _leave(" = %p (picked %08x)",
254 server
, ntohl(server
->addr
.s_addr
));
270 ret
== -ENETUNREACH
||
271 ret
== -EHOSTUNREACH
)
278 ret
== -ENETUNREACH
||
279 ret
== -EHOSTUNREACH
||
280 ret
== -ECONNREFUSED
)
286 /* no available servers
287 * - TODO: handle the no active servers case better
289 up_read(&volume
->server_sem
);
290 _leave(" = %d", ret
);
295 * release a server after use
296 * - releases the ref on the server struct that was acquired by picking
297 * - records result of using a particular server to access a volume
298 * - return 0 to try again, 1 if okay or to issue error
299 * - the caller must release the server struct if result was 0
301 int afs_volume_release_fileserver(struct afs_vnode
*vnode
,
302 struct afs_server
*server
,
305 struct afs_volume
*volume
= vnode
->volume
;
309 volume
->vlocation
->vldb
.name
, ntohl(server
->addr
.s_addr
),
315 server
->fs_act_jif
= jiffies
;
316 server
->fs_state
= 0;
320 /* the fileserver denied all knowledge of the volume */
322 server
->fs_act_jif
= jiffies
;
323 down_write(&volume
->server_sem
);
325 /* firstly, find where the server is in the active list (if it
327 for (loop
= 0; loop
< volume
->nservers
; loop
++)
328 if (volume
->servers
[loop
] == server
)
331 /* no longer there - may have been discarded by another op */
332 goto try_next_server_upw
;
336 memmove(&volume
->servers
[loop
],
337 &volume
->servers
[loop
+ 1],
338 sizeof(volume
->servers
[loop
]) *
339 (volume
->nservers
- loop
));
340 volume
->servers
[volume
->nservers
] = NULL
;
341 afs_put_server(server
);
344 if (volume
->nservers
> 0)
345 /* another server might acknowledge its existence */
346 goto try_next_server_upw
;
348 /* handle the case where all the fileservers have rejected the
350 * - TODO: try asking the fileservers for volume information
351 * - TODO: contact the VL server again to see if the volume is
352 * no longer registered
354 up_write(&volume
->server_sem
);
355 afs_put_server(server
);
356 _leave(" [completely rejected]");
359 /* problem reaching the server */
366 /* mark the server as dead
367 * TODO: vary dead timeout depending on error
369 spin_lock(&server
->fs_lock
);
370 if (!server
->fs_state
) {
371 server
->fs_dead_jif
= jiffies
+ HZ
* 10;
372 server
->fs_state
= result
;
373 printk("kAFS: SERVER DEAD state=%d\n", result
);
375 spin_unlock(&server
->fs_lock
);
376 goto try_next_server
;
378 /* miscellaneous error */
380 server
->fs_act_jif
= jiffies
;
383 /* tell the caller to accept the result */
384 afs_put_server(server
);
385 _leave(" [local failure]");
389 /* tell the caller to loop around and try the next server */
391 up_write(&volume
->server_sem
);
393 afs_put_server(server
);
394 _leave(" [try next server]");