Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/fs/afs/vnode.c
15109 views
1
/* AFS vnode management
2
*
3
* Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
4
* Written by David Howells ([email protected])
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/fs.h>
16
#include <linux/sched.h>
17
#include "internal.h"
18
19
#if 0
20
static 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);
33
_debug("%c %*.*s%c%p {%d}",
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
}
41
42
if (node->rb_right)
43
bad |= dump_tree_aux(node->rb_right, node, depth + 2, '\\');
44
45
return bad;
46
}
47
48
static noinline void dump_tree(const char *name, struct afs_server *server)
49
{
50
_enter("%s", name);
51
if (dump_tree_aux(server->cb_promises.rb_node, NULL, 0, '-'))
52
BUG();
53
}
54
#endif
55
56
/*
57
* insert a vnode into the backing server's vnode tree
58
*/
59
static void afs_install_vnode(struct afs_vnode *vnode,
60
struct afs_server *server)
61
{
62
struct afs_server *old_server = vnode->server;
63
struct afs_vnode *xvnode;
64
struct rb_node *parent, **p;
65
66
_enter("%p,%p", vnode, server);
67
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
}
73
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
}
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);
106
_leave("");
107
}
108
109
/*
110
* insert a vnode into the promising server's update/expiration tree
111
* - caller must hold vnode->lock
112
*/
113
static 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
*/
174
static void afs_vnode_deleted_remotely(struct afs_vnode *vnode)
175
{
176
struct afs_server *server;
177
178
_enter("{%p}", vnode->server);
179
180
set_bit(AFS_VNODE_DELETED, &vnode->flags);
181
182
server = vnode->server;
183
if (server) {
184
if (vnode->cb_promised) {
185
spin_lock(&server->cb_lock);
186
if (vnode->cb_promised) {
187
rb_erase(&vnode->cb_promise,
188
&server->cb_promises);
189
vnode->cb_promised = false;
190
}
191
spin_unlock(&server->cb_lock);
192
}
193
194
spin_lock(&server->fs_lock);
195
rb_erase(&vnode->server_rb, &server->fs_vnodes);
196
spin_unlock(&server->fs_lock);
197
198
vnode->server = NULL;
199
afs_put_server(server);
200
} else {
201
ASSERT(!vnode->cb_promised);
202
}
203
204
_leave("");
205
}
206
207
/*
208
* finish off updating the recorded status of a file after a successful
209
* operation completion
210
* - starts callback expiry timer
211
* - adds to server's callback list
212
*/
213
void afs_vnode_finalise_status_update(struct afs_vnode *vnode,
214
struct afs_server *server)
215
{
216
struct afs_server *oldserver = NULL;
217
218
_enter("%p,%p", vnode, server);
219
220
spin_lock(&vnode->lock);
221
clear_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
222
afs_vnode_note_promise(vnode, server);
223
vnode->update_cnt--;
224
ASSERTCMP(vnode->update_cnt, >=, 0);
225
spin_unlock(&vnode->lock);
226
227
wake_up_all(&vnode->update_waitq);
228
afs_put_server(oldserver);
229
_leave("");
230
}
231
232
/*
233
* finish off updating the recorded status of a file after an operation failed
234
*/
235
static void afs_vnode_status_update_failed(struct afs_vnode *vnode, int ret)
236
{
237
_enter("{%x:%u},%d", vnode->fid.vid, vnode->fid.vnode, ret);
238
239
spin_lock(&vnode->lock);
240
241
clear_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
242
243
if (ret == -ENOENT) {
244
/* the file was deleted on the server */
245
_debug("got NOENT from server - marking file deleted");
246
afs_vnode_deleted_remotely(vnode);
247
}
248
249
vnode->update_cnt--;
250
ASSERTCMP(vnode->update_cnt, >=, 0);
251
spin_unlock(&vnode->lock);
252
253
wake_up_all(&vnode->update_waitq);
254
_leave("");
255
}
256
257
/*
258
* fetch file status from the volume
259
* - don't issue a fetch if:
260
* - the changed bit is not set and there's a valid callback
261
* - there are any outstanding ops that will fetch the status
262
* - TODO implement local caching
263
*/
264
int afs_vnode_fetch_status(struct afs_vnode *vnode,
265
struct afs_vnode *auth_vnode, struct key *key)
266
{
267
struct afs_server *server;
268
unsigned long acl_order;
269
int ret;
270
271
DECLARE_WAITQUEUE(myself, current);
272
273
_enter("%s,{%x:%u.%u}",
274
vnode->volume->vlocation->vldb.name,
275
vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
276
277
if (!test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) &&
278
vnode->cb_promised) {
279
_leave(" [unchanged]");
280
return 0;
281
}
282
283
if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
284
_leave(" [deleted]");
285
return -ENOENT;
286
}
287
288
acl_order = 0;
289
if (auth_vnode)
290
acl_order = auth_vnode->acl_order;
291
292
spin_lock(&vnode->lock);
293
294
if (!test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) &&
295
vnode->cb_promised) {
296
spin_unlock(&vnode->lock);
297
_leave(" [unchanged]");
298
return 0;
299
}
300
301
ASSERTCMP(vnode->update_cnt, >=, 0);
302
303
if (vnode->update_cnt > 0) {
304
/* someone else started a fetch */
305
_debug("wait on fetch %d", vnode->update_cnt);
306
307
set_current_state(TASK_UNINTERRUPTIBLE);
308
ASSERT(myself.func != NULL);
309
add_wait_queue(&vnode->update_waitq, &myself);
310
311
/* wait for the status to be updated */
312
for (;;) {
313
if (!test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags))
314
break;
315
if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
316
break;
317
318
/* check to see if it got updated and invalidated all
319
* before we saw it */
320
if (vnode->update_cnt == 0) {
321
remove_wait_queue(&vnode->update_waitq,
322
&myself);
323
set_current_state(TASK_RUNNING);
324
goto get_anyway;
325
}
326
327
spin_unlock(&vnode->lock);
328
329
schedule();
330
set_current_state(TASK_UNINTERRUPTIBLE);
331
332
spin_lock(&vnode->lock);
333
}
334
335
remove_wait_queue(&vnode->update_waitq, &myself);
336
spin_unlock(&vnode->lock);
337
set_current_state(TASK_RUNNING);
338
339
return test_bit(AFS_VNODE_DELETED, &vnode->flags) ?
340
-ENOENT : 0;
341
}
342
343
get_anyway:
344
/* okay... we're going to have to initiate the op */
345
vnode->update_cnt++;
346
347
spin_unlock(&vnode->lock);
348
349
/* merge AFS status fetches and clear outstanding callback on this
350
* vnode */
351
do {
352
/* pick a server to query */
353
server = afs_volume_pick_fileserver(vnode);
354
if (IS_ERR(server))
355
goto no_server;
356
357
_debug("USING SERVER: %p{%08x}",
358
server, ntohl(server->addr.s_addr));
359
360
ret = afs_fs_fetch_file_status(server, key, vnode, NULL,
361
&afs_sync_call);
362
363
} while (!afs_volume_release_fileserver(vnode, server, ret));
364
365
/* adjust the flags */
366
if (ret == 0) {
367
_debug("adjust");
368
if (auth_vnode)
369
afs_cache_permit(vnode, key, acl_order);
370
afs_vnode_finalise_status_update(vnode, server);
371
afs_put_server(server);
372
} else {
373
_debug("failed [%d]", ret);
374
afs_vnode_status_update_failed(vnode, ret);
375
}
376
377
ASSERTCMP(vnode->update_cnt, >=, 0);
378
379
_leave(" = %d [cnt %d]", ret, vnode->update_cnt);
380
return ret;
381
382
no_server:
383
spin_lock(&vnode->lock);
384
vnode->update_cnt--;
385
ASSERTCMP(vnode->update_cnt, >=, 0);
386
spin_unlock(&vnode->lock);
387
_leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt);
388
return PTR_ERR(server);
389
}
390
391
/*
392
* fetch file data from the volume
393
* - TODO implement caching
394
*/
395
int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key,
396
off_t offset, size_t length, struct page *page)
397
{
398
struct afs_server *server;
399
int ret;
400
401
_enter("%s{%x:%u.%u},%x,,,",
402
vnode->volume->vlocation->vldb.name,
403
vnode->fid.vid,
404
vnode->fid.vnode,
405
vnode->fid.unique,
406
key_serial(key));
407
408
/* this op will fetch the status */
409
spin_lock(&vnode->lock);
410
vnode->update_cnt++;
411
spin_unlock(&vnode->lock);
412
413
/* merge in AFS status fetches and clear outstanding callback on this
414
* vnode */
415
do {
416
/* pick a server to query */
417
server = afs_volume_pick_fileserver(vnode);
418
if (IS_ERR(server))
419
goto no_server;
420
421
_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
422
423
ret = afs_fs_fetch_data(server, key, vnode, offset, length,
424
page, &afs_sync_call);
425
426
} while (!afs_volume_release_fileserver(vnode, server, ret));
427
428
/* adjust the flags */
429
if (ret == 0) {
430
afs_vnode_finalise_status_update(vnode, server);
431
afs_put_server(server);
432
} else {
433
afs_vnode_status_update_failed(vnode, ret);
434
}
435
436
_leave(" = %d", ret);
437
return ret;
438
439
no_server:
440
spin_lock(&vnode->lock);
441
vnode->update_cnt--;
442
ASSERTCMP(vnode->update_cnt, >=, 0);
443
spin_unlock(&vnode->lock);
444
return PTR_ERR(server);
445
}
446
447
/*
448
* make a file or a directory
449
*/
450
int afs_vnode_create(struct afs_vnode *vnode, struct key *key,
451
const char *name, umode_t mode, struct afs_fid *newfid,
452
struct afs_file_status *newstatus,
453
struct afs_callback *newcb, struct afs_server **_server)
454
{
455
struct afs_server *server;
456
int ret;
457
458
_enter("%s{%x:%u.%u},%x,%s,,",
459
vnode->volume->vlocation->vldb.name,
460
vnode->fid.vid,
461
vnode->fid.vnode,
462
vnode->fid.unique,
463
key_serial(key),
464
name);
465
466
/* this op will fetch the status on the directory we're creating in */
467
spin_lock(&vnode->lock);
468
vnode->update_cnt++;
469
spin_unlock(&vnode->lock);
470
471
do {
472
/* pick a server to query */
473
server = afs_volume_pick_fileserver(vnode);
474
if (IS_ERR(server))
475
goto no_server;
476
477
_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
478
479
ret = afs_fs_create(server, key, vnode, name, mode, newfid,
480
newstatus, newcb, &afs_sync_call);
481
482
} while (!afs_volume_release_fileserver(vnode, server, ret));
483
484
/* adjust the flags */
485
if (ret == 0) {
486
afs_vnode_finalise_status_update(vnode, server);
487
*_server = server;
488
} else {
489
afs_vnode_status_update_failed(vnode, ret);
490
*_server = NULL;
491
}
492
493
_leave(" = %d [cnt %d]", ret, vnode->update_cnt);
494
return ret;
495
496
no_server:
497
spin_lock(&vnode->lock);
498
vnode->update_cnt--;
499
ASSERTCMP(vnode->update_cnt, >=, 0);
500
spin_unlock(&vnode->lock);
501
_leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt);
502
return PTR_ERR(server);
503
}
504
505
/*
506
* remove a file or directory
507
*/
508
int afs_vnode_remove(struct afs_vnode *vnode, struct key *key, const char *name,
509
bool isdir)
510
{
511
struct afs_server *server;
512
int ret;
513
514
_enter("%s{%x:%u.%u},%x,%s",
515
vnode->volume->vlocation->vldb.name,
516
vnode->fid.vid,
517
vnode->fid.vnode,
518
vnode->fid.unique,
519
key_serial(key),
520
name);
521
522
/* this op will fetch the status on the directory we're removing from */
523
spin_lock(&vnode->lock);
524
vnode->update_cnt++;
525
spin_unlock(&vnode->lock);
526
527
do {
528
/* pick a server to query */
529
server = afs_volume_pick_fileserver(vnode);
530
if (IS_ERR(server))
531
goto no_server;
532
533
_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
534
535
ret = afs_fs_remove(server, key, vnode, name, isdir,
536
&afs_sync_call);
537
538
} while (!afs_volume_release_fileserver(vnode, server, ret));
539
540
/* adjust the flags */
541
if (ret == 0) {
542
afs_vnode_finalise_status_update(vnode, server);
543
afs_put_server(server);
544
} else {
545
afs_vnode_status_update_failed(vnode, ret);
546
}
547
548
_leave(" = %d [cnt %d]", ret, vnode->update_cnt);
549
return ret;
550
551
no_server:
552
spin_lock(&vnode->lock);
553
vnode->update_cnt--;
554
ASSERTCMP(vnode->update_cnt, >=, 0);
555
spin_unlock(&vnode->lock);
556
_leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt);
557
return PTR_ERR(server);
558
}
559
560
/*
561
* create a hard link
562
*/
563
int afs_vnode_link(struct afs_vnode *dvnode, struct afs_vnode *vnode,
564
struct key *key, const char *name)
565
{
566
struct afs_server *server;
567
int ret;
568
569
_enter("%s{%x:%u.%u},%s{%x:%u.%u},%x,%s",
570
dvnode->volume->vlocation->vldb.name,
571
dvnode->fid.vid,
572
dvnode->fid.vnode,
573
dvnode->fid.unique,
574
vnode->volume->vlocation->vldb.name,
575
vnode->fid.vid,
576
vnode->fid.vnode,
577
vnode->fid.unique,
578
key_serial(key),
579
name);
580
581
/* this op will fetch the status on the directory we're removing from */
582
spin_lock(&vnode->lock);
583
vnode->update_cnt++;
584
spin_unlock(&vnode->lock);
585
spin_lock(&dvnode->lock);
586
dvnode->update_cnt++;
587
spin_unlock(&dvnode->lock);
588
589
do {
590
/* pick a server to query */
591
server = afs_volume_pick_fileserver(dvnode);
592
if (IS_ERR(server))
593
goto no_server;
594
595
_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
596
597
ret = afs_fs_link(server, key, dvnode, vnode, name,
598
&afs_sync_call);
599
600
} while (!afs_volume_release_fileserver(dvnode, server, ret));
601
602
/* adjust the flags */
603
if (ret == 0) {
604
afs_vnode_finalise_status_update(vnode, server);
605
afs_vnode_finalise_status_update(dvnode, server);
606
afs_put_server(server);
607
} else {
608
afs_vnode_status_update_failed(vnode, ret);
609
afs_vnode_status_update_failed(dvnode, ret);
610
}
611
612
_leave(" = %d [cnt %d]", ret, vnode->update_cnt);
613
return ret;
614
615
no_server:
616
spin_lock(&vnode->lock);
617
vnode->update_cnt--;
618
ASSERTCMP(vnode->update_cnt, >=, 0);
619
spin_unlock(&vnode->lock);
620
spin_lock(&dvnode->lock);
621
dvnode->update_cnt--;
622
ASSERTCMP(dvnode->update_cnt, >=, 0);
623
spin_unlock(&dvnode->lock);
624
_leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt);
625
return PTR_ERR(server);
626
}
627
628
/*
629
* create a symbolic link
630
*/
631
int afs_vnode_symlink(struct afs_vnode *vnode, struct key *key,
632
const char *name, const char *content,
633
struct afs_fid *newfid,
634
struct afs_file_status *newstatus,
635
struct afs_server **_server)
636
{
637
struct afs_server *server;
638
int ret;
639
640
_enter("%s{%x:%u.%u},%x,%s,%s,,,",
641
vnode->volume->vlocation->vldb.name,
642
vnode->fid.vid,
643
vnode->fid.vnode,
644
vnode->fid.unique,
645
key_serial(key),
646
name, content);
647
648
/* this op will fetch the status on the directory we're creating in */
649
spin_lock(&vnode->lock);
650
vnode->update_cnt++;
651
spin_unlock(&vnode->lock);
652
653
do {
654
/* pick a server to query */
655
server = afs_volume_pick_fileserver(vnode);
656
if (IS_ERR(server))
657
goto no_server;
658
659
_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
660
661
ret = afs_fs_symlink(server, key, vnode, name, content,
662
newfid, newstatus, &afs_sync_call);
663
664
} while (!afs_volume_release_fileserver(vnode, server, ret));
665
666
/* adjust the flags */
667
if (ret == 0) {
668
afs_vnode_finalise_status_update(vnode, server);
669
*_server = server;
670
} else {
671
afs_vnode_status_update_failed(vnode, ret);
672
*_server = NULL;
673
}
674
675
_leave(" = %d [cnt %d]", ret, vnode->update_cnt);
676
return ret;
677
678
no_server:
679
spin_lock(&vnode->lock);
680
vnode->update_cnt--;
681
ASSERTCMP(vnode->update_cnt, >=, 0);
682
spin_unlock(&vnode->lock);
683
_leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt);
684
return PTR_ERR(server);
685
}
686
687
/*
688
* rename a file
689
*/
690
int afs_vnode_rename(struct afs_vnode *orig_dvnode,
691
struct afs_vnode *new_dvnode,
692
struct key *key,
693
const char *orig_name,
694
const char *new_name)
695
{
696
struct afs_server *server;
697
int ret;
698
699
_enter("%s{%x:%u.%u},%s{%u,%u,%u},%x,%s,%s",
700
orig_dvnode->volume->vlocation->vldb.name,
701
orig_dvnode->fid.vid,
702
orig_dvnode->fid.vnode,
703
orig_dvnode->fid.unique,
704
new_dvnode->volume->vlocation->vldb.name,
705
new_dvnode->fid.vid,
706
new_dvnode->fid.vnode,
707
new_dvnode->fid.unique,
708
key_serial(key),
709
orig_name,
710
new_name);
711
712
/* this op will fetch the status on both the directories we're dealing
713
* with */
714
spin_lock(&orig_dvnode->lock);
715
orig_dvnode->update_cnt++;
716
spin_unlock(&orig_dvnode->lock);
717
if (new_dvnode != orig_dvnode) {
718
spin_lock(&new_dvnode->lock);
719
new_dvnode->update_cnt++;
720
spin_unlock(&new_dvnode->lock);
721
}
722
723
do {
724
/* pick a server to query */
725
server = afs_volume_pick_fileserver(orig_dvnode);
726
if (IS_ERR(server))
727
goto no_server;
728
729
_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
730
731
ret = afs_fs_rename(server, key, orig_dvnode, orig_name,
732
new_dvnode, new_name, &afs_sync_call);
733
734
} while (!afs_volume_release_fileserver(orig_dvnode, server, ret));
735
736
/* adjust the flags */
737
if (ret == 0) {
738
afs_vnode_finalise_status_update(orig_dvnode, server);
739
if (new_dvnode != orig_dvnode)
740
afs_vnode_finalise_status_update(new_dvnode, server);
741
afs_put_server(server);
742
} else {
743
afs_vnode_status_update_failed(orig_dvnode, ret);
744
if (new_dvnode != orig_dvnode)
745
afs_vnode_status_update_failed(new_dvnode, ret);
746
}
747
748
_leave(" = %d [cnt %d]", ret, orig_dvnode->update_cnt);
749
return ret;
750
751
no_server:
752
spin_lock(&orig_dvnode->lock);
753
orig_dvnode->update_cnt--;
754
ASSERTCMP(orig_dvnode->update_cnt, >=, 0);
755
spin_unlock(&orig_dvnode->lock);
756
if (new_dvnode != orig_dvnode) {
757
spin_lock(&new_dvnode->lock);
758
new_dvnode->update_cnt--;
759
ASSERTCMP(new_dvnode->update_cnt, >=, 0);
760
spin_unlock(&new_dvnode->lock);
761
}
762
_leave(" = %ld [cnt %d]", PTR_ERR(server), orig_dvnode->update_cnt);
763
return PTR_ERR(server);
764
}
765
766
/*
767
* write to a file
768
*/
769
int afs_vnode_store_data(struct afs_writeback *wb, pgoff_t first, pgoff_t last,
770
unsigned offset, unsigned to)
771
{
772
struct afs_server *server;
773
struct afs_vnode *vnode = wb->vnode;
774
int ret;
775
776
_enter("%s{%x:%u.%u},%x,%lx,%lx,%x,%x",
777
vnode->volume->vlocation->vldb.name,
778
vnode->fid.vid,
779
vnode->fid.vnode,
780
vnode->fid.unique,
781
key_serial(wb->key),
782
first, last, offset, to);
783
784
/* this op will fetch the status */
785
spin_lock(&vnode->lock);
786
vnode->update_cnt++;
787
spin_unlock(&vnode->lock);
788
789
do {
790
/* pick a server to query */
791
server = afs_volume_pick_fileserver(vnode);
792
if (IS_ERR(server))
793
goto no_server;
794
795
_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
796
797
ret = afs_fs_store_data(server, wb, first, last, offset, to,
798
&afs_sync_call);
799
800
} while (!afs_volume_release_fileserver(vnode, server, ret));
801
802
/* adjust the flags */
803
if (ret == 0) {
804
afs_vnode_finalise_status_update(vnode, server);
805
afs_put_server(server);
806
} else {
807
afs_vnode_status_update_failed(vnode, ret);
808
}
809
810
_leave(" = %d", ret);
811
return ret;
812
813
no_server:
814
spin_lock(&vnode->lock);
815
vnode->update_cnt--;
816
ASSERTCMP(vnode->update_cnt, >=, 0);
817
spin_unlock(&vnode->lock);
818
return PTR_ERR(server);
819
}
820
821
/*
822
* set the attributes on a file
823
*/
824
int afs_vnode_setattr(struct afs_vnode *vnode, struct key *key,
825
struct iattr *attr)
826
{
827
struct afs_server *server;
828
int ret;
829
830
_enter("%s{%x:%u.%u},%x",
831
vnode->volume->vlocation->vldb.name,
832
vnode->fid.vid,
833
vnode->fid.vnode,
834
vnode->fid.unique,
835
key_serial(key));
836
837
/* this op will fetch the status */
838
spin_lock(&vnode->lock);
839
vnode->update_cnt++;
840
spin_unlock(&vnode->lock);
841
842
do {
843
/* pick a server to query */
844
server = afs_volume_pick_fileserver(vnode);
845
if (IS_ERR(server))
846
goto no_server;
847
848
_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
849
850
ret = afs_fs_setattr(server, key, vnode, attr, &afs_sync_call);
851
852
} while (!afs_volume_release_fileserver(vnode, server, ret));
853
854
/* adjust the flags */
855
if (ret == 0) {
856
afs_vnode_finalise_status_update(vnode, server);
857
afs_put_server(server);
858
} else {
859
afs_vnode_status_update_failed(vnode, ret);
860
}
861
862
_leave(" = %d", ret);
863
return ret;
864
865
no_server:
866
spin_lock(&vnode->lock);
867
vnode->update_cnt--;
868
ASSERTCMP(vnode->update_cnt, >=, 0);
869
spin_unlock(&vnode->lock);
870
return PTR_ERR(server);
871
}
872
873
/*
874
* get the status of a volume
875
*/
876
int afs_vnode_get_volume_status(struct afs_vnode *vnode, struct key *key,
877
struct afs_volume_status *vs)
878
{
879
struct afs_server *server;
880
int ret;
881
882
_enter("%s{%x:%u.%u},%x,",
883
vnode->volume->vlocation->vldb.name,
884
vnode->fid.vid,
885
vnode->fid.vnode,
886
vnode->fid.unique,
887
key_serial(key));
888
889
do {
890
/* pick a server to query */
891
server = afs_volume_pick_fileserver(vnode);
892
if (IS_ERR(server))
893
goto no_server;
894
895
_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
896
897
ret = afs_fs_get_volume_status(server, key, vnode, vs, &afs_sync_call);
898
899
} while (!afs_volume_release_fileserver(vnode, server, ret));
900
901
/* adjust the flags */
902
if (ret == 0)
903
afs_put_server(server);
904
905
_leave(" = %d", ret);
906
return ret;
907
908
no_server:
909
return PTR_ERR(server);
910
}
911
912
/*
913
* get a lock on a file
914
*/
915
int afs_vnode_set_lock(struct afs_vnode *vnode, struct key *key,
916
afs_lock_type_t type)
917
{
918
struct afs_server *server;
919
int ret;
920
921
_enter("%s{%x:%u.%u},%x,%u",
922
vnode->volume->vlocation->vldb.name,
923
vnode->fid.vid,
924
vnode->fid.vnode,
925
vnode->fid.unique,
926
key_serial(key), type);
927
928
do {
929
/* pick a server to query */
930
server = afs_volume_pick_fileserver(vnode);
931
if (IS_ERR(server))
932
goto no_server;
933
934
_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
935
936
ret = afs_fs_set_lock(server, key, vnode, type, &afs_sync_call);
937
938
} while (!afs_volume_release_fileserver(vnode, server, ret));
939
940
/* adjust the flags */
941
if (ret == 0)
942
afs_put_server(server);
943
944
_leave(" = %d", ret);
945
return ret;
946
947
no_server:
948
return PTR_ERR(server);
949
}
950
951
/*
952
* extend a lock on a file
953
*/
954
int afs_vnode_extend_lock(struct afs_vnode *vnode, struct key *key)
955
{
956
struct afs_server *server;
957
int ret;
958
959
_enter("%s{%x:%u.%u},%x",
960
vnode->volume->vlocation->vldb.name,
961
vnode->fid.vid,
962
vnode->fid.vnode,
963
vnode->fid.unique,
964
key_serial(key));
965
966
do {
967
/* pick a server to query */
968
server = afs_volume_pick_fileserver(vnode);
969
if (IS_ERR(server))
970
goto no_server;
971
972
_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
973
974
ret = afs_fs_extend_lock(server, key, vnode, &afs_sync_call);
975
976
} while (!afs_volume_release_fileserver(vnode, server, ret));
977
978
/* adjust the flags */
979
if (ret == 0)
980
afs_put_server(server);
981
982
_leave(" = %d", ret);
983
return ret;
984
985
no_server:
986
return PTR_ERR(server);
987
}
988
989
/*
990
* release a lock on a file
991
*/
992
int afs_vnode_release_lock(struct afs_vnode *vnode, struct key *key)
993
{
994
struct afs_server *server;
995
int ret;
996
997
_enter("%s{%x:%u.%u},%x",
998
vnode->volume->vlocation->vldb.name,
999
vnode->fid.vid,
1000
vnode->fid.vnode,
1001
vnode->fid.unique,
1002
key_serial(key));
1003
1004
do {
1005
/* pick a server to query */
1006
server = afs_volume_pick_fileserver(vnode);
1007
if (IS_ERR(server))
1008
goto no_server;
1009
1010
_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
1011
1012
ret = afs_fs_release_lock(server, key, vnode, &afs_sync_call);
1013
1014
} while (!afs_volume_release_fileserver(vnode, server, ret));
1015
1016
/* adjust the flags */
1017
if (ret == 0)
1018
afs_put_server(server);
1019
1020
_leave(" = %d", ret);
1021
return ret;
1022
1023
no_server:
1024
return PTR_ERR(server);
1025
}
1026
1027