blob: a1904ab8426adb12fdecfcc3a353da6b909bdee1 [file] [log] [blame]
David Howellsec268152007-04-26 15:49:28 -07001/* AFS vnode management
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 *
David Howells08e0e7c2007-04-26 15:55:03 -07003 * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * Written by David Howells (dhowells@redhat.com)
5 *
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.
10 */
11
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/slab.h>
16#include <linux/fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include "internal.h"
18
David Howells08e0e7c2007-04-26 15:55:03 -070019#if 0
20static noinline bool dump_tree_aux(struct rb_node *node, struct rb_node *parent,
21 int depth, char lr)
22{
23 struct afs_vnode *vnode;
24 bool bad = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
David Howells08e0e7c2007-04-26 15:55:03 -070026 if (!node)
27 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
David Howells08e0e7c2007-04-26 15:55:03 -070029 if (node->rb_left)
30 bad = dump_tree_aux(node->rb_left, node, depth + 2, '/');
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
David Howells08e0e7c2007-04-26 15:55:03 -070032 vnode = rb_entry(node, struct afs_vnode, cb_promise);
David Howells260a9802007-04-26 15:59:35 -070033 _debug("%c %*.*s%c%p {%d}",
David Howells08e0e7c2007-04-26 15:55:03 -070034 rb_is_red(node) ? 'R' : 'B',
35 depth, depth, "", lr,
36 vnode, vnode->cb_expires_at);
37 if (rb_parent(node) != parent) {
38 printk("BAD: %p != %p\n", rb_parent(node), parent);
39 bad = true;
40 }
41
42 if (node->rb_right)
43 bad |= dump_tree_aux(node->rb_right, node, depth + 2, '\\');
44
45 return bad;
46}
47
48static noinline void dump_tree(const char *name, struct afs_server *server)
49{
David Howells260a9802007-04-26 15:59:35 -070050 _enter("%s", name);
David Howells08e0e7c2007-04-26 15:55:03 -070051 if (dump_tree_aux(server->cb_promises.rb_node, NULL, 0, '-'))
52 BUG();
53}
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#endif
55
Linus Torvalds1da177e2005-04-16 15:20:36 -070056/*
David Howells08e0e7c2007-04-26 15:55:03 -070057 * insert a vnode into the backing server's vnode tree
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 */
David Howells08e0e7c2007-04-26 15:55:03 -070059static void afs_install_vnode(struct afs_vnode *vnode,
60 struct afs_server *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -070061{
David Howells08e0e7c2007-04-26 15:55:03 -070062 struct afs_server *old_server = vnode->server;
63 struct afs_vnode *xvnode;
64 struct rb_node *parent, **p;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
David Howells08e0e7c2007-04-26 15:55:03 -070066 _enter("%p,%p", vnode, server);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
David Howells08e0e7c2007-04-26 15:55:03 -070068 if (old_server) {
69 spin_lock(&old_server->fs_lock);
70 rb_erase(&vnode->server_rb, &old_server->fs_vnodes);
71 spin_unlock(&old_server->fs_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 }
73
David Howells08e0e7c2007-04-26 15:55:03 -070074 afs_get_server(server);
75 vnode->server = server;
76 afs_put_server(old_server);
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
David Howells08e0e7c2007-04-26 15:55:03 -070078 /* insert into the server's vnode tree in FID order */
79 spin_lock(&server->fs_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
David Howells08e0e7c2007-04-26 15:55:03 -070081 parent = NULL;
82 p = &server->fs_vnodes.rb_node;
83 while (*p) {
84 parent = *p;
85 xvnode = rb_entry(parent, struct afs_vnode, server_rb);
86 if (vnode->fid.vid < xvnode->fid.vid)
87 p = &(*p)->rb_left;
88 else if (vnode->fid.vid > xvnode->fid.vid)
89 p = &(*p)->rb_right;
90 else if (vnode->fid.vnode < xvnode->fid.vnode)
91 p = &(*p)->rb_left;
92 else if (vnode->fid.vnode > xvnode->fid.vnode)
93 p = &(*p)->rb_right;
94 else if (vnode->fid.unique < xvnode->fid.unique)
95 p = &(*p)->rb_left;
96 else if (vnode->fid.unique > xvnode->fid.unique)
97 p = &(*p)->rb_right;
98 else
99 BUG(); /* can't happen unless afs_iget() malfunctions */
100 }
101
102 rb_link_node(&vnode->server_rb, parent, p);
103 rb_insert_color(&vnode->server_rb, &server->fs_vnodes);
104
105 spin_unlock(&server->fs_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 _leave("");
David Howellsec268152007-04-26 15:49:28 -0700107}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109/*
David Howells08e0e7c2007-04-26 15:55:03 -0700110 * insert a vnode into the promising server's update/expiration tree
111 * - caller must hold vnode->lock
112 */
113static void afs_vnode_note_promise(struct afs_vnode *vnode,
114 struct afs_server *server)
115{
116 struct afs_server *old_server;
117 struct afs_vnode *xvnode;
118 struct rb_node *parent, **p;
119
120 _enter("%p,%p", vnode, server);
121
122 ASSERT(server != NULL);
123
124 old_server = vnode->server;
125 if (vnode->cb_promised) {
126 if (server == old_server &&
127 vnode->cb_expires == vnode->cb_expires_at) {
128 _leave(" [no change]");
129 return;
130 }
131
132 spin_lock(&old_server->cb_lock);
133 if (vnode->cb_promised) {
134 _debug("delete");
135 rb_erase(&vnode->cb_promise, &old_server->cb_promises);
136 vnode->cb_promised = false;
137 }
138 spin_unlock(&old_server->cb_lock);
139 }
140
141 if (vnode->server != server)
142 afs_install_vnode(vnode, server);
143
144 vnode->cb_expires_at = vnode->cb_expires;
145 _debug("PROMISE on %p {%lu}",
146 vnode, (unsigned long) vnode->cb_expires_at);
147
148 /* abuse an RB-tree to hold the expiration order (we may have multiple
149 * items with the same expiration time) */
150 spin_lock(&server->cb_lock);
151
152 parent = NULL;
153 p = &server->cb_promises.rb_node;
154 while (*p) {
155 parent = *p;
156 xvnode = rb_entry(parent, struct afs_vnode, cb_promise);
157 if (vnode->cb_expires_at < xvnode->cb_expires_at)
158 p = &(*p)->rb_left;
159 else
160 p = &(*p)->rb_right;
161 }
162
163 rb_link_node(&vnode->cb_promise, parent, p);
164 rb_insert_color(&vnode->cb_promise, &server->cb_promises);
165 vnode->cb_promised = true;
166
167 spin_unlock(&server->cb_lock);
168 _leave("");
169}
170
171/*
172 * handle remote file deletion by discarding the callback promise
173 */
174static void afs_vnode_deleted_remotely(struct afs_vnode *vnode)
175{
176 struct afs_server *server;
177
178 set_bit(AFS_VNODE_DELETED, &vnode->flags);
179
180 server = vnode->server;
181 if (vnode->cb_promised) {
182 spin_lock(&server->cb_lock);
183 if (vnode->cb_promised) {
184 rb_erase(&vnode->cb_promise, &server->cb_promises);
185 vnode->cb_promised = false;
186 }
187 spin_unlock(&server->cb_lock);
188 }
189
David Howells260a9802007-04-26 15:59:35 -0700190 spin_lock(&vnode->server->fs_lock);
191 rb_erase(&vnode->server_rb, &vnode->server->fs_vnodes);
192 spin_unlock(&vnode->server->fs_lock);
193
194 vnode->server = NULL;
David Howells08e0e7c2007-04-26 15:55:03 -0700195 afs_put_server(server);
196}
197
198/*
David Howells260a9802007-04-26 15:59:35 -0700199 * finish off updating the recorded status of a file after a successful
200 * operation completion
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 * - starts callback expiry timer
202 * - adds to server's callback list
203 */
David Howells260a9802007-04-26 15:59:35 -0700204void afs_vnode_finalise_status_update(struct afs_vnode *vnode,
205 struct afs_server *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206{
207 struct afs_server *oldserver = NULL;
208
David Howells260a9802007-04-26 15:59:35 -0700209 _enter("%p,%p", vnode, server);
210
211 spin_lock(&vnode->lock);
212 clear_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
213 afs_vnode_note_promise(vnode, server);
214 vnode->update_cnt--;
215 ASSERTCMP(vnode->update_cnt, >=, 0);
216 spin_unlock(&vnode->lock);
217
218 wake_up_all(&vnode->update_waitq);
219 afs_put_server(oldserver);
220 _leave("");
221}
222
223/*
224 * finish off updating the recorded status of a file after an operation failed
225 */
226static void afs_vnode_status_update_failed(struct afs_vnode *vnode, int ret)
227{
228 _enter("%p,%d", vnode, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229
230 spin_lock(&vnode->lock);
231
David Howells08e0e7c2007-04-26 15:55:03 -0700232 clear_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233
David Howells260a9802007-04-26 15:59:35 -0700234 if (ret == -ENOENT) {
David Howells08e0e7c2007-04-26 15:55:03 -0700235 /* the file was deleted on the server */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 _debug("got NOENT from server - marking file deleted");
David Howells08e0e7c2007-04-26 15:55:03 -0700237 afs_vnode_deleted_remotely(vnode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 }
239
240 vnode->update_cnt--;
David Howells260a9802007-04-26 15:59:35 -0700241 ASSERTCMP(vnode->update_cnt, >=, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 spin_unlock(&vnode->lock);
243
244 wake_up_all(&vnode->update_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 _leave("");
David Howellsec268152007-04-26 15:49:28 -0700246}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248/*
249 * fetch file status from the volume
250 * - don't issue a fetch if:
251 * - the changed bit is not set and there's a valid callback
252 * - there are any outstanding ops that will fetch the status
253 * - TODO implement local caching
254 */
David Howells00d3b7a2007-04-26 15:57:07 -0700255int afs_vnode_fetch_status(struct afs_vnode *vnode,
256 struct afs_vnode *auth_vnode, struct key *key)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257{
258 struct afs_server *server;
David Howells00d3b7a2007-04-26 15:57:07 -0700259 unsigned long acl_order;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 int ret;
261
262 DECLARE_WAITQUEUE(myself, current);
263
264 _enter("%s,{%u,%u,%u}",
265 vnode->volume->vlocation->vldb.name,
266 vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
267
David Howells08e0e7c2007-04-26 15:55:03 -0700268 if (!test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) &&
269 vnode->cb_promised) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 _leave(" [unchanged]");
271 return 0;
272 }
273
David Howells08e0e7c2007-04-26 15:55:03 -0700274 if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 _leave(" [deleted]");
276 return -ENOENT;
277 }
278
David Howells00d3b7a2007-04-26 15:57:07 -0700279 acl_order = 0;
280 if (auth_vnode)
281 acl_order = auth_vnode->acl_order;
282
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 spin_lock(&vnode->lock);
284
David Howells08e0e7c2007-04-26 15:55:03 -0700285 if (!test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) &&
286 vnode->cb_promised) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 spin_unlock(&vnode->lock);
288 _leave(" [unchanged]");
289 return 0;
290 }
291
David Howells260a9802007-04-26 15:59:35 -0700292 ASSERTCMP(vnode->update_cnt, >=, 0);
293
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 if (vnode->update_cnt > 0) {
295 /* someone else started a fetch */
David Howells260a9802007-04-26 15:59:35 -0700296 _debug("wait on fetch %d", vnode->update_cnt);
297
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 set_current_state(TASK_UNINTERRUPTIBLE);
David Howells08e0e7c2007-04-26 15:55:03 -0700299 ASSERT(myself.func != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 add_wait_queue(&vnode->update_waitq, &myself);
301
302 /* wait for the status to be updated */
303 for (;;) {
David Howells08e0e7c2007-04-26 15:55:03 -0700304 if (!test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 break;
David Howells08e0e7c2007-04-26 15:55:03 -0700306 if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 break;
308
David Howells08e0e7c2007-04-26 15:55:03 -0700309 /* check to see if it got updated and invalidated all
310 * before we saw it */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 if (vnode->update_cnt == 0) {
312 remove_wait_queue(&vnode->update_waitq,
313 &myself);
314 set_current_state(TASK_RUNNING);
315 goto get_anyway;
316 }
317
318 spin_unlock(&vnode->lock);
319
320 schedule();
321 set_current_state(TASK_UNINTERRUPTIBLE);
322
323 spin_lock(&vnode->lock);
324 }
325
326 remove_wait_queue(&vnode->update_waitq, &myself);
327 spin_unlock(&vnode->lock);
328 set_current_state(TASK_RUNNING);
329
David Howells08e0e7c2007-04-26 15:55:03 -0700330 return test_bit(AFS_VNODE_DELETED, &vnode->flags) ?
331 -ENOENT : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 }
333
David Howellsec268152007-04-26 15:49:28 -0700334get_anyway:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 /* okay... we're going to have to initiate the op */
336 vnode->update_cnt++;
337
338 spin_unlock(&vnode->lock);
339
340 /* merge AFS status fetches and clear outstanding callback on this
341 * vnode */
342 do {
343 /* pick a server to query */
David Howells08e0e7c2007-04-26 15:55:03 -0700344 server = afs_volume_pick_fileserver(vnode);
345 if (IS_ERR(server))
David Howells260a9802007-04-26 15:59:35 -0700346 goto no_server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
David Howells08e0e7c2007-04-26 15:55:03 -0700348 _debug("USING SERVER: %p{%08x}",
349 server, ntohl(server->addr.s_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
David Howells00d3b7a2007-04-26 15:57:07 -0700351 ret = afs_fs_fetch_file_status(server, key, vnode, NULL,
David Howells08e0e7c2007-04-26 15:55:03 -0700352 &afs_sync_call);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
David Howells08e0e7c2007-04-26 15:55:03 -0700354 } while (!afs_volume_release_fileserver(vnode, server, ret));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
356 /* adjust the flags */
David Howells260a9802007-04-26 15:59:35 -0700357 if (ret == 0) {
358 _debug("adjust");
359 if (auth_vnode)
360 afs_cache_permit(vnode, key, acl_order);
361 afs_vnode_finalise_status_update(vnode, server);
362 afs_put_server(server);
363 } else {
364 _debug("failed [%d]", ret);
365 afs_vnode_status_update_failed(vnode, ret);
366 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
David Howells260a9802007-04-26 15:59:35 -0700368 ASSERTCMP(vnode->update_cnt, >=, 0);
369
370 _leave(" = %d [cnt %d]", ret, vnode->update_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 return ret;
David Howells260a9802007-04-26 15:59:35 -0700372
373no_server:
374 spin_lock(&vnode->lock);
375 vnode->update_cnt--;
376 ASSERTCMP(vnode->update_cnt, >=, 0);
377 spin_unlock(&vnode->lock);
378 _leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt);
379 return PTR_ERR(server);
David Howellsec268152007-04-26 15:49:28 -0700380}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382/*
383 * fetch file data from the volume
David Howells260a9802007-04-26 15:59:35 -0700384 * - TODO implement caching
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 */
David Howells00d3b7a2007-04-26 15:57:07 -0700386int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key,
387 off_t offset, size_t length, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388{
389 struct afs_server *server;
390 int ret;
391
David Howells00d3b7a2007-04-26 15:57:07 -0700392 _enter("%s{%u,%u,%u},%x,,,",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 vnode->volume->vlocation->vldb.name,
394 vnode->fid.vid,
395 vnode->fid.vnode,
David Howells00d3b7a2007-04-26 15:57:07 -0700396 vnode->fid.unique,
397 key_serial(key));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
399 /* this op will fetch the status */
400 spin_lock(&vnode->lock);
401 vnode->update_cnt++;
402 spin_unlock(&vnode->lock);
403
404 /* merge in AFS status fetches and clear outstanding callback on this
405 * vnode */
406 do {
407 /* pick a server to query */
David Howells08e0e7c2007-04-26 15:55:03 -0700408 server = afs_volume_pick_fileserver(vnode);
409 if (IS_ERR(server))
David Howells260a9802007-04-26 15:59:35 -0700410 goto no_server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411
412 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
413
David Howells00d3b7a2007-04-26 15:57:07 -0700414 ret = afs_fs_fetch_data(server, key, vnode, offset, length,
David Howells260a9802007-04-26 15:59:35 -0700415 page, &afs_sync_call);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
David Howells08e0e7c2007-04-26 15:55:03 -0700417 } while (!afs_volume_release_fileserver(vnode, server, ret));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
419 /* adjust the flags */
David Howells260a9802007-04-26 15:59:35 -0700420 if (ret == 0) {
421 afs_vnode_finalise_status_update(vnode, server);
422 afs_put_server(server);
423 } else {
424 afs_vnode_status_update_failed(vnode, ret);
425 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
427 _leave(" = %d", ret);
428 return ret;
David Howells260a9802007-04-26 15:59:35 -0700429
430no_server:
431 spin_lock(&vnode->lock);
432 vnode->update_cnt--;
433 ASSERTCMP(vnode->update_cnt, >=, 0);
434 spin_unlock(&vnode->lock);
435 return PTR_ERR(server);
436}
437
438/*
439 * make a file or a directory
440 */
441int afs_vnode_create(struct afs_vnode *vnode, struct key *key,
442 const char *name, umode_t mode, struct afs_fid *newfid,
443 struct afs_file_status *newstatus,
444 struct afs_callback *newcb, struct afs_server **_server)
445{
446 struct afs_server *server;
447 int ret;
448
449 _enter("%s{%u,%u,%u},%x,%s,,",
450 vnode->volume->vlocation->vldb.name,
451 vnode->fid.vid,
452 vnode->fid.vnode,
453 vnode->fid.unique,
454 key_serial(key),
455 name);
456
457 /* this op will fetch the status on the directory we're creating in */
458 spin_lock(&vnode->lock);
459 vnode->update_cnt++;
460 spin_unlock(&vnode->lock);
461
462 do {
463 /* pick a server to query */
464 server = afs_volume_pick_fileserver(vnode);
465 if (IS_ERR(server))
466 goto no_server;
467
468 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
469
470 ret = afs_fs_create(server, key, vnode, name, mode, newfid,
471 newstatus, newcb, &afs_sync_call);
472
473 } while (!afs_volume_release_fileserver(vnode, server, ret));
474
475 /* adjust the flags */
476 if (ret == 0) {
477 afs_vnode_finalise_status_update(vnode, server);
478 *_server = server;
479 } else {
480 afs_vnode_status_update_failed(vnode, ret);
481 *_server = NULL;
482 }
483
484 _leave(" = %d [cnt %d]", ret, vnode->update_cnt);
485 return ret;
486
487no_server:
488 spin_lock(&vnode->lock);
489 vnode->update_cnt--;
490 ASSERTCMP(vnode->update_cnt, >=, 0);
491 spin_unlock(&vnode->lock);
492 _leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt);
493 return PTR_ERR(server);
494}
495
496/*
497 * remove a file or directory
498 */
499int afs_vnode_remove(struct afs_vnode *vnode, struct key *key, const char *name,
500 bool isdir)
501{
502 struct afs_server *server;
503 int ret;
504
505 _enter("%s{%u,%u,%u},%x,%s",
506 vnode->volume->vlocation->vldb.name,
507 vnode->fid.vid,
508 vnode->fid.vnode,
509 vnode->fid.unique,
510 key_serial(key),
511 name);
512
513 /* this op will fetch the status on the directory we're removing from */
514 spin_lock(&vnode->lock);
515 vnode->update_cnt++;
516 spin_unlock(&vnode->lock);
517
518 do {
519 /* pick a server to query */
520 server = afs_volume_pick_fileserver(vnode);
521 if (IS_ERR(server))
522 goto no_server;
523
524 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
525
526 ret = afs_fs_remove(server, key, vnode, name, isdir,
527 &afs_sync_call);
528
529 } while (!afs_volume_release_fileserver(vnode, server, ret));
530
531 /* adjust the flags */
532 if (ret == 0) {
533 afs_vnode_finalise_status_update(vnode, server);
534 afs_put_server(server);
535 } else {
536 afs_vnode_status_update_failed(vnode, ret);
537 }
538
539 _leave(" = %d [cnt %d]", ret, vnode->update_cnt);
540 return ret;
541
542no_server:
543 spin_lock(&vnode->lock);
544 vnode->update_cnt--;
545 ASSERTCMP(vnode->update_cnt, >=, 0);
546 spin_unlock(&vnode->lock);
547 _leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt);
548 return PTR_ERR(server);
549}
550
551/*
552 * create a hard link
553 */
554extern int afs_vnode_link(struct afs_vnode *dvnode, struct afs_vnode *vnode,
555 struct key *key, const char *name)
556{
557 struct afs_server *server;
558 int ret;
559
560 _enter("%s{%u,%u,%u},%s{%u,%u,%u},%x,%s",
561 dvnode->volume->vlocation->vldb.name,
562 dvnode->fid.vid,
563 dvnode->fid.vnode,
564 dvnode->fid.unique,
565 vnode->volume->vlocation->vldb.name,
566 vnode->fid.vid,
567 vnode->fid.vnode,
568 vnode->fid.unique,
569 key_serial(key),
570 name);
571
572 /* this op will fetch the status on the directory we're removing from */
573 spin_lock(&vnode->lock);
574 vnode->update_cnt++;
575 spin_unlock(&vnode->lock);
576 spin_lock(&dvnode->lock);
577 dvnode->update_cnt++;
578 spin_unlock(&dvnode->lock);
579
580 do {
581 /* pick a server to query */
582 server = afs_volume_pick_fileserver(dvnode);
583 if (IS_ERR(server))
584 goto no_server;
585
586 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
587
588 ret = afs_fs_link(server, key, dvnode, vnode, name,
589 &afs_sync_call);
590
591 } while (!afs_volume_release_fileserver(dvnode, server, ret));
592
593 /* adjust the flags */
594 if (ret == 0) {
595 afs_vnode_finalise_status_update(vnode, server);
596 afs_vnode_finalise_status_update(dvnode, server);
597 afs_put_server(server);
598 } else {
599 afs_vnode_status_update_failed(vnode, ret);
600 afs_vnode_status_update_failed(dvnode, ret);
601 }
602
603 _leave(" = %d [cnt %d]", ret, vnode->update_cnt);
604 return ret;
605
606no_server:
607 spin_lock(&vnode->lock);
608 vnode->update_cnt--;
609 ASSERTCMP(vnode->update_cnt, >=, 0);
610 spin_unlock(&vnode->lock);
611 spin_lock(&dvnode->lock);
612 dvnode->update_cnt--;
613 ASSERTCMP(dvnode->update_cnt, >=, 0);
614 spin_unlock(&dvnode->lock);
615 _leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt);
616 return PTR_ERR(server);
617}
618
619/*
620 * create a symbolic link
621 */
622int afs_vnode_symlink(struct afs_vnode *vnode, struct key *key,
623 const char *name, const char *content,
624 struct afs_fid *newfid,
625 struct afs_file_status *newstatus,
626 struct afs_server **_server)
627{
628 struct afs_server *server;
629 int ret;
630
631 _enter("%s{%u,%u,%u},%x,%s,%s,,,",
632 vnode->volume->vlocation->vldb.name,
633 vnode->fid.vid,
634 vnode->fid.vnode,
635 vnode->fid.unique,
636 key_serial(key),
637 name, content);
638
639 /* this op will fetch the status on the directory we're creating in */
640 spin_lock(&vnode->lock);
641 vnode->update_cnt++;
642 spin_unlock(&vnode->lock);
643
644 do {
645 /* pick a server to query */
646 server = afs_volume_pick_fileserver(vnode);
647 if (IS_ERR(server))
648 goto no_server;
649
650 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
651
652 ret = afs_fs_symlink(server, key, vnode, name, content,
653 newfid, newstatus, &afs_sync_call);
654
655 } while (!afs_volume_release_fileserver(vnode, server, ret));
656
657 /* adjust the flags */
658 if (ret == 0) {
659 afs_vnode_finalise_status_update(vnode, server);
660 *_server = server;
661 } else {
662 afs_vnode_status_update_failed(vnode, ret);
663 *_server = NULL;
664 }
665
666 _leave(" = %d [cnt %d]", ret, vnode->update_cnt);
667 return ret;
668
669no_server:
670 spin_lock(&vnode->lock);
671 vnode->update_cnt--;
672 ASSERTCMP(vnode->update_cnt, >=, 0);
673 spin_unlock(&vnode->lock);
674 _leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt);
675 return PTR_ERR(server);
676}
677
678/*
679 * rename a file
680 */
681int afs_vnode_rename(struct afs_vnode *orig_dvnode,
682 struct afs_vnode *new_dvnode,
683 struct key *key,
684 const char *orig_name,
685 const char *new_name)
686{
687 struct afs_server *server;
688 int ret;
689
690 _enter("%s{%u,%u,%u},%s{%u,%u,%u},%x,%s,%s",
691 orig_dvnode->volume->vlocation->vldb.name,
692 orig_dvnode->fid.vid,
693 orig_dvnode->fid.vnode,
694 orig_dvnode->fid.unique,
695 new_dvnode->volume->vlocation->vldb.name,
696 new_dvnode->fid.vid,
697 new_dvnode->fid.vnode,
698 new_dvnode->fid.unique,
699 key_serial(key),
700 orig_name,
701 new_name);
702
703 /* this op will fetch the status on both the directories we're dealing
704 * with */
705 spin_lock(&orig_dvnode->lock);
706 orig_dvnode->update_cnt++;
707 spin_unlock(&orig_dvnode->lock);
708 if (new_dvnode != orig_dvnode) {
709 spin_lock(&new_dvnode->lock);
710 new_dvnode->update_cnt++;
711 spin_unlock(&new_dvnode->lock);
712 }
713
714 do {
715 /* pick a server to query */
716 server = afs_volume_pick_fileserver(orig_dvnode);
717 if (IS_ERR(server))
718 goto no_server;
719
720 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
721
722 ret = afs_fs_rename(server, key, orig_dvnode, orig_name,
723 new_dvnode, new_name, &afs_sync_call);
724
725 } while (!afs_volume_release_fileserver(orig_dvnode, server, ret));
726
727 /* adjust the flags */
728 if (ret == 0) {
729 afs_vnode_finalise_status_update(orig_dvnode, server);
730 if (new_dvnode != orig_dvnode)
731 afs_vnode_finalise_status_update(new_dvnode, server);
732 afs_put_server(server);
733 } else {
734 afs_vnode_status_update_failed(orig_dvnode, ret);
735 if (new_dvnode != orig_dvnode)
736 afs_vnode_status_update_failed(new_dvnode, ret);
737 }
738
739 _leave(" = %d [cnt %d]", ret, orig_dvnode->update_cnt);
740 return ret;
741
742no_server:
743 spin_lock(&orig_dvnode->lock);
744 orig_dvnode->update_cnt--;
745 ASSERTCMP(orig_dvnode->update_cnt, >=, 0);
746 spin_unlock(&orig_dvnode->lock);
747 if (new_dvnode != orig_dvnode) {
748 spin_lock(&new_dvnode->lock);
749 new_dvnode->update_cnt--;
750 ASSERTCMP(new_dvnode->update_cnt, >=, 0);
751 spin_unlock(&new_dvnode->lock);
752 }
753 _leave(" = %ld [cnt %d]", PTR_ERR(server), orig_dvnode->update_cnt);
754 return PTR_ERR(server);
David Howellsec268152007-04-26 15:49:28 -0700755}