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 CONFIG_AFS_FSCACHE
128 volume
->cache
= fscache_acquire_cookie(vlocation
->cache
,
129 &afs_volume_cache_index_def
,
132 afs_get_vlocation(vlocation
);
133 volume
->vlocation
= vlocation
;
135 vlocation
->vols
[volume
->type
] = volume
;
138 _debug("kAFS selected %s volume %08x",
139 afs_voltypes
[volume
->type
], volume
->vid
);
140 up_write(¶ms
->cell
->vl_sem
);
141 afs_put_vlocation(vlocation
);
142 _leave(" = %p", volume
);
147 up_write(¶ms
->cell
->vl_sem
);
149 afs_put_vlocation(vlocation
);
150 _leave(" = %d", ret
);
154 up_write(¶ms
->cell
->vl_sem
);
156 for (loop
= volume
->nservers
- 1; loop
>= 0; loop
--)
157 afs_put_server(volume
->servers
[loop
]);
164 * destroy a volume record
166 void afs_put_volume(struct afs_volume
*volume
)
168 struct afs_vlocation
*vlocation
;
174 _enter("%p", volume
);
176 ASSERTCMP(atomic_read(&volume
->usage
), >, 0);
178 vlocation
= volume
->vlocation
;
180 /* to prevent a race, the decrement and the dequeue must be effectively
182 down_write(&vlocation
->cell
->vl_sem
);
184 if (likely(!atomic_dec_and_test(&volume
->usage
))) {
185 up_write(&vlocation
->cell
->vl_sem
);
190 vlocation
->vols
[volume
->type
] = NULL
;
192 up_write(&vlocation
->cell
->vl_sem
);
194 /* finish cleaning up the volume */
195 #ifdef CONFIG_AFS_FSCACHE
196 fscache_relinquish_cookie(volume
->cache
, 0);
198 afs_put_vlocation(vlocation
);
200 for (loop
= volume
->nservers
- 1; loop
>= 0; loop
--)
201 afs_put_server(volume
->servers
[loop
]);
205 _leave(" [destroyed]");
209 * pick a server to use to try accessing this volume
210 * - returns with an elevated usage count on the server chosen
212 struct afs_server
*afs_volume_pick_fileserver(struct afs_vnode
*vnode
)
214 struct afs_volume
*volume
= vnode
->volume
;
215 struct afs_server
*server
;
216 int ret
, state
, loop
;
218 _enter("%s", volume
->vlocation
->vldb
.name
);
220 /* stick with the server we're already using if we can */
221 if (vnode
->server
&& vnode
->server
->fs_state
== 0) {
222 afs_get_server(vnode
->server
);
223 _leave(" = %p [current]", vnode
->server
);
224 return vnode
->server
;
227 down_read(&volume
->server_sem
);
229 /* handle the no-server case */
230 if (volume
->nservers
== 0) {
231 ret
= volume
->rjservers
? -ENOMEDIUM
: -ESTALE
;
232 up_read(&volume
->server_sem
);
233 _leave(" = %d [no servers]", ret
);
237 /* basically, just search the list for the first live server and use
240 for (loop
= 0; loop
< volume
->nservers
; loop
++) {
241 server
= volume
->servers
[loop
];
242 state
= server
->fs_state
;
244 _debug("consider %d [%d]", loop
, state
);
247 /* found an apparently healthy server */
249 afs_get_server(server
);
250 up_read(&volume
->server_sem
);
251 _leave(" = %p (picked %08x)",
252 server
, ntohl(server
->addr
.s_addr
));
268 ret
== -ENETUNREACH
||
269 ret
== -EHOSTUNREACH
)
276 ret
== -ENETUNREACH
||
277 ret
== -EHOSTUNREACH
||
278 ret
== -ECONNREFUSED
)
284 /* no available servers
285 * - TODO: handle the no active servers case better
287 up_read(&volume
->server_sem
);
288 _leave(" = %d", ret
);
293 * release a server after use
294 * - releases the ref on the server struct that was acquired by picking
295 * - records result of using a particular server to access a volume
296 * - return 0 to try again, 1 if okay or to issue error
297 * - the caller must release the server struct if result was 0
299 int afs_volume_release_fileserver(struct afs_vnode
*vnode
,
300 struct afs_server
*server
,
303 struct afs_volume
*volume
= vnode
->volume
;
307 volume
->vlocation
->vldb
.name
, ntohl(server
->addr
.s_addr
),
313 server
->fs_act_jif
= jiffies
;
314 server
->fs_state
= 0;
318 /* the fileserver denied all knowledge of the volume */
320 server
->fs_act_jif
= jiffies
;
321 down_write(&volume
->server_sem
);
323 /* firstly, find where the server is in the active list (if it
325 for (loop
= 0; loop
< volume
->nservers
; loop
++)
326 if (volume
->servers
[loop
] == server
)
329 /* no longer there - may have been discarded by another op */
330 goto try_next_server_upw
;
334 memmove(&volume
->servers
[loop
],
335 &volume
->servers
[loop
+ 1],
336 sizeof(volume
->servers
[loop
]) *
337 (volume
->nservers
- loop
));
338 volume
->servers
[volume
->nservers
] = NULL
;
339 afs_put_server(server
);
342 if (volume
->nservers
> 0)
343 /* another server might acknowledge its existence */
344 goto try_next_server_upw
;
346 /* handle the case where all the fileservers have rejected the
348 * - TODO: try asking the fileservers for volume information
349 * - TODO: contact the VL server again to see if the volume is
350 * no longer registered
352 up_write(&volume
->server_sem
);
353 afs_put_server(server
);
354 _leave(" [completely rejected]");
357 /* problem reaching the server */
364 /* mark the server as dead
365 * TODO: vary dead timeout depending on error
367 spin_lock(&server
->fs_lock
);
368 if (!server
->fs_state
) {
369 server
->fs_dead_jif
= jiffies
+ HZ
* 10;
370 server
->fs_state
= result
;
371 printk("kAFS: SERVER DEAD state=%d\n", result
);
373 spin_unlock(&server
->fs_lock
);
374 goto try_next_server
;
376 /* miscellaneous error */
378 server
->fs_act_jif
= jiffies
;
381 /* tell the caller to accept the result */
382 afs_put_server(server
);
383 _leave(" [local failure]");
387 /* tell the caller to loop around and try the next server */
389 up_write(&volume
->server_sem
);
391 afs_put_server(server
);
392 _leave(" [try next server]");