AFS: export a couple of core functions for AFS write support
[deliverable/linux.git] / fs / afs / vnode.c
CommitLineData
ec26815a 1/* AFS vnode management
1da177e4 2 *
08e0e7c8 3 * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
1da177e4
LT
4 * 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>
1da177e4
LT
17#include "internal.h"
18
08e0e7c8
DH
19#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;
25
26 if (!node)
27 return false;
28
29 if (node->rb_left)
30 bad = dump_tree_aux(node->rb_left, node, depth + 2, '/');
31
32 vnode = rb_entry(node, struct afs_vnode, cb_promise);
260a9803 33 _debug("%c %*.*s%c%p {%d}",
08e0e7c8
DH
34 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 }
1da177e4 41
08e0e7c8
DH
42 if (node->rb_right)
43 bad |= dump_tree_aux(node->rb_right, node, depth + 2, '\\');
1da177e4 44
08e0e7c8
DH
45 return bad;
46}
1da177e4 47
08e0e7c8
DH
48static noinline void dump_tree(const char *name, struct afs_server *server)
49{
260a9803 50 _enter("%s", name);
08e0e7c8
DH
51 if (dump_tree_aux(server->cb_promises.rb_node, NULL, 0, '-'))
52 BUG();
53}
1da177e4
LT
54#endif
55
1da177e4 56/*
08e0e7c8 57 * insert a vnode into the backing server's vnode tree
1da177e4 58 */
08e0e7c8
DH
59static void afs_install_vnode(struct afs_vnode *vnode,
60 struct afs_server *server)
1da177e4 61{
08e0e7c8
DH
62 struct afs_server *old_server = vnode->server;
63 struct afs_vnode *xvnode;
64 struct rb_node *parent, **p;
1da177e4 65
08e0e7c8 66 _enter("%p,%p", vnode, server);
1da177e4 67
08e0e7c8
DH
68 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);
72 }
1da177e4 73
08e0e7c8
DH
74 afs_get_server(server);
75 vnode->server = server;
76 afs_put_server(old_server);
77
78 /* insert into the server's vnode tree in FID order */
79 spin_lock(&server->fs_lock);
80
81 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 }
1da177e4 101
08e0e7c8
DH
102 rb_link_node(&vnode->server_rb, parent, p);
103 rb_insert_color(&vnode->server_rb, &server->fs_vnodes);
1da177e4 104
08e0e7c8
DH
105 spin_unlock(&server->fs_lock);
106 _leave("");
107}
1da177e4 108
08e0e7c8
DH
109/*
110 * 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);
1da177e4
LT
139 }
140
08e0e7c8
DH
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 }
1da177e4 162
08e0e7c8
DH
163 rb_link_node(&vnode->cb_promise, parent, p);
164 rb_insert_color(&vnode->cb_promise, &server->cb_promises);
165 vnode->cb_promised = true;
1da177e4 166
08e0e7c8 167 spin_unlock(&server->cb_lock);
1da177e4 168 _leave("");
ec26815a 169}
1da177e4 170
08e0e7c8
DH
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
260a9803
DH
190 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;
08e0e7c8
DH
195 afs_put_server(server);
196}
197
1da177e4 198/*
260a9803
DH
199 * finish off updating the recorded status of a file after a successful
200 * operation completion
1da177e4
LT
201 * - starts callback expiry timer
202 * - adds to server's callback list
203 */
260a9803
DH
204void afs_vnode_finalise_status_update(struct afs_vnode *vnode,
205 struct afs_server *server)
1da177e4
LT
206{
207 struct afs_server *oldserver = NULL;
208
260a9803
DH
209 _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);
1da177e4
LT
229
230 spin_lock(&vnode->lock);
231
08e0e7c8 232 clear_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
1da177e4 233
260a9803 234 if (ret == -ENOENT) {
08e0e7c8 235 /* the file was deleted on the server */
1da177e4 236 _debug("got NOENT from server - marking file deleted");
08e0e7c8 237 afs_vnode_deleted_remotely(vnode);
1da177e4
LT
238 }
239
240 vnode->update_cnt--;
260a9803 241 ASSERTCMP(vnode->update_cnt, >=, 0);
1da177e4
LT
242 spin_unlock(&vnode->lock);
243
244 wake_up_all(&vnode->update_waitq);
1da177e4 245 _leave("");
ec26815a 246}
1da177e4 247
1da177e4
LT
248/*
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 */
00d3b7a4
DH
255int afs_vnode_fetch_status(struct afs_vnode *vnode,
256 struct afs_vnode *auth_vnode, struct key *key)
1da177e4
LT
257{
258 struct afs_server *server;
00d3b7a4 259 unsigned long acl_order;
1da177e4
LT
260 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
08e0e7c8
DH
268 if (!test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) &&
269 vnode->cb_promised) {
1da177e4
LT
270 _leave(" [unchanged]");
271 return 0;
272 }
273
08e0e7c8 274 if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
1da177e4
LT
275 _leave(" [deleted]");
276 return -ENOENT;
277 }
278
00d3b7a4
DH
279 acl_order = 0;
280 if (auth_vnode)
281 acl_order = auth_vnode->acl_order;
282
1da177e4
LT
283 spin_lock(&vnode->lock);
284
08e0e7c8
DH
285 if (!test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) &&
286 vnode->cb_promised) {
1da177e4
LT
287 spin_unlock(&vnode->lock);
288 _leave(" [unchanged]");
289 return 0;
290 }
291
260a9803
DH
292 ASSERTCMP(vnode->update_cnt, >=, 0);
293
1da177e4
LT
294 if (vnode->update_cnt > 0) {
295 /* someone else started a fetch */
260a9803
DH
296 _debug("wait on fetch %d", vnode->update_cnt);
297
1da177e4 298 set_current_state(TASK_UNINTERRUPTIBLE);
08e0e7c8 299 ASSERT(myself.func != NULL);
1da177e4
LT
300 add_wait_queue(&vnode->update_waitq, &myself);
301
302 /* wait for the status to be updated */
303 for (;;) {
08e0e7c8 304 if (!test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags))
1da177e4 305 break;
08e0e7c8 306 if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
1da177e4
LT
307 break;
308
08e0e7c8
DH
309 /* check to see if it got updated and invalidated all
310 * before we saw it */
1da177e4
LT
311 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
08e0e7c8
DH
330 return test_bit(AFS_VNODE_DELETED, &vnode->flags) ?
331 -ENOENT : 0;
1da177e4
LT
332 }
333
ec26815a 334get_anyway:
1da177e4
LT
335 /* 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 */
08e0e7c8
DH
344 server = afs_volume_pick_fileserver(vnode);
345 if (IS_ERR(server))
260a9803 346 goto no_server;
1da177e4 347
08e0e7c8
DH
348 _debug("USING SERVER: %p{%08x}",
349 server, ntohl(server->addr.s_addr));
1da177e4 350
00d3b7a4 351 ret = afs_fs_fetch_file_status(server, key, vnode, NULL,
08e0e7c8 352 &afs_sync_call);
1da177e4 353
08e0e7c8 354 } while (!afs_volume_release_fileserver(vnode, server, ret));
1da177e4
LT
355
356 /* adjust the flags */
260a9803
DH
357 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 }
1da177e4 367
260a9803
DH
368 ASSERTCMP(vnode->update_cnt, >=, 0);
369
370 _leave(" = %d [cnt %d]", ret, vnode->update_cnt);
1da177e4 371 return ret;
260a9803
DH
372
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);
ec26815a 380}
1da177e4 381
1da177e4
LT
382/*
383 * fetch file data from the volume
260a9803 384 * - TODO implement caching
1da177e4 385 */
00d3b7a4
DH
386int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key,
387 off_t offset, size_t length, struct page *page)
1da177e4
LT
388{
389 struct afs_server *server;
390 int ret;
391
00d3b7a4 392 _enter("%s{%u,%u,%u},%x,,,",
1da177e4
LT
393 vnode->volume->vlocation->vldb.name,
394 vnode->fid.vid,
395 vnode->fid.vnode,
00d3b7a4
DH
396 vnode->fid.unique,
397 key_serial(key));
1da177e4
LT
398
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 */
08e0e7c8
DH
408 server = afs_volume_pick_fileserver(vnode);
409 if (IS_ERR(server))
260a9803 410 goto no_server;
1da177e4
LT
411
412 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
413
00d3b7a4 414 ret = afs_fs_fetch_data(server, key, vnode, offset, length,
260a9803 415 page, &afs_sync_call);
1da177e4 416
08e0e7c8 417 } while (!afs_volume_release_fileserver(vnode, server, ret));
1da177e4
LT
418
419 /* adjust the flags */
260a9803
DH
420 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 }
1da177e4
LT
426
427 _leave(" = %d", ret);
428 return ret;
260a9803
DH
429
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);
ec26815a 755}
This page took 0.219311 seconds and 5 git commands to generate.