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>
20 static const char *afs_voltypes
[] = { "R/W", "R/O", "BAK" };
23 * lookup a volume by name
24 * - this can be one of the following:
25 * "%[cell:]volume[.]" R/W volume
26 * "#[cell:]volume[.]" R/O or R/W volume (rwparent=0),
27 * or R/W (rwparent=1) volume
28 * "%[cell:]volume.readonly" R/O volume
29 * "#[cell:]volume.readonly" R/O volume
30 * "%[cell:]volume.backup" Backup volume
31 * "#[cell:]volume.backup" Backup volume
33 * The cell name is optional, and defaults to the current cell.
35 * See "The Rules of Mount Point Traversal" in Chapter 5 of the AFS SysAdmin
37 * - Rule 1: Explicit type suffix forces access of that type or nothing
38 * (no suffix, then use Rule 2 & 3)
39 * - Rule 2: If parent volume is R/O, then mount R/O volume by preference, R/W
41 * - Rule 3: If parent volume is R/W, then only mount R/W volume unless
42 * explicitly told otherwise
44 struct afs_volume
*afs_volume_lookup(struct afs_mount_params
*params
)
46 struct afs_vlocation
*vlocation
= NULL
;
47 struct afs_volume
*volume
= NULL
;
48 struct afs_server
*server
= NULL
;
53 params
->volnamesz
, params
->volnamesz
, params
->volname
, params
->rwpath
);
55 /* lookup the volume location record */
56 vlocation
= afs_vlocation_lookup(params
->cell
, params
->key
,
57 params
->volname
, params
->volnamesz
);
58 if (IS_ERR(vlocation
)) {
59 ret
= PTR_ERR(vlocation
);
64 /* make the final decision on the type we want */
66 if (params
->force
&& !(vlocation
->vldb
.vidmask
& (1 << params
->type
)))
70 for (loop
= 0; loop
< vlocation
->vldb
.nservers
; loop
++)
71 srvtmask
|= vlocation
->vldb
.srvtmask
[loop
];
74 if (!(srvtmask
& (1 << params
->type
)))
76 } else if (srvtmask
& AFS_VOL_VTM_RO
) {
77 params
->type
= AFSVL_ROVOL
;
78 } else if (srvtmask
& AFS_VOL_VTM_RW
) {
79 params
->type
= AFSVL_RWVOL
;
84 down_write(¶ms
->cell
->vl_sem
);
86 /* is the volume already active? */
87 if (vlocation
->vols
[params
->type
]) {
89 volume
= vlocation
->vols
[params
->type
];
90 afs_get_volume(volume
);
94 /* create a new volume record */
95 _debug("creating new volume record");
98 volume
= kzalloc(sizeof(struct afs_volume
), GFP_KERNEL
);
102 atomic_set(&volume
->usage
, 1);
103 volume
->type
= params
->type
;
104 volume
->type_force
= params
->force
;
105 volume
->cell
= params
->cell
;
106 volume
->vid
= vlocation
->vldb
.vid
[params
->type
];
108 init_rwsem(&volume
->server_sem
);
110 /* look up all the applicable server records */
111 for (loop
= 0; loop
< 8; loop
++) {
112 if (vlocation
->vldb
.srvtmask
[loop
] & (1 << volume
->type
)) {
113 server
= afs_lookup_server(
114 volume
->cell
, &vlocation
->vldb
.servers
[loop
]);
115 if (IS_ERR(server
)) {
116 ret
= PTR_ERR(server
);
120 volume
->servers
[volume
->nservers
] = server
;
125 /* attach the cache and volume location */
126 #ifdef AFS_CACHING_SUPPORT
127 cachefs_acquire_cookie(vlocation
->cache
,
128 &afs_vnode_cache_index_def
,
133 afs_get_vlocation(vlocation
);
134 volume
->vlocation
= vlocation
;
136 vlocation
->vols
[volume
->type
] = volume
;
139 _debug("kAFS selected %s volume %08x",
140 afs_voltypes
[volume
->type
], volume
->vid
);
141 up_write(¶ms
->cell
->vl_sem
);
142 afs_put_vlocation(vlocation
);
143 _leave(" = %p", volume
);
148 up_write(¶ms
->cell
->vl_sem
);
150 afs_put_vlocation(vlocation
);
151 _leave(" = %d", ret
);
155 up_write(¶ms
->cell
->vl_sem
);
157 for (loop
= volume
->nservers
- 1; loop
>= 0; loop
--)
158 afs_put_server(volume
->servers
[loop
]);
165 * destroy a volume record
167 void afs_put_volume(struct afs_volume
*volume
)
169 struct afs_vlocation
*vlocation
;
175 _enter("%p", volume
);
177 ASSERTCMP(atomic_read(&volume
->usage
), >, 0);
179 vlocation
= volume
->vlocation
;
181 /* to prevent a race, the decrement and the dequeue must be effectively
183 down_write(&vlocation
->cell
->vl_sem
);
185 if (likely(!atomic_dec_and_test(&volume
->usage
))) {
186 up_write(&vlocation
->cell
->vl_sem
);
191 vlocation
->vols
[volume
->type
] = NULL
;
193 up_write(&vlocation
->cell
->vl_sem
);
195 /* finish cleaning up the volume */
196 #ifdef AFS_CACHING_SUPPORT
197 cachefs_relinquish_cookie(volume
->cache
, 0);
199 afs_put_vlocation(vlocation
);
201 for (loop
= volume
->nservers
- 1; loop
>= 0; loop
--)
202 afs_put_server(volume
->servers
[loop
]);
206 _leave(" [destroyed]");
210 * pick a server to use to try accessing this volume
211 * - returns with an elevated usage count on the server chosen
213 struct afs_server
*afs_volume_pick_fileserver(struct afs_vnode
*vnode
)
215 struct afs_volume
*volume
= vnode
->volume
;
216 struct afs_server
*server
;
217 int ret
, state
, loop
;
219 _enter("%s", volume
->vlocation
->vldb
.name
);
221 /* stick with the server we're already using if we can */
222 if (vnode
->server
&& vnode
->server
->fs_state
== 0) {
223 afs_get_server(vnode
->server
);
224 _leave(" = %p [current]", vnode
->server
);
225 return vnode
->server
;
228 down_read(&volume
->server_sem
);
230 /* handle the no-server case */
231 if (volume
->nservers
== 0) {
232 ret
= volume
->rjservers
? -ENOMEDIUM
: -ESTALE
;
233 up_read(&volume
->server_sem
);
234 _leave(" = %d [no servers]", ret
);
238 /* basically, just search the list for the first live server and use
241 for (loop
= 0; loop
< volume
->nservers
; loop
++) {
242 server
= volume
->servers
[loop
];
243 state
= server
->fs_state
;
245 _debug("consider %d [%d]", loop
, state
);
248 /* found an apparently healthy server */
250 afs_get_server(server
);
251 up_read(&volume
->server_sem
);
252 _leave(" = %p (picked %08x)",
253 server
, ntohl(server
->addr
.s_addr
));
269 ret
== -ENETUNREACH
||
270 ret
== -EHOSTUNREACH
)
277 ret
== -ENETUNREACH
||
278 ret
== -EHOSTUNREACH
||
279 ret
== -ECONNREFUSED
)
285 /* no available servers
286 * - TODO: handle the no active servers case better
288 up_read(&volume
->server_sem
);
289 _leave(" = %d", ret
);
294 * release a server after use
295 * - releases the ref on the server struct that was acquired by picking
296 * - records result of using a particular server to access a volume
297 * - return 0 to try again, 1 if okay or to issue error
298 * - the caller must release the server struct if result was 0
300 int afs_volume_release_fileserver(struct afs_vnode
*vnode
,
301 struct afs_server
*server
,
304 struct afs_volume
*volume
= vnode
->volume
;
308 volume
->vlocation
->vldb
.name
, ntohl(server
->addr
.s_addr
),
314 server
->fs_act_jif
= jiffies
;
315 server
->fs_state
= 0;
319 /* the fileserver denied all knowledge of the volume */
321 server
->fs_act_jif
= jiffies
;
322 down_write(&volume
->server_sem
);
324 /* firstly, find where the server is in the active list (if it
326 for (loop
= 0; loop
< volume
->nservers
; loop
++)
327 if (volume
->servers
[loop
] == server
)
330 /* no longer there - may have been discarded by another op */
331 goto try_next_server_upw
;
335 memmove(&volume
->servers
[loop
],
336 &volume
->servers
[loop
+ 1],
337 sizeof(volume
->servers
[loop
]) *
338 (volume
->nservers
- loop
));
339 volume
->servers
[volume
->nservers
] = NULL
;
340 afs_put_server(server
);
343 if (volume
->nservers
> 0)
344 /* another server might acknowledge its existence */
345 goto try_next_server_upw
;
347 /* handle the case where all the fileservers have rejected the
349 * - TODO: try asking the fileservers for volume information
350 * - TODO: contact the VL server again to see if the volume is
351 * no longer registered
353 up_write(&volume
->server_sem
);
354 afs_put_server(server
);
355 _leave(" [completely rejected]");
358 /* problem reaching the server */
365 /* mark the server as dead
366 * TODO: vary dead timeout depending on error
368 spin_lock(&server
->fs_lock
);
369 if (!server
->fs_state
) {
370 server
->fs_dead_jif
= jiffies
+ HZ
* 10;
371 server
->fs_state
= result
;
372 printk("kAFS: SERVER DEAD state=%d\n", result
);
374 spin_unlock(&server
->fs_lock
);
375 goto try_next_server
;
377 /* miscellaneous error */
379 server
->fs_act_jif
= jiffies
;
382 /* tell the caller to accept the result */
383 afs_put_server(server
);
384 _leave(" [local failure]");
388 /* tell the caller to loop around and try the next server */
390 up_write(&volume
->server_sem
);
392 afs_put_server(server
);
393 _leave(" [try next server]");