aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/scripts
diff options
context:
space:
mode:
authorMikulas Patocka <mikulas@artax.karlin.mff.cuni.cz>2014-01-28 18:11:33 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-02-02 19:24:07 -0500
commit1c0b8a7a62c3d3ebf53a8e40cc6da22f5e192d63 (patch)
tree3ecae7ff3391cfcd628c2d78acee83a78e9de66e /tools/perf/scripts
parent2cbe5c76fc5e38e9af4b709593146e4b8272b69e (diff)
hpfs: optimize quad buffer loading
HPFS needs to load 4 consecutive 512-byte sectors when accessing the directory nodes or bitmaps. We can't switch to 2048-byte block size because files are allocated in the units of 512-byte sectors. Previously, the driver would allocate a 2048-byte area using kmalloc, copy the data from four buffers to this area and eventually copy them back if they were modified. In the current implementation of the buffer cache, buffers are allocated in the pagecache. That means that 4 consecutive 512-byte buffers are stored in consecutive areas in the kernel address space. So, we don't need to allocate extra memory and copy the content of the buffers there. This patch optimizes the code to avoid copying the buffers. It checks if the four buffers are stored in contiguous memory - if they are not, it falls back to allocating a 2048-byte area and copying data there. Signed-off-by: Mikulas Patocka <mikulas@artax.karlin.mff.cuni.cz> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'tools/perf/scripts')
0 files changed, 0 insertions, 0 deletions
re>e5e940170b21
ab7017a3a0a6
1b340d0118da
1da177e4c3f4

1da177e4c3f4
f43bf0bebed7


90ab5ee94171
f43bf0bebed7
1da177e4c3f4
24aa1fe6779e
1da177e4c3f4
e18b890bb088
b7fa0554cf1b
1da177e4c3f4





f43bf0bebed7
72cb77f4a5ac






d310310cbff1
72cb77f4a5ac

89d77c8fa8e6
72cb77f4a5ac

f43bf0bebed7







3fa0b4e201d2




f43bf0bebed7








19d87ca36239
1da177e4c3f4
da6d503aa0a7



1c3c07e9f6cc
ada70d9425bc
1c3c07e9f6cc
ef79c097bbe9
1da177e4c3f4
89d77c8fa8e6
1da177e4c3f4
b57922d97fd6


dbd5768f87ff
b57922d97fd6


29884df0d89c




5cf95214ccb9
29884df0d89c
5cf95214ccb9



29884df0d89c


1da177e4c3f4


b37b03b70514
1da177e4c3f4



91d5b47023b6

c7c209730d63

1da177e4c3f4


552968098180
1da177e4c3f4
552968098180
b37b03b70514
dc59250c6ebe
b37b03b70514



dc59250c6ebe
ada70d9425bc

cd9ae2b6a75b








f41f74183848
ada70d9425bc





dc59250c6ebe
552968098180
dc59250c6ebe
1da177e4c3f4
1c606fb74c75
1da177e4c3f4
c4812998398d





ddda8e0aa8b9
c4812998398d
1da177e4c3f4
b37b03b70514

1da177e4c3f4
b37b03b70514
1da177e4c3f4
3a10c30acc48
b37b03b70514
1da177e4c3f4


































99fadcd76465
1da177e4c3f4



1da177e4c3f4










03f28e3a2059
1da177e4c3f4

7ebb931598cd

533eb4611c9e

1da177e4c3f4
9e6e70f8d8b6
1da177e4c3f4
1da177e4c3f4


03f28e3a2059


1da177e4c3f4
03f28e3a2059
1da177e4c3f4


b0c4fddca2bc
1da177e4c3f4







62ab460cf5e4

4124bbc52118
1da177e4c3f4


8fa5c000d7f9
1da177e4c3f4
1788ea6e3b2a
1da177e4c3f4


8fa5c000d7f9
1da177e4c3f4
11de3b11e08c
55a975937d40
7ebb931598cd

6b97fd3da1ea



55a975937d40
36d43a43761b
55a975937d40
1da177e4c3f4




9e6e70f8d8b6


a9a4a87a5942
9e6e70f8d8b6
6d6b77f163c7
9e6e70f8d8b6



2701d086dbfc

9e6e70f8d8b6
33801147a8fd
4704f0e27482
9e6e70f8d8b6

62ab460cf5e4

9e6e70f8d8b6

62ab460cf5e4
4124bbc52118
9e6e70f8d8b6

62ab460cf5e4
4124bbc52118
9e6e70f8d8b6
a9a4a87a5942
62ab460cf5e4
4124bbc52118
9e6e70f8d8b6

62ab460cf5e4

62ab460cf5e4
9e6e70f8d8b6
bfe868486960
62ab460cf5e4

9e6e70f8d8b6

62ab460cf5e4
4124bbc52118
9e6e70f8d8b6

62ab460cf5e4
4124bbc52118
9e6e70f8d8b6


1da177e4c3f4



1da177e4c3f4

b0c4fddca2bc
1c3c07e9f6cc
1da177e4c3f4
ef79c097bbe9

1da177e4c3f4


4f1abd226d80
1da177e4c3f4

4f1abd226d80
1da177e4c3f4





03f28e3a2059
1da177e4c3f4

89d77c8fa8e6
1da177e4c3f4
536e43d12b95
1da177e4c3f4




987f8dfc9862

1da177e4c3f4
91d5b47023b6

188b95dd8ecb



1da177e4c3f4






536e43d12b95
1da177e4c3f4

755c1e20cd2a
1d59d61f6065

e1552e199857
1d59d61f6065
987f8dfc9862



642ac54923e0



57ec14c55dee
987f8dfc9862
65e4308d2500
987f8dfc9862


65e4308d2500

ddda8e0aa8b9
65e4308d2500

a3d01454bc58









c08d3b0e33ed

a3d01454bc58
c08d3b0e33ed


a3d01454bc58
c08d3b0e33ed







a3d01454bc58


65e4308d2500









2f28ea614ff4
1da177e4c3f4
65e4308d2500

1da177e4c3f4





552968098180
dc59250c6ebe
65e4308d2500

91d5b47023b6
a3d01454bc58
65e4308d2500
1da177e4c3f4
ddda8e0aa8b9
1da177e4c3f4
1da177e4c3f4


552968098180
1da177e4c3f4

acdc53b2146c
28c494c5c8d4
1d59d61f6065
acdc53b2146c


28c494c5c8d4
fc33a7bb9c6d











1da177e4c3f4
fc33a7bb9c6d
1da177e4c3f4



4e769b934e76
1da177e4c3f4
f43bf0bebed7
4e769b934e76
acdc53b2146c
1da177e4c3f4

ddda8e0aa8b9
1da177e4c3f4
f11ac8db5d07

























3d4ff43d895c
f11ac8db5d07

























3d4ff43d895c
f11ac8db5d07







7fe5c398fc21
















3d4ff43d895c
7fe5c398fc21






ddda8e0aa8b9
7fe5c398fc21
5ede7b1cfa82
1da177e4c3f4

5ede7b1cfa82


1da177e4c3f4
f52720ca5f48
5ede7b1cfa82


1da177e4c3f4
5ede7b1cfa82









82be417aa37c
1da177e4c3f4

89d77c8fa8e6
1da177e4c3f4



f11ac8db5d07
1da177e4c3f4

89d77c8fa8e6
1da177e4c3f4
7fe5c398fc21
1da177e4c3f4
3d4ff43d895c

3bec63db5546
5c78f58e2d5c
ef84303ebc77



ef84303ebc77
5e11934d13c9
5c78f58e2d5c

3bec63db5546

3d4ff43d895c

82be417aa37c
3bec63db5546


a49c3c7736a2



89d77c8fa8e6
a49c3c7736a2
1da177e4c3f4



cd9a1c0e5ac6
1da177e4c3f4
01cce933d8b5
1da177e4c3f4






89d77c8fa8e6
1da177e4c3f4
d530838bfa50


dc0b027dfadf
1da177e4c3f4





d530838bfa50

1544fa0f7a46



1da177e4c3f4




b92dccf65bab
1da177e4c3f4
01cce933d8b5
cd3758e37dde
1da177e4c3f4





f895c53f8ace
1da177e4c3f4








1da177e4c3f4
5ede7b1cfa82


1da177e4c3f4

ef79c097bbe9
1da177e4c3f4




1da177e4c3f4











a3cba2aad9c0
1da177e4c3f4
1da177e4c3f4



85233a7a436a
691beb13cdc8
1da177e4c3f4
412d582ec1dd
7fdc49c4e49b
a3cba2aad9c0




691beb13cdc8
a3cba2aad9c0
1da177e4c3f4






3a10c30acc48
1da177e4c3f4



a3cba2aad9c0
1da177e4c3f4





552968098180
24aa1fe6779e
ada70d9425bc
552968098180
1da177e4c3f4



412d582ec1dd
a3cba2aad9c0
1da177e4c3f4






d7cf8dd01289




b4d2314bb88b
1da177e4c3f4
d7cf8dd01289
1da177e4c3f4










44b11874ff58
d7cf8dd01289
1da177e4c3f4


1c606fb74c75
1da177e4c3f4
1cda707d52e5
717d44e84921









2f78e4313afd
717d44e84921
717d44e84921

ef79c097bbe9
717d44e84921




b4b1eadf7c5f








717d44e84921



717d44e84921




dc59250c6ebe
29418aa4bd48



b4b1eadf7c5f
717d44e84921


7d52e86274e0
717d44e84921

cd9ae2b6a75b
44b11874ff58
7d52e86274e0

27dc1cd3ad93
a895b4a198dd

27dc1cd3ad93
a895b4a198dd
9e6e70f8d8b6

a9a4a87a5942

70ca88521fc7

27dc1cd3ad93
70ca88521fc7
a895b4a198dd
9e6e70f8d8b6

27dc1cd3ad93



9e6e70f8d8b6



27dc1cd3ad93



a895b4a198dd
9e6e70f8d8b6


27dc1cd3ad93




a895b4a198dd

1da177e4c3f4
33801147a8fd
1da177e4c3f4






33801147a8fd
1da177e4c3f4


2a3f5fd45938
1da177e4c3f4
dc59250c6ebe
01da47bde78f

ca62b9c3f7b8
9e6e70f8d8b6


ca62b9c3f7b8
ca62b9c3f7b8
9e6e70f8d8b6
a9a4a87a5942
2a3f5fd45938
1da177e4c3f4
1da177e4c3f4
9e6e70f8d8b6
fee7fe196c41
ca62b9c3f7b8
9e6e70f8d8b6





1da177e4c3f4

9e6e70f8d8b6




2a3f5fd45938
1da177e4c3f4

9e6e70f8d8b6
2a3f5fd45938
1da177e4c3f4
9e6e70f8d8b6
2a3f5fd45938



1da177e4c3f4
33801147a8fd
1da177e4c3f4


a10ad1763002
870a5be8b921
9e6e70f8d8b6

a10ad1763002




9e6e70f8d8b6

a10ad1763002

870a5be8b921
ae05f2694005
4704f0e27482


ae05f2694005
4704f0e27482



ae05f2694005
4704f0e27482






6926afd1925a

4704f0e27482
ddda8e0aa8b9
4704f0e27482
2d36bfde8565








ddda8e0aa8b9
2d36bfde8565









ddda8e0aa8b9
2d36bfde8565
e27d359e9b7e
d8e0539ebdff















20d27e929fb4






20d27e929fb4



fa68a1ba1de3
20d27e929fb4



d8e0539ebdff

20d27e929fb4


























a10ad1763002











4704f0e27482
a10ad1763002








4704f0e27482
03254e65a60d

4704f0e27482
a10ad1763002




870a5be8b921



33801147a8fd











33801147a8fd




870a5be8b921
33801147a8fd
ef79c097bbe9
33801147a8fd

ddda8e0aa8b9
33801147a8fd
d65f557f3944











decf491f3076






f551e44ff11d





decf491f3076


d65f557f3944
decf491f3076
7668fdbe9aae
d65f557f3944
7668fdbe9aae
870a5be8b921
decf491f3076
1c606fb74c75
decf491f3076
70ca88521fc7












d65f557f3944





9e6e70f8d8b6



d65f557f3944

9e6e70f8d8b6

a9a4a87a5942
9e6e70f8d8b6
70ca88521fc7
9e6e70f8d8b6

70ca88521fc7
9e6e70f8d8b6



70ca88521fc7
9e6e70f8d8b6



a3d01454bc58
9e6e70f8d8b6
70ca88521fc7
d65f557f3944



70ca88521fc7
ddda8e0aa8b9
70ca88521fc7
1da177e4c3f4











24aa1fe6779e
1da177e4c3f4
8b4bdcf8995d
1da177e4c3f4
951a143b3fcf
2a3f5fd45938
3e7d950a5284
62ab460cf5e4
1da177e4c3f4
4f1abd226d80
3110ff8048fb
4f1abd226d80
1da177e4c3f4

e73e6c9e85ed







1da177e4c3f4



e73e6c9e85ed







1da177e4c3f4
8b4bdcf8995d
a0356862bcbe
9e6e70f8d8b6
c37dcd334c0b
36d43a43761b
8b4bdcf8995d

1da177e4c3f4


33801147a8fd
3e7d950a5284
62ab460cf5e4




1da177e4c3f4
a895b4a198dd
27dc1cd3ad93
a895b4a198dd
47aabaa7e453
9e6e70f8d8b6
a9a4a87a5942
9e6e70f8d8b6

6a4506c0b568




9e6e70f8d8b6

a9a4a87a5942
9e6e70f8d8b6
62ab460cf5e4

9e6e70f8d8b6

fee7fe196c41
62ab460cf5e4

62ab460cf5e4

9e6e70f8d8b6
fee7fe196c41
62ab460cf5e4

62ab460cf5e4
47aabaa7e453
951a143b3fcf
9e6e70f8d8b6





0f66b5984df2

9e6e70f8d8b6


60c16ea87754





1da177e4c3f4
62ab460cf5e4



1da177e4c3f4
1da177e4c3f4
9e6e70f8d8b6

62ab460cf5e4


1da177e4c3f4
9e6e70f8d8b6

9b4b351346b4


9e6e70f8d8b6
9e6e70f8d8b6
62ab460cf5e4





9e6e70f8d8b6




62ab460cf5e4





9e6e70f8d8b6




62ab460cf5e4




921615f11110
9e6e70f8d8b6




bfe868486960
9e6e70f8d8b6
62ab460cf5e4


1da177e4c3f4
9e6e70f8d8b6
1da177e4c3f4



1da177e4c3f4
9e6e70f8d8b6

1da177e4c3f4


91d5b47023b6
1da177e4c3f4
3e7d950a5284
4704f0e27482
6d2b29668691
64672d55d93c
6d2b29668691



1da177e4c3f4
f2115dc9877d
1da177e4c3f4



011e2a7fd5e9
62ab460cf5e4
552968098180
1da177e4c3f4

b37b03b70514
1da177e4c3f4





1da177e4c3f4


f7b422b17ee5
1da177e4c3f4

e94b1766097d
1da177e4c3f4

552968098180

458818ed76d3



89d77c8fa8e6
e50a1c2e1f81

1da177e4c3f4

89d77c8fa8e6
1da177e4c3f4
fa0d7e3de6d6
1da177e4c3f4
fa0d7e3de6d6
1da177e4c3f4


fa0d7e3de6d6



89d77c8fa8e6
fa0d7e3de6d6
d75d54147db9

89d77c8fa8e6
d75d54147db9



e5e940170b21
d75d54147db9

f7b422b17ee5
51cc50685a42
1da177e4c3f4


a35afb830f8d
a35afb830f8d


ea2cf2282b42
a35afb830f8d
ea2cf2282b42
1a0de48ae56b
565277f63c61


a35afb830f8d
1da177e4c3f4
20c2df83d25c
f7b422b17ee5
1da177e4c3f4


fffb60f93ce5

20c2df83d25c
1da177e4c3f4





266bee88699d
1da177e4c3f4
1a1d92c10dd2
1da177e4c3f4

5746006f1d17
89d77c8fa8e6
5746006f1d17







ada609ee2ac2
5746006f1d17



















1b340d0118da
9e2e74dba6dd
1b340d0118da


6b13168b36b6
1b340d0118da





28cd1b3f262d
1b340d0118da








1da177e4c3f4






e571cbf1a4f8

89d77c8fa8e6
1b340d0118da


89d77c8fa8e6
e571cbf1a4f8
8ec442ae4c65

89d77c8fa8e6
8ec442ae4c65
5746006f1d17

89d77c8fa8e6
5746006f1d17
6aaca5665032

89d77c8fa8e6
6aaca5665032
1da177e4c3f4

89d77c8fa8e6
1da177e4c3f4


89d77c8fa8e6
1da177e4c3f4


89d77c8fa8e6
1da177e4c3f4


89d77c8fa8e6
1da177e4c3f4
1da177e4c3f4

89d77c8fa8e6
1da177e4c3f4

ec7652aaf261
1da177e4c3f4
f7b422b17ee5
129d1977ed39

1da177e4c3f4
129d1977ed39
1da177e4c3f4
ec7652aaf261
1da177e4c3f4
1da177e4c3f4
89d77c8fa8e6
129d1977ed39
89d77c8fa8e6
129d1977ed39
89d77c8fa8e6
129d1977ed39
89d77c8fa8e6
129d1977ed39
89d77c8fa8e6
129d1977ed39
89d77c8fa8e6
129d1977ed39
89d77c8fa8e6
129d1977ed39
89d77c8fa8e6
129d1977ed39
89d77c8fa8e6
129d1977ed39
89d77c8fa8e6
1da177e4c3f4




1da177e4c3f4
1da177e4c3f4



8ec442ae4c65
1b340d0118da
e571cbf1a4f8
1da177e4c3f4
ec7652aaf261
1da177e4c3f4
f7b422b17ee5
6aaca5665032
5746006f1d17
1da177e4c3f4




f43bf0bebed7
1da177e4c3f4


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735






                                               
                                                                          






                                                                         

                         
                        








                               
                                 



                             

                           
                      

                          
                       
                         
                          
                        
 

                        
                    
                     
                       
                   
                     
                    
                        
                 
                
                  

                                          
 


                                                 
                                                            
 
                                                 
                                                                
 
                                            
 





                                                  
   






                                                                              
                             

                 
                                         

   







                                                                    




                           








                                                                  
                                         
 



                                               
                                                       
                                 
                                    
                                                
 
                                   
 


                                                
                           


                               




                                                                    
                    
 



                                                      


                   


                              
                                                      



                                              

                                                    

                                                  


                                                                        
                                                                                                                                                     
            
                                                                                                                                
 
 



                                        
                                    

 








                                                                        
                                           





                                                            
                                  
                                                             
                                    
 
                                     
 





                                                              
                                        
 
  

                                              
   
                                                     
 
                                                     
                                     


































                                                                       
                                             



                                             










                                                                             
                                               

                           

                                             

                                                            
                                  
                                                      
                                  


                                         


                                                                               
                                  
         


                                                      
                                            







                                                                                     

                                                                           
                                                                     


                                                                              
                                                                              
                                             
                                                                                 


                                                                                       
                                                                                     
                                                           
                                                            
                                                            

                                                                                    



                                                                                       
                                                    
                                                              
                         




                                                                              


                                                                   
                                     
                                  
                                   



                                                                      

                                   
 
                                                             
                                                      

                                                        

                                                                     

                                                        
                                                                  
                                                                     

                                                        
                                                                  
                                                                     
                                                         
                                                              
                                                                        
                                                                     

                                                                        

                                                                    
                                                          
                                                        
                                                       

                                                                     

                                                        
                                                                  
                                                                     

                                                        
                                                                        
                                                                     


                                                                



                                                                                   

                                                          
                                                
                                             
 

                                                     


                                                
                                                               

                                             
                                             





                                              
                                                                           

                 
                             
 
                                                                                                                                       




                                                      

                                
 

                                                



                                                                      






                                                                                   
                                                           

                         
                                  

                                          
                                  
         



                                  



                                                                  
                                                           
                                                               
                       


                                                

                     
                               

   









                                                                

                       
 


                                              
 







                                                   


   









                                                                         
                                          
                                                        

                                                             





                                                     
                                                                                           
                                            

                                                
                                                          
                                                     
         
 
                                            
 


                                                                                
                                                                              

                
                                                                         
                                     
                                          


                                                               
         











                                                                          
                               
 



                                                                       
                   
                                              
                                                                     
         
    

                   
                               
 

























                                                                                     
                                                   

























                                                                           
                                                   







                                                                
















                                                                    
                                     






                                                   
                                     
 
                                                                                      

                                     


                                                  
 
                                                


                                        
         









                                                  
                                 

                   
                                          



                                                                           
                                                     

                   
                                        
 
                                                                             
 

                                                   
 
                                      



                                                                                   
                                                                  
                       

                                                              

                                       

                            
                                 


                   



                                                       
                                        
 



                                                                        
                                                                               
 
                                                           






                                                       
                                             
 


                                                                              
                                                                                                        





                                                           

                                                      



                                                                   




                                    
                                                          
 
                                                           
                                                                   





                                                                      
                                                                              








                                                                  
 


                                                                        

                                             
                                                  




                                                       











                                                                      
                                       
                                              



                                                                 
                                
                         
                             
                         
 




                                  
                                                     
                                                                         






                                                                                                
                                                                             



                         
                                                 





                                                                                                
 
                                                       
                                         
 



                                                                    
     
                              






                                              




                                                                                                                  
                                                 
                         
                                            










                                                                              
                                                                  
                                                               


                                                      
                                        
 
                                                                                     









                                                           
                                   
                                                                      

                                                    
                                              




                                                                         








                                                                       



                                                    




                                                                              
 



                                                      
                                                       


                                                                       
         

                                                             
    
                   

 
                                                                                       

                                              
                              
 

                                                                 

                                                                        

                                                                     
                                            
         
                                                                       

                                                                



                                                                                



                                                                                



                                                                               
         


                                                                                    




                                                                     

 
   
                                                                               






                                                                        
                                                                                   


                                              
                                  
 
 

                                                 
                                                             


                                                                                                       
                            
 
                                                          
                                                               
                                                                        
 
                                                           
                                                                                                     
                                                
 





                                                                                

                                                




                                                                                                             
                                                                                               

                                         
                                                                                    
                                                
 
                                                                                                     



                                                 
 
                                                     


                 
                                                                                          
 

                                                   




                                                                                         

                                                  

                                                                    
 
                                                 


                                                           
                                                              



                                                   
                                                                    






                                                            

                                 
 
                                  
 








                                                  
                                   









                                                      
                                     
 
                















                                                                          






                                                                   



                                                                       
                                          



                                                                        

                                                                     


























                                                                              











                                                                            
                                                        








                                                                                                
                                                                         

                                                      
                                                                                           




                                                                                 



                                                        











                                                                          




                                                 
                                                        
                                    
 

                      
                                     
 











                                                                                        






                                                                     





                                                                  


                                                                          
                   
 
                                  
                                                               
                                    
                      
 
                                            
 












                                                                                    





                                                                         



                                                           

                                 

                                                                         
                                                          
                                                         
         

                                                                        
                                                                                     



                                                                        
                                                                                     



                                                                       
                                                     
                                                       
         



                                                               
 
                                                      
 











                                                                           
                                                                         
 
                                  
                                              
                                    
                                  
                                    
                                          
 
                                                                        
                                                                  
                                                                

                                                                    







                                                                                      



                                                     







                                                                                                         
 
                                   
                              
                                                                             
                                                                       
                                             

                                           


                                                                 
                                                     
 




                                                      
 
                                                      
                                                      
 
                                           
                                                   
                                                             

                                                                                      




                                                          

                                                                   
                                                              
                 

                                                      

                                                  
                                                                               

                                                                      

                                                        
                                                  
                                                                               

                                                                      
                                                        
 
                                                    





                                                                            

                                                                                                   


                                                                                     





                                                                              
                 



                                                                      
 
 

                                                                               


                                                                       
 

                                                                               


                                                                 
                                                                                                   
                 





                                                                      




                                                                                                   





                                                                      




                                                                                                   




                                                                      
 




                                                                
                                                       
                 


                                                                      
 
                                                       



                                                                           
         

                                                        


                                                                        
                                                            
                                                          
                                                
                                                                        
                
                                                                                                                       



                                                                              
         
                                         



                                                              
                                                                    
                                                                     
                                                

                 
         





                                                              


                       
                                                     

                               
                                                                                  

                            

                                   



                                             
                             

                              

                                
                                   
 
                                                 
 
                                                                      


                                                        



                                                
                                     
 

                                                         
                             



                                           
                            

      
 
                                


                                                          
                                          


                                                      
                                                
                         
                                      
                                                   


                                              
                             
 
 
                                           


                                                                      

                                                                      
                                                        





                                     
                                        
 
                                             

 
                                          
                                    







                                                          
                                                          



















                                    
               
                              


                                        
                              





                                                
                                      








                                               






                                   

                                      
                            


                                                   
                          
 

                                     
                          
 

                             
                          
 

                                 
                          
 

                                      
                          


                                    
                          


                                       
                          


                                        
                          
 

                                     
                          

                     
                                                   
      
                                           

                          
                 
     
                     
                                              
      
                                  
     
                                     
     
                                    
     
                                 
     
                                   
     
                           
     
                      
     
                                 
     
                                               
     
                                   
      




                                    
                                  



                                     
                                 
                                               
                                   
                     
                                              
      
                            
                           
                      




                                                
                                       


                        
/*
 *  linux/fs/nfs/inode.c
 *
 *  Copyright (C) 1992  Rick Sladkey
 *
 *  nfs inode and superblock handling functions
 *
 *  Modularised by Alan Cox <alan@lxorguk.ukuu.org.uk>, while hacking some
 *  experimental NFS changes. Modularisation taken straight from SYS5 fs.
 *
 *  Change to nfs_read_super() to permit NFS mounts to multi-homed hosts.
 *  J.S.Peatfield@damtp.cam.ac.uk
 *
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/stats.h>
#include <linux/sunrpc/metrics.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_mount.h>
#include <linux/nfs4_mount.h>
#include <linux/lockd/bind.h>
#include <linux/seq_file.h>
#include <linux/mount.h>
#include <linux/vfs.h>
#include <linux/inet.h>
#include <linux/nfs_xdr.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/freezer.h>
#include <linux/crc32.h>

#include <asm/uaccess.h>

#include "nfs4_fs.h"
#include "callback.h"
#include "delegation.h"
#include "iostat.h"
#include "internal.h"
#include "fscache.h"
#include "dns_resolve.h"
#include "pnfs.h"
#include "nfs.h"
#include "netns.h"

#define NFSDBG_FACILITY		NFSDBG_VFS

#define NFS_64_BIT_INODE_NUMBERS_ENABLED	1

/* Default is to see 64-bit inode numbers */
static bool enable_ino64 = NFS_64_BIT_INODE_NUMBERS_ENABLED;

static void nfs_invalidate_inode(struct inode *);
static int nfs_update_inode(struct inode *, struct nfs_fattr *);

static struct kmem_cache * nfs_inode_cachep;

static inline unsigned long
nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
{
	return nfs_fileid_to_ino_t(fattr->fileid);
}

/**
 * nfs_wait_bit_killable - helper for functions that are sleeping on bit locks
 * @word: long word containing the bit lock
 */
int nfs_wait_bit_killable(void *word)
{
	if (fatal_signal_pending(current))
		return -ERESTARTSYS;
	freezable_schedule();
	return 0;
}
EXPORT_SYMBOL_GPL(nfs_wait_bit_killable);

/**
 * nfs_compat_user_ino64 - returns the user-visible inode number
 * @fileid: 64-bit fileid
 *
 * This function returns a 32-bit inode number if the boot parameter
 * nfs.enable_ino64 is zero.
 */
u64 nfs_compat_user_ino64(u64 fileid)
{
#ifdef CONFIG_COMPAT
	compat_ulong_t ino;
#else	
	unsigned long ino;
#endif

	if (enable_ino64)
		return fileid;
	ino = fileid;
	if (sizeof(ino) < sizeof(fileid))
		ino ^= fileid >> (sizeof(fileid)-sizeof(ino)) * 8;
	return ino;
}

void nfs_clear_inode(struct inode *inode)
{
	/*
	 * The following should never happen...
	 */
	BUG_ON(nfs_have_writebacks(inode));
	BUG_ON(!list_empty(&NFS_I(inode)->open_files));
	nfs_zap_acl_cache(inode);
	nfs_access_zap_cache(inode);
	nfs_fscache_release_inode_cookie(inode);
}
EXPORT_SYMBOL_GPL(nfs_clear_inode);

void nfs_evict_inode(struct inode *inode)
{
	truncate_inode_pages(&inode->i_data, 0);
	clear_inode(inode);
	nfs_clear_inode(inode);
}

/**
 * nfs_sync_mapping - helper to flush all mmapped dirty data to disk
 */
int nfs_sync_mapping(struct address_space *mapping)
{
	int ret = 0;

	if (mapping->nrpages != 0) {
		unmap_mapping_range(mapping, 0, 0, 0);
		ret = nfs_wb_all(mapping->host);
	}
	return ret;
}

/*
 * Invalidate the local caches
 */
static void nfs_zap_caches_locked(struct inode *inode)
{
	struct nfs_inode *nfsi = NFS_I(inode);
	int mode = inode->i_mode;

	nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);

	nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
	nfsi->attrtimeo_timestamp = jiffies;

	memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
	if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))
		nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE;
	else
		nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE;
}

void nfs_zap_caches(struct inode *inode)
{
	spin_lock(&inode->i_lock);
	nfs_zap_caches_locked(inode);
	spin_unlock(&inode->i_lock);
}

void nfs_zap_mapping(struct inode *inode, struct address_space *mapping)
{
	if (mapping->nrpages != 0) {
		spin_lock(&inode->i_lock);
		NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA;
		spin_unlock(&inode->i_lock);
	}
}

void nfs_zap_acl_cache(struct inode *inode)
{
	void (*clear_acl_cache)(struct inode *);

	clear_acl_cache = NFS_PROTO(inode)->clear_acl_cache;
	if (clear_acl_cache != NULL)
		clear_acl_cache(inode);
	spin_lock(&inode->i_lock);
	NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_ACL;
	spin_unlock(&inode->i_lock);
}
EXPORT_SYMBOL_GPL(nfs_zap_acl_cache);

void nfs_invalidate_atime(struct inode *inode)
{
	spin_lock(&inode->i_lock);
	NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME;
	spin_unlock(&inode->i_lock);
}
EXPORT_SYMBOL_GPL(nfs_invalidate_atime);

/*
 * Invalidate, but do not unhash, the inode.
 * NB: must be called with inode->i_lock held!
 */
static void nfs_invalidate_inode(struct inode *inode)
{
	set_bit(NFS_INO_STALE, &NFS_I(inode)->flags);
	nfs_zap_caches_locked(inode);
}

struct nfs_find_desc {
	struct nfs_fh		*fh;
	struct nfs_fattr	*fattr;
};

/*
 * In NFSv3 we can have 64bit inode numbers. In order to support
 * this, and re-exported directories (also seen in NFSv2)
 * we are forced to allow 2 different inodes to have the same
 * i_ino.
 */
static int
nfs_find_actor(struct inode *inode, void *opaque)
{
	struct nfs_find_desc	*desc = (struct nfs_find_desc *)opaque;
	struct nfs_fh		*fh = desc->fh;
	struct nfs_fattr	*fattr = desc->fattr;

	if (NFS_FILEID(inode) != fattr->fileid)
		return 0;
	if (nfs_compare_fh(NFS_FH(inode), fh))
		return 0;
	if (is_bad_inode(inode) || NFS_STALE(inode))
		return 0;
	return 1;
}

static int
nfs_init_locked(struct inode *inode, void *opaque)
{
	struct nfs_find_desc	*desc = (struct nfs_find_desc *)opaque;
	struct nfs_fattr	*fattr = desc->fattr;

	set_nfs_fileid(inode, fattr->fileid);
	nfs_copy_fh(NFS_FH(inode), desc->fh);
	return 0;
}

/*
 * This is our front-end to iget that looks up inodes by file handle
 * instead of inode number.
 */
struct inode *
nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
{
	struct nfs_find_desc desc = {
		.fh	= fh,
		.fattr	= fattr
	};
	struct inode *inode = ERR_PTR(-ENOENT);
	unsigned long hash;

	nfs_attr_check_mountpoint(sb, fattr);

	if (((fattr->valid & NFS_ATTR_FATTR_FILEID) == 0) &&
	    !nfs_attr_use_mounted_on_fileid(fattr))
		goto out_no_inode;
	if ((fattr->valid & NFS_ATTR_FATTR_TYPE) == 0)
		goto out_no_inode;

	hash = nfs_fattr_to_ino_t(fattr);

	inode = iget5_locked(sb, hash, nfs_find_actor, nfs_init_locked, &desc);
	if (inode == NULL) {
		inode = ERR_PTR(-ENOMEM);
		goto out_no_inode;
	}

	if (inode->i_state & I_NEW) {
		struct nfs_inode *nfsi = NFS_I(inode);
		unsigned long now = jiffies;

		/* We set i_ino for the few things that still rely on it,
		 * such as stat(2) */
		inode->i_ino = hash;

		/* We can't support update_atime(), since the server will reset it */
		inode->i_flags |= S_NOATIME|S_NOCMTIME;
		inode->i_mode = fattr->mode;
		if ((fattr->valid & NFS_ATTR_FATTR_MODE) == 0
				&& nfs_server_capable(inode, NFS_CAP_MODE))
			nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
		/* Why so? Because we want revalidate for devices/FIFOs, and
		 * that's precisely what we have in nfs_file_inode_operations.
		 */
		inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->file_inode_ops;
		if (S_ISREG(inode->i_mode)) {
			inode->i_fop = NFS_SB(sb)->nfs_client->rpc_ops->file_ops;
			inode->i_data.a_ops = &nfs_file_aops;
			inode->i_data.backing_dev_info = &NFS_SB(sb)->backing_dev_info;
		} else if (S_ISDIR(inode->i_mode)) {
			inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops;
			inode->i_fop = &nfs_dir_operations;
			inode->i_data.a_ops = &nfs_dir_aops;
			/* Deal with crossing mountpoints */
			if (fattr->valid & NFS_ATTR_FATTR_MOUNTPOINT ||
					fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) {
				if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
					inode->i_op = &nfs_referral_inode_operations;
				else
					inode->i_op = &nfs_mountpoint_inode_operations;
				inode->i_fop = NULL;
				inode->i_flags |= S_AUTOMOUNT;
			}
		} else if (S_ISLNK(inode->i_mode))
			inode->i_op = &nfs_symlink_inode_operations;
		else
			init_special_inode(inode, inode->i_mode, fattr->rdev);

		memset(&inode->i_atime, 0, sizeof(inode->i_atime));
		memset(&inode->i_mtime, 0, sizeof(inode->i_mtime));
		memset(&inode->i_ctime, 0, sizeof(inode->i_ctime));
		inode->i_version = 0;
		inode->i_size = 0;
		clear_nlink(inode);
		inode->i_uid = -2;
		inode->i_gid = -2;
		inode->i_blocks = 0;
		memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
		nfsi->write_io = 0;
		nfsi->read_io = 0;

		nfsi->read_cache_jiffies = fattr->time_start;
		nfsi->attr_gencount = fattr->gencount;
		if (fattr->valid & NFS_ATTR_FATTR_ATIME)
			inode->i_atime = fattr->atime;
		else if (nfs_server_capable(inode, NFS_CAP_ATIME))
			nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
		if (fattr->valid & NFS_ATTR_FATTR_MTIME)
			inode->i_mtime = fattr->mtime;
		else if (nfs_server_capable(inode, NFS_CAP_MTIME))
			nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
		if (fattr->valid & NFS_ATTR_FATTR_CTIME)
			inode->i_ctime = fattr->ctime;
		else if (nfs_server_capable(inode, NFS_CAP_CTIME))
			nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
		if (fattr->valid & NFS_ATTR_FATTR_CHANGE)
			inode->i_version = fattr->change_attr;
		else if (nfs_server_capable(inode, NFS_CAP_CHANGE_ATTR))
			nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
		if (fattr->valid & NFS_ATTR_FATTR_SIZE)
			inode->i_size = nfs_size_to_loff_t(fattr->size);
		else
			nfsi->cache_validity |= NFS_INO_INVALID_ATTR
				| NFS_INO_REVAL_PAGECACHE;
		if (fattr->valid & NFS_ATTR_FATTR_NLINK)
			set_nlink(inode, fattr->nlink);
		else if (nfs_server_capable(inode, NFS_CAP_NLINK))
			nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
		if (fattr->valid & NFS_ATTR_FATTR_OWNER)
			inode->i_uid = fattr->uid;
		else if (nfs_server_capable(inode, NFS_CAP_OWNER))
			nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
		if (fattr->valid & NFS_ATTR_FATTR_GROUP)
			inode->i_gid = fattr->gid;
		else if (nfs_server_capable(inode, NFS_CAP_OWNER_GROUP))
			nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
		if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
			inode->i_blocks = fattr->du.nfs2.blocks;
		if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
			/*
			 * report the blocks in 512byte units
			 */
			inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
		}
		nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
		nfsi->attrtimeo_timestamp = now;
		nfsi->access_cache = RB_ROOT;

		nfs_fscache_init_inode_cookie(inode);

		unlock_new_inode(inode);
	} else
		nfs_refresh_inode(inode, fattr);
	dprintk("NFS: nfs_fhget(%s/%Ld fh_crc=0x%08x ct=%d)\n",
		inode->i_sb->s_id,
		(long long)NFS_FILEID(inode),
		nfs_display_fhandle_hash(fh),
		atomic_read(&inode->i_count));

out:
	return inode;

out_no_inode:
	dprintk("nfs_fhget: iget failed with error %ld\n", PTR_ERR(inode));
	goto out;
}
EXPORT_SYMBOL_GPL(nfs_fhget);

#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET|ATTR_FILE|ATTR_OPEN)

int
nfs_setattr(struct dentry *dentry, struct iattr *attr)
{
	struct inode *inode = dentry->d_inode;
	struct nfs_fattr *fattr;
	int error = -ENOMEM;

	nfs_inc_stats(inode, NFSIOS_VFSSETATTR);

	/* skip mode change if it's just for clearing setuid/setgid */
	if (attr->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID))
		attr->ia_valid &= ~ATTR_MODE;

	if (attr->ia_valid & ATTR_SIZE) {
		if (!S_ISREG(inode->i_mode) || attr->ia_size == i_size_read(inode))
			attr->ia_valid &= ~ATTR_SIZE;
	}

	/* Optimization: if the end result is no change, don't RPC */
	attr->ia_valid &= NFS_VALID_ATTRS;
	if ((attr->ia_valid & ~(ATTR_FILE|ATTR_OPEN)) == 0)
		return 0;

	/* Write all dirty data */
	if (S_ISREG(inode->i_mode)) {
		nfs_inode_dio_wait(inode);
		nfs_wb_all(inode);
	}

	fattr = nfs_alloc_fattr();
	if (fattr == NULL)
		goto out;
	/*
	 * Return any delegations if we're going to change ACLs
	 */
	if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0)
		NFS_PROTO(inode)->return_delegation(inode);
	error = NFS_PROTO(inode)->setattr(dentry, fattr, attr);
	if (error == 0)
		nfs_refresh_inode(inode, fattr);
	nfs_free_fattr(fattr);
out:
	return error;
}
EXPORT_SYMBOL_GPL(nfs_setattr);

/**
 * nfs_vmtruncate - unmap mappings "freed" by truncate() syscall
 * @inode: inode of the file used
 * @offset: file offset to start truncating
 *
 * This is a copy of the common vmtruncate, but with the locking
 * corrected to take into account the fact that NFS requires
 * inode->i_size to be updated under the inode->i_lock.
 */
static int nfs_vmtruncate(struct inode * inode, loff_t offset)
{
	loff_t oldsize;
	int err;

	err = inode_newsize_ok(inode, offset);
	if (err)
		goto out;

	spin_lock(&inode->i_lock);
	oldsize = inode->i_size;
	i_size_write(inode, offset);
	spin_unlock(&inode->i_lock);

	truncate_pagecache(inode, oldsize, offset);
out:
	return err;
}

/**
 * nfs_setattr_update_inode - Update inode metadata after a setattr call.
 * @inode: pointer to struct inode
 * @attr: pointer to struct iattr
 *
 * Note: we do this in the *proc.c in order to ensure that
 *       it works for things like exclusive creates too.
 */
void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr)
{
	if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) {
		spin_lock(&inode->i_lock);
		if ((attr->ia_valid & ATTR_MODE) != 0) {
			int mode = attr->ia_mode & S_IALLUGO;
			mode |= inode->i_mode & ~S_IALLUGO;
			inode->i_mode = mode;
		}
		if ((attr->ia_valid & ATTR_UID) != 0)
			inode->i_uid = attr->ia_uid;
		if ((attr->ia_valid & ATTR_GID) != 0)
			inode->i_gid = attr->ia_gid;
		NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
		spin_unlock(&inode->i_lock);
	}
	if ((attr->ia_valid & ATTR_SIZE) != 0) {
		nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC);
		nfs_vmtruncate(inode, attr->ia_size);
	}
}
EXPORT_SYMBOL_GPL(nfs_setattr_update_inode);

int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
{
	struct inode *inode = dentry->d_inode;
	int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME;
	int err;

	/* Flush out writes to the server in order to update c/mtime.  */
	if (S_ISREG(inode->i_mode)) {
		nfs_inode_dio_wait(inode);
		err = filemap_write_and_wait(inode->i_mapping);
		if (err)
			goto out;
	}

	/*
	 * We may force a getattr if the user cares about atime.
	 *
	 * Note that we only have to check the vfsmount flags here:
	 *  - NFS always sets S_NOATIME by so checking it would give a
	 *    bogus result
	 *  - NFS never sets MS_NOATIME or MS_NODIRATIME so there is
	 *    no point in checking those.
	 */
 	if ((mnt->mnt_flags & MNT_NOATIME) ||
 	    ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)))
		need_atime = 0;

	if (need_atime)
		err = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
	else
		err = nfs_revalidate_inode(NFS_SERVER(inode), inode);
	if (!err) {
		generic_fillattr(inode, stat);
		stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode));
	}
out:
	return err;
}
EXPORT_SYMBOL_GPL(nfs_getattr);

static void nfs_init_lock_context(struct nfs_lock_context *l_ctx)
{
	atomic_set(&l_ctx->count, 1);
	l_ctx->lockowner = current->files;
	l_ctx->pid = current->tgid;
	INIT_LIST_HEAD(&l_ctx->list);
}

static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context *ctx)
{
	struct nfs_lock_context *pos;

	list_for_each_entry(pos, &ctx->lock_context.list, list) {
		if (pos->lockowner != current->files)
			continue;
		if (pos->pid != current->tgid)
			continue;
		atomic_inc(&pos->count);
		return pos;
	}
	return NULL;
}

struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx)
{
	struct nfs_lock_context *res, *new = NULL;
	struct inode *inode = ctx->dentry->d_inode;

	spin_lock(&inode->i_lock);
	res = __nfs_find_lock_context(ctx);
	if (res == NULL) {
		spin_unlock(&inode->i_lock);
		new = kmalloc(sizeof(*new), GFP_KERNEL);
		if (new == NULL)
			return NULL;
		nfs_init_lock_context(new);
		spin_lock(&inode->i_lock);
		res = __nfs_find_lock_context(ctx);
		if (res == NULL) {
			list_add_tail(&new->list, &ctx->lock_context.list);
			new->open_context = ctx;
			res = new;
			new = NULL;
		}
	}
	spin_unlock(&inode->i_lock);
	kfree(new);
	return res;
}

void nfs_put_lock_context(struct nfs_lock_context *l_ctx)
{
	struct nfs_open_context *ctx = l_ctx->open_context;
	struct inode *inode = ctx->dentry->d_inode;

	if (!atomic_dec_and_lock(&l_ctx->count, &inode->i_lock))
		return;
	list_del(&l_ctx->list);
	spin_unlock(&inode->i_lock);
	kfree(l_ctx);
}

/**
 * nfs_close_context - Common close_context() routine NFSv2/v3
 * @ctx: pointer to context
 * @is_sync: is this a synchronous close
 *
 * always ensure that the attributes are up to date if we're mounted
 * with close-to-open semantics
 */
void nfs_close_context(struct nfs_open_context *ctx, int is_sync)
{
	struct inode *inode;
	struct nfs_server *server;

	if (!(ctx->mode & FMODE_WRITE))
		return;
	if (!is_sync)
		return;
	inode = ctx->dentry->d_inode;
	if (!list_empty(&NFS_I(inode)->open_files))
		return;
	server = NFS_SERVER(inode);
	if (server->flags & NFS_MOUNT_NOCTO)
		return;
	nfs_revalidate_inode(server, inode);
}
EXPORT_SYMBOL_GPL(nfs_close_context);

struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, fmode_t f_mode)
{
	struct nfs_open_context *ctx;
	struct rpc_cred *cred = rpc_lookup_cred();
	if (IS_ERR(cred))
		return ERR_CAST(cred);

	ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
	if (!ctx) {
		put_rpccred(cred);
		return ERR_PTR(-ENOMEM);
	}
	nfs_sb_active(dentry->d_sb);
	ctx->dentry = dget(dentry);
	ctx->cred = cred;
	ctx->state = NULL;
	ctx->mode = f_mode;
	ctx->flags = 0;
	ctx->error = 0;
	nfs_init_lock_context(&ctx->lock_context);
	ctx->lock_context.open_context = ctx;
	INIT_LIST_HEAD(&ctx->list);
	ctx->mdsthreshold = NULL;
	return ctx;
}
EXPORT_SYMBOL_GPL(alloc_nfs_open_context);

struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
{
	if (ctx != NULL)
		atomic_inc(&ctx->lock_context.count);
	return ctx;
}
EXPORT_SYMBOL_GPL(get_nfs_open_context);

static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync)
{
	struct inode *inode = ctx->dentry->d_inode;
	struct super_block *sb = ctx->dentry->d_sb;

	if (!list_empty(&ctx->list)) {
		if (!atomic_dec_and_lock(&ctx->lock_context.count, &inode->i_lock))
			return;
		list_del(&ctx->list);
		spin_unlock(&inode->i_lock);
	} else if (!atomic_dec_and_test(&ctx->lock_context.count))
		return;
	if (inode != NULL)
		NFS_PROTO(inode)->close_context(ctx, is_sync);
	if (ctx->cred != NULL)
		put_rpccred(ctx->cred);
	dput(ctx->dentry);
	nfs_sb_deactive(sb);
	kfree(ctx->mdsthreshold);
	kfree(ctx);
}

void put_nfs_open_context(struct nfs_open_context *ctx)
{
	__put_nfs_open_context(ctx, 0);
}
EXPORT_SYMBOL_GPL(put_nfs_open_context);

/*
 * Ensure that mmap has a recent RPC credential for use when writing out
 * shared pages
 */
void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx)
{
	struct inode *inode = filp->f_path.dentry->d_inode;
	struct nfs_inode *nfsi = NFS_I(inode);

	filp->private_data = get_nfs_open_context(ctx);
	spin_lock(&inode->i_lock);
	list_add(&ctx->list, &nfsi->open_files);
	spin_unlock(&inode->i_lock);
}
EXPORT_SYMBOL_GPL(nfs_file_set_open_context);

/*
 * Given an inode, search for an open context with the desired characteristics
 */
struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode)
{
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_open_context *pos, *ctx = NULL;

	spin_lock(&inode->i_lock);
	list_for_each_entry(pos, &nfsi->open_files, list) {
		if (cred != NULL && pos->cred != cred)
			continue;
		if ((pos->mode & (FMODE_READ|FMODE_WRITE)) != mode)
			continue;
		ctx = get_nfs_open_context(pos);
		break;
	}
	spin_unlock(&inode->i_lock);
	return ctx;
}

static void nfs_file_clear_open_context(struct file *filp)
{
	struct inode *inode = filp->f_path.dentry->d_inode;
	struct nfs_open_context *ctx = nfs_file_open_context(filp);

	if (ctx) {
		filp->private_data = NULL;
		spin_lock(&inode->i_lock);
		list_move_tail(&ctx->list, &NFS_I(inode)->open_files);
		spin_unlock(&inode->i_lock);
		__put_nfs_open_context(ctx, filp->f_flags & O_DIRECT ? 0 : 1);
	}
}

/*
 * These allocate and release file read/write context information.
 */
int nfs_open(struct inode *inode, struct file *filp)
{
	struct nfs_open_context *ctx;

	ctx = alloc_nfs_open_context(filp->f_path.dentry, filp->f_mode);
	if (IS_ERR(ctx))
		return PTR_ERR(ctx);
	nfs_file_set_open_context(filp, ctx);
	put_nfs_open_context(ctx);
	nfs_fscache_set_inode_cookie(inode, filp);
	return 0;
}

int nfs_release(struct inode *inode, struct file *filp)
{
	nfs_file_clear_open_context(filp);
	return 0;
}

/*
 * This function is called whenever some part of NFS notices that
 * the cached attributes have to be refreshed.
 */
int
__nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
{
	int		 status = -ESTALE;
	struct nfs_fattr *fattr = NULL;
	struct nfs_inode *nfsi = NFS_I(inode);

	dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n",
		inode->i_sb->s_id, (long long)NFS_FILEID(inode));

	if (is_bad_inode(inode))
		goto out;
	if (NFS_STALE(inode))
		goto out;

	status = -ENOMEM;
	fattr = nfs_alloc_fattr();
	if (fattr == NULL)
		goto out;

	nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
	status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr);
	if (status != 0) {
		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n",
			 inode->i_sb->s_id,
			 (long long)NFS_FILEID(inode), status);
		if (status == -ESTALE) {
			nfs_zap_caches(inode);
			if (!S_ISDIR(inode->i_mode))
				set_bit(NFS_INO_STALE, &NFS_I(inode)->flags);
		}
		goto out;
	}

	status = nfs_refresh_inode(inode, fattr);
	if (status) {
		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n",
			 inode->i_sb->s_id,
			 (long long)NFS_FILEID(inode), status);
		goto out;
	}

	if (nfsi->cache_validity & NFS_INO_INVALID_ACL)
		nfs_zap_acl_cache(inode);

	dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n",
		inode->i_sb->s_id,
		(long long)NFS_FILEID(inode));

 out:
	nfs_free_fattr(fattr);
	return status;
}

int nfs_attribute_timeout(struct inode *inode)
{
	struct nfs_inode *nfsi = NFS_I(inode);

	return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo);
}

static int nfs_attribute_cache_expired(struct inode *inode)
{
	if (nfs_have_delegated_attributes(inode))
		return 0;
	return nfs_attribute_timeout(inode);
}

/**
 * nfs_revalidate_inode - Revalidate the inode attributes
 * @server - pointer to nfs_server struct
 * @inode - pointer to inode struct
 *
 * Updates inode attribute information by retrieving the data from the server.
 */
int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
{
	if (!(NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATTR)
			&& !nfs_attribute_cache_expired(inode))
		return NFS_STALE(inode) ? -ESTALE : 0;
	return __nfs_revalidate_inode(server, inode);
}
EXPORT_SYMBOL_GPL(nfs_revalidate_inode);

static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping)
{
	struct nfs_inode *nfsi = NFS_I(inode);
	
	if (mapping->nrpages != 0) {
		int ret = invalidate_inode_pages2(mapping);
		if (ret < 0)
			return ret;
	}
	spin_lock(&inode->i_lock);
	nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
	if (S_ISDIR(inode->i_mode))
		memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
	spin_unlock(&inode->i_lock);
	nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
	nfs_fscache_reset_inode_cookie(inode);
	dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n",
			inode->i_sb->s_id, (long long)NFS_FILEID(inode));
	return 0;
}

static bool nfs_mapping_need_revalidate_inode(struct inode *inode)
{
	if (nfs_have_delegated_attributes(inode))
		return false;
	return (NFS_I(inode)->cache_validity & NFS_INO_REVAL_PAGECACHE)
		|| nfs_attribute_timeout(inode)
		|| NFS_STALE(inode);
}

/**
 * nfs_revalidate_mapping - Revalidate the pagecache
 * @inode - pointer to host inode
 * @mapping - pointer to mapping
 */
int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
{
	struct nfs_inode *nfsi = NFS_I(inode);
	int ret = 0;

	/* swapfiles are not supposed to be shared. */
	if (IS_SWAPFILE(inode))
		goto out;

	if (nfs_mapping_need_revalidate_inode(inode)) {
		ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
		if (ret < 0)
			goto out;
	}
	if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
		ret = nfs_invalidate_mapping(inode, mapping);
out:
	return ret;
}

static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
{
	struct nfs_inode *nfsi = NFS_I(inode);
	unsigned long ret = 0;

	if ((fattr->valid & NFS_ATTR_FATTR_PRECHANGE)
			&& (fattr->valid & NFS_ATTR_FATTR_CHANGE)
			&& inode->i_version == fattr->pre_change_attr) {
		inode->i_version = fattr->change_attr;
		if (S_ISDIR(inode->i_mode))
			nfsi->cache_validity |= NFS_INO_INVALID_DATA;
		ret |= NFS_INO_INVALID_ATTR;
	}
	/* If we have atomic WCC data, we may update some attributes */
	if ((fattr->valid & NFS_ATTR_FATTR_PRECTIME)
			&& (fattr->valid & NFS_ATTR_FATTR_CTIME)
			&& timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) {
		memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
		ret |= NFS_INO_INVALID_ATTR;
	}

	if ((fattr->valid & NFS_ATTR_FATTR_PREMTIME)
			&& (fattr->valid & NFS_ATTR_FATTR_MTIME)
			&& timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) {
		memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
		if (S_ISDIR(inode->i_mode))
			nfsi->cache_validity |= NFS_INO_INVALID_DATA;
		ret |= NFS_INO_INVALID_ATTR;
	}
	if ((fattr->valid & NFS_ATTR_FATTR_PRESIZE)
			&& (fattr->valid & NFS_ATTR_FATTR_SIZE)
			&& i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size)
			&& nfsi->npages == 0) {
		i_size_write(inode, nfs_size_to_loff_t(fattr->size));
		ret |= NFS_INO_INVALID_ATTR;
	}
	return ret;
}

/**
 * nfs_check_inode_attributes - verify consistency of the inode attribute cache
 * @inode - pointer to inode
 * @fattr - updated attributes
 *
 * Verifies the attribute cache. If we have just changed the attributes,
 * so that fattr carries weak cache consistency data, then it may
 * also update the ctime/mtime/change_attribute.
 */
static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fattr)
{
	struct nfs_inode *nfsi = NFS_I(inode);
	loff_t cur_size, new_isize;
	unsigned long invalid = 0;


	if (nfs_have_delegated_attributes(inode))
		return 0;
	/* Has the inode gone and changed behind our back? */
	if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid)
		return -EIO;
	if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
		return -EIO;

	if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 &&
			inode->i_version != fattr->change_attr)
		invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;

	/* Verify a few of the more important attributes */
	if ((fattr->valid & NFS_ATTR_FATTR_MTIME) && !timespec_equal(&inode->i_mtime, &fattr->mtime))
		invalid |= NFS_INO_INVALID_ATTR;

	if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
		cur_size = i_size_read(inode);
		new_isize = nfs_size_to_loff_t(fattr->size);
		if (cur_size != new_isize && nfsi->npages == 0)
			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
	}

	/* Have any file permissions changed? */
	if ((fattr->valid & NFS_ATTR_FATTR_MODE) && (inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO))
		invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
	if ((fattr->valid & NFS_ATTR_FATTR_OWNER) && inode->i_uid != fattr->uid)
		invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
	if ((fattr->valid & NFS_ATTR_FATTR_GROUP) && inode->i_gid != fattr->gid)
		invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;

	/* Has the link count changed? */
	if ((fattr->valid & NFS_ATTR_FATTR_NLINK) && inode->i_nlink != fattr->nlink)
		invalid |= NFS_INO_INVALID_ATTR;

	if ((fattr->valid & NFS_ATTR_FATTR_ATIME) && !timespec_equal(&inode->i_atime, &fattr->atime))
		invalid |= NFS_INO_INVALID_ATIME;

	if (invalid != 0)
		nfsi->cache_validity |= invalid;

	nfsi->read_cache_jiffies = fattr->time_start;
	return 0;
}

static int nfs_ctime_need_update(const struct inode *inode, const struct nfs_fattr *fattr)
{
	if (!(fattr->valid & NFS_ATTR_FATTR_CTIME))
		return 0;
	return timespec_compare(&fattr->ctime, &inode->i_ctime) > 0;
}

static int nfs_size_need_update(const struct inode *inode, const struct nfs_fattr *fattr)
{
	if (!(fattr->valid & NFS_ATTR_FATTR_SIZE))
		return 0;
	return nfs_size_to_loff_t(fattr->size) > i_size_read(inode);
}

static atomic_long_t nfs_attr_generation_counter;

static unsigned long nfs_read_attr_generation_counter(void)
{
	return atomic_long_read(&nfs_attr_generation_counter);
}

unsigned long nfs_inc_attr_generation_counter(void)
{
	return atomic_long_inc_return(&nfs_attr_generation_counter);
}

void nfs_fattr_init(struct nfs_fattr *fattr)
{
	fattr->valid = 0;
	fattr->time_start = jiffies;
	fattr->gencount = nfs_inc_attr_generation_counter();
	fattr->owner_name = NULL;
	fattr->group_name = NULL;
}
EXPORT_SYMBOL_GPL(nfs_fattr_init);

struct nfs_fattr *nfs_alloc_fattr(void)
{
	struct nfs_fattr *fattr;

	fattr = kmalloc(sizeof(*fattr), GFP_NOFS);
	if (fattr != NULL)
		nfs_fattr_init(fattr);
	return fattr;
}
EXPORT_SYMBOL_GPL(nfs_alloc_fattr);

struct nfs_fh *nfs_alloc_fhandle(void)
{
	struct nfs_fh *fh;

	fh = kmalloc(sizeof(struct nfs_fh), GFP_NOFS);
	if (fh != NULL)
		fh->size = 0;
	return fh;
}
EXPORT_SYMBOL_GPL(nfs_alloc_fhandle);

#ifdef NFS_DEBUG
/*
 * _nfs_display_fhandle_hash - calculate the crc32 hash for the filehandle
 *                             in the same way that wireshark does
 *
 * @fh: file handle
 *
 * For debugging only.
 */
u32 _nfs_display_fhandle_hash(const struct nfs_fh *fh)
{
	/* wireshark uses 32-bit AUTODIN crc and does a bitwise
	 * not on the result */
	return ~crc32(0xFFFFFFFF, &fh->data[0], fh->size);
}

/*
 * _nfs_display_fhandle - display an NFS file handle on the console
 *
 * @fh: file handle to display
 * @caption: display caption
 *
 * For debugging only.
 */
void _nfs_display_fhandle(const struct nfs_fh *fh, const char *caption)
{
	unsigned short i;

	if (fh == NULL || fh->size == 0) {
		printk(KERN_DEFAULT "%s at %p is empty\n", caption, fh);
		return;
	}

	printk(KERN_DEFAULT "%s at %p is %u bytes, crc: 0x%08x:\n",
	       caption, fh, fh->size, _nfs_display_fhandle_hash(fh));
	for (i = 0; i < fh->size; i += 16) {
		__be32 *pos = (__be32 *)&fh->data[i];

		switch ((fh->size - i - 1) >> 2) {
		case 0:
			printk(KERN_DEFAULT " %08x\n",
				be32_to_cpup(pos));
			break;
		case 1:
			printk(KERN_DEFAULT " %08x %08x\n",
				be32_to_cpup(pos), be32_to_cpup(pos + 1));
			break;
		case 2:
			printk(KERN_DEFAULT " %08x %08x %08x\n",
				be32_to_cpup(pos), be32_to_cpup(pos + 1),
				be32_to_cpup(pos + 2));
			break;
		default:
			printk(KERN_DEFAULT " %08x %08x %08x %08x\n",
				be32_to_cpup(pos), be32_to_cpup(pos + 1),
				be32_to_cpup(pos + 2), be32_to_cpup(pos + 3));
		}
	}
}
#endif

/**
 * nfs_inode_attrs_need_update - check if the inode attributes need updating
 * @inode - pointer to inode
 * @fattr - attributes
 *
 * Attempt to divine whether or not an RPC call reply carrying stale
 * attributes got scheduled after another call carrying updated ones.
 *
 * To do so, the function first assumes that a more recent ctime means
 * that the attributes in fattr are newer, however it also attempt to
 * catch the case where ctime either didn't change, or went backwards
 * (if someone reset the clock on the server) by looking at whether
 * or not this RPC call was started after the inode was last updated.
 * Note also the check for wraparound of 'attr_gencount'
 *
 * The function returns 'true' if it thinks the attributes in 'fattr' are
 * more recent than the ones cached in the inode.
 *
 */
static int nfs_inode_attrs_need_update(const struct inode *inode, const struct nfs_fattr *fattr)
{
	const struct nfs_inode *nfsi = NFS_I(inode);

	return ((long)fattr->gencount - (long)nfsi->attr_gencount) > 0 ||
		nfs_ctime_need_update(inode, fattr) ||
		nfs_size_need_update(inode, fattr) ||
		((long)nfsi->attr_gencount - (long)nfs_read_attr_generation_counter() > 0);
}

static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
{
	if (nfs_inode_attrs_need_update(inode, fattr))
		return nfs_update_inode(inode, fattr);
	return nfs_check_inode_attributes(inode, fattr);
}

/**
 * nfs_refresh_inode - try to update the inode attribute cache
 * @inode - pointer to inode
 * @fattr - updated attributes
 *
 * Check that an RPC call that returned attributes has not overlapped with
 * other recent updates of the inode metadata, then decide whether it is
 * safe to do a full update of the inode attributes, or whether just to
 * call nfs_check_inode_attributes.
 */
int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
{
	int status;

	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
		return 0;
	spin_lock(&inode->i_lock);
	status = nfs_refresh_inode_locked(inode, fattr);
	spin_unlock(&inode->i_lock);

	return status;
}
EXPORT_SYMBOL_GPL(nfs_refresh_inode);

static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
{
	struct nfs_inode *nfsi = NFS_I(inode);

	nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
	if (S_ISDIR(inode->i_mode))
		nfsi->cache_validity |= NFS_INO_INVALID_DATA;
	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
		return 0;
	return nfs_refresh_inode_locked(inode, fattr);
}

/**
 * nfs_post_op_update_inode - try to update the inode attribute cache
 * @inode - pointer to inode
 * @fattr - updated attributes
 *
 * After an operation that has changed the inode metadata, mark the
 * attribute cache as being invalid, then try to update it.
 *
 * NB: if the server didn't return any post op attributes, this
 * function will force the retrieval of attributes before the next
 * NFS request.  Thus it should be used only for operations that
 * are expected to change one or more attributes, to avoid
 * unnecessary NFS requests and trips through nfs_update_inode().
 */
int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
{
	int status;

	spin_lock(&inode->i_lock);
	status = nfs_post_op_update_inode_locked(inode, fattr);
	spin_unlock(&inode->i_lock);
	return status;
}
EXPORT_SYMBOL_GPL(nfs_post_op_update_inode);

/**
 * nfs_post_op_update_inode_force_wcc - try to update the inode attribute cache
 * @inode - pointer to inode
 * @fattr - updated attributes
 *
 * After an operation that has changed the inode metadata, mark the
 * attribute cache as being invalid, then try to update it. Fake up
 * weak cache consistency data, if none exist.
 *
 * This function is mainly designed to be used by the ->write_done() functions.
 */
int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr)
{
	int status;

	spin_lock(&inode->i_lock);
	/* Don't do a WCC update if these attributes are already stale */
	if ((fattr->valid & NFS_ATTR_FATTR) == 0 ||
			!nfs_inode_attrs_need_update(inode, fattr)) {
		fattr->valid &= ~(NFS_ATTR_FATTR_PRECHANGE
				| NFS_ATTR_FATTR_PRESIZE
				| NFS_ATTR_FATTR_PREMTIME
				| NFS_ATTR_FATTR_PRECTIME);
		goto out_noforce;
	}
	if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 &&
			(fattr->valid & NFS_ATTR_FATTR_PRECHANGE) == 0) {
		fattr->pre_change_attr = inode->i_version;
		fattr->valid |= NFS_ATTR_FATTR_PRECHANGE;
	}
	if ((fattr->valid & NFS_ATTR_FATTR_CTIME) != 0 &&
			(fattr->valid & NFS_ATTR_FATTR_PRECTIME) == 0) {
		memcpy(&fattr->pre_ctime, &inode->i_ctime, sizeof(fattr->pre_ctime));
		fattr->valid |= NFS_ATTR_FATTR_PRECTIME;
	}
	if ((fattr->valid & NFS_ATTR_FATTR_MTIME) != 0 &&
			(fattr->valid & NFS_ATTR_FATTR_PREMTIME) == 0) {
		memcpy(&fattr->pre_mtime, &inode->i_mtime, sizeof(fattr->pre_mtime));
		fattr->valid |= NFS_ATTR_FATTR_PREMTIME;
	}
	if ((fattr->valid & NFS_ATTR_FATTR_SIZE) != 0 &&
			(fattr->valid & NFS_ATTR_FATTR_PRESIZE) == 0) {
		fattr->pre_size = i_size_read(inode);
		fattr->valid |= NFS_ATTR_FATTR_PRESIZE;
	}
out_noforce:
	status = nfs_post_op_update_inode_locked(inode, fattr);
	spin_unlock(&inode->i_lock);
	return status;
}
EXPORT_SYMBOL_GPL(nfs_post_op_update_inode_force_wcc);

/*
 * Many nfs protocol calls return the new file attributes after
 * an operation.  Here we update the inode to reflect the state
 * of the server's inode.
 *
 * This is a bit tricky because we have to make sure all dirty pages
 * have been sent off to the server before calling invalidate_inode_pages.
 * To make sure no other process adds more write requests while we try
 * our best to flush them, we make them sleep during the attribute refresh.
 *
 * A very similar scenario holds for the dir cache.
 */
static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
{
	struct nfs_server *server;
	struct nfs_inode *nfsi = NFS_I(inode);
	loff_t cur_isize, new_isize;
	unsigned long invalid = 0;
	unsigned long now = jiffies;
	unsigned long save_cache_validity;

	dfprintk(VFS, "NFS: %s(%s/%ld fh_crc=0x%08x ct=%d info=0x%x)\n",
			__func__, inode->i_sb->s_id, inode->i_ino,
			nfs_display_fhandle_hash(NFS_FH(inode)),
			atomic_read(&inode->i_count), fattr->valid);

	if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid) {
		printk(KERN_ERR "NFS: server %s error: fileid changed\n"
			"fsid %s: expected fileid 0x%Lx, got 0x%Lx\n",
			NFS_SERVER(inode)->nfs_client->cl_hostname,
			inode->i_sb->s_id, (long long)nfsi->fileid,
			(long long)fattr->fileid);
		goto out_err;
	}

	/*
	 * Make sure the inode's type hasn't changed.
	 */
	if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) {
		/*
		* Big trouble! The inode has become a different object.
		*/
		printk(KERN_DEBUG "NFS: %s: inode %ld mode changed, %07o to %07o\n",
				__func__, inode->i_ino, inode->i_mode, fattr->mode);
		goto out_err;
	}

	server = NFS_SERVER(inode);
	/* Update the fsid? */
	if (S_ISDIR(inode->i_mode) && (fattr->valid & NFS_ATTR_FATTR_FSID) &&
			!nfs_fsid_equal(&server->fsid, &fattr->fsid) &&
			!IS_AUTOMOUNT(inode))
		server->fsid = fattr->fsid;

	/*
	 * Update the read time so we don't revalidate too often.
	 */
	nfsi->read_cache_jiffies = fattr->time_start;

	save_cache_validity = nfsi->cache_validity;
	nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR
			| NFS_INO_INVALID_ATIME
			| NFS_INO_REVAL_FORCED
			| NFS_INO_REVAL_PAGECACHE);

	/* Do atomic weak cache consistency updates */
	invalid |= nfs_wcc_update_inode(inode, fattr);

	/* More cache consistency checks */
	if (fattr->valid & NFS_ATTR_FATTR_CHANGE) {
		if (inode->i_version != fattr->change_attr) {
			dprintk("NFS: change_attr change on server for file %s/%ld\n",
					inode->i_sb->s_id, inode->i_ino);
			invalid |= NFS_INO_INVALID_ATTR
				| NFS_INO_INVALID_DATA
				| NFS_INO_INVALID_ACCESS
				| NFS_INO_INVALID_ACL
				| NFS_INO_REVAL_PAGECACHE;
			if (S_ISDIR(inode->i_mode))
				nfs_force_lookup_revalidate(inode);
			inode->i_version = fattr->change_attr;
		}
	} else if (server->caps & NFS_CAP_CHANGE_ATTR)
		invalid |= save_cache_validity;

	if (fattr->valid & NFS_ATTR_FATTR_MTIME) {
		memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
	} else if (server->caps & NFS_CAP_MTIME)
		invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
				| NFS_INO_REVAL_FORCED);

	if (fattr->valid & NFS_ATTR_FATTR_CTIME) {
		memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
	} else if (server->caps & NFS_CAP_CTIME)
		invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
				| NFS_INO_REVAL_FORCED);

	/* Check if our cached file size is stale */
	if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
		new_isize = nfs_size_to_loff_t(fattr->size);
		cur_isize = i_size_read(inode);
		if (new_isize != cur_isize) {
			/* Do we perhaps have any outstanding writes, or has
			 * the file grown beyond our last write? */
			if ((nfsi->npages == 0 && !test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) ||
			     new_isize > cur_isize) {
				i_size_write(inode, new_isize);
				invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
			}
			dprintk("NFS: isize change on server for file %s/%ld "
					"(%Ld to %Ld)\n",
					inode->i_sb->s_id,
					inode->i_ino,
					(long long)cur_isize,
					(long long)new_isize);
		}
	} else
		invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
				| NFS_INO_REVAL_PAGECACHE
				| NFS_INO_REVAL_FORCED);


	if (fattr->valid & NFS_ATTR_FATTR_ATIME)
		memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
	else if (server->caps & NFS_CAP_ATIME)
		invalid |= save_cache_validity & (NFS_INO_INVALID_ATIME
				| NFS_INO_REVAL_FORCED);

	if (fattr->valid & NFS_ATTR_FATTR_MODE) {
		if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) {
			umode_t newmode = inode->i_mode & S_IFMT;
			newmode |= fattr->mode & S_IALLUGO;
			inode->i_mode = newmode;
			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
		}
	} else if (server->caps & NFS_CAP_MODE)
		invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
				| NFS_INO_INVALID_ACCESS
				| NFS_INO_INVALID_ACL
				| NFS_INO_REVAL_FORCED);

	if (fattr->valid & NFS_ATTR_FATTR_OWNER) {
		if (inode->i_uid != fattr->uid) {
			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
			inode->i_uid = fattr->uid;
		}
	} else if (server->caps & NFS_CAP_OWNER)
		invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
				| NFS_INO_INVALID_ACCESS
				| NFS_INO_INVALID_ACL
				| NFS_INO_REVAL_FORCED);

	if (fattr->valid & NFS_ATTR_FATTR_GROUP) {
		if (inode->i_gid != fattr->gid) {
			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
			inode->i_gid = fattr->gid;
		}
	} else if (server->caps & NFS_CAP_OWNER_GROUP)
		invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
				| NFS_INO_INVALID_ACCESS
				| NFS_INO_INVALID_ACL
				| NFS_INO_REVAL_FORCED);

	if (fattr->valid & NFS_ATTR_FATTR_NLINK) {
		if (inode->i_nlink != fattr->nlink) {
			invalid |= NFS_INO_INVALID_ATTR;
			if (S_ISDIR(inode->i_mode))
				invalid |= NFS_INO_INVALID_DATA;
			set_nlink(inode, fattr->nlink);
		}
	} else if (server->caps & NFS_CAP_NLINK)
		invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
				| NFS_INO_REVAL_FORCED);

	if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
		/*
		 * report the blocks in 512byte units
		 */
		inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
 	}
	if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
		inode->i_blocks = fattr->du.nfs2.blocks;

	/* Update attrtimeo value if we're out of the unstable period */
	if (invalid & NFS_INO_INVALID_ATTR) {
		nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
		nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
		nfsi->attrtimeo_timestamp = now;
		nfsi->attr_gencount = nfs_inc_attr_generation_counter();
	} else {
		if (!time_in_range_open(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) {
			if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode))
				nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
			nfsi->attrtimeo_timestamp = now;
		}
	}
	invalid &= ~NFS_INO_INVALID_ATTR;
	/* Don't invalidate the data if we were to blame */
	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
				|| S_ISLNK(inode->i_mode)))
		invalid &= ~NFS_INO_INVALID_DATA;
	if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ) ||
			(save_cache_validity & NFS_INO_REVAL_FORCED))
		nfsi->cache_validity |= invalid;

	return 0;
 out_err:
	/*
	 * No need to worry about unhashing the dentry, as the
	 * lookup validation will know that the inode is bad.
	 * (But we fall through to invalidate the caches.)
	 */
	nfs_invalidate_inode(inode);
	return -ESTALE;
}

struct inode *nfs_alloc_inode(struct super_block *sb)
{
	struct nfs_inode *nfsi;
	nfsi = (struct nfs_inode *)kmem_cache_alloc(nfs_inode_cachep, GFP_KERNEL);
	if (!nfsi)
		return NULL;
	nfsi->flags = 0UL;
	nfsi->cache_validity = 0UL;
#ifdef CONFIG_NFS_V3_ACL
	nfsi->acl_access = ERR_PTR(-EAGAIN);
	nfsi->acl_default = ERR_PTR(-EAGAIN);
#endif
#if IS_ENABLED(CONFIG_NFS_V4)
	nfsi->nfs4_acl = NULL;
#endif /* CONFIG_NFS_V4 */
	return &nfsi->vfs_inode;
}
EXPORT_SYMBOL_GPL(nfs_alloc_inode);

static void nfs_i_callback(struct rcu_head *head)
{
	struct inode *inode = container_of(head, struct inode, i_rcu);
	kmem_cache_free(nfs_inode_cachep, NFS_I(inode));
}

void nfs_destroy_inode(struct inode *inode)
{
	call_rcu(&inode->i_rcu, nfs_i_callback);
}
EXPORT_SYMBOL_GPL(nfs_destroy_inode);

static inline void nfs4_init_once(struct nfs_inode *nfsi)
{
#if IS_ENABLED(CONFIG_NFS_V4)
	INIT_LIST_HEAD(&nfsi->open_states);
	nfsi->delegation = NULL;
	nfsi->delegation_state = 0;
	init_rwsem(&nfsi->rwsem);
	nfsi->layout = NULL;
#endif
}

static void init_once(void *foo)
{
	struct nfs_inode *nfsi = (struct nfs_inode *) foo;

	inode_init_once(&nfsi->vfs_inode);
	INIT_LIST_HEAD(&nfsi->open_files);
	INIT_LIST_HEAD(&nfsi->access_cache_entry_lru);
	INIT_LIST_HEAD(&nfsi->access_cache_inode_lru);
	INIT_LIST_HEAD(&nfsi->commit_info.list);
	nfsi->npages = 0;
	nfsi->commit_info.ncommit = 0;
	atomic_set(&nfsi->commit_info.rpcs_out, 0);
	atomic_set(&nfsi->silly_count, 1);
	INIT_HLIST_HEAD(&nfsi->silly_list);
	init_waitqueue_head(&nfsi->waitqueue);
	nfs4_init_once(nfsi);
}

static int __init nfs_init_inodecache(void)
{
	nfs_inode_cachep = kmem_cache_create("nfs_inode_cache",
					     sizeof(struct nfs_inode),
					     0, (SLAB_RECLAIM_ACCOUNT|
						SLAB_MEM_SPREAD),
					     init_once);
	if (nfs_inode_cachep == NULL)
		return -ENOMEM;

	return 0;
}

static void nfs_destroy_inodecache(void)
{
	kmem_cache_destroy(nfs_inode_cachep);
}

struct workqueue_struct *nfsiod_workqueue;
EXPORT_SYMBOL_GPL(nfsiod_workqueue);

/*
 * start up the nfsiod workqueue
 */
static int nfsiod_start(void)
{
	struct workqueue_struct *wq;
	dprintk("RPC:       creating workqueue nfsiod\n");
	wq = alloc_workqueue("nfsiod", WQ_MEM_RECLAIM, 0);
	if (wq == NULL)
		return -ENOMEM;
	nfsiod_workqueue = wq;
	return 0;
}

/*
 * Destroy the nfsiod workqueue
 */
static void nfsiod_stop(void)
{
	struct workqueue_struct *wq;

	wq = nfsiod_workqueue;
	if (wq == NULL)
		return;
	nfsiod_workqueue = NULL;
	destroy_workqueue(wq);
}

int nfs_net_id;
EXPORT_SYMBOL_GPL(nfs_net_id);

static int nfs_net_init(struct net *net)
{
	nfs_clients_init(net);
	return nfs_dns_resolver_cache_init(net);
}

static void nfs_net_exit(struct net *net)
{
	nfs_dns_resolver_cache_destroy(net);
	nfs_cleanup_cb_ident_idr(net);
}

static struct pernet_operations nfs_net_ops = {
	.init = nfs_net_init,
	.exit = nfs_net_exit,
	.id   = &nfs_net_id,
	.size = sizeof(struct nfs_net),
};

/*
 * Initialize NFS
 */
static int __init init_nfs_fs(void)
{
	int err;

	err = nfs_dns_resolver_init();
	if (err < 0)
		goto out10;;

	err = register_pernet_subsys(&nfs_net_ops);
	if (err < 0)
		goto out9;

	err = nfs_fscache_register();
	if (err < 0)
		goto out8;

	err = nfsiod_start();
	if (err)
		goto out7;

	err = nfs_fs_proc_init();
	if (err)
		goto out6;

	err = nfs_init_nfspagecache();
	if (err)
		goto out5;

	err = nfs_init_inodecache();
	if (err)
		goto out4;

	err = nfs_init_readpagecache();
	if (err)
		goto out3;

	err = nfs_init_writepagecache();
	if (err)
		goto out2;

	err = nfs_init_directcache();
	if (err)
		goto out1;

#ifdef CONFIG_PROC_FS
	rpc_proc_register(&init_net, &nfs_rpcstat);
#endif
	if ((err = register_nfs_fs()) != 0)
		goto out0;

	return 0;
out0:
#ifdef CONFIG_PROC_FS
	rpc_proc_unregister(&init_net, "nfs");
#endif
	nfs_destroy_directcache();
out1:
	nfs_destroy_writepagecache();
out2:
	nfs_destroy_readpagecache();
out3:
	nfs_destroy_inodecache();
out4:
	nfs_destroy_nfspagecache();
out5:
	nfs_fs_proc_exit();
out6:
	nfsiod_stop();
out7:
	nfs_fscache_unregister();
out8:
	unregister_pernet_subsys(&nfs_net_ops);
out9:
	nfs_dns_resolver_destroy();
out10:
	return err;
}

static void __exit exit_nfs_fs(void)
{
	nfs_destroy_directcache();
	nfs_destroy_writepagecache();
	nfs_destroy_readpagecache();
	nfs_destroy_inodecache();
	nfs_destroy_nfspagecache();
	nfs_fscache_unregister();
	unregister_pernet_subsys(&nfs_net_ops);
	nfs_dns_resolver_destroy();
#ifdef CONFIG_PROC_FS
	rpc_proc_unregister(&init_net, "nfs");
#endif
	unregister_nfs_fs();
	nfs_fs_proc_exit();
	nfsiod_stop();
}

/* Not quite true; I just maintain it */
MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
MODULE_LICENSE("GPL");
module_param(enable_ino64, bool, 0644);

module_init(init_nfs_fs)
module_exit(exit_nfs_fs)