aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/pohmelfs
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/staging/pohmelfs
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/staging/pohmelfs')
-rw-r--r--drivers/staging/pohmelfs/Kconfig28
-rw-r--r--drivers/staging/pohmelfs/Makefile3
-rw-r--r--drivers/staging/pohmelfs/config.c611
-rw-r--r--drivers/staging/pohmelfs/crypto.c878
-rw-r--r--drivers/staging/pohmelfs/dir.c1101
-rw-r--r--drivers/staging/pohmelfs/inode.c2056
-rw-r--r--drivers/staging/pohmelfs/lock.c182
-rw-r--r--drivers/staging/pohmelfs/mcache.c171
-rw-r--r--drivers/staging/pohmelfs/net.c1209
-rw-r--r--drivers/staging/pohmelfs/netfs.h919
-rw-r--r--drivers/staging/pohmelfs/path_entry.c120
-rw-r--r--drivers/staging/pohmelfs/trans.c706
12 files changed, 7984 insertions, 0 deletions
diff --git a/drivers/staging/pohmelfs/Kconfig b/drivers/staging/pohmelfs/Kconfig
new file mode 100644
index 00000000000..58158b8780f
--- /dev/null
+++ b/drivers/staging/pohmelfs/Kconfig
@@ -0,0 +1,28 @@
1config POHMELFS
2 tristate "POHMELFS filesystem support"
3 depends on NET
4 select CONNECTOR
5 select CRYPTO
6 select CRYPTO_BLKCIPHER
7 select CRYPTO_HMAC
8 help
9 POHMELFS stands for Parallel Optimized Host Message Exchange Layered
10 File System. This is a network filesystem which supports coherent
11 caching of data and metadata on clients.
12
13config POHMELFS_DEBUG
14 bool "POHMELFS debugging"
15 depends on POHMELFS
16 default n
17 help
18 Turns on excessive POHMELFS debugging facilities.
19 You usually do not want to slow things down noticeably and get really
20 lots of kernel messages in syslog.
21
22config POHMELFS_CRYPTO
23 bool "POHMELFS crypto support"
24 depends on POHMELFS
25 help
26 This option allows to encrypt and/or protect with strong
27 cryptographic hash all dataflow between server and clients.
28 Each config group can have its own keys.
diff --git a/drivers/staging/pohmelfs/Makefile b/drivers/staging/pohmelfs/Makefile
new file mode 100644
index 00000000000..196561ca26b
--- /dev/null
+++ b/drivers/staging/pohmelfs/Makefile
@@ -0,0 +1,3 @@
1obj-$(CONFIG_POHMELFS) += pohmelfs.o
2
3pohmelfs-y := inode.o config.o dir.o net.o path_entry.o trans.o crypto.o lock.o mcache.o
diff --git a/drivers/staging/pohmelfs/config.c b/drivers/staging/pohmelfs/config.c
new file mode 100644
index 00000000000..b6c42cb0d1c
--- /dev/null
+++ b/drivers/staging/pohmelfs/config.c
@@ -0,0 +1,611 @@
1/*
2 * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
3 * All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/kernel.h>
17#include <linux/connector.h>
18#include <linux/crypto.h>
19#include <linux/list.h>
20#include <linux/mutex.h>
21#include <linux/string.h>
22#include <linux/in.h>
23#include <linux/slab.h>
24
25#include "netfs.h"
26
27/*
28 * Global configuration list.
29 * Each client can be asked to get one of them.
30 *
31 * Allows to provide remote server address (ipv4/v6/whatever), port
32 * and so on via kernel connector.
33 */
34
35static struct cb_id pohmelfs_cn_id = {.idx = POHMELFS_CN_IDX, .val = POHMELFS_CN_VAL};
36static LIST_HEAD(pohmelfs_config_list);
37static DEFINE_MUTEX(pohmelfs_config_lock);
38
39static inline int pohmelfs_config_eql(struct pohmelfs_ctl *sc, struct pohmelfs_ctl *ctl)
40{
41 if (sc->idx == ctl->idx && sc->type == ctl->type &&
42 sc->proto == ctl->proto &&
43 sc->addrlen == ctl->addrlen &&
44 !memcmp(&sc->addr, &ctl->addr, ctl->addrlen))
45 return 1;
46
47 return 0;
48}
49
50static struct pohmelfs_config_group *pohmelfs_find_config_group(unsigned int idx)
51{
52 struct pohmelfs_config_group *g, *group = NULL;
53
54 list_for_each_entry(g, &pohmelfs_config_list, group_entry) {
55 if (g->idx == idx) {
56 group = g;
57 break;
58 }
59 }
60
61 return group;
62}
63
64static struct pohmelfs_config_group *pohmelfs_find_create_config_group(unsigned int idx)
65{
66 struct pohmelfs_config_group *g;
67
68 g = pohmelfs_find_config_group(idx);
69 if (g)
70 return g;
71
72 g = kzalloc(sizeof(struct pohmelfs_config_group), GFP_KERNEL);
73 if (!g)
74 return NULL;
75
76 INIT_LIST_HEAD(&g->config_list);
77 g->idx = idx;
78 g->num_entry = 0;
79
80 list_add_tail(&g->group_entry, &pohmelfs_config_list);
81
82 return g;
83}
84
85static inline void pohmelfs_insert_config_entry(struct pohmelfs_sb *psb, struct pohmelfs_config *dst)
86{
87 struct pohmelfs_config *tmp;
88
89 INIT_LIST_HEAD(&dst->config_entry);
90
91 list_for_each_entry(tmp, &psb->state_list, config_entry) {
92 if (dst->state.ctl.prio > tmp->state.ctl.prio)
93 list_add_tail(&dst->config_entry, &tmp->config_entry);
94 }
95 if (list_empty(&dst->config_entry))
96 list_add_tail(&dst->config_entry, &psb->state_list);
97}
98
99static int pohmelfs_move_config_entry(struct pohmelfs_sb *psb,
100 struct pohmelfs_config *dst, struct pohmelfs_config *new)
101{
102 if ((dst->state.ctl.prio == new->state.ctl.prio) &&
103 (dst->state.ctl.perm == new->state.ctl.perm))
104 return 0;
105
106 dprintk("%s: dst: prio: %d, perm: %x, new: prio: %d, perm: %d.\n",
107 __func__, dst->state.ctl.prio, dst->state.ctl.perm,
108 new->state.ctl.prio, new->state.ctl.perm);
109 dst->state.ctl.prio = new->state.ctl.prio;
110 dst->state.ctl.perm = new->state.ctl.perm;
111
112 list_del_init(&dst->config_entry);
113 pohmelfs_insert_config_entry(psb, dst);
114 return 0;
115}
116
117/*
118 * pohmelfs_copy_config() is used to copy new state configs from the
119 * config group (controlled by the netlink messages) into the superblock.
120 * This happens either at startup time where no transactions can access
121 * the list of the configs (and thus list of the network states), or at
122 * run-time, where it is protected by the psb->state_lock.
123 */
124int pohmelfs_copy_config(struct pohmelfs_sb *psb)
125{
126 struct pohmelfs_config_group *g;
127 struct pohmelfs_config *c, *dst;
128 int err = -ENODEV;
129
130 mutex_lock(&pohmelfs_config_lock);
131
132 g = pohmelfs_find_config_group(psb->idx);
133 if (!g)
134 goto out_unlock;
135
136 /*
137 * Run over all entries in given config group and try to create and
138 * initialize those, which do not exist in superblock list.
139 * Skip all existing entries.
140 */
141
142 list_for_each_entry(c, &g->config_list, config_entry) {
143 err = 0;
144 list_for_each_entry(dst, &psb->state_list, config_entry) {
145 if (pohmelfs_config_eql(&dst->state.ctl, &c->state.ctl)) {
146 err = pohmelfs_move_config_entry(psb, dst, c);
147 if (!err)
148 err = -EEXIST;
149 break;
150 }
151 }
152
153 if (err)
154 continue;
155
156 dst = kzalloc(sizeof(struct pohmelfs_config), GFP_KERNEL);
157 if (!dst) {
158 err = -ENOMEM;
159 break;
160 }
161
162 memcpy(&dst->state.ctl, &c->state.ctl, sizeof(struct pohmelfs_ctl));
163
164 pohmelfs_insert_config_entry(psb, dst);
165
166 err = pohmelfs_state_init_one(psb, dst);
167 if (err) {
168 list_del(&dst->config_entry);
169 kfree(dst);
170 }
171
172 err = 0;
173 }
174
175out_unlock:
176 mutex_unlock(&pohmelfs_config_lock);
177
178 return err;
179}
180
181int pohmelfs_copy_crypto(struct pohmelfs_sb *psb)
182{
183 struct pohmelfs_config_group *g;
184 int err = -ENOENT;
185
186 mutex_lock(&pohmelfs_config_lock);
187 g = pohmelfs_find_config_group(psb->idx);
188 if (!g)
189 goto err_out_exit;
190
191 if (g->hash_string) {
192 err = -ENOMEM;
193 psb->hash_string = kstrdup(g->hash_string, GFP_KERNEL);
194 if (!psb->hash_string)
195 goto err_out_exit;
196 psb->hash_strlen = g->hash_strlen;
197 }
198
199 if (g->cipher_string) {
200 psb->cipher_string = kstrdup(g->cipher_string, GFP_KERNEL);
201 if (!psb->cipher_string)
202 goto err_out_free_hash_string;
203 psb->cipher_strlen = g->cipher_strlen;
204 }
205
206 if (g->hash_keysize) {
207 psb->hash_key = kmemdup(g->hash_key, g->hash_keysize,
208 GFP_KERNEL);
209 if (!psb->hash_key)
210 goto err_out_free_cipher_string;
211 psb->hash_keysize = g->hash_keysize;
212 }
213
214 if (g->cipher_keysize) {
215 psb->cipher_key = kmemdup(g->cipher_key, g->cipher_keysize,
216 GFP_KERNEL);
217 if (!psb->cipher_key)
218 goto err_out_free_hash;
219 psb->cipher_keysize = g->cipher_keysize;
220 }
221
222 mutex_unlock(&pohmelfs_config_lock);
223
224 return 0;
225
226err_out_free_hash:
227 kfree(psb->hash_key);
228err_out_free_cipher_string:
229 kfree(psb->cipher_string);
230err_out_free_hash_string:
231 kfree(psb->hash_string);
232err_out_exit:
233 mutex_unlock(&pohmelfs_config_lock);
234 return err;
235}
236
237static int pohmelfs_send_reply(int err, int msg_num, int action, struct cn_msg *msg, struct pohmelfs_ctl *ctl)
238{
239 struct pohmelfs_cn_ack *ack;
240
241 ack = kzalloc(sizeof(struct pohmelfs_cn_ack), GFP_KERNEL);
242 if (!ack)
243 return -ENOMEM;
244
245 memcpy(&ack->msg, msg, sizeof(struct cn_msg));
246
247 if (action == POHMELFS_CTLINFO_ACK)
248 memcpy(&ack->ctl, ctl, sizeof(struct pohmelfs_ctl));
249
250 ack->msg.len = sizeof(struct pohmelfs_cn_ack) - sizeof(struct cn_msg);
251 ack->msg.ack = msg->ack + 1;
252 ack->error = err;
253 ack->msg_num = msg_num;
254
255 cn_netlink_send(&ack->msg, 0, GFP_KERNEL);
256 kfree(ack);
257 return 0;
258}
259
260static int pohmelfs_cn_disp(struct cn_msg *msg)
261{
262 struct pohmelfs_config_group *g;
263 struct pohmelfs_ctl *ctl = (struct pohmelfs_ctl *)msg->data;
264 struct pohmelfs_config *c, *tmp;
265 int err = 0, i = 1;
266
267 if (msg->len != sizeof(struct pohmelfs_ctl))
268 return -EBADMSG;
269
270 mutex_lock(&pohmelfs_config_lock);
271
272 g = pohmelfs_find_config_group(ctl->idx);
273 if (!g) {
274 pohmelfs_send_reply(err, 0, POHMELFS_NOINFO_ACK, msg, NULL);
275 goto out_unlock;
276 }
277
278 list_for_each_entry_safe(c, tmp, &g->config_list, config_entry) {
279 struct pohmelfs_ctl *sc = &c->state.ctl;
280 if (pohmelfs_send_reply(err, g->num_entry - i, POHMELFS_CTLINFO_ACK, msg, sc)) {
281 err = -ENOMEM;
282 goto out_unlock;
283 }
284 i += 1;
285 }
286
287 out_unlock:
288 mutex_unlock(&pohmelfs_config_lock);
289 return err;
290}
291
292static int pohmelfs_cn_dump(struct cn_msg *msg)
293{
294 struct pohmelfs_config_group *g;
295 struct pohmelfs_config *c, *tmp;
296 int err = 0, i = 1;
297 int total_msg = 0;
298
299 if (msg->len != sizeof(struct pohmelfs_ctl))
300 return -EBADMSG;
301
302 mutex_lock(&pohmelfs_config_lock);
303
304 list_for_each_entry(g, &pohmelfs_config_list, group_entry)
305 total_msg += g->num_entry;
306 if (total_msg == 0) {
307 if (pohmelfs_send_reply(err, 0, POHMELFS_NOINFO_ACK, msg, NULL))
308 err = -ENOMEM;
309 goto out_unlock;
310 }
311
312 list_for_each_entry(g, &pohmelfs_config_list, group_entry) {
313 list_for_each_entry_safe(c, tmp, &g->config_list,
314 config_entry) {
315 struct pohmelfs_ctl *sc = &c->state.ctl;
316 if (pohmelfs_send_reply(err, total_msg - i,
317 POHMELFS_CTLINFO_ACK, msg,
318 sc)) {
319 err = -ENOMEM;
320 goto out_unlock;
321 }
322 i += 1;
323 }
324 }
325
326out_unlock:
327 mutex_unlock(&pohmelfs_config_lock);
328 return err;
329}
330
331static int pohmelfs_cn_flush(struct cn_msg *msg)
332{
333 struct pohmelfs_config_group *g;
334 struct pohmelfs_ctl *ctl = (struct pohmelfs_ctl *)msg->data;
335 struct pohmelfs_config *c, *tmp;
336 int err = 0;
337
338 if (msg->len != sizeof(struct pohmelfs_ctl))
339 return -EBADMSG;
340
341 mutex_lock(&pohmelfs_config_lock);
342
343 if (ctl->idx != POHMELFS_NULL_IDX) {
344 g = pohmelfs_find_config_group(ctl->idx);
345
346 if (!g)
347 goto out_unlock;
348
349 list_for_each_entry_safe(c, tmp, &g->config_list, config_entry) {
350 list_del(&c->config_entry);
351 g->num_entry--;
352 kfree(c);
353 }
354 } else {
355 list_for_each_entry(g, &pohmelfs_config_list, group_entry) {
356 list_for_each_entry_safe(c, tmp, &g->config_list,
357 config_entry) {
358 list_del(&c->config_entry);
359 g->num_entry--;
360 kfree(c);
361 }
362 }
363 }
364
365out_unlock:
366 mutex_unlock(&pohmelfs_config_lock);
367 pohmelfs_cn_dump(msg);
368
369 return err;
370}
371
372static int pohmelfs_modify_config(struct pohmelfs_ctl *old, struct pohmelfs_ctl *new)
373{
374 old->perm = new->perm;
375 old->prio = new->prio;
376 return 0;
377}
378
379static int pohmelfs_cn_ctl(struct cn_msg *msg, int action)
380{
381 struct pohmelfs_config_group *g;
382 struct pohmelfs_ctl *ctl = (struct pohmelfs_ctl *)msg->data;
383 struct pohmelfs_config *c, *tmp;
384 int err = 0;
385
386 if (msg->len != sizeof(struct pohmelfs_ctl))
387 return -EBADMSG;
388
389 mutex_lock(&pohmelfs_config_lock);
390
391 g = pohmelfs_find_create_config_group(ctl->idx);
392 if (!g) {
393 err = -ENOMEM;
394 goto out_unlock;
395 }
396
397 list_for_each_entry_safe(c, tmp, &g->config_list, config_entry) {
398 struct pohmelfs_ctl *sc = &c->state.ctl;
399
400 if (pohmelfs_config_eql(sc, ctl)) {
401 if (action == POHMELFS_FLAGS_ADD) {
402 err = -EEXIST;
403 goto out_unlock;
404 } else if (action == POHMELFS_FLAGS_DEL) {
405 list_del(&c->config_entry);
406 g->num_entry--;
407 kfree(c);
408 goto out_unlock;
409 } else if (action == POHMELFS_FLAGS_MODIFY) {
410 err = pohmelfs_modify_config(sc, ctl);
411 goto out_unlock;
412 } else {
413 err = -EEXIST;
414 goto out_unlock;
415 }
416 }
417 }
418 if (action == POHMELFS_FLAGS_DEL) {
419 err = -EBADMSG;
420 goto out_unlock;
421 }
422
423 c = kzalloc(sizeof(struct pohmelfs_config), GFP_KERNEL);
424 if (!c) {
425 err = -ENOMEM;
426 goto out_unlock;
427 }
428 memcpy(&c->state.ctl, ctl, sizeof(struct pohmelfs_ctl));
429 g->num_entry++;
430
431 list_add_tail(&c->config_entry, &g->config_list);
432
433 out_unlock:
434 mutex_unlock(&pohmelfs_config_lock);
435 if (pohmelfs_send_reply(err, 0, POHMELFS_NOINFO_ACK, msg, NULL))
436 err = -ENOMEM;
437
438 return err;
439}
440
441static int pohmelfs_crypto_hash_init(struct pohmelfs_config_group *g, struct pohmelfs_crypto *c)
442{
443 char *algo = (char *)c->data;
444 u8 *key = (u8 *)(algo + c->strlen);
445
446 if (g->hash_string)
447 return -EEXIST;
448
449 g->hash_string = kstrdup(algo, GFP_KERNEL);
450 if (!g->hash_string)
451 return -ENOMEM;
452 g->hash_strlen = c->strlen;
453 g->hash_keysize = c->keysize;
454
455 g->hash_key = kmemdup(key, c->keysize, GFP_KERNEL);
456 if (!g->hash_key) {
457 kfree(g->hash_string);
458 return -ENOMEM;
459 }
460
461 return 0;
462}
463
464static int pohmelfs_crypto_cipher_init(struct pohmelfs_config_group *g, struct pohmelfs_crypto *c)
465{
466 char *algo = (char *)c->data;
467 u8 *key = (u8 *)(algo + c->strlen);
468
469 if (g->cipher_string)
470 return -EEXIST;
471
472 g->cipher_string = kstrdup(algo, GFP_KERNEL);
473 if (!g->cipher_string)
474 return -ENOMEM;
475 g->cipher_strlen = c->strlen;
476 g->cipher_keysize = c->keysize;
477
478 g->cipher_key = kmemdup(key, c->keysize, GFP_KERNEL);
479 if (!g->cipher_key) {
480 kfree(g->cipher_string);
481 return -ENOMEM;
482 }
483
484 return 0;
485}
486
487static int pohmelfs_cn_crypto(struct cn_msg *msg)
488{
489 struct pohmelfs_crypto *crypto = (struct pohmelfs_crypto *)msg->data;
490 struct pohmelfs_config_group *g;
491 int err = 0;
492
493 dprintk("%s: idx: %u, strlen: %u, type: %u, keysize: %u, algo: %s.\n",
494 __func__, crypto->idx, crypto->strlen, crypto->type,
495 crypto->keysize, (char *)crypto->data);
496
497 mutex_lock(&pohmelfs_config_lock);
498 g = pohmelfs_find_create_config_group(crypto->idx);
499 if (!g) {
500 err = -ENOMEM;
501 goto out_unlock;
502 }
503
504 switch (crypto->type) {
505 case POHMELFS_CRYPTO_HASH:
506 err = pohmelfs_crypto_hash_init(g, crypto);
507 break;
508 case POHMELFS_CRYPTO_CIPHER:
509 err = pohmelfs_crypto_cipher_init(g, crypto);
510 break;
511 default:
512 err = -ENOTSUPP;
513 break;
514 }
515
516out_unlock:
517 mutex_unlock(&pohmelfs_config_lock);
518 if (pohmelfs_send_reply(err, 0, POHMELFS_NOINFO_ACK, msg, NULL))
519 err = -ENOMEM;
520
521 return err;
522}
523
524static void pohmelfs_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
525{
526 int err;
527
528 if (!cap_raised(current_cap(), CAP_SYS_ADMIN))
529 return;
530
531 switch (msg->flags) {
532 case POHMELFS_FLAGS_ADD:
533 case POHMELFS_FLAGS_DEL:
534 case POHMELFS_FLAGS_MODIFY:
535 err = pohmelfs_cn_ctl(msg, msg->flags);
536 break;
537 case POHMELFS_FLAGS_FLUSH:
538 err = pohmelfs_cn_flush(msg);
539 break;
540 case POHMELFS_FLAGS_SHOW:
541 err = pohmelfs_cn_disp(msg);
542 break;
543 case POHMELFS_FLAGS_DUMP:
544 err = pohmelfs_cn_dump(msg);
545 break;
546 case POHMELFS_FLAGS_CRYPTO:
547 err = pohmelfs_cn_crypto(msg);
548 break;
549 default:
550 err = -ENOSYS;
551 break;
552 }
553}
554
555int pohmelfs_config_check(struct pohmelfs_config *config, int idx)
556{
557 struct pohmelfs_ctl *ctl = &config->state.ctl;
558 struct pohmelfs_config *tmp;
559 int err = -ENOENT;
560 struct pohmelfs_ctl *sc;
561 struct pohmelfs_config_group *g;
562
563 mutex_lock(&pohmelfs_config_lock);
564
565 g = pohmelfs_find_config_group(ctl->idx);
566 if (g) {
567 list_for_each_entry(tmp, &g->config_list, config_entry) {
568 sc = &tmp->state.ctl;
569
570 if (pohmelfs_config_eql(sc, ctl)) {
571 err = 0;
572 break;
573 }
574 }
575 }
576
577 mutex_unlock(&pohmelfs_config_lock);
578
579 return err;
580}
581
582int __init pohmelfs_config_init(void)
583{
584 /* XXX remove (void *) cast when vanilla connector got synced */
585 return cn_add_callback(&pohmelfs_cn_id, "pohmelfs", (void *)pohmelfs_cn_callback);
586}
587
588void pohmelfs_config_exit(void)
589{
590 struct pohmelfs_config *c, *tmp;
591 struct pohmelfs_config_group *g, *gtmp;
592
593 cn_del_callback(&pohmelfs_cn_id);
594
595 mutex_lock(&pohmelfs_config_lock);
596 list_for_each_entry_safe(g, gtmp, &pohmelfs_config_list, group_entry) {
597 list_for_each_entry_safe(c, tmp, &g->config_list, config_entry) {
598 list_del(&c->config_entry);
599 kfree(c);
600 }
601
602 list_del(&g->group_entry);
603
604 kfree(g->hash_string);
605
606 kfree(g->cipher_string);
607
608 kfree(g);
609 }
610 mutex_unlock(&pohmelfs_config_lock);
611}
diff --git a/drivers/staging/pohmelfs/crypto.c b/drivers/staging/pohmelfs/crypto.c
new file mode 100644
index 00000000000..ad92771dce5
--- /dev/null
+++ b/drivers/staging/pohmelfs/crypto.c
@@ -0,0 +1,878 @@
1/*
2 * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
3 * All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/crypto.h>
17#include <linux/highmem.h>
18#include <linux/kthread.h>
19#include <linux/pagemap.h>
20#include <linux/scatterlist.h>
21#include <linux/slab.h>
22
23#include "netfs.h"
24
25static struct crypto_hash *pohmelfs_init_hash(struct pohmelfs_sb *psb)
26{
27 int err;
28 struct crypto_hash *hash;
29
30 hash = crypto_alloc_hash(psb->hash_string, 0, CRYPTO_ALG_ASYNC);
31 if (IS_ERR(hash)) {
32 err = PTR_ERR(hash);
33 dprintk("%s: idx: %u: failed to allocate hash '%s', err: %d.\n",
34 __func__, psb->idx, psb->hash_string, err);
35 goto err_out_exit;
36 }
37
38 psb->crypto_attached_size = crypto_hash_digestsize(hash);
39
40 if (!psb->hash_keysize)
41 return hash;
42
43 err = crypto_hash_setkey(hash, psb->hash_key, psb->hash_keysize);
44 if (err) {
45 dprintk("%s: idx: %u: failed to set key for hash '%s', err: %d.\n",
46 __func__, psb->idx, psb->hash_string, err);
47 goto err_out_free;
48 }
49
50 return hash;
51
52err_out_free:
53 crypto_free_hash(hash);
54err_out_exit:
55 return ERR_PTR(err);
56}
57
58static struct crypto_ablkcipher *pohmelfs_init_cipher(struct pohmelfs_sb *psb)
59{
60 int err = -EINVAL;
61 struct crypto_ablkcipher *cipher;
62
63 if (!psb->cipher_keysize)
64 goto err_out_exit;
65
66 cipher = crypto_alloc_ablkcipher(psb->cipher_string, 0, 0);
67 if (IS_ERR(cipher)) {
68 err = PTR_ERR(cipher);
69 dprintk("%s: idx: %u: failed to allocate cipher '%s', err: %d.\n",
70 __func__, psb->idx, psb->cipher_string, err);
71 goto err_out_exit;
72 }
73
74 crypto_ablkcipher_clear_flags(cipher, ~0);
75
76 err = crypto_ablkcipher_setkey(cipher, psb->cipher_key, psb->cipher_keysize);
77 if (err) {
78 dprintk("%s: idx: %u: failed to set key for cipher '%s', err: %d.\n",
79 __func__, psb->idx, psb->cipher_string, err);
80 goto err_out_free;
81 }
82
83 return cipher;
84
85err_out_free:
86 crypto_free_ablkcipher(cipher);
87err_out_exit:
88 return ERR_PTR(err);
89}
90
91int pohmelfs_crypto_engine_init(struct pohmelfs_crypto_engine *e, struct pohmelfs_sb *psb)
92{
93 int err;
94
95 e->page_num = 0;
96
97 e->size = PAGE_SIZE;
98 e->data = kmalloc(e->size, GFP_KERNEL);
99 if (!e->data) {
100 err = -ENOMEM;
101 goto err_out_exit;
102 }
103
104 if (psb->hash_string) {
105 e->hash = pohmelfs_init_hash(psb);
106 if (IS_ERR(e->hash)) {
107 err = PTR_ERR(e->hash);
108 e->hash = NULL;
109 goto err_out_free;
110 }
111 }
112
113 if (psb->cipher_string) {
114 e->cipher = pohmelfs_init_cipher(psb);
115 if (IS_ERR(e->cipher)) {
116 err = PTR_ERR(e->cipher);
117 e->cipher = NULL;
118 goto err_out_free_hash;
119 }
120 }
121
122 return 0;
123
124err_out_free_hash:
125 crypto_free_hash(e->hash);
126err_out_free:
127 kfree(e->data);
128err_out_exit:
129 return err;
130}
131
132void pohmelfs_crypto_engine_exit(struct pohmelfs_crypto_engine *e)
133{
134 crypto_free_hash(e->hash);
135 crypto_free_ablkcipher(e->cipher);
136 kfree(e->data);
137}
138
139static void pohmelfs_crypto_complete(struct crypto_async_request *req, int err)
140{
141 struct pohmelfs_crypto_completion *c = req->data;
142
143 if (err == -EINPROGRESS)
144 return;
145
146 dprintk("%s: req: %p, err: %d.\n", __func__, req, err);
147 c->error = err;
148 complete(&c->complete);
149}
150
151static int pohmelfs_crypto_process(struct ablkcipher_request *req,
152 struct scatterlist *sg_dst, struct scatterlist *sg_src,
153 void *iv, int enc, unsigned long timeout)
154{
155 struct pohmelfs_crypto_completion complete;
156 int err;
157
158 init_completion(&complete.complete);
159 complete.error = -EINPROGRESS;
160
161 ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
162 pohmelfs_crypto_complete, &complete);
163
164 ablkcipher_request_set_crypt(req, sg_src, sg_dst, sg_src->length, iv);
165
166 if (enc)
167 err = crypto_ablkcipher_encrypt(req);
168 else
169 err = crypto_ablkcipher_decrypt(req);
170
171 switch (err) {
172 case -EINPROGRESS:
173 case -EBUSY:
174 err = wait_for_completion_interruptible_timeout(&complete.complete,
175 timeout);
176 if (!err)
177 err = -ETIMEDOUT;
178 else if (err > 0)
179 err = complete.error;
180 break;
181 default:
182 break;
183 }
184
185 return err;
186}
187
188int pohmelfs_crypto_process_input_data(struct pohmelfs_crypto_engine *e, u64 cmd_iv,
189 void *data, struct page *page, unsigned int size)
190{
191 int err;
192 struct scatterlist sg;
193
194 if (!e->cipher && !e->hash)
195 return 0;
196
197 dprintk("%s: eng: %p, iv: %llx, data: %p, page: %p/%lu, size: %u.\n",
198 __func__, e, cmd_iv, data, page, (page) ? page->index : 0, size);
199
200 if (data) {
201 sg_init_one(&sg, data, size);
202 } else {
203 sg_init_table(&sg, 1);
204 sg_set_page(&sg, page, size, 0);
205 }
206
207 if (e->cipher) {
208 struct ablkcipher_request *req = e->data + crypto_hash_digestsize(e->hash);
209 u8 iv[32];
210
211 memset(iv, 0, sizeof(iv));
212 memcpy(iv, &cmd_iv, sizeof(cmd_iv));
213
214 ablkcipher_request_set_tfm(req, e->cipher);
215
216 err = pohmelfs_crypto_process(req, &sg, &sg, iv, 0, e->timeout);
217 if (err)
218 goto err_out_exit;
219 }
220
221 if (e->hash) {
222 struct hash_desc desc;
223 void *dst = e->data + e->size/2;
224
225 desc.tfm = e->hash;
226 desc.flags = 0;
227
228 err = crypto_hash_init(&desc);
229 if (err)
230 goto err_out_exit;
231
232 err = crypto_hash_update(&desc, &sg, size);
233 if (err)
234 goto err_out_exit;
235
236 err = crypto_hash_final(&desc, dst);
237 if (err)
238 goto err_out_exit;
239
240 err = !!memcmp(dst, e->data, crypto_hash_digestsize(e->hash));
241
242 if (err) {
243#ifdef CONFIG_POHMELFS_DEBUG
244 unsigned int i;
245 unsigned char *recv = e->data, *calc = dst;
246
247 dprintk("%s: eng: %p, hash: %p, cipher: %p: iv : %llx, hash mismatch (recv/calc): ",
248 __func__, e, e->hash, e->cipher, cmd_iv);
249 for (i = 0; i < crypto_hash_digestsize(e->hash); ++i) {
250#if 0
251 dprintka("%02x ", recv[i]);
252 if (recv[i] != calc[i]) {
253 dprintka("| calc byte: %02x.\n", calc[i]);
254 break;
255 }
256#else
257 dprintka("%02x/%02x ", recv[i], calc[i]);
258#endif
259 }
260 dprintk("\n");
261#endif
262 goto err_out_exit;
263 } else {
264 dprintk("%s: eng: %p, hash: %p, cipher: %p: hashes matched.\n",
265 __func__, e, e->hash, e->cipher);
266 }
267 }
268
269 dprintk("%s: eng: %p, size: %u, hash: %p, cipher: %p: completed.\n",
270 __func__, e, e->size, e->hash, e->cipher);
271
272 return 0;
273
274err_out_exit:
275 dprintk("%s: eng: %p, hash: %p, cipher: %p: err: %d.\n",
276 __func__, e, e->hash, e->cipher, err);
277 return err;
278}
279
280static int pohmelfs_trans_iter(struct netfs_trans *t, struct pohmelfs_crypto_engine *e,
281 int (*iterator) (struct pohmelfs_crypto_engine *e,
282 struct scatterlist *dst,
283 struct scatterlist *src))
284{
285 void *data = t->iovec.iov_base + sizeof(struct netfs_cmd) + t->psb->crypto_attached_size;
286 unsigned int size = t->iovec.iov_len - sizeof(struct netfs_cmd) - t->psb->crypto_attached_size;
287 struct netfs_cmd *cmd = data;
288 unsigned int sz, pages = t->attached_pages, i, csize, cmd_cmd, dpage_idx;
289 struct scatterlist sg_src, sg_dst;
290 int err;
291
292 while (size) {
293 cmd = data;
294 cmd_cmd = __be16_to_cpu(cmd->cmd);
295 csize = __be32_to_cpu(cmd->size);
296 cmd->iv = __cpu_to_be64(e->iv);
297
298 if (cmd_cmd == NETFS_READ_PAGES || cmd_cmd == NETFS_READ_PAGE)
299 csize = __be16_to_cpu(cmd->ext);
300
301 sz = csize + __be16_to_cpu(cmd->cpad) + sizeof(struct netfs_cmd);
302
303 dprintk("%s: size: %u, sz: %u, cmd_size: %u, cmd_cpad: %u.\n",
304 __func__, size, sz, __be32_to_cpu(cmd->size), __be16_to_cpu(cmd->cpad));
305
306 data += sz;
307 size -= sz;
308
309 sg_init_one(&sg_src, cmd->data, sz - sizeof(struct netfs_cmd));
310 sg_init_one(&sg_dst, cmd->data, sz - sizeof(struct netfs_cmd));
311
312 err = iterator(e, &sg_dst, &sg_src);
313 if (err)
314 return err;
315 }
316
317 if (!pages)
318 return 0;
319
320 dpage_idx = 0;
321 for (i = 0; i < t->page_num; ++i) {
322 struct page *page = t->pages[i];
323 struct page *dpage = e->pages[dpage_idx];
324
325 if (!page)
326 continue;
327
328 sg_init_table(&sg_src, 1);
329 sg_init_table(&sg_dst, 1);
330 sg_set_page(&sg_src, page, page_private(page), 0);
331 sg_set_page(&sg_dst, dpage, page_private(page), 0);
332
333 err = iterator(e, &sg_dst, &sg_src);
334 if (err)
335 return err;
336
337 pages--;
338 if (!pages)
339 break;
340 dpage_idx++;
341 }
342
343 return 0;
344}
345
346static int pohmelfs_encrypt_iterator(struct pohmelfs_crypto_engine *e,
347 struct scatterlist *sg_dst, struct scatterlist *sg_src)
348{
349 struct ablkcipher_request *req = e->data;
350 u8 iv[32];
351
352 memset(iv, 0, sizeof(iv));
353
354 memcpy(iv, &e->iv, sizeof(e->iv));
355
356 return pohmelfs_crypto_process(req, sg_dst, sg_src, iv, 1, e->timeout);
357}
358
359static int pohmelfs_encrypt(struct pohmelfs_crypto_thread *tc)
360{
361 struct netfs_trans *t = tc->trans;
362 struct pohmelfs_crypto_engine *e = &tc->eng;
363 struct ablkcipher_request *req = e->data;
364
365 memset(req, 0, sizeof(struct ablkcipher_request));
366 ablkcipher_request_set_tfm(req, e->cipher);
367
368 e->iv = pohmelfs_gen_iv(t);
369
370 return pohmelfs_trans_iter(t, e, pohmelfs_encrypt_iterator);
371}
372
373static int pohmelfs_hash_iterator(struct pohmelfs_crypto_engine *e,
374 struct scatterlist *sg_dst, struct scatterlist *sg_src)
375{
376 return crypto_hash_update(e->data, sg_src, sg_src->length);
377}
378
379static int pohmelfs_hash(struct pohmelfs_crypto_thread *tc)
380{
381 struct pohmelfs_crypto_engine *e = &tc->eng;
382 struct hash_desc *desc = e->data;
383 unsigned char *dst = tc->trans->iovec.iov_base + sizeof(struct netfs_cmd);
384 int err;
385
386 desc->tfm = e->hash;
387 desc->flags = 0;
388
389 err = crypto_hash_init(desc);
390 if (err)
391 return err;
392
393 err = pohmelfs_trans_iter(tc->trans, e, pohmelfs_hash_iterator);
394 if (err)
395 return err;
396
397 err = crypto_hash_final(desc, dst);
398 if (err)
399 return err;
400
401 {
402 unsigned int i;
403 dprintk("%s: ", __func__);
404 for (i = 0; i < tc->psb->crypto_attached_size; ++i)
405 dprintka("%02x ", dst[i]);
406 dprintka("\n");
407 }
408
409 return 0;
410}
411
412static void pohmelfs_crypto_pages_free(struct pohmelfs_crypto_engine *e)
413{
414 unsigned int i;
415
416 for (i = 0; i < e->page_num; ++i)
417 __free_page(e->pages[i]);
418 kfree(e->pages);
419}
420
421static int pohmelfs_crypto_pages_alloc(struct pohmelfs_crypto_engine *e, struct pohmelfs_sb *psb)
422{
423 unsigned int i;
424
425 e->pages = kmalloc(psb->trans_max_pages * sizeof(struct page *), GFP_KERNEL);
426 if (!e->pages)
427 return -ENOMEM;
428
429 for (i = 0; i < psb->trans_max_pages; ++i) {
430 e->pages[i] = alloc_page(GFP_KERNEL);
431 if (!e->pages[i])
432 break;
433 }
434
435 e->page_num = i;
436 if (!e->page_num)
437 goto err_out_free;
438
439 return 0;
440
441err_out_free:
442 kfree(e->pages);
443 return -ENOMEM;
444}
445
446static void pohmelfs_sys_crypto_exit_one(struct pohmelfs_crypto_thread *t)
447{
448 struct pohmelfs_sb *psb = t->psb;
449
450 if (t->thread)
451 kthread_stop(t->thread);
452
453 mutex_lock(&psb->crypto_thread_lock);
454 list_del(&t->thread_entry);
455 psb->crypto_thread_num--;
456 mutex_unlock(&psb->crypto_thread_lock);
457
458 pohmelfs_crypto_engine_exit(&t->eng);
459 pohmelfs_crypto_pages_free(&t->eng);
460 kfree(t);
461}
462
463static int pohmelfs_crypto_finish(struct netfs_trans *t, struct pohmelfs_sb *psb, int err)
464{
465 struct netfs_cmd *cmd = t->iovec.iov_base;
466 netfs_convert_cmd(cmd);
467
468 if (likely(!err))
469 err = netfs_trans_finish_send(t, psb);
470
471 t->result = err;
472 netfs_trans_put(t);
473
474 return err;
475}
476
477void pohmelfs_crypto_thread_make_ready(struct pohmelfs_crypto_thread *th)
478{
479 struct pohmelfs_sb *psb = th->psb;
480
481 th->page = NULL;
482 th->trans = NULL;
483
484 mutex_lock(&psb->crypto_thread_lock);
485 list_move_tail(&th->thread_entry, &psb->crypto_ready_list);
486 mutex_unlock(&psb->crypto_thread_lock);
487 wake_up(&psb->wait);
488}
489
490static int pohmelfs_crypto_thread_trans(struct pohmelfs_crypto_thread *t)
491{
492 struct netfs_trans *trans;
493 int err = 0;
494
495 trans = t->trans;
496 trans->eng = NULL;
497
498 if (t->eng.hash) {
499 err = pohmelfs_hash(t);
500 if (err)
501 goto out_complete;
502 }
503
504 if (t->eng.cipher) {
505 err = pohmelfs_encrypt(t);
506 if (err)
507 goto out_complete;
508 trans->eng = &t->eng;
509 }
510
511out_complete:
512 t->page = NULL;
513 t->trans = NULL;
514
515 if (!trans->eng)
516 pohmelfs_crypto_thread_make_ready(t);
517
518 pohmelfs_crypto_finish(trans, t->psb, err);
519 return err;
520}
521
522static int pohmelfs_crypto_thread_page(struct pohmelfs_crypto_thread *t)
523{
524 struct pohmelfs_crypto_engine *e = &t->eng;
525 struct page *page = t->page;
526 int err;
527
528 WARN_ON(!PageChecked(page));
529
530 err = pohmelfs_crypto_process_input_data(e, e->iv, NULL, page, t->size);
531 if (!err)
532 SetPageUptodate(page);
533 else
534 SetPageError(page);
535 unlock_page(page);
536 page_cache_release(page);
537
538 pohmelfs_crypto_thread_make_ready(t);
539
540 return err;
541}
542
543static int pohmelfs_crypto_thread_func(void *data)
544{
545 struct pohmelfs_crypto_thread *t = data;
546
547 while (!kthread_should_stop()) {
548 wait_event_interruptible(t->wait, kthread_should_stop() ||
549 t->trans || t->page);
550
551 if (kthread_should_stop())
552 break;
553
554 if (!t->trans && !t->page)
555 continue;
556
557 dprintk("%s: thread: %p, trans: %p, page: %p.\n",
558 __func__, t, t->trans, t->page);
559
560 if (t->trans)
561 pohmelfs_crypto_thread_trans(t);
562 else if (t->page)
563 pohmelfs_crypto_thread_page(t);
564 }
565
566 return 0;
567}
568
569static void pohmelfs_crypto_flush(struct pohmelfs_sb *psb, struct list_head *head)
570{
571 while (!list_empty(head)) {
572 struct pohmelfs_crypto_thread *t = NULL;
573
574 mutex_lock(&psb->crypto_thread_lock);
575 if (!list_empty(head)) {
576 t = list_first_entry(head, struct pohmelfs_crypto_thread, thread_entry);
577 list_del_init(&t->thread_entry);
578 }
579 mutex_unlock(&psb->crypto_thread_lock);
580
581 if (t)
582 pohmelfs_sys_crypto_exit_one(t);
583 }
584}
585
586static void pohmelfs_sys_crypto_exit(struct pohmelfs_sb *psb)
587{
588 while (!list_empty(&psb->crypto_active_list) || !list_empty(&psb->crypto_ready_list)) {
589 dprintk("%s: crypto_thread_num: %u.\n", __func__, psb->crypto_thread_num);
590 pohmelfs_crypto_flush(psb, &psb->crypto_active_list);
591 pohmelfs_crypto_flush(psb, &psb->crypto_ready_list);
592 }
593}
594
595static int pohmelfs_sys_crypto_init(struct pohmelfs_sb *psb)
596{
597 unsigned int i;
598 struct pohmelfs_crypto_thread *t;
599 struct pohmelfs_config *c;
600 struct netfs_state *st;
601 int err;
602
603 list_for_each_entry(c, &psb->state_list, config_entry) {
604 st = &c->state;
605
606 err = pohmelfs_crypto_engine_init(&st->eng, psb);
607 if (err)
608 goto err_out_exit;
609
610 dprintk("%s: st: %p, eng: %p, hash: %p, cipher: %p.\n",
611 __func__, st, &st->eng, &st->eng.hash, &st->eng.cipher);
612 }
613
614 for (i = 0; i < psb->crypto_thread_num; ++i) {
615 err = -ENOMEM;
616 t = kzalloc(sizeof(struct pohmelfs_crypto_thread), GFP_KERNEL);
617 if (!t)
618 goto err_out_free_state_engines;
619
620 init_waitqueue_head(&t->wait);
621
622 t->psb = psb;
623 t->trans = NULL;
624 t->eng.thread = t;
625
626 err = pohmelfs_crypto_engine_init(&t->eng, psb);
627 if (err)
628 goto err_out_free_state_engines;
629
630 err = pohmelfs_crypto_pages_alloc(&t->eng, psb);
631 if (err)
632 goto err_out_free;
633
634 t->thread = kthread_run(pohmelfs_crypto_thread_func, t,
635 "pohmelfs-crypto-%d-%d", psb->idx, i);
636 if (IS_ERR(t->thread)) {
637 err = PTR_ERR(t->thread);
638 t->thread = NULL;
639 goto err_out_free;
640 }
641
642 if (t->eng.cipher)
643 psb->crypto_align_size = crypto_ablkcipher_blocksize(t->eng.cipher);
644
645 mutex_lock(&psb->crypto_thread_lock);
646 list_add_tail(&t->thread_entry, &psb->crypto_ready_list);
647 mutex_unlock(&psb->crypto_thread_lock);
648 }
649
650 psb->crypto_thread_num = i;
651 return 0;
652
653err_out_free:
654 pohmelfs_sys_crypto_exit_one(t);
655err_out_free_state_engines:
656 list_for_each_entry(c, &psb->state_list, config_entry) {
657 st = &c->state;
658 pohmelfs_crypto_engine_exit(&st->eng);
659 }
660err_out_exit:
661 pohmelfs_sys_crypto_exit(psb);
662 return err;
663}
664
665void pohmelfs_crypto_exit(struct pohmelfs_sb *psb)
666{
667 pohmelfs_sys_crypto_exit(psb);
668
669 kfree(psb->hash_string);
670 kfree(psb->cipher_string);
671}
672
673static int pohmelfs_crypt_init_complete(struct page **pages, unsigned int page_num,
674 void *private, int err)
675{
676 struct pohmelfs_sb *psb = private;
677
678 psb->flags = -err;
679 dprintk("%s: err: %d.\n", __func__, err);
680
681 wake_up(&psb->wait);
682
683 return err;
684}
685
686static int pohmelfs_crypto_init_handshake(struct pohmelfs_sb *psb)
687{
688 struct netfs_trans *t;
689 struct netfs_crypto_capabilities *cap;
690 struct netfs_cmd *cmd;
691 char *str;
692 int err = -ENOMEM, size;
693
694 size = sizeof(struct netfs_crypto_capabilities) +
695 psb->cipher_strlen + psb->hash_strlen + 2; /* 0 bytes */
696
697 t = netfs_trans_alloc(psb, size, 0, 0);
698 if (!t)
699 goto err_out_exit;
700
701 t->complete = pohmelfs_crypt_init_complete;
702 t->private = psb;
703
704 cmd = netfs_trans_current(t);
705 cap = (struct netfs_crypto_capabilities *)(cmd + 1);
706 str = (char *)(cap + 1);
707
708 cmd->cmd = NETFS_CAPABILITIES;
709 cmd->id = POHMELFS_CRYPTO_CAPABILITIES;
710 cmd->size = size;
711 cmd->start = 0;
712 cmd->ext = 0;
713 cmd->csize = 0;
714
715 netfs_convert_cmd(cmd);
716 netfs_trans_update(cmd, t, size);
717
718 cap->hash_strlen = psb->hash_strlen;
719 if (cap->hash_strlen) {
720 sprintf(str, "%s", psb->hash_string);
721 str += cap->hash_strlen;
722 }
723
724 cap->cipher_strlen = psb->cipher_strlen;
725 cap->cipher_keysize = psb->cipher_keysize;
726 if (cap->cipher_strlen)
727 sprintf(str, "%s", psb->cipher_string);
728
729 netfs_convert_crypto_capabilities(cap);
730
731 psb->flags = ~0;
732 err = netfs_trans_finish(t, psb);
733 if (err)
734 goto err_out_exit;
735
736 err = wait_event_interruptible_timeout(psb->wait, (psb->flags != ~0),
737 psb->wait_on_page_timeout);
738 if (!err)
739 err = -ETIMEDOUT;
740 else if (err > 0)
741 err = -psb->flags;
742
743 if (!err)
744 psb->perform_crypto = 1;
745 psb->flags = 0;
746
747 /*
748 * At this point NETFS_CAPABILITIES response command
749 * should setup superblock in a way, which is acceptable
750 * for both client and server, so if server refuses connection,
751 * it will send error in transaction response.
752 */
753
754 if (err)
755 goto err_out_exit;
756
757 return 0;
758
759err_out_exit:
760 return err;
761}
762
763int pohmelfs_crypto_init(struct pohmelfs_sb *psb)
764{
765 int err;
766
767 if (!psb->cipher_string && !psb->hash_string)
768 return 0;
769
770 err = pohmelfs_crypto_init_handshake(psb);
771 if (err)
772 return err;
773
774 err = pohmelfs_sys_crypto_init(psb);
775 if (err)
776 return err;
777
778 return 0;
779}
780
781static int pohmelfs_crypto_thread_get(struct pohmelfs_sb *psb,
782 int (*action)(struct pohmelfs_crypto_thread *t, void *data), void *data)
783{
784 struct pohmelfs_crypto_thread *t = NULL;
785 int err;
786
787 while (!t) {
788 err = wait_event_interruptible_timeout(psb->wait,
789 !list_empty(&psb->crypto_ready_list),
790 psb->wait_on_page_timeout);
791
792 t = NULL;
793 err = 0;
794 mutex_lock(&psb->crypto_thread_lock);
795 if (!list_empty(&psb->crypto_ready_list)) {
796 t = list_entry(psb->crypto_ready_list.prev,
797 struct pohmelfs_crypto_thread,
798 thread_entry);
799
800 list_move_tail(&t->thread_entry,
801 &psb->crypto_active_list);
802
803 action(t, data);
804 wake_up(&t->wait);
805
806 }
807 mutex_unlock(&psb->crypto_thread_lock);
808 }
809
810 return err;
811}
812
813static int pohmelfs_trans_crypt_action(struct pohmelfs_crypto_thread *t, void *data)
814{
815 struct netfs_trans *trans = data;
816
817 netfs_trans_get(trans);
818 t->trans = trans;
819
820 dprintk("%s: t: %p, gen: %u, thread: %p.\n", __func__, trans, trans->gen, t);
821 return 0;
822}
823
824int pohmelfs_trans_crypt(struct netfs_trans *trans, struct pohmelfs_sb *psb)
825{
826 if ((!psb->hash_string && !psb->cipher_string) || !psb->perform_crypto) {
827 netfs_trans_get(trans);
828 return pohmelfs_crypto_finish(trans, psb, 0);
829 }
830
831 return pohmelfs_crypto_thread_get(psb, pohmelfs_trans_crypt_action, trans);
832}
833
834struct pohmelfs_crypto_input_action_data {
835 struct page *page;
836 struct pohmelfs_crypto_engine *e;
837 u64 iv;
838 unsigned int size;
839};
840
841static int pohmelfs_crypt_input_page_action(struct pohmelfs_crypto_thread *t, void *data)
842{
843 struct pohmelfs_crypto_input_action_data *act = data;
844
845 memcpy(t->eng.data, act->e->data, t->psb->crypto_attached_size);
846
847 t->size = act->size;
848 t->eng.iv = act->iv;
849
850 t->page = act->page;
851 return 0;
852}
853
854int pohmelfs_crypto_process_input_page(struct pohmelfs_crypto_engine *e,
855 struct page *page, unsigned int size, u64 iv)
856{
857 struct inode *inode = page->mapping->host;
858 struct pohmelfs_crypto_input_action_data act;
859 int err = -ENOENT;
860
861 act.page = page;
862 act.e = e;
863 act.size = size;
864 act.iv = iv;
865
866 err = pohmelfs_crypto_thread_get(POHMELFS_SB(inode->i_sb),
867 pohmelfs_crypt_input_page_action, &act);
868 if (err)
869 goto err_out_exit;
870
871 return 0;
872
873err_out_exit:
874 SetPageUptodate(page);
875 page_cache_release(page);
876
877 return err;
878}
diff --git a/drivers/staging/pohmelfs/dir.c b/drivers/staging/pohmelfs/dir.c
new file mode 100644
index 00000000000..7598e77672a
--- /dev/null
+++ b/drivers/staging/pohmelfs/dir.c
@@ -0,0 +1,1101 @@
1/*
2 * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
3 * All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/kernel.h>
17#include <linux/fs.h>
18#include <linux/jhash.h>
19#include <linux/namei.h>
20#include <linux/slab.h>
21#include <linux/pagemap.h>
22
23#include "netfs.h"
24
25static int pohmelfs_cmp_hash(struct pohmelfs_name *n, u32 hash)
26{
27 if (n->hash > hash)
28 return -1;
29 if (n->hash < hash)
30 return 1;
31
32 return 0;
33}
34
35static struct pohmelfs_name *pohmelfs_search_hash_unprecise(struct pohmelfs_inode *pi, u32 hash)
36{
37 struct rb_node *n = pi->hash_root.rb_node;
38 struct pohmelfs_name *tmp = NULL;
39 int cmp;
40
41 while (n) {
42 tmp = rb_entry(n, struct pohmelfs_name, hash_node);
43
44 cmp = pohmelfs_cmp_hash(tmp, hash);
45 if (cmp < 0)
46 n = n->rb_left;
47 else if (cmp > 0)
48 n = n->rb_right;
49 else
50 break;
51
52 }
53
54 return tmp;
55}
56
57struct pohmelfs_name *pohmelfs_search_hash(struct pohmelfs_inode *pi, u32 hash)
58{
59 struct pohmelfs_name *tmp;
60
61 tmp = pohmelfs_search_hash_unprecise(pi, hash);
62 if (tmp && (tmp->hash == hash))
63 return tmp;
64
65 return NULL;
66}
67
68static void __pohmelfs_name_del(struct pohmelfs_inode *parent, struct pohmelfs_name *node)
69{
70 rb_erase(&node->hash_node, &parent->hash_root);
71}
72
73/*
74 * Remove name cache entry from its caches and free it.
75 */
76static void pohmelfs_name_free(struct pohmelfs_inode *parent, struct pohmelfs_name *node)
77{
78 __pohmelfs_name_del(parent, node);
79 list_del(&node->sync_create_entry);
80 kfree(node);
81}
82
83static struct pohmelfs_name *pohmelfs_insert_hash(struct pohmelfs_inode *pi,
84 struct pohmelfs_name *new)
85{
86 struct rb_node **n = &pi->hash_root.rb_node, *parent = NULL;
87 struct pohmelfs_name *ret = NULL, *tmp;
88 int cmp;
89
90 while (*n) {
91 parent = *n;
92
93 tmp = rb_entry(parent, struct pohmelfs_name, hash_node);
94
95 cmp = pohmelfs_cmp_hash(tmp, new->hash);
96 if (cmp < 0)
97 n = &parent->rb_left;
98 else if (cmp > 0)
99 n = &parent->rb_right;
100 else {
101 ret = tmp;
102 break;
103 }
104 }
105
106 if (ret) {
107 printk("%s: exist: parent: %llu, ino: %llu, hash: %x, len: %u, data: '%s', "
108 "new: ino: %llu, hash: %x, len: %u, data: '%s'.\n",
109 __func__, pi->ino,
110 ret->ino, ret->hash, ret->len, ret->data,
111 new->ino, new->hash, new->len, new->data);
112 ret->ino = new->ino;
113 return ret;
114 }
115
116 rb_link_node(&new->hash_node, parent, n);
117 rb_insert_color(&new->hash_node, &pi->hash_root);
118
119 return NULL;
120}
121
122/*
123 * Free name cache for given inode.
124 */
125void pohmelfs_free_names(struct pohmelfs_inode *parent)
126{
127 struct rb_node *rb_node;
128 struct pohmelfs_name *n;
129
130 for (rb_node = rb_first(&parent->hash_root); rb_node;) {
131 n = rb_entry(rb_node, struct pohmelfs_name, hash_node);
132 rb_node = rb_next(rb_node);
133
134 pohmelfs_name_free(parent, n);
135 }
136}
137
138static void pohmelfs_fix_offset(struct pohmelfs_inode *parent, struct pohmelfs_name *node)
139{
140 parent->total_len -= node->len;
141}
142
143/*
144 * Free name cache entry helper.
145 */
146void pohmelfs_name_del(struct pohmelfs_inode *parent, struct pohmelfs_name *node)
147{
148 pohmelfs_fix_offset(parent, node);
149 pohmelfs_name_free(parent, node);
150}
151
152/*
153 * Insert new name cache entry into all hash cache.
154 */
155static int pohmelfs_insert_name(struct pohmelfs_inode *parent, struct pohmelfs_name *n)
156{
157 struct pohmelfs_name *name;
158
159 name = pohmelfs_insert_hash(parent, n);
160 if (name)
161 return -EEXIST;
162
163 parent->total_len += n->len;
164 list_add_tail(&n->sync_create_entry, &parent->sync_create_list);
165
166 return 0;
167}
168
169/*
170 * Allocate new name cache entry.
171 */
172static struct pohmelfs_name *pohmelfs_name_alloc(unsigned int len)
173{
174 struct pohmelfs_name *n;
175
176 n = kzalloc(sizeof(struct pohmelfs_name) + len, GFP_KERNEL);
177 if (!n)
178 return NULL;
179
180 INIT_LIST_HEAD(&n->sync_create_entry);
181
182 n->data = (char *)(n+1);
183
184 return n;
185}
186
187/*
188 * Add new name entry into directory's cache.
189 */
190static int pohmelfs_add_dir(struct pohmelfs_sb *psb, struct pohmelfs_inode *parent,
191 struct pohmelfs_inode *npi, struct qstr *str, unsigned int mode, int link)
192{
193 int err = -ENOMEM;
194 struct pohmelfs_name *n;
195
196 n = pohmelfs_name_alloc(str->len + 1);
197 if (!n)
198 goto err_out_exit;
199
200 n->ino = npi->ino;
201 n->mode = mode;
202 n->len = str->len;
203 n->hash = str->hash;
204 sprintf(n->data, "%s", str->name);
205
206 mutex_lock(&parent->offset_lock);
207 err = pohmelfs_insert_name(parent, n);
208 mutex_unlock(&parent->offset_lock);
209
210 if (err) {
211 if (err != -EEXIST)
212 goto err_out_free;
213 kfree(n);
214 }
215
216 return 0;
217
218err_out_free:
219 kfree(n);
220err_out_exit:
221 return err;
222}
223
224/*
225 * Create new inode for given parameters (name, inode info, parent).
226 * This does not create object on the server, it will be synced there during writeback.
227 */
228struct pohmelfs_inode *pohmelfs_new_inode(struct pohmelfs_sb *psb,
229 struct pohmelfs_inode *parent, struct qstr *str,
230 struct netfs_inode_info *info, int link)
231{
232 struct inode *new = NULL;
233 struct pohmelfs_inode *npi;
234 int err = -EEXIST;
235
236 dprintk("%s: creating inode: parent: %llu, ino: %llu, str: %p.\n",
237 __func__, (parent) ? parent->ino : 0, info->ino, str);
238
239 err = -ENOMEM;
240 new = iget_locked(psb->sb, info->ino);
241 if (!new)
242 goto err_out_exit;
243
244 npi = POHMELFS_I(new);
245 npi->ino = info->ino;
246 err = 0;
247
248 if (new->i_state & I_NEW) {
249 dprintk("%s: filling VFS inode: %lu/%llu.\n",
250 __func__, new->i_ino, info->ino);
251 pohmelfs_fill_inode(new, info);
252
253 if (S_ISDIR(info->mode)) {
254 struct qstr s;
255
256 s.name = ".";
257 s.len = 1;
258 s.hash = jhash(s.name, s.len, 0);
259
260 err = pohmelfs_add_dir(psb, npi, npi, &s, info->mode, 0);
261 if (err)
262 goto err_out_put;
263
264 s.name = "..";
265 s.len = 2;
266 s.hash = jhash(s.name, s.len, 0);
267
268 err = pohmelfs_add_dir(psb, npi, (parent) ? parent : npi, &s,
269 (parent) ? parent->vfs_inode.i_mode : npi->vfs_inode.i_mode, 0);
270 if (err)
271 goto err_out_put;
272 }
273 }
274
275 if (str) {
276 if (parent) {
277 err = pohmelfs_add_dir(psb, parent, npi, str, info->mode, link);
278
279 dprintk("%s: %s inserted name: '%s', new_offset: %llu, ino: %llu, parent: %llu.\n",
280 __func__, (err) ? "unsuccessfully" : "successfully",
281 str->name, parent->total_len, info->ino, parent->ino);
282
283 if (err && err != -EEXIST)
284 goto err_out_put;
285 }
286 }
287
288 if (new->i_state & I_NEW) {
289 if (parent)
290 mark_inode_dirty(&parent->vfs_inode);
291 mark_inode_dirty(new);
292 }
293
294 set_bit(NETFS_INODE_OWNED, &npi->state);
295 npi->lock_type = POHMELFS_WRITE_LOCK;
296 unlock_new_inode(new);
297
298 return npi;
299
300err_out_put:
301 printk("%s: putting inode: %p, npi: %p, error: %d.\n", __func__, new, npi, err);
302 iput(new);
303err_out_exit:
304 return ERR_PTR(err);
305}
306
307static int pohmelfs_remote_sync_complete(struct page **pages, unsigned int page_num,
308 void *private, int err)
309{
310 struct pohmelfs_inode *pi = private;
311 struct pohmelfs_sb *psb = POHMELFS_SB(pi->vfs_inode.i_sb);
312
313 dprintk("%s: ino: %llu, err: %d.\n", __func__, pi->ino, err);
314
315 if (err)
316 pi->error = err;
317 wake_up(&psb->wait);
318 pohmelfs_put_inode(pi);
319
320 return err;
321}
322
323/*
324 * Receive directory content from the server.
325 * This should be only done for objects, which were not created locally,
326 * and which were not synced previously.
327 */
328static int pohmelfs_sync_remote_dir(struct pohmelfs_inode *pi)
329{
330 struct inode *inode = &pi->vfs_inode;
331 struct pohmelfs_sb *psb = POHMELFS_SB(inode->i_sb);
332 long ret = psb->wait_on_page_timeout;
333 int err;
334
335 dprintk("%s: dir: %llu, state: %lx: remote_synced: %d.\n",
336 __func__, pi->ino, pi->state, test_bit(NETFS_INODE_REMOTE_SYNCED, &pi->state));
337
338 if (test_bit(NETFS_INODE_REMOTE_DIR_SYNCED, &pi->state))
339 return 0;
340
341 if (!igrab(inode)) {
342 err = -ENOENT;
343 goto err_out_exit;
344 }
345
346 err = pohmelfs_meta_command(pi, NETFS_READDIR, NETFS_TRANS_SINGLE_DST,
347 pohmelfs_remote_sync_complete, pi, 0);
348 if (err)
349 goto err_out_exit;
350
351 pi->error = 0;
352 ret = wait_event_interruptible_timeout(psb->wait,
353 test_bit(NETFS_INODE_REMOTE_DIR_SYNCED, &pi->state) || pi->error, ret);
354 dprintk("%s: awake dir: %llu, ret: %ld, err: %d.\n", __func__, pi->ino, ret, pi->error);
355 if (ret <= 0) {
356 err = ret;
357 if (!err)
358 err = -ETIMEDOUT;
359 goto err_out_exit;
360 }
361
362 if (pi->error)
363 return pi->error;
364
365 return 0;
366
367err_out_exit:
368 clear_bit(NETFS_INODE_REMOTE_SYNCED, &pi->state);
369
370 return err;
371}
372
373static int pohmelfs_dir_open(struct inode *inode, struct file *file)
374{
375 file->private_data = NULL;
376 return 0;
377}
378
379/*
380 * VFS readdir callback. Syncs directory content from server if needed,
381 * and provides direntry info to the userspace.
382 */
383static int pohmelfs_readdir(struct file *file, void *dirent, filldir_t filldir)
384{
385 struct inode *inode = file->f_path.dentry->d_inode;
386 struct pohmelfs_inode *pi = POHMELFS_I(inode);
387 struct pohmelfs_name *n;
388 struct rb_node *rb_node;
389 int err = 0, mode;
390 u64 len;
391
392 dprintk("%s: parent: %llu, fpos: %llu, hash: %08lx.\n",
393 __func__, pi->ino, (u64)file->f_pos,
394 (unsigned long)file->private_data);
395#if 0
396 err = pohmelfs_data_lock(pi, 0, ~0, POHMELFS_READ_LOCK);
397 if (err)
398 return err;
399#endif
400 err = pohmelfs_sync_remote_dir(pi);
401 if (err)
402 return err;
403
404 if (file->private_data && (file->private_data == (void *)(unsigned long)file->f_pos))
405 return 0;
406
407 mutex_lock(&pi->offset_lock);
408 n = pohmelfs_search_hash_unprecise(pi, (unsigned long)file->private_data);
409
410 while (n) {
411 mode = (n->mode >> 12) & 15;
412
413 dprintk("%s: offset: %llu, parent ino: %llu, name: '%s', len: %u, ino: %llu, "
414 "mode: %o/%o, fpos: %llu, hash: %08x.\n",
415 __func__, file->f_pos, pi->ino, n->data, n->len,
416 n->ino, n->mode, mode, file->f_pos, n->hash);
417
418 file->private_data = (void *)(unsigned long)n->hash;
419
420 len = n->len;
421 err = filldir(dirent, n->data, n->len, file->f_pos, n->ino, mode);
422
423 if (err < 0) {
424 dprintk("%s: err: %d.\n", __func__, err);
425 err = 0;
426 break;
427 }
428
429 file->f_pos += len;
430
431 rb_node = rb_next(&n->hash_node);
432
433 if (!rb_node || (rb_node == &n->hash_node)) {
434 file->private_data = (void *)(unsigned long)file->f_pos;
435 break;
436 }
437
438 n = rb_entry(rb_node, struct pohmelfs_name, hash_node);
439 }
440 mutex_unlock(&pi->offset_lock);
441
442 return err;
443}
444
445static loff_t pohmelfs_dir_lseek(struct file *file, loff_t offset, int origin)
446{
447 file->f_pos = offset;
448 file->private_data = NULL;
449 return offset;
450}
451
452const struct file_operations pohmelfs_dir_fops = {
453 .open = pohmelfs_dir_open,
454 .read = generic_read_dir,
455 .llseek = pohmelfs_dir_lseek,
456 .readdir = pohmelfs_readdir,
457};
458
459/*
460 * Lookup single object on server.
461 */
462static int pohmelfs_lookup_single(struct pohmelfs_inode *parent,
463 struct qstr *str, u64 ino)
464{
465 struct pohmelfs_sb *psb = POHMELFS_SB(parent->vfs_inode.i_sb);
466 long ret = msecs_to_jiffies(5000);
467 int err;
468
469 set_bit(NETFS_COMMAND_PENDING, &parent->state);
470 err = pohmelfs_meta_command_data(parent, parent->ino, NETFS_LOOKUP,
471 (char *)str->name, NETFS_TRANS_SINGLE_DST, NULL, NULL, ino);
472 if (err)
473 goto err_out_exit;
474
475 err = 0;
476 ret = wait_event_interruptible_timeout(psb->wait,
477 !test_bit(NETFS_COMMAND_PENDING, &parent->state), ret);
478 if (ret <= 0) {
479 err = ret;
480 if (!err)
481 err = -ETIMEDOUT;
482 }
483
484 if (err)
485 goto err_out_exit;
486
487 return 0;
488
489err_out_exit:
490 clear_bit(NETFS_COMMAND_PENDING, &parent->state);
491
492 printk("%s: failed: parent: %llu, ino: %llu, name: '%s', err: %d.\n",
493 __func__, parent->ino, ino, str->name, err);
494
495 return err;
496}
497
498/*
499 * VFS lookup callback.
500 * We first try to get inode number from local name cache, if we have one,
501 * then inode can be found in inode cache. If there is no inode or no object in
502 * local cache, try to lookup it on server. This only should be done for directories,
503 * which were not created locally, otherwise remote server does not know about dir at all,
504 * so no need to try to know that.
505 */
506struct dentry *pohmelfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
507{
508 struct pohmelfs_inode *parent = POHMELFS_I(dir);
509 struct pohmelfs_name *n;
510 struct inode *inode = NULL;
511 unsigned long ino = 0;
512 int err, lock_type = POHMELFS_READ_LOCK, need_lock = 1;
513 struct qstr str = dentry->d_name;
514
515 if ((nd->intent.open.flags & O_ACCMODE) != O_RDONLY)
516 lock_type = POHMELFS_WRITE_LOCK;
517
518 if (test_bit(NETFS_INODE_OWNED, &parent->state)) {
519 if (lock_type == parent->lock_type)
520 need_lock = 0;
521 if ((lock_type == POHMELFS_READ_LOCK) && (parent->lock_type == POHMELFS_WRITE_LOCK))
522 need_lock = 0;
523 }
524
525 if ((lock_type == POHMELFS_READ_LOCK) && !test_bit(NETFS_INODE_REMOTE_DIR_SYNCED, &parent->state))
526 need_lock = 1;
527
528 str.hash = jhash(dentry->d_name.name, dentry->d_name.len, 0);
529
530 mutex_lock(&parent->offset_lock);
531 n = pohmelfs_search_hash(parent, str.hash);
532 if (n)
533 ino = n->ino;
534 mutex_unlock(&parent->offset_lock);
535
536 dprintk("%s: start ino: %lu, inode: %p, name: '%s', hash: %x, parent_state: %lx, need_lock: %d.\n",
537 __func__, ino, inode, str.name, str.hash, parent->state, need_lock);
538
539 if (ino) {
540 inode = ilookup(dir->i_sb, ino);
541 if (inode)
542 goto out;
543 }
544
545 dprintk("%s: no inode dir: %p, dir_ino: %llu, name: '%s', len: %u, dir_state: %lx, ino: %lu.\n",
546 __func__, dir, parent->ino,
547 str.name, str.len, parent->state, ino);
548
549 if (!ino) {
550 if (!need_lock)
551 goto out;
552 }
553
554 err = pohmelfs_data_lock(parent, 0, ~0, lock_type);
555 if (err)
556 goto out;
557
558 err = pohmelfs_lookup_single(parent, &str, ino);
559 if (err)
560 goto out;
561
562 if (!ino) {
563 mutex_lock(&parent->offset_lock);
564 n = pohmelfs_search_hash(parent, str.hash);
565 if (n)
566 ino = n->ino;
567 mutex_unlock(&parent->offset_lock);
568 }
569
570 if (ino) {
571 inode = ilookup(dir->i_sb, ino);
572 dprintk("%s: second lookup ino: %lu, inode: %p, name: '%s', hash: %x.\n",
573 __func__, ino, inode, str.name, str.hash);
574 if (!inode) {
575 dprintk("%s: No inode for ino: %lu, name: '%s', hash: %x.\n",
576 __func__, ino, str.name, str.hash);
577 /* return NULL; */
578 return ERR_PTR(-EACCES);
579 }
580 } else {
581 printk("%s: No inode number : name: '%s', hash: %x.\n",
582 __func__, str.name, str.hash);
583 }
584out:
585 return d_splice_alias(inode, dentry);
586}
587
588/*
589 * Create new object in local cache. Object will be synced to server
590 * during writeback for given inode.
591 */
592struct pohmelfs_inode *pohmelfs_create_entry_local(struct pohmelfs_sb *psb,
593 struct pohmelfs_inode *parent, struct qstr *str, u64 start, int mode)
594{
595 struct pohmelfs_inode *npi;
596 int err = -ENOMEM;
597 struct netfs_inode_info info;
598
599 dprintk("%s: name: '%s', mode: %o, start: %llu.\n",
600 __func__, str->name, mode, start);
601
602 info.mode = mode;
603 info.ino = start;
604
605 if (!start)
606 info.ino = pohmelfs_new_ino(psb);
607
608 info.nlink = S_ISDIR(mode) ? 2 : 1;
609 info.uid = current_fsuid();
610 info.gid = current_fsgid();
611 info.size = 0;
612 info.blocksize = 512;
613 info.blocks = 0;
614 info.rdev = 0;
615 info.version = 0;
616
617 npi = pohmelfs_new_inode(psb, parent, str, &info, !!start);
618 if (IS_ERR(npi)) {
619 err = PTR_ERR(npi);
620 goto err_out_unlock;
621 }
622
623 return npi;
624
625err_out_unlock:
626 dprintk("%s: err: %d.\n", __func__, err);
627 return ERR_PTR(err);
628}
629
630/*
631 * Create local object and bind it to dentry.
632 */
633static int pohmelfs_create_entry(struct inode *dir, struct dentry *dentry, u64 start, int mode)
634{
635 struct pohmelfs_sb *psb = POHMELFS_SB(dir->i_sb);
636 struct pohmelfs_inode *npi, *parent;
637 struct qstr str = dentry->d_name;
638 int err;
639
640 parent = POHMELFS_I(dir);
641
642 err = pohmelfs_data_lock(parent, 0, ~0, POHMELFS_WRITE_LOCK);
643 if (err)
644 return err;
645
646 str.hash = jhash(dentry->d_name.name, dentry->d_name.len, 0);
647
648 npi = pohmelfs_create_entry_local(psb, parent, &str, start, mode);
649 if (IS_ERR(npi))
650 return PTR_ERR(npi);
651
652 d_instantiate(dentry, &npi->vfs_inode);
653
654 dprintk("%s: parent: %llu, inode: %llu, name: '%s', parent_nlink: %d, nlink: %d.\n",
655 __func__, parent->ino, npi->ino, dentry->d_name.name,
656 (signed)dir->i_nlink, (signed)npi->vfs_inode.i_nlink);
657
658 return 0;
659}
660
661/*
662 * VFS create and mkdir callbacks.
663 */
664static int pohmelfs_create(struct inode *dir, struct dentry *dentry, int mode,
665 struct nameidata *nd)
666{
667 return pohmelfs_create_entry(dir, dentry, 0, mode);
668}
669
670static int pohmelfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
671{
672 int err;
673
674 inode_inc_link_count(dir);
675 err = pohmelfs_create_entry(dir, dentry, 0, mode | S_IFDIR);
676 if (err)
677 inode_dec_link_count(dir);
678
679 return err;
680}
681
682static int pohmelfs_remove_entry(struct inode *dir, struct dentry *dentry)
683{
684 struct pohmelfs_sb *psb = POHMELFS_SB(dir->i_sb);
685 struct inode *inode = dentry->d_inode;
686 struct pohmelfs_inode *parent = POHMELFS_I(dir), *pi = POHMELFS_I(inode);
687 struct pohmelfs_name *n;
688 int err = -ENOENT;
689 struct qstr str = dentry->d_name;
690
691 err = pohmelfs_data_lock(parent, 0, ~0, POHMELFS_WRITE_LOCK);
692 if (err)
693 return err;
694
695 str.hash = jhash(dentry->d_name.name, dentry->d_name.len, 0);
696
697 dprintk("%s: dir_ino: %llu, inode: %llu, name: '%s', nlink: %d.\n",
698 __func__, parent->ino, pi->ino,
699 str.name, (signed)inode->i_nlink);
700
701 BUG_ON(!inode);
702
703 mutex_lock(&parent->offset_lock);
704 n = pohmelfs_search_hash(parent, str.hash);
705 if (n) {
706 pohmelfs_fix_offset(parent, n);
707 if (test_bit(NETFS_INODE_REMOTE_SYNCED, &pi->state))
708 pohmelfs_remove_child(pi, n);
709
710 pohmelfs_name_free(parent, n);
711 err = 0;
712 }
713 mutex_unlock(&parent->offset_lock);
714
715 if (!err) {
716 psb->avail_size += inode->i_size;
717
718 pohmelfs_inode_del_inode(psb, pi);
719
720 mark_inode_dirty(dir);
721
722 inode->i_ctime = dir->i_ctime;
723 if (inode->i_nlink)
724 inode_dec_link_count(inode);
725 }
726
727 return err;
728}
729
730/*
731 * Unlink and rmdir VFS callbacks.
732 */
733static int pohmelfs_unlink(struct inode *dir, struct dentry *dentry)
734{
735 return pohmelfs_remove_entry(dir, dentry);
736}
737
738static int pohmelfs_rmdir(struct inode *dir, struct dentry *dentry)
739{
740 int err;
741 struct inode *inode = dentry->d_inode;
742
743 dprintk("%s: parent: %llu, inode: %llu, name: '%s', parent_nlink: %d, nlink: %d.\n",
744 __func__, POHMELFS_I(dir)->ino, POHMELFS_I(inode)->ino,
745 dentry->d_name.name, (signed)dir->i_nlink, (signed)inode->i_nlink);
746
747 err = pohmelfs_remove_entry(dir, dentry);
748 if (!err) {
749 inode_dec_link_count(dir);
750 inode_dec_link_count(inode);
751 }
752
753 return err;
754}
755
756/*
757 * Link creation is synchronous.
758 * I'm lazy.
759 * Earth is somewhat round.
760 */
761static int pohmelfs_create_link(struct pohmelfs_inode *parent, struct qstr *obj,
762 struct pohmelfs_inode *target, struct qstr *tstr)
763{
764 struct super_block *sb = parent->vfs_inode.i_sb;
765 struct pohmelfs_sb *psb = POHMELFS_SB(sb);
766 struct netfs_cmd *cmd;
767 struct netfs_trans *t;
768 void *data;
769 int err, parent_len, target_len = 0, cur_len, path_size = 0;
770
771 err = pohmelfs_data_lock(parent, 0, ~0, POHMELFS_WRITE_LOCK);
772 if (err)
773 return err;
774
775 err = sb->s_op->write_inode(&parent->vfs_inode, 0);
776 if (err)
777 goto err_out_exit;
778
779 if (tstr)
780 target_len = tstr->len;
781
782 parent_len = pohmelfs_path_length(parent);
783 if (target)
784 target_len += pohmelfs_path_length(target);
785
786 if (parent_len < 0) {
787 err = parent_len;
788 goto err_out_exit;
789 }
790
791 if (target_len < 0) {
792 err = target_len;
793 goto err_out_exit;
794 }
795
796 t = netfs_trans_alloc(psb, parent_len + target_len + obj->len + 2, 0, 0);
797 if (!t) {
798 err = -ENOMEM;
799 goto err_out_exit;
800 }
801 cur_len = netfs_trans_cur_len(t);
802
803 cmd = netfs_trans_current(t);
804 if (IS_ERR(cmd)) {
805 err = PTR_ERR(cmd);
806 goto err_out_free;
807 }
808
809 data = (void *)(cmd + 1);
810 cur_len -= sizeof(struct netfs_cmd);
811
812 err = pohmelfs_construct_path_string(parent, data, parent_len);
813 if (err > 0) {
814 /* Do not place null-byte before the slash */
815 path_size = err - 1;
816 cur_len -= path_size;
817
818 err = snprintf(data + path_size, cur_len, "/%s|", obj->name);
819
820 path_size += err;
821 cur_len -= err;
822
823 cmd->ext = path_size - 1; /* No | symbol */
824
825 if (target) {
826 err = pohmelfs_construct_path_string(target, data + path_size, target_len);
827 if (err > 0) {
828 path_size += err;
829 cur_len -= err;
830 }
831 }
832 }
833
834 if (err < 0)
835 goto err_out_free;
836
837 cmd->start = 0;
838
839 if (!target && tstr) {
840 if (tstr->len > cur_len - 1) {
841 err = -ENAMETOOLONG;
842 goto err_out_free;
843 }
844
845 err = snprintf(data + path_size, cur_len, "%s", tstr->name) + 1; /* 0-byte */
846 path_size += err;
847 cur_len -= err;
848 cmd->start = 1;
849 }
850
851 dprintk("%s: parent: %llu, obj: '%s', target_inode: %llu, target_str: '%s', full: '%s'.\n",
852 __func__, parent->ino, obj->name, (target) ? target->ino : 0, (tstr) ? tstr->name : NULL,
853 (char *)data);
854
855 cmd->cmd = NETFS_LINK;
856 cmd->size = path_size;
857 cmd->id = parent->ino;
858
859 netfs_convert_cmd(cmd);
860
861 netfs_trans_update(cmd, t, path_size);
862
863 err = netfs_trans_finish(t, psb);
864 if (err)
865 goto err_out_exit;
866
867 return 0;
868
869err_out_free:
870 t->result = err;
871 netfs_trans_put(t);
872err_out_exit:
873 return err;
874}
875
876/*
877 * VFS hard and soft link callbacks.
878 */
879static int pohmelfs_link(struct dentry *old_dentry, struct inode *dir,
880 struct dentry *dentry)
881{
882 struct inode *inode = old_dentry->d_inode;
883 struct pohmelfs_inode *pi = POHMELFS_I(inode);
884 int err;
885 struct qstr str = dentry->d_name;
886
887 str.hash = jhash(dentry->d_name.name, dentry->d_name.len, 0);
888
889 err = inode->i_sb->s_op->write_inode(inode, 0);
890 if (err)
891 return err;
892
893 err = pohmelfs_create_link(POHMELFS_I(dir), &str, pi, NULL);
894 if (err)
895 return err;
896
897 return pohmelfs_create_entry(dir, dentry, pi->ino, inode->i_mode);
898}
899
900static int pohmelfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
901{
902 struct qstr sym_str;
903 struct qstr str = dentry->d_name;
904 struct inode *inode;
905 int err;
906
907 str.hash = jhash(dentry->d_name.name, dentry->d_name.len, 0);
908
909 sym_str.name = symname;
910 sym_str.len = strlen(symname);
911
912 err = pohmelfs_create_link(POHMELFS_I(dir), &str, NULL, &sym_str);
913 if (err)
914 goto err_out_exit;
915
916 err = pohmelfs_create_entry(dir, dentry, 0, S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO);
917 if (err)
918 goto err_out_exit;
919
920 inode = dentry->d_inode;
921
922 err = page_symlink(inode, symname, sym_str.len + 1);
923 if (err)
924 goto err_out_put;
925
926 return 0;
927
928err_out_put:
929 iput(inode);
930err_out_exit:
931 return err;
932}
933
934static int pohmelfs_send_rename(struct pohmelfs_inode *pi, struct pohmelfs_inode *parent,
935 struct qstr *str)
936{
937 int path_len, err, total_len = 0, inode_len, parent_len;
938 char *path;
939 struct netfs_trans *t;
940 struct netfs_cmd *cmd;
941 struct pohmelfs_sb *psb = POHMELFS_SB(pi->vfs_inode.i_sb);
942
943 parent_len = pohmelfs_path_length(parent);
944 inode_len = pohmelfs_path_length(pi);
945
946 if (parent_len < 0 || inode_len < 0)
947 return -EINVAL;
948
949 path_len = parent_len + inode_len + str->len + 3;
950
951 t = netfs_trans_alloc(psb, path_len, 0, 0);
952 if (!t)
953 return -ENOMEM;
954
955 cmd = netfs_trans_current(t);
956 path = (char *)(cmd + 1);
957
958 err = pohmelfs_construct_path_string(pi, path, inode_len);
959 if (err < 0)
960 goto err_out_unlock;
961
962 cmd->ext = err;
963
964 path += err;
965 total_len += err;
966 path_len -= err;
967
968 *path = '|';
969 path++;
970 total_len++;
971 path_len--;
972
973 err = pohmelfs_construct_path_string(parent, path, parent_len);
974 if (err < 0)
975 goto err_out_unlock;
976
977 /*
978 * Do not place a null-byte before the final slash and the name.
979 */
980 err--;
981 path += err;
982 total_len += err;
983 path_len -= err;
984
985 err = snprintf(path, path_len - 1, "/%s", str->name);
986
987 total_len += err + 1; /* 0 symbol */
988 path_len -= err + 1;
989
990 cmd->cmd = NETFS_RENAME;
991 cmd->id = pi->ino;
992 cmd->start = parent->ino;
993 cmd->size = total_len;
994
995 netfs_convert_cmd(cmd);
996
997 netfs_trans_update(cmd, t, total_len);
998
999 return netfs_trans_finish(t, psb);
1000
1001err_out_unlock:
1002 netfs_trans_free(t);
1003 return err;
1004}
1005
1006static int pohmelfs_rename(struct inode *old_dir, struct dentry *old_dentry,
1007 struct inode *new_dir, struct dentry *new_dentry)
1008{
1009 struct inode *inode = old_dentry->d_inode;
1010 struct pohmelfs_inode *old_parent, *pi, *new_parent;
1011 struct qstr str = new_dentry->d_name;
1012 struct pohmelfs_name *n;
1013 unsigned int old_hash;
1014 int err = -ENOENT;
1015
1016 pi = POHMELFS_I(inode);
1017 old_parent = POHMELFS_I(old_dir);
1018
1019 if (new_dir)
1020 new_dir->i_sb->s_op->write_inode(new_dir, 0);
1021
1022 old_hash = jhash(old_dentry->d_name.name, old_dentry->d_name.len, 0);
1023 str.hash = jhash(new_dentry->d_name.name, new_dentry->d_name.len, 0);
1024
1025 str.len = new_dentry->d_name.len;
1026 str.name = new_dentry->d_name.name;
1027 str.hash = jhash(new_dentry->d_name.name, new_dentry->d_name.len, 0);
1028
1029 if (new_dir) {
1030 new_parent = POHMELFS_I(new_dir);
1031 err = -ENOTEMPTY;
1032
1033 if (S_ISDIR(inode->i_mode) &&
1034 new_parent->total_len <= 3)
1035 goto err_out_exit;
1036 } else {
1037 new_parent = old_parent;
1038 }
1039
1040 dprintk("%s: ino: %llu, parent: %llu, name: '%s' -> parent: %llu, name: '%s', i_size: %llu.\n",
1041 __func__, pi->ino, old_parent->ino, old_dentry->d_name.name,
1042 new_parent->ino, new_dentry->d_name.name, inode->i_size);
1043
1044 if (test_bit(NETFS_INODE_REMOTE_SYNCED, &pi->state) &&
1045 test_bit(NETFS_INODE_OWNED, &pi->state)) {
1046 err = pohmelfs_send_rename(pi, new_parent, &str);
1047 if (err)
1048 goto err_out_exit;
1049 }
1050
1051 n = pohmelfs_name_alloc(str.len + 1);
1052 if (!n)
1053 goto err_out_exit;
1054
1055 mutex_lock(&new_parent->offset_lock);
1056 n->ino = pi->ino;
1057 n->mode = inode->i_mode;
1058 n->len = str.len;
1059 n->hash = str.hash;
1060 sprintf(n->data, "%s", str.name);
1061
1062 err = pohmelfs_insert_name(new_parent, n);
1063 mutex_unlock(&new_parent->offset_lock);
1064
1065 if (err)
1066 goto err_out_exit;
1067
1068 mutex_lock(&old_parent->offset_lock);
1069 n = pohmelfs_search_hash(old_parent, old_hash);
1070 if (n)
1071 pohmelfs_name_del(old_parent, n);
1072 mutex_unlock(&old_parent->offset_lock);
1073
1074 mark_inode_dirty(inode);
1075 mark_inode_dirty(&new_parent->vfs_inode);
1076
1077 WARN_ON_ONCE(list_empty(&inode->i_dentry));
1078
1079 return 0;
1080
1081err_out_exit:
1082
1083 clear_bit(NETFS_INODE_REMOTE_SYNCED, &pi->state);
1084
1085 return err;
1086}
1087
1088/*
1089 * POHMELFS directory inode operations.
1090 */
1091const struct inode_operations pohmelfs_dir_inode_ops = {
1092 .link = pohmelfs_link,
1093 .symlink = pohmelfs_symlink,
1094 .unlink = pohmelfs_unlink,
1095 .mkdir = pohmelfs_mkdir,
1096 .rmdir = pohmelfs_rmdir,
1097 .create = pohmelfs_create,
1098 .lookup = pohmelfs_lookup,
1099 .setattr = pohmelfs_setattr,
1100 .rename = pohmelfs_rename,
1101};
diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c
new file mode 100644
index 00000000000..f3c6060c96b
--- /dev/null
+++ b/drivers/staging/pohmelfs/inode.c
@@ -0,0 +1,2056 @@
1/*
2 * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
3 * All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/module.h>
17#include <linux/backing-dev.h>
18#include <linux/crypto.h>
19#include <linux/fs.h>
20#include <linux/jhash.h>
21#include <linux/hash.h>
22#include <linux/ktime.h>
23#include <linux/mm.h>
24#include <linux/mount.h>
25#include <linux/pagemap.h>
26#include <linux/pagevec.h>
27#include <linux/parser.h>
28#include <linux/swap.h>
29#include <linux/slab.h>
30#include <linux/statfs.h>
31#include <linux/writeback.h>
32#include <linux/prefetch.h>
33
34#include "netfs.h"
35
36#define POHMELFS_MAGIC_NUM 0x504f482e
37
38static struct kmem_cache *pohmelfs_inode_cache;
39static atomic_t psb_bdi_num = ATOMIC_INIT(0);
40
41/*
42 * Removes inode from all trees, drops local name cache and removes all queued
43 * requests for object removal.
44 */
45void pohmelfs_inode_del_inode(struct pohmelfs_sb *psb, struct pohmelfs_inode *pi)
46{
47 mutex_lock(&pi->offset_lock);
48 pohmelfs_free_names(pi);
49 mutex_unlock(&pi->offset_lock);
50
51 dprintk("%s: deleted stuff in ino: %llu.\n", __func__, pi->ino);
52}
53
54/*
55 * Sync inode to server.
56 * Returns zero in success and negative error value otherwise.
57 * It will gather path to root directory into structures containing
58 * creation mode, permissions and names, so that the whole path
59 * to given inode could be created using only single network command.
60 */
61int pohmelfs_write_inode_create(struct inode *inode, struct netfs_trans *trans)
62{
63 struct pohmelfs_inode *pi = POHMELFS_I(inode);
64 int err = -ENOMEM, size;
65 struct netfs_cmd *cmd;
66 void *data;
67 int cur_len = netfs_trans_cur_len(trans);
68
69 if (unlikely(cur_len < 0))
70 return -ETOOSMALL;
71
72 cmd = netfs_trans_current(trans);
73 cur_len -= sizeof(struct netfs_cmd);
74
75 data = (void *)(cmd + 1);
76
77 err = pohmelfs_construct_path_string(pi, data, cur_len);
78 if (err < 0)
79 goto err_out_exit;
80
81 size = err;
82
83 cmd->start = i_size_read(inode);
84 cmd->cmd = NETFS_CREATE;
85 cmd->size = size;
86 cmd->id = pi->ino;
87 cmd->ext = inode->i_mode;
88
89 netfs_convert_cmd(cmd);
90
91 netfs_trans_update(cmd, trans, size);
92
93 return 0;
94
95err_out_exit:
96 printk("%s: completed ino: %llu, err: %d.\n", __func__, pi->ino, err);
97 return err;
98}
99
100static int pohmelfs_write_trans_complete(struct page **pages, unsigned int page_num,
101 void *private, int err)
102{
103 unsigned i;
104
105 dprintk("%s: pages: %lu-%lu, page_num: %u, err: %d.\n",
106 __func__, pages[0]->index, pages[page_num-1]->index,
107 page_num, err);
108
109 for (i = 0; i < page_num; i++) {
110 struct page *page = pages[i];
111
112 if (!page)
113 continue;
114
115 end_page_writeback(page);
116
117 if (err < 0) {
118 SetPageError(page);
119 set_page_dirty(page);
120 }
121
122 unlock_page(page);
123 page_cache_release(page);
124
125 /* dprintk("%s: %3u/%u: page: %p.\n", __func__, i, page_num, page); */
126 }
127 return err;
128}
129
130static int pohmelfs_inode_has_dirty_pages(struct address_space *mapping, pgoff_t index)
131{
132 int ret;
133 struct page *page;
134
135 rcu_read_lock();
136 ret = radix_tree_gang_lookup_tag(&mapping->page_tree,
137 (void **)&page, index, 1, PAGECACHE_TAG_DIRTY);
138 rcu_read_unlock();
139 return ret;
140}
141
142static int pohmelfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
143{
144 struct inode *inode = mapping->host;
145 struct pohmelfs_inode *pi = POHMELFS_I(inode);
146 struct pohmelfs_sb *psb = POHMELFS_SB(inode->i_sb);
147 int err = 0;
148 int done = 0;
149 int nr_pages;
150 pgoff_t index;
151 pgoff_t end; /* Inclusive */
152 int scanned = 0;
153 int range_whole = 0;
154
155 if (wbc->range_cyclic) {
156 index = mapping->writeback_index; /* Start from prev offset */
157 end = -1;
158 } else {
159 index = wbc->range_start >> PAGE_CACHE_SHIFT;
160 end = wbc->range_end >> PAGE_CACHE_SHIFT;
161 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
162 range_whole = 1;
163 scanned = 1;
164 }
165retry:
166 while (!done && (index <= end)) {
167 unsigned int i = min(end - index, (pgoff_t)psb->trans_max_pages);
168 int path_len;
169 struct netfs_trans *trans;
170
171 err = pohmelfs_inode_has_dirty_pages(mapping, index);
172 if (!err)
173 break;
174
175 err = pohmelfs_path_length(pi);
176 if (err < 0)
177 break;
178
179 path_len = err;
180
181 if (path_len <= 2) {
182 err = -ENOENT;
183 break;
184 }
185
186 trans = netfs_trans_alloc(psb, path_len, 0, i);
187 if (!trans) {
188 err = -ENOMEM;
189 break;
190 }
191 trans->complete = &pohmelfs_write_trans_complete;
192
193 trans->page_num = nr_pages = find_get_pages_tag(mapping, &index,
194 PAGECACHE_TAG_DIRTY, trans->page_num,
195 trans->pages);
196
197 dprintk("%s: t: %p, nr_pages: %u, end: %lu, index: %lu, max: %u.\n",
198 __func__, trans, nr_pages, end, index, trans->page_num);
199
200 if (!nr_pages)
201 goto err_out_reset;
202
203 err = pohmelfs_write_inode_create(inode, trans);
204 if (err)
205 goto err_out_reset;
206
207 err = 0;
208 scanned = 1;
209
210 for (i = 0; i < trans->page_num; i++) {
211 struct page *page = trans->pages[i];
212
213 lock_page(page);
214
215 if (unlikely(page->mapping != mapping))
216 goto out_continue;
217
218 if (!wbc->range_cyclic && page->index > end) {
219 done = 1;
220 goto out_continue;
221 }
222
223 if (wbc->sync_mode != WB_SYNC_NONE)
224 wait_on_page_writeback(page);
225
226 if (PageWriteback(page) ||
227 !clear_page_dirty_for_io(page)) {
228 dprintk("%s: not clear for io page: %p, writeback: %d.\n",
229 __func__, page, PageWriteback(page));
230 goto out_continue;
231 }
232
233 set_page_writeback(page);
234
235 trans->attached_size += page_private(page);
236 trans->attached_pages++;
237#if 0
238 dprintk("%s: %u/%u added trans: %p, gen: %u, page: %p, [High: %d], size: %lu, idx: %lu.\n",
239 __func__, i, trans->page_num, trans, trans->gen, page,
240 !!PageHighMem(page), page_private(page), page->index);
241#endif
242 wbc->nr_to_write--;
243
244 if (wbc->nr_to_write <= 0)
245 done = 1;
246
247 continue;
248out_continue:
249 unlock_page(page);
250 trans->pages[i] = NULL;
251 }
252
253 err = netfs_trans_finish(trans, psb);
254 if (err)
255 break;
256
257 continue;
258
259err_out_reset:
260 trans->result = err;
261 netfs_trans_reset(trans);
262 netfs_trans_put(trans);
263 break;
264 }
265
266 if (!scanned && !done) {
267 /*
268 * We hit the last page and there is more work to be done: wrap
269 * back to the start of the file
270 */
271 scanned = 1;
272 index = 0;
273 goto retry;
274 }
275
276 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
277 mapping->writeback_index = index;
278
279 return err;
280}
281
282/*
283 * Inode writeback creation completion callback.
284 * Only invoked for just created inodes, which do not have pages attached,
285 * like dirs and empty files.
286 */
287static int pohmelfs_write_inode_complete(struct page **pages, unsigned int page_num,
288 void *private, int err)
289{
290 struct inode *inode = private;
291 struct pohmelfs_inode *pi = POHMELFS_I(inode);
292
293 if (inode) {
294 if (err) {
295 mark_inode_dirty(inode);
296 clear_bit(NETFS_INODE_REMOTE_SYNCED, &pi->state);
297 } else {
298 set_bit(NETFS_INODE_REMOTE_SYNCED, &pi->state);
299 }
300
301 pohmelfs_put_inode(pi);
302 }
303
304 return err;
305}
306
307int pohmelfs_write_create_inode(struct pohmelfs_inode *pi)
308{
309 struct netfs_trans *t;
310 struct inode *inode = &pi->vfs_inode;
311 struct pohmelfs_sb *psb = POHMELFS_SB(inode->i_sb);
312 int err;
313
314 if (test_bit(NETFS_INODE_REMOTE_SYNCED, &pi->state))
315 return 0;
316
317 dprintk("%s: started ino: %llu.\n", __func__, pi->ino);
318
319 err = pohmelfs_path_length(pi);
320 if (err < 0)
321 goto err_out_exit;
322
323 t = netfs_trans_alloc(psb, err + 1, 0, 0);
324 if (!t) {
325 err = -ENOMEM;
326 goto err_out_exit;
327 }
328 t->complete = pohmelfs_write_inode_complete;
329 t->private = igrab(inode);
330 if (!t->private) {
331 err = -ENOENT;
332 goto err_out_put;
333 }
334
335 err = pohmelfs_write_inode_create(inode, t);
336 if (err)
337 goto err_out_put;
338
339 netfs_trans_finish(t, POHMELFS_SB(inode->i_sb));
340
341 return 0;
342
343err_out_put:
344 t->result = err;
345 netfs_trans_put(t);
346err_out_exit:
347 return err;
348}
349
350/*
351 * Sync all not-yet-created children in given directory to the server.
352 */
353static int pohmelfs_write_inode_create_children(struct inode *inode)
354{
355 struct pohmelfs_inode *parent = POHMELFS_I(inode);
356 struct super_block *sb = inode->i_sb;
357 struct pohmelfs_name *n;
358
359 while (!list_empty(&parent->sync_create_list)) {
360 n = NULL;
361 mutex_lock(&parent->offset_lock);
362 if (!list_empty(&parent->sync_create_list)) {
363 n = list_first_entry(&parent->sync_create_list,
364 struct pohmelfs_name, sync_create_entry);
365 list_del_init(&n->sync_create_entry);
366 }
367 mutex_unlock(&parent->offset_lock);
368
369 if (!n)
370 break;
371
372 inode = ilookup(sb, n->ino);
373
374 dprintk("%s: parent: %llu, ino: %llu, inode: %p.\n",
375 __func__, parent->ino, n->ino, inode);
376
377 if (inode && (inode->i_state & I_DIRTY)) {
378 struct pohmelfs_inode *pi = POHMELFS_I(inode);
379 pohmelfs_write_create_inode(pi);
380 /* pohmelfs_meta_command(pi, NETFS_INODE_INFO, 0, NULL, NULL, 0); */
381 iput(inode);
382 }
383 }
384
385 return 0;
386}
387
388/*
389 * Removes given child from given inode on server.
390 */
391int pohmelfs_remove_child(struct pohmelfs_inode *pi, struct pohmelfs_name *n)
392{
393 return pohmelfs_meta_command_data(pi, pi->ino, NETFS_REMOVE, NULL, 0, NULL, NULL, 0);
394}
395
396/*
397 * Writeback for given inode.
398 */
399static int pohmelfs_write_inode(struct inode *inode,
400 struct writeback_control *wbc)
401{
402 struct pohmelfs_inode *pi = POHMELFS_I(inode);
403
404 pohmelfs_write_create_inode(pi);
405 pohmelfs_write_inode_create_children(inode);
406
407 return 0;
408}
409
410/*
411 * It is not exported, sorry...
412 */
413static inline wait_queue_head_t *page_waitqueue(struct page *page)
414{
415 const struct zone *zone = page_zone(page);
416
417 return &zone->wait_table[hash_ptr(page, zone->wait_table_bits)];
418}
419
420static int pohmelfs_wait_on_page_locked(struct page *page)
421{
422 struct pohmelfs_sb *psb = POHMELFS_SB(page->mapping->host->i_sb);
423 long ret = psb->wait_on_page_timeout;
424 DEFINE_WAIT_BIT(wait, &page->flags, PG_locked);
425 int err = 0;
426
427 if (!PageLocked(page))
428 return 0;
429
430 for (;;) {
431 prepare_to_wait(page_waitqueue(page),
432 &wait.wait, TASK_INTERRUPTIBLE);
433
434 dprintk("%s: page: %p, locked: %d, uptodate: %d, error: %d, flags: %lx.\n",
435 __func__, page, PageLocked(page), PageUptodate(page),
436 PageError(page), page->flags);
437
438 if (!PageLocked(page))
439 break;
440
441 if (!signal_pending(current)) {
442 ret = schedule_timeout(ret);
443 if (!ret)
444 break;
445 continue;
446 }
447 ret = -ERESTARTSYS;
448 break;
449 }
450 finish_wait(page_waitqueue(page), &wait.wait);
451
452 if (!ret)
453 err = -ETIMEDOUT;
454
455
456 if (!err)
457 SetPageUptodate(page);
458
459 if (err)
460 printk("%s: page: %p, uptodate: %d, locked: %d, err: %d.\n",
461 __func__, page, PageUptodate(page), PageLocked(page), err);
462
463 return err;
464}
465
466static int pohmelfs_read_page_complete(struct page **pages, unsigned int page_num,
467 void *private, int err)
468{
469 struct page *page = private;
470
471 if (PageChecked(page))
472 return err;
473
474 if (err < 0) {
475 dprintk("%s: page: %p, err: %d.\n", __func__, page, err);
476 SetPageError(page);
477 }
478
479 unlock_page(page);
480
481 return err;
482}
483
484/*
485 * Read a page from remote server.
486 * Function will wait until page is unlocked.
487 */
488static int pohmelfs_readpage(struct file *file, struct page *page)
489{
490 struct inode *inode = page->mapping->host;
491 struct pohmelfs_sb *psb = POHMELFS_SB(inode->i_sb);
492 struct pohmelfs_inode *pi = POHMELFS_I(inode);
493 struct netfs_trans *t;
494 struct netfs_cmd *cmd;
495 int err, path_len;
496 void *data;
497 u64 isize;
498
499 err = pohmelfs_data_lock(pi, page->index << PAGE_CACHE_SHIFT,
500 PAGE_SIZE, POHMELFS_READ_LOCK);
501 if (err)
502 goto err_out_exit;
503
504 isize = i_size_read(inode);
505 if (isize <= page->index << PAGE_CACHE_SHIFT) {
506 SetPageUptodate(page);
507 unlock_page(page);
508 return 0;
509 }
510
511 path_len = pohmelfs_path_length(pi);
512 if (path_len < 0) {
513 err = path_len;
514 goto err_out_exit;
515 }
516
517 t = netfs_trans_alloc(psb, path_len, NETFS_TRANS_SINGLE_DST, 0);
518 if (!t) {
519 err = -ENOMEM;
520 goto err_out_exit;
521 }
522
523 t->complete = pohmelfs_read_page_complete;
524 t->private = page;
525
526 cmd = netfs_trans_current(t);
527 data = (void *)(cmd + 1);
528
529 err = pohmelfs_construct_path_string(pi, data, path_len);
530 if (err < 0)
531 goto err_out_free;
532
533 path_len = err;
534
535 cmd->id = pi->ino;
536 cmd->start = page->index;
537 cmd->start <<= PAGE_CACHE_SHIFT;
538 cmd->size = PAGE_CACHE_SIZE + path_len;
539 cmd->cmd = NETFS_READ_PAGE;
540 cmd->ext = path_len;
541
542 dprintk("%s: path: '%s', page: %p, ino: %llu, start: %llu, size: %lu.\n",
543 __func__, (char *)data, page, pi->ino, cmd->start, PAGE_CACHE_SIZE);
544
545 netfs_convert_cmd(cmd);
546 netfs_trans_update(cmd, t, path_len);
547
548 err = netfs_trans_finish(t, psb);
549 if (err)
550 goto err_out_return;
551
552 return pohmelfs_wait_on_page_locked(page);
553
554err_out_free:
555 t->result = err;
556 netfs_trans_put(t);
557err_out_exit:
558 SetPageError(page);
559 if (PageLocked(page))
560 unlock_page(page);
561err_out_return:
562 printk("%s: page: %p, start: %lu, size: %lu, err: %d.\n",
563 __func__, page, page->index << PAGE_CACHE_SHIFT, PAGE_CACHE_SIZE, err);
564
565 return err;
566}
567
568/*
569 * Write begin/end magic.
570 * Allocates a page and writes inode if it was not synced to server before.
571 */
572static int pohmelfs_write_begin(struct file *file, struct address_space *mapping,
573 loff_t pos, unsigned len, unsigned flags,
574 struct page **pagep, void **fsdata)
575{
576 struct inode *inode = mapping->host;
577 struct page *page;
578 pgoff_t index;
579 unsigned start, end;
580 int err;
581
582 *pagep = NULL;
583
584 index = pos >> PAGE_CACHE_SHIFT;
585 start = pos & (PAGE_CACHE_SIZE - 1);
586 end = start + len;
587
588 page = grab_cache_page(mapping, index);
589#if 0
590 dprintk("%s: page: %p pos: %llu, len: %u, index: %lu, start: %u, end: %u, uptodate: %d.\n",
591 __func__, page, pos, len, index, start, end, PageUptodate(page));
592#endif
593 if (!page) {
594 err = -ENOMEM;
595 goto err_out_exit;
596 }
597
598 while (!PageUptodate(page)) {
599 if (start && test_bit(NETFS_INODE_REMOTE_SYNCED, &POHMELFS_I(inode)->state)) {
600 err = pohmelfs_readpage(file, page);
601 if (err)
602 goto err_out_exit;
603
604 lock_page(page);
605 continue;
606 }
607
608 if (len != PAGE_CACHE_SIZE) {
609 void *kaddr = kmap_atomic(page, KM_USER0);
610
611 memset(kaddr + start, 0, PAGE_CACHE_SIZE - start);
612 flush_dcache_page(page);
613 kunmap_atomic(kaddr, KM_USER0);
614 }
615 SetPageUptodate(page);
616 }
617
618 set_page_private(page, end);
619
620 *pagep = page;
621
622 return 0;
623
624err_out_exit:
625 page_cache_release(page);
626 *pagep = NULL;
627
628 return err;
629}
630
631static int pohmelfs_write_end(struct file *file, struct address_space *mapping,
632 loff_t pos, unsigned len, unsigned copied,
633 struct page *page, void *fsdata)
634{
635 struct inode *inode = mapping->host;
636
637 if (copied != len) {
638 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
639 void *kaddr = kmap_atomic(page, KM_USER0);
640
641 memset(kaddr + from + copied, 0, len - copied);
642 flush_dcache_page(page);
643 kunmap_atomic(kaddr, KM_USER0);
644 }
645
646 SetPageUptodate(page);
647 set_page_dirty(page);
648#if 0
649 dprintk("%s: page: %p [U: %d, D: %d, L: %d], pos: %llu, len: %u, copied: %u.\n",
650 __func__, page,
651 PageUptodate(page), PageDirty(page), PageLocked(page),
652 pos, len, copied);
653#endif
654 flush_dcache_page(page);
655
656 unlock_page(page);
657 page_cache_release(page);
658
659 if (pos + copied > inode->i_size) {
660 struct pohmelfs_sb *psb = POHMELFS_SB(inode->i_sb);
661
662 psb->avail_size -= pos + copied - inode->i_size;
663
664 i_size_write(inode, pos + copied);
665 }
666
667 return copied;
668}
669
670static int pohmelfs_readpages_trans_complete(struct page **__pages, unsigned int page_num,
671 void *private, int err)
672{
673 struct pohmelfs_inode *pi = private;
674 unsigned int i, num;
675 struct page **pages, *page = (struct page *)__pages;
676 loff_t index = page->index;
677
678 pages = kzalloc(sizeof(void *) * page_num, GFP_NOIO);
679 if (!pages)
680 return -ENOMEM;
681
682 num = find_get_pages_contig(pi->vfs_inode.i_mapping, index, page_num, pages);
683 if (num <= 0) {
684 err = num;
685 goto err_out_free;
686 }
687
688 for (i = 0; i < num; ++i) {
689 page = pages[i];
690
691 if (err)
692 printk("%s: %u/%u: page: %p, index: %lu, uptodate: %d, locked: %d, err: %d.\n",
693 __func__, i, num, page, page->index,
694 PageUptodate(page), PageLocked(page), err);
695
696 if (!PageChecked(page)) {
697 if (err < 0)
698 SetPageError(page);
699 unlock_page(page);
700 }
701 page_cache_release(page);
702 page_cache_release(page);
703 }
704
705err_out_free:
706 kfree(pages);
707 return err;
708}
709
710static int pohmelfs_send_readpages(struct pohmelfs_inode *pi, struct page *first, unsigned int num)
711{
712 struct netfs_trans *t;
713 struct netfs_cmd *cmd;
714 struct pohmelfs_sb *psb = POHMELFS_SB(pi->vfs_inode.i_sb);
715 int err, path_len;
716 void *data;
717
718 err = pohmelfs_data_lock(pi, first->index << PAGE_CACHE_SHIFT,
719 num * PAGE_SIZE, POHMELFS_READ_LOCK);
720 if (err)
721 goto err_out_exit;
722
723 path_len = pohmelfs_path_length(pi);
724 if (path_len < 0) {
725 err = path_len;
726 goto err_out_exit;
727 }
728
729 t = netfs_trans_alloc(psb, path_len, NETFS_TRANS_SINGLE_DST, 0);
730 if (!t) {
731 err = -ENOMEM;
732 goto err_out_exit;
733 }
734
735 cmd = netfs_trans_current(t);
736 data = (void *)(cmd + 1);
737
738 t->complete = pohmelfs_readpages_trans_complete;
739 t->private = pi;
740 t->page_num = num;
741 t->pages = (struct page **)first;
742
743 err = pohmelfs_construct_path_string(pi, data, path_len);
744 if (err < 0)
745 goto err_out_put;
746
747 path_len = err;
748
749 cmd->cmd = NETFS_READ_PAGES;
750 cmd->start = first->index;
751 cmd->start <<= PAGE_CACHE_SHIFT;
752 cmd->size = (num << 8 | PAGE_CACHE_SHIFT);
753 cmd->id = pi->ino;
754 cmd->ext = path_len;
755
756 dprintk("%s: t: %p, gen: %u, path: '%s', path_len: %u, "
757 "start: %lu, num: %u.\n",
758 __func__, t, t->gen, (char *)data, path_len,
759 first->index, num);
760
761 netfs_convert_cmd(cmd);
762 netfs_trans_update(cmd, t, path_len);
763
764 return netfs_trans_finish(t, psb);
765
766err_out_put:
767 netfs_trans_free(t);
768err_out_exit:
769 pohmelfs_readpages_trans_complete((struct page **)first, num, pi, err);
770 return err;
771}
772
773#define list_to_page(head) (list_entry((head)->prev, struct page, lru))
774
775static int pohmelfs_readpages(struct file *file, struct address_space *mapping,
776 struct list_head *pages, unsigned nr_pages)
777{
778 unsigned int page_idx, num = 0;
779 struct page *page = NULL, *first = NULL;
780
781 for (page_idx = 0; page_idx < nr_pages; page_idx++) {
782 page = list_to_page(pages);
783
784 prefetchw(&page->flags);
785 list_del(&page->lru);
786
787 if (!add_to_page_cache_lru(page, mapping,
788 page->index, GFP_KERNEL)) {
789
790 if (!num) {
791 num = 1;
792 first = page;
793 continue;
794 }
795
796 dprintk("%s: added to lru page: %p, page_index: %lu, first_index: %lu.\n",
797 __func__, page, page->index, first->index);
798
799 if (unlikely(first->index + num != page->index) || (num > 500)) {
800 pohmelfs_send_readpages(POHMELFS_I(mapping->host),
801 first, num);
802 first = page;
803 num = 0;
804 }
805
806 num++;
807 }
808 }
809 pohmelfs_send_readpages(POHMELFS_I(mapping->host), first, num);
810
811 /*
812 * This will be sync read, so when last page is processed,
813 * all previous are alerady unlocked and ready to be used.
814 */
815 return 0;
816}
817
818/*
819 * Small address space operations for POHMELFS.
820 */
821const struct address_space_operations pohmelfs_aops = {
822 .readpage = pohmelfs_readpage,
823 .readpages = pohmelfs_readpages,
824 .writepages = pohmelfs_writepages,
825 .write_begin = pohmelfs_write_begin,
826 .write_end = pohmelfs_write_end,
827 .set_page_dirty = __set_page_dirty_nobuffers,
828};
829
830static void pohmelfs_i_callback(struct rcu_head *head)
831{
832 struct inode *inode = container_of(head, struct inode, i_rcu);
833 INIT_LIST_HEAD(&inode->i_dentry);
834 kmem_cache_free(pohmelfs_inode_cache, POHMELFS_I(inode));
835}
836
837/*
838 * ->destroy_inode() callback. Deletes inode from the caches
839 * and frees private data.
840 */
841static void pohmelfs_destroy_inode(struct inode *inode)
842{
843 struct super_block *sb = inode->i_sb;
844 struct pohmelfs_sb *psb = POHMELFS_SB(sb);
845 struct pohmelfs_inode *pi = POHMELFS_I(inode);
846
847 /* pohmelfs_data_unlock(pi, 0, inode->i_size, POHMELFS_READ_LOCK); */
848
849 pohmelfs_inode_del_inode(psb, pi);
850
851 dprintk("%s: pi: %p, inode: %p, ino: %llu.\n",
852 __func__, pi, &pi->vfs_inode, pi->ino);
853 atomic_long_dec(&psb->total_inodes);
854 call_rcu(&inode->i_rcu, pohmelfs_i_callback);
855}
856
857/*
858 * ->alloc_inode() callback. Allocates inode and initializes private data.
859 */
860static struct inode *pohmelfs_alloc_inode(struct super_block *sb)
861{
862 struct pohmelfs_inode *pi;
863
864 pi = kmem_cache_alloc(pohmelfs_inode_cache, GFP_NOIO);
865 if (!pi)
866 return NULL;
867
868 pi->hash_root = RB_ROOT;
869 mutex_init(&pi->offset_lock);
870
871 INIT_LIST_HEAD(&pi->sync_create_list);
872
873 INIT_LIST_HEAD(&pi->inode_entry);
874
875 pi->lock_type = 0;
876 pi->state = 0;
877 pi->total_len = 0;
878 pi->drop_count = 0;
879
880 dprintk("%s: pi: %p, inode: %p.\n", __func__, pi, &pi->vfs_inode);
881
882 atomic_long_inc(&POHMELFS_SB(sb)->total_inodes);
883
884 return &pi->vfs_inode;
885}
886
887/*
888 * We want fsync() to work on POHMELFS.
889 */
890static int pohmelfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
891{
892 struct inode *inode = file->f_mapping->host;
893 int err = filemap_write_and_wait_range(inode->i_mapping, start, end);
894 if (!err) {
895 mutex_lock(&inode->i_mutex);
896 err = sync_inode_metadata(inode, 1);
897 mutex_unlock(&inode->i_mutex);
898 }
899 return err;
900}
901
902ssize_t pohmelfs_write(struct file *file, const char __user *buf,
903 size_t len, loff_t *ppos)
904{
905 struct address_space *mapping = file->f_mapping;
906 struct inode *inode = mapping->host;
907 struct pohmelfs_inode *pi = POHMELFS_I(inode);
908 struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };
909 struct kiocb kiocb;
910 ssize_t ret;
911 loff_t pos = *ppos;
912
913 init_sync_kiocb(&kiocb, file);
914 kiocb.ki_pos = pos;
915 kiocb.ki_left = len;
916
917 dprintk("%s: len: %zu, pos: %llu.\n", __func__, len, pos);
918
919 mutex_lock(&inode->i_mutex);
920 ret = pohmelfs_data_lock(pi, pos, len, POHMELFS_WRITE_LOCK);
921 if (ret)
922 goto err_out_unlock;
923
924 ret = __generic_file_aio_write(&kiocb, &iov, 1, &kiocb.ki_pos);
925 *ppos = kiocb.ki_pos;
926
927 mutex_unlock(&inode->i_mutex);
928 WARN_ON(ret < 0);
929
930 if (ret > 0) {
931 ssize_t err;
932
933 err = generic_write_sync(file, pos, ret);
934 if (err < 0)
935 ret = err;
936 WARN_ON(ret < 0);
937 }
938
939 return ret;
940
941err_out_unlock:
942 mutex_unlock(&inode->i_mutex);
943 return ret;
944}
945
946static const struct file_operations pohmelfs_file_ops = {
947 .open = generic_file_open,
948 .fsync = pohmelfs_fsync,
949
950 .llseek = generic_file_llseek,
951
952 .read = do_sync_read,
953 .aio_read = generic_file_aio_read,
954
955 .mmap = generic_file_mmap,
956
957 .splice_read = generic_file_splice_read,
958 .splice_write = generic_file_splice_write,
959
960 .write = pohmelfs_write,
961 .aio_write = generic_file_aio_write,
962};
963
964const struct inode_operations pohmelfs_symlink_inode_operations = {
965 .readlink = generic_readlink,
966 .follow_link = page_follow_link_light,
967 .put_link = page_put_link,
968};
969
970int pohmelfs_setattr_raw(struct inode *inode, struct iattr *attr)
971{
972 int err;
973
974 err = inode_change_ok(inode, attr);
975 if (err) {
976 dprintk("%s: ino: %llu, inode changes are not allowed.\n", __func__, POHMELFS_I(inode)->ino);
977 goto err_out_exit;
978 }
979
980 if ((attr->ia_valid & ATTR_SIZE) &&
981 attr->ia_size != i_size_read(inode)) {
982 err = vmtruncate(inode, attr->ia_size);
983 if (err) {
984 dprintk("%s: ino: %llu, failed to set the attributes.\n", __func__, POHMELFS_I(inode)->ino);
985 goto err_out_exit;
986 }
987 }
988
989 setattr_copy(inode, attr);
990 mark_inode_dirty(inode);
991
992 dprintk("%s: ino: %llu, mode: %o -> %o, uid: %u -> %u, gid: %u -> %u, size: %llu -> %llu.\n",
993 __func__, POHMELFS_I(inode)->ino, inode->i_mode, attr->ia_mode,
994 inode->i_uid, attr->ia_uid, inode->i_gid, attr->ia_gid, inode->i_size, attr->ia_size);
995
996 return 0;
997
998err_out_exit:
999 return err;
1000}
1001
1002int pohmelfs_setattr(struct dentry *dentry, struct iattr *attr)
1003{
1004 struct inode *inode = dentry->d_inode;
1005 struct pohmelfs_inode *pi = POHMELFS_I(inode);
1006 int err;
1007
1008 err = pohmelfs_data_lock(pi, 0, ~0, POHMELFS_WRITE_LOCK);
1009 if (err)
1010 goto err_out_exit;
1011
1012 err = security_inode_setattr(dentry, attr);
1013 if (err)
1014 goto err_out_exit;
1015
1016 err = pohmelfs_setattr_raw(inode, attr);
1017 if (err)
1018 goto err_out_exit;
1019
1020 return 0;
1021
1022err_out_exit:
1023 return err;
1024}
1025
1026static int pohmelfs_send_xattr_req(struct pohmelfs_inode *pi, u64 id, u64 start,
1027 const char *name, const void *value, size_t attrsize, int command)
1028{
1029 struct pohmelfs_sb *psb = POHMELFS_SB(pi->vfs_inode.i_sb);
1030 int err, path_len, namelen = strlen(name) + 1; /* 0-byte */
1031 struct netfs_trans *t;
1032 struct netfs_cmd *cmd;
1033 void *data;
1034
1035 dprintk("%s: id: %llu, start: %llu, name: '%s', attrsize: %zu, cmd: %d.\n",
1036 __func__, id, start, name, attrsize, command);
1037
1038 path_len = pohmelfs_path_length(pi);
1039 if (path_len < 0) {
1040 err = path_len;
1041 goto err_out_exit;
1042 }
1043
1044 t = netfs_trans_alloc(psb, namelen + path_len + attrsize, 0, 0);
1045 if (!t) {
1046 err = -ENOMEM;
1047 goto err_out_exit;
1048 }
1049
1050 cmd = netfs_trans_current(t);
1051 data = cmd + 1;
1052
1053 path_len = pohmelfs_construct_path_string(pi, data, path_len);
1054 if (path_len < 0) {
1055 err = path_len;
1056 goto err_out_put;
1057 }
1058 data += path_len;
1059
1060 /*
1061 * 'name' is a NUL-terminated string already and
1062 * 'namelen' includes 0-byte.
1063 */
1064 memcpy(data, name, namelen);
1065 data += namelen;
1066
1067 memcpy(data, value, attrsize);
1068
1069 cmd->cmd = command;
1070 cmd->id = id;
1071 cmd->start = start;
1072 cmd->size = attrsize + namelen + path_len;
1073 cmd->ext = path_len;
1074 cmd->csize = 0;
1075 cmd->cpad = 0;
1076
1077 netfs_convert_cmd(cmd);
1078 netfs_trans_update(cmd, t, namelen + path_len + attrsize);
1079
1080 return netfs_trans_finish(t, psb);
1081
1082err_out_put:
1083 t->result = err;
1084 netfs_trans_put(t);
1085err_out_exit:
1086 return err;
1087}
1088
1089static int pohmelfs_setxattr(struct dentry *dentry, const char *name,
1090 const void *value, size_t attrsize, int flags)
1091{
1092 struct inode *inode = dentry->d_inode;
1093 struct pohmelfs_inode *pi = POHMELFS_I(inode);
1094 struct pohmelfs_sb *psb = POHMELFS_SB(inode->i_sb);
1095
1096 if (!(psb->state_flags & POHMELFS_FLAGS_XATTR))
1097 return -EOPNOTSUPP;
1098
1099 return pohmelfs_send_xattr_req(pi, flags, attrsize, name,
1100 value, attrsize, NETFS_XATTR_SET);
1101}
1102
1103static ssize_t pohmelfs_getxattr(struct dentry *dentry, const char *name,
1104 void *value, size_t attrsize)
1105{
1106 struct inode *inode = dentry->d_inode;
1107 struct pohmelfs_inode *pi = POHMELFS_I(inode);
1108 struct pohmelfs_sb *psb = POHMELFS_SB(inode->i_sb);
1109 struct pohmelfs_mcache *m;
1110 int err;
1111 long timeout = psb->mcache_timeout;
1112
1113 if (!(psb->state_flags & POHMELFS_FLAGS_XATTR))
1114 return -EOPNOTSUPP;
1115
1116 m = pohmelfs_mcache_alloc(psb, 0, attrsize, value);
1117 if (IS_ERR(m))
1118 return PTR_ERR(m);
1119
1120 dprintk("%s: ino: %llu, name: '%s', size: %zu.\n",
1121 __func__, pi->ino, name, attrsize);
1122
1123 err = pohmelfs_send_xattr_req(pi, m->gen, attrsize, name, value, 0, NETFS_XATTR_GET);
1124 if (err)
1125 goto err_out_put;
1126
1127 do {
1128 err = wait_for_completion_timeout(&m->complete, timeout);
1129 if (err) {
1130 err = m->err;
1131 break;
1132 }
1133
1134 /*
1135 * This loop is a bit ugly, since it waits until reference counter
1136 * hits 1 and then puts the object here. Main goal is to prevent race with
1137 * the network thread, when it can start processing the given request, i.e.
1138 * increase its reference counter but yet not complete it, while
1139 * we will exit from ->getxattr() with timeout, and although request
1140 * will not be freed (its reference counter was increased by network
1141 * thread), data pointer provided by user may be released, so we will
1142 * overwrite an already freed area in the network thread.
1143 *
1144 * Now after timeout we remove request from the cache, so it can not be
1145 * found by network thread, and wait for its reference counter to hit 1,
1146 * i.e. if network thread already started to process this request, we wait
1147 * for it to finish, and then free object locally. If reference counter is
1148 * already 1, i.e. request is not used by anyone else, we can free it without
1149 * problem.
1150 */
1151 err = -ETIMEDOUT;
1152 timeout = HZ;
1153
1154 pohmelfs_mcache_remove_locked(psb, m);
1155 } while (atomic_read(&m->refcnt) != 1);
1156
1157 pohmelfs_mcache_put(psb, m);
1158
1159 dprintk("%s: ino: %llu, err: %d.\n", __func__, pi->ino, err);
1160
1161 return err;
1162
1163err_out_put:
1164 pohmelfs_mcache_put(psb, m);
1165 return err;
1166}
1167
1168static int pohmelfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
1169{
1170 struct inode *inode = dentry->d_inode;
1171#if 0
1172 struct pohmelfs_inode *pi = POHMELFS_I(inode);
1173 int err;
1174
1175 err = pohmelfs_data_lock(pi, 0, ~0, POHMELFS_READ_LOCK);
1176 if (err)
1177 return err;
1178 dprintk("%s: ino: %llu, mode: %o, uid: %u, gid: %u, size: %llu.\n",
1179 __func__, pi->ino, inode->i_mode, inode->i_uid,
1180 inode->i_gid, inode->i_size);
1181#endif
1182
1183 generic_fillattr(inode, stat);
1184 return 0;
1185}
1186
1187const struct inode_operations pohmelfs_file_inode_operations = {
1188 .setattr = pohmelfs_setattr,
1189 .getattr = pohmelfs_getattr,
1190 .setxattr = pohmelfs_setxattr,
1191 .getxattr = pohmelfs_getxattr,
1192};
1193
1194/*
1195 * Fill inode data: mode, size, operation callbacks and so on...
1196 */
1197void pohmelfs_fill_inode(struct inode *inode, struct netfs_inode_info *info)
1198{
1199 inode->i_mode = info->mode;
1200 inode->i_nlink = info->nlink;
1201 inode->i_uid = info->uid;
1202 inode->i_gid = info->gid;
1203 inode->i_blocks = info->blocks;
1204 inode->i_rdev = info->rdev;
1205 inode->i_size = info->size;
1206 inode->i_version = info->version;
1207 inode->i_blkbits = ffs(info->blocksize);
1208
1209 dprintk("%s: inode: %p, num: %lu/%llu inode is regular: %d, dir: %d, link: %d, mode: %o, size: %llu.\n",
1210 __func__, inode, inode->i_ino, info->ino,
1211 S_ISREG(inode->i_mode), S_ISDIR(inode->i_mode),
1212 S_ISLNK(inode->i_mode), inode->i_mode, inode->i_size);
1213
1214 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
1215
1216 /*
1217 * i_mapping is a pointer to i_data during inode initialization.
1218 */
1219 inode->i_data.a_ops = &pohmelfs_aops;
1220
1221 if (S_ISREG(inode->i_mode)) {
1222 inode->i_fop = &pohmelfs_file_ops;
1223 inode->i_op = &pohmelfs_file_inode_operations;
1224 } else if (S_ISDIR(inode->i_mode)) {
1225 inode->i_fop = &pohmelfs_dir_fops;
1226 inode->i_op = &pohmelfs_dir_inode_ops;
1227 } else if (S_ISLNK(inode->i_mode)) {
1228 inode->i_op = &pohmelfs_symlink_inode_operations;
1229 inode->i_fop = &pohmelfs_file_ops;
1230 } else {
1231 inode->i_fop = &generic_ro_fops;
1232 }
1233}
1234
1235static int pohmelfs_drop_inode(struct inode *inode)
1236{
1237 struct pohmelfs_sb *psb = POHMELFS_SB(inode->i_sb);
1238 struct pohmelfs_inode *pi = POHMELFS_I(inode);
1239
1240 spin_lock(&psb->ino_lock);
1241 list_del_init(&pi->inode_entry);
1242 spin_unlock(&psb->ino_lock);
1243
1244 return generic_drop_inode(inode);
1245}
1246
1247static struct pohmelfs_inode *pohmelfs_get_inode_from_list(struct pohmelfs_sb *psb,
1248 struct list_head *head, unsigned int *count)
1249{
1250 struct pohmelfs_inode *pi = NULL;
1251
1252 spin_lock(&psb->ino_lock);
1253 if (!list_empty(head)) {
1254 pi = list_entry(head->next, struct pohmelfs_inode,
1255 inode_entry);
1256 list_del_init(&pi->inode_entry);
1257 *count = pi->drop_count;
1258 pi->drop_count = 0;
1259 }
1260 spin_unlock(&psb->ino_lock);
1261
1262 return pi;
1263}
1264
1265static void pohmelfs_flush_transactions(struct pohmelfs_sb *psb)
1266{
1267 struct pohmelfs_config *c;
1268
1269 mutex_lock(&psb->state_lock);
1270 list_for_each_entry(c, &psb->state_list, config_entry) {
1271 pohmelfs_state_flush_transactions(&c->state);
1272 }
1273 mutex_unlock(&psb->state_lock);
1274}
1275
1276/*
1277 * ->put_super() callback. Invoked before superblock is destroyed,
1278 * so it has to clean all private data.
1279 */
1280static void pohmelfs_put_super(struct super_block *sb)
1281{
1282 struct pohmelfs_sb *psb = POHMELFS_SB(sb);
1283 struct pohmelfs_inode *pi;
1284 unsigned int count = 0;
1285 unsigned int in_drop_list = 0;
1286 struct inode *inode, *tmp;
1287
1288 dprintk("%s.\n", __func__);
1289
1290 /*
1291 * Kill pending transactions, which could affect inodes in-flight.
1292 */
1293 pohmelfs_flush_transactions(psb);
1294
1295 while ((pi = pohmelfs_get_inode_from_list(psb, &psb->drop_list, &count))) {
1296 inode = &pi->vfs_inode;
1297
1298 dprintk("%s: ino: %llu, pi: %p, inode: %p, count: %u.\n",
1299 __func__, pi->ino, pi, inode, count);
1300
1301 if (atomic_read(&inode->i_count) != count) {
1302 printk("%s: ino: %llu, pi: %p, inode: %p, count: %u, i_count: %d.\n",
1303 __func__, pi->ino, pi, inode, count,
1304 atomic_read(&inode->i_count));
1305 count = atomic_read(&inode->i_count);
1306 in_drop_list++;
1307 }
1308
1309 while (count--)
1310 iput(&pi->vfs_inode);
1311 }
1312
1313 list_for_each_entry_safe(inode, tmp, &sb->s_inodes, i_sb_list) {
1314 pi = POHMELFS_I(inode);
1315
1316 dprintk("%s: ino: %llu, pi: %p, inode: %p, i_count: %u.\n",
1317 __func__, pi->ino, pi, inode, atomic_read(&inode->i_count));
1318
1319 /*
1320 * These are special inodes, they were created during
1321 * directory reading or lookup, and were not bound to dentry,
1322 * so they live here with reference counter being 1 and prevent
1323 * umount from succeed since it believes that they are busy.
1324 */
1325 count = atomic_read(&inode->i_count);
1326 if (count) {
1327 list_del_init(&inode->i_sb_list);
1328 while (count--)
1329 iput(&pi->vfs_inode);
1330 }
1331 }
1332
1333 psb->trans_scan_timeout = psb->drop_scan_timeout = 0;
1334 cancel_delayed_work_sync(&psb->dwork);
1335 cancel_delayed_work_sync(&psb->drop_dwork);
1336 flush_scheduled_work();
1337
1338 dprintk("%s: stopped workqueues.\n", __func__);
1339
1340 pohmelfs_crypto_exit(psb);
1341 pohmelfs_state_exit(psb);
1342
1343 bdi_destroy(&psb->bdi);
1344
1345 kfree(psb);
1346 sb->s_fs_info = NULL;
1347}
1348
1349static int pohmelfs_statfs(struct dentry *dentry, struct kstatfs *buf)
1350{
1351 struct super_block *sb = dentry->d_sb;
1352 struct pohmelfs_sb *psb = POHMELFS_SB(sb);
1353
1354 /*
1355 * There are no filesystem size limits yet.
1356 */
1357 memset(buf, 0, sizeof(struct kstatfs));
1358
1359 buf->f_type = POHMELFS_MAGIC_NUM; /* 'POH.' */
1360 buf->f_bsize = sb->s_blocksize;
1361 buf->f_files = psb->ino;
1362 buf->f_namelen = 255;
1363 buf->f_files = atomic_long_read(&psb->total_inodes);
1364 buf->f_bfree = buf->f_bavail = psb->avail_size >> PAGE_SHIFT;
1365 buf->f_blocks = psb->total_size >> PAGE_SHIFT;
1366
1367 dprintk("%s: total: %llu, avail: %llu, inodes: %llu, bsize: %lu.\n",
1368 __func__, psb->total_size, psb->avail_size, buf->f_files, sb->s_blocksize);
1369
1370 return 0;
1371}
1372
1373static int pohmelfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
1374{
1375 struct pohmelfs_sb *psb = POHMELFS_SB(vfs->mnt_sb);
1376
1377 seq_printf(seq, ",idx=%u", psb->idx);
1378 seq_printf(seq, ",trans_scan_timeout=%u", jiffies_to_msecs(psb->trans_scan_timeout));
1379 seq_printf(seq, ",drop_scan_timeout=%u", jiffies_to_msecs(psb->drop_scan_timeout));
1380 seq_printf(seq, ",wait_on_page_timeout=%u", jiffies_to_msecs(psb->wait_on_page_timeout));
1381 seq_printf(seq, ",trans_retries=%u", psb->trans_retries);
1382 seq_printf(seq, ",crypto_thread_num=%u", psb->crypto_thread_num);
1383 seq_printf(seq, ",trans_max_pages=%u", psb->trans_max_pages);
1384 seq_printf(seq, ",mcache_timeout=%u", jiffies_to_msecs(psb->mcache_timeout));
1385 if (psb->crypto_fail_unsupported)
1386 seq_printf(seq, ",crypto_fail_unsupported");
1387
1388 return 0;
1389}
1390
1391enum {
1392 pohmelfs_opt_idx,
1393 pohmelfs_opt_crypto_thread_num,
1394 pohmelfs_opt_trans_max_pages,
1395 pohmelfs_opt_crypto_fail_unsupported,
1396
1397 /* Remountable options */
1398 pohmelfs_opt_trans_scan_timeout,
1399 pohmelfs_opt_drop_scan_timeout,
1400 pohmelfs_opt_wait_on_page_timeout,
1401 pohmelfs_opt_trans_retries,
1402 pohmelfs_opt_mcache_timeout,
1403};
1404
1405static struct match_token pohmelfs_tokens[] = {
1406 {pohmelfs_opt_idx, "idx=%u"},
1407 {pohmelfs_opt_crypto_thread_num, "crypto_thread_num=%u"},
1408 {pohmelfs_opt_trans_max_pages, "trans_max_pages=%u"},
1409 {pohmelfs_opt_crypto_fail_unsupported, "crypto_fail_unsupported"},
1410 {pohmelfs_opt_trans_scan_timeout, "trans_scan_timeout=%u"},
1411 {pohmelfs_opt_drop_scan_timeout, "drop_scan_timeout=%u"},
1412 {pohmelfs_opt_wait_on_page_timeout, "wait_on_page_timeout=%u"},
1413 {pohmelfs_opt_trans_retries, "trans_retries=%u"},
1414 {pohmelfs_opt_mcache_timeout, "mcache_timeout=%u"},
1415};
1416
1417static int pohmelfs_parse_options(char *options, struct pohmelfs_sb *psb, int remount)
1418{
1419 char *p;
1420 substring_t args[MAX_OPT_ARGS];
1421 int option, err;
1422
1423 if (!options)
1424 return 0;
1425
1426 while ((p = strsep(&options, ",")) != NULL) {
1427 int token;
1428 if (!*p)
1429 continue;
1430
1431 token = match_token(p, pohmelfs_tokens, args);
1432
1433 err = match_int(&args[0], &option);
1434 if (err)
1435 return err;
1436
1437 if (remount && token <= pohmelfs_opt_crypto_fail_unsupported)
1438 continue;
1439
1440 switch (token) {
1441 case pohmelfs_opt_idx:
1442 psb->idx = option;
1443 break;
1444 case pohmelfs_opt_trans_scan_timeout:
1445 psb->trans_scan_timeout = msecs_to_jiffies(option);
1446 break;
1447 case pohmelfs_opt_drop_scan_timeout:
1448 psb->drop_scan_timeout = msecs_to_jiffies(option);
1449 break;
1450 case pohmelfs_opt_wait_on_page_timeout:
1451 psb->wait_on_page_timeout = msecs_to_jiffies(option);
1452 break;
1453 case pohmelfs_opt_mcache_timeout:
1454 psb->mcache_timeout = msecs_to_jiffies(option);
1455 break;
1456 case pohmelfs_opt_trans_retries:
1457 psb->trans_retries = option;
1458 break;
1459 case pohmelfs_opt_crypto_thread_num:
1460 psb->crypto_thread_num = option;
1461 break;
1462 case pohmelfs_opt_trans_max_pages:
1463 psb->trans_max_pages = option;
1464 break;
1465 case pohmelfs_opt_crypto_fail_unsupported:
1466 psb->crypto_fail_unsupported = 1;
1467 break;
1468 default:
1469 return -EINVAL;
1470 }
1471 }
1472
1473 return 0;
1474}
1475
1476static int pohmelfs_remount(struct super_block *sb, int *flags, char *data)
1477{
1478 int err;
1479 struct pohmelfs_sb *psb = POHMELFS_SB(sb);
1480 unsigned long old_sb_flags = sb->s_flags;
1481
1482 err = pohmelfs_parse_options(data, psb, 1);
1483 if (err)
1484 goto err_out_restore;
1485
1486 if (!(*flags & MS_RDONLY))
1487 sb->s_flags &= ~MS_RDONLY;
1488 return 0;
1489
1490err_out_restore:
1491 sb->s_flags = old_sb_flags;
1492 return err;
1493}
1494
1495static void pohmelfs_flush_inode(struct pohmelfs_inode *pi, unsigned int count)
1496{
1497 struct inode *inode = &pi->vfs_inode;
1498
1499 dprintk("%s: %p: ino: %llu, owned: %d.\n",
1500 __func__, inode, pi->ino, test_bit(NETFS_INODE_OWNED, &pi->state));
1501
1502 mutex_lock(&inode->i_mutex);
1503 if (test_and_clear_bit(NETFS_INODE_OWNED, &pi->state)) {
1504 filemap_fdatawrite(inode->i_mapping);
1505 inode->i_sb->s_op->write_inode(inode, 0);
1506 }
1507
1508#ifdef POHMELFS_TRUNCATE_ON_INODE_FLUSH
1509 truncate_inode_pages(inode->i_mapping, 0);
1510#endif
1511
1512 pohmelfs_data_unlock(pi, 0, ~0, POHMELFS_WRITE_LOCK);
1513 mutex_unlock(&inode->i_mutex);
1514}
1515
1516static void pohmelfs_put_inode_count(struct pohmelfs_inode *pi, unsigned int count)
1517{
1518 dprintk("%s: ino: %llu, pi: %p, inode: %p, count: %u.\n",
1519 __func__, pi->ino, pi, &pi->vfs_inode, count);
1520
1521 if (test_and_clear_bit(NETFS_INODE_NEED_FLUSH, &pi->state))
1522 pohmelfs_flush_inode(pi, count);
1523
1524 while (count--)
1525 iput(&pi->vfs_inode);
1526}
1527
1528static void pohmelfs_drop_scan(struct work_struct *work)
1529{
1530 struct pohmelfs_sb *psb =
1531 container_of(work, struct pohmelfs_sb, drop_dwork.work);
1532 struct pohmelfs_inode *pi;
1533 unsigned int count = 0;
1534
1535 while ((pi = pohmelfs_get_inode_from_list(psb, &psb->drop_list, &count)))
1536 pohmelfs_put_inode_count(pi, count);
1537
1538 pohmelfs_check_states(psb);
1539
1540 if (psb->drop_scan_timeout)
1541 schedule_delayed_work(&psb->drop_dwork, psb->drop_scan_timeout);
1542}
1543
1544/*
1545 * Run through all transactions starting from the oldest,
1546 * drop transaction from current state and try to send it
1547 * to all remote nodes, which are currently installed.
1548 */
1549static void pohmelfs_trans_scan_state(struct netfs_state *st)
1550{
1551 struct rb_node *rb_node;
1552 struct netfs_trans_dst *dst;
1553 struct pohmelfs_sb *psb = st->psb;
1554 unsigned int timeout = psb->trans_scan_timeout;
1555 struct netfs_trans *t;
1556 int err;
1557
1558 mutex_lock(&st->trans_lock);
1559 for (rb_node = rb_first(&st->trans_root); rb_node; ) {
1560 dst = rb_entry(rb_node, struct netfs_trans_dst, state_entry);
1561 t = dst->trans;
1562
1563 if (timeout && time_after(dst->send_time + timeout, jiffies)
1564 && dst->retries == 0)
1565 break;
1566
1567 dprintk("%s: t: %p, gen: %u, st: %p, retries: %u, max: %u.\n",
1568 __func__, t, t->gen, st, dst->retries, psb->trans_retries);
1569 netfs_trans_get(t);
1570
1571 rb_node = rb_next(rb_node);
1572
1573 err = -ETIMEDOUT;
1574 if (timeout && (++dst->retries < psb->trans_retries))
1575 err = netfs_trans_resend(t, psb);
1576
1577 if (err || (t->flags & NETFS_TRANS_SINGLE_DST)) {
1578 if (netfs_trans_remove_nolock(dst, st))
1579 netfs_trans_drop_dst_nostate(dst);
1580 }
1581
1582 t->result = err;
1583 netfs_trans_put(t);
1584 }
1585 mutex_unlock(&st->trans_lock);
1586}
1587
1588/*
1589 * Walk through all installed network states and resend all
1590 * transactions, which are old enough.
1591 */
1592static void pohmelfs_trans_scan(struct work_struct *work)
1593{
1594 struct pohmelfs_sb *psb =
1595 container_of(work, struct pohmelfs_sb, dwork.work);
1596 struct netfs_state *st;
1597 struct pohmelfs_config *c;
1598
1599 mutex_lock(&psb->state_lock);
1600 list_for_each_entry(c, &psb->state_list, config_entry) {
1601 st = &c->state;
1602
1603 pohmelfs_trans_scan_state(st);
1604 }
1605 mutex_unlock(&psb->state_lock);
1606
1607 /*
1608 * If no timeout specified then system is in the middle of umount process,
1609 * so no need to reschedule scanning process again.
1610 */
1611 if (psb->trans_scan_timeout)
1612 schedule_delayed_work(&psb->dwork, psb->trans_scan_timeout);
1613}
1614
1615int pohmelfs_meta_command_data(struct pohmelfs_inode *pi, u64 id, unsigned int cmd_op, char *addon,
1616 unsigned int flags, netfs_trans_complete_t complete, void *priv, u64 start)
1617{
1618 struct inode *inode = &pi->vfs_inode;
1619 struct pohmelfs_sb *psb = POHMELFS_SB(inode->i_sb);
1620 int err = 0, sz;
1621 struct netfs_trans *t;
1622 int path_len, addon_len = 0;
1623 void *data;
1624 struct netfs_inode_info *info;
1625 struct netfs_cmd *cmd;
1626
1627 dprintk("%s: ino: %llu, cmd: %u, addon: %p.\n", __func__, pi->ino, cmd_op, addon);
1628
1629 path_len = pohmelfs_path_length(pi);
1630 if (path_len < 0) {
1631 err = path_len;
1632 goto err_out_exit;
1633 }
1634
1635 if (addon)
1636 addon_len = strlen(addon) + 1; /* 0-byte */
1637 sz = addon_len;
1638
1639 if (cmd_op == NETFS_INODE_INFO)
1640 sz += sizeof(struct netfs_inode_info);
1641
1642 t = netfs_trans_alloc(psb, sz + path_len, flags, 0);
1643 if (!t) {
1644 err = -ENOMEM;
1645 goto err_out_exit;
1646 }
1647 t->complete = complete;
1648 t->private = priv;
1649
1650 cmd = netfs_trans_current(t);
1651 data = (void *)(cmd + 1);
1652
1653 if (cmd_op == NETFS_INODE_INFO) {
1654 info = (struct netfs_inode_info *)(cmd + 1);
1655 data = (void *)(info + 1);
1656
1657 /*
1658 * We are under i_mutex, can read and change whatever we want...
1659 */
1660 info->mode = inode->i_mode;
1661 info->nlink = inode->i_nlink;
1662 info->uid = inode->i_uid;
1663 info->gid = inode->i_gid;
1664 info->blocks = inode->i_blocks;
1665 info->rdev = inode->i_rdev;
1666 info->size = inode->i_size;
1667 info->version = inode->i_version;
1668
1669 netfs_convert_inode_info(info);
1670 }
1671
1672 path_len = pohmelfs_construct_path_string(pi, data, path_len);
1673 if (path_len < 0)
1674 goto err_out_free;
1675
1676 dprintk("%s: path_len: %d.\n", __func__, path_len);
1677
1678 if (addon) {
1679 path_len--; /* Do not place null-byte before the addon */
1680 path_len += sprintf(data + path_len, "/%s", addon) + 1; /* 0 - byte */
1681 }
1682
1683 sz += path_len;
1684
1685 cmd->cmd = cmd_op;
1686 cmd->ext = path_len;
1687 cmd->size = sz;
1688 cmd->id = id;
1689 cmd->start = start;
1690
1691 netfs_convert_cmd(cmd);
1692 netfs_trans_update(cmd, t, sz);
1693
1694 /*
1695 * Note, that it is possible to leak error here: transaction callback will not
1696 * be invoked for allocation path failure.
1697 */
1698 return netfs_trans_finish(t, psb);
1699
1700err_out_free:
1701 netfs_trans_free(t);
1702err_out_exit:
1703 if (complete)
1704 complete(NULL, 0, priv, err);
1705 return err;
1706}
1707
1708int pohmelfs_meta_command(struct pohmelfs_inode *pi, unsigned int cmd_op, unsigned int flags,
1709 netfs_trans_complete_t complete, void *priv, u64 start)
1710{
1711 return pohmelfs_meta_command_data(pi, pi->ino, cmd_op, NULL, flags, complete, priv, start);
1712}
1713
1714/*
1715 * Send request and wait for POHMELFS root capabilities response,
1716 * which will update server's informaion about size of the export,
1717 * permissions, number of objects, available size and so on.
1718 */
1719static int pohmelfs_root_handshake(struct pohmelfs_sb *psb)
1720{
1721 struct netfs_trans *t;
1722 struct netfs_cmd *cmd;
1723 int err = -ENOMEM;
1724
1725 t = netfs_trans_alloc(psb, 0, 0, 0);
1726 if (!t)
1727 goto err_out_exit;
1728
1729 cmd = netfs_trans_current(t);
1730
1731 cmd->cmd = NETFS_CAPABILITIES;
1732 cmd->id = POHMELFS_ROOT_CAPABILITIES;
1733 cmd->size = 0;
1734 cmd->start = 0;
1735 cmd->ext = 0;
1736 cmd->csize = 0;
1737
1738 netfs_convert_cmd(cmd);
1739 netfs_trans_update(cmd, t, 0);
1740
1741 err = netfs_trans_finish(t, psb);
1742 if (err)
1743 goto err_out_exit;
1744
1745 psb->flags = ~0;
1746 err = wait_event_interruptible_timeout(psb->wait,
1747 (psb->flags != ~0),
1748 psb->wait_on_page_timeout);
1749 if (!err)
1750 err = -ETIMEDOUT;
1751 else if (err > 0)
1752 err = -psb->flags;
1753
1754 if (err)
1755 goto err_out_exit;
1756
1757 return 0;
1758
1759err_out_exit:
1760 return err;
1761}
1762
1763static int pohmelfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
1764{
1765 struct netfs_state *st;
1766 struct pohmelfs_ctl *ctl;
1767 struct pohmelfs_sb *psb = POHMELFS_SB(mnt->mnt_sb);
1768 struct pohmelfs_config *c;
1769
1770 mutex_lock(&psb->state_lock);
1771
1772 seq_printf(m, "\nidx addr(:port) socket_type protocol active priority permissions\n");
1773
1774 list_for_each_entry(c, &psb->state_list, config_entry) {
1775 st = &c->state;
1776 ctl = &st->ctl;
1777
1778 seq_printf(m, "%u ", ctl->idx);
1779 if (ctl->addr.sa_family == AF_INET) {
1780 struct sockaddr_in *sin = (struct sockaddr_in *)&st->ctl.addr;
1781 seq_printf(m, "%pI4:%u", &sin->sin_addr.s_addr, ntohs(sin->sin_port));
1782 } else if (ctl->addr.sa_family == AF_INET6) {
1783 struct sockaddr_in6 *sin = (struct sockaddr_in6 *)&st->ctl.addr;
1784 seq_printf(m, "%pi6:%u", &sin->sin6_addr, ntohs(sin->sin6_port));
1785 } else {
1786 unsigned int i;
1787 for (i = 0; i < ctl->addrlen; ++i)
1788 seq_printf(m, "%02x.", ctl->addr.addr[i]);
1789 }
1790
1791 seq_printf(m, " %u %u %d %u %x\n",
1792 ctl->type, ctl->proto,
1793 st->socket != NULL,
1794 ctl->prio, ctl->perm);
1795 }
1796 mutex_unlock(&psb->state_lock);
1797
1798 return 0;
1799}
1800
1801static const struct super_operations pohmelfs_sb_ops = {
1802 .alloc_inode = pohmelfs_alloc_inode,
1803 .destroy_inode = pohmelfs_destroy_inode,
1804 .drop_inode = pohmelfs_drop_inode,
1805 .write_inode = pohmelfs_write_inode,
1806 .put_super = pohmelfs_put_super,
1807 .remount_fs = pohmelfs_remount,
1808 .statfs = pohmelfs_statfs,
1809 .show_options = pohmelfs_show_options,
1810 .show_stats = pohmelfs_show_stats,
1811};
1812
1813/*
1814 * Allocate private superblock and create root dir.
1815 */
1816static int pohmelfs_fill_super(struct super_block *sb, void *data, int silent)
1817{
1818 struct pohmelfs_sb *psb;
1819 int err = -ENOMEM;
1820 struct inode *root;
1821 struct pohmelfs_inode *npi;
1822 struct qstr str;
1823
1824 psb = kzalloc(sizeof(struct pohmelfs_sb), GFP_KERNEL);
1825 if (!psb)
1826 goto err_out_exit;
1827
1828 err = bdi_init(&psb->bdi);
1829 if (err)
1830 goto err_out_free_sb;
1831
1832 err = bdi_register(&psb->bdi, NULL, "pfs-%d", atomic_inc_return(&psb_bdi_num));
1833 if (err) {
1834 bdi_destroy(&psb->bdi);
1835 goto err_out_free_sb;
1836 }
1837
1838 sb->s_fs_info = psb;
1839 sb->s_op = &pohmelfs_sb_ops;
1840 sb->s_magic = POHMELFS_MAGIC_NUM;
1841 sb->s_maxbytes = MAX_LFS_FILESIZE;
1842 sb->s_blocksize = PAGE_SIZE;
1843 sb->s_bdi = &psb->bdi;
1844
1845 psb->sb = sb;
1846
1847 psb->ino = 2;
1848 psb->idx = 0;
1849 psb->active_state = NULL;
1850 psb->trans_retries = 5;
1851 psb->trans_data_size = PAGE_SIZE;
1852 psb->drop_scan_timeout = msecs_to_jiffies(1000);
1853 psb->trans_scan_timeout = msecs_to_jiffies(5000);
1854 psb->wait_on_page_timeout = msecs_to_jiffies(5000);
1855 init_waitqueue_head(&psb->wait);
1856
1857 spin_lock_init(&psb->ino_lock);
1858
1859 INIT_LIST_HEAD(&psb->drop_list);
1860
1861 mutex_init(&psb->mcache_lock);
1862 psb->mcache_root = RB_ROOT;
1863 psb->mcache_timeout = msecs_to_jiffies(5000);
1864 atomic_long_set(&psb->mcache_gen, 0);
1865
1866 psb->trans_max_pages = 100;
1867
1868 psb->crypto_align_size = 16;
1869 psb->crypto_attached_size = 0;
1870 psb->hash_strlen = 0;
1871 psb->cipher_strlen = 0;
1872 psb->perform_crypto = 0;
1873 psb->crypto_thread_num = 2;
1874 psb->crypto_fail_unsupported = 0;
1875 mutex_init(&psb->crypto_thread_lock);
1876 INIT_LIST_HEAD(&psb->crypto_ready_list);
1877 INIT_LIST_HEAD(&psb->crypto_active_list);
1878
1879 atomic_set(&psb->trans_gen, 1);
1880 atomic_long_set(&psb->total_inodes, 0);
1881
1882 mutex_init(&psb->state_lock);
1883 INIT_LIST_HEAD(&psb->state_list);
1884
1885 err = pohmelfs_parse_options((char *) data, psb, 0);
1886 if (err)
1887 goto err_out_free_bdi;
1888
1889 err = pohmelfs_copy_crypto(psb);
1890 if (err)
1891 goto err_out_free_bdi;
1892
1893 err = pohmelfs_state_init(psb);
1894 if (err)
1895 goto err_out_free_strings;
1896
1897 err = pohmelfs_crypto_init(psb);
1898 if (err)
1899 goto err_out_state_exit;
1900
1901 err = pohmelfs_root_handshake(psb);
1902 if (err)
1903 goto err_out_crypto_exit;
1904
1905 str.name = "/";
1906 str.hash = jhash("/", 1, 0);
1907 str.len = 1;
1908
1909 npi = pohmelfs_create_entry_local(psb, NULL, &str, 0, 0755|S_IFDIR);
1910 if (IS_ERR(npi)) {
1911 err = PTR_ERR(npi);
1912 goto err_out_crypto_exit;
1913 }
1914 set_bit(NETFS_INODE_REMOTE_SYNCED, &npi->state);
1915 clear_bit(NETFS_INODE_OWNED, &npi->state);
1916
1917 root = &npi->vfs_inode;
1918
1919 sb->s_root = d_alloc_root(root);
1920 if (!sb->s_root)
1921 goto err_out_put_root;
1922
1923 INIT_DELAYED_WORK(&psb->drop_dwork, pohmelfs_drop_scan);
1924 schedule_delayed_work(&psb->drop_dwork, psb->drop_scan_timeout);
1925
1926 INIT_DELAYED_WORK(&psb->dwork, pohmelfs_trans_scan);
1927 schedule_delayed_work(&psb->dwork, psb->trans_scan_timeout);
1928
1929 return 0;
1930
1931err_out_put_root:
1932 iput(root);
1933err_out_crypto_exit:
1934 pohmelfs_crypto_exit(psb);
1935err_out_state_exit:
1936 pohmelfs_state_exit(psb);
1937err_out_free_strings:
1938 kfree(psb->cipher_string);
1939 kfree(psb->hash_string);
1940err_out_free_bdi:
1941 bdi_destroy(&psb->bdi);
1942err_out_free_sb:
1943 kfree(psb);
1944err_out_exit:
1945
1946 dprintk("%s: err: %d.\n", __func__, err);
1947 return err;
1948}
1949
1950/*
1951 * Some VFS magic here...
1952 */
1953static struct dentry *pohmelfs_mount(struct file_system_type *fs_type,
1954 int flags, const char *dev_name, void *data)
1955{
1956 return mount_nodev(fs_type, flags, data, pohmelfs_fill_super);
1957}
1958
1959/*
1960 * We need this to sync all inodes earlier, since when writeback
1961 * is invoked from the umount/mntput path dcache is already shrunk,
1962 * see generic_shutdown_super(), and no inodes can access the path.
1963 */
1964static void pohmelfs_kill_super(struct super_block *sb)
1965{
1966 sync_inodes_sb(sb);
1967 kill_anon_super(sb);
1968}
1969
1970static struct file_system_type pohmel_fs_type = {
1971 .owner = THIS_MODULE,
1972 .name = "pohmel",
1973 .mount = pohmelfs_mount,
1974 .kill_sb = pohmelfs_kill_super,
1975};
1976
1977/*
1978 * Cache and module initializations and freeing routings.
1979 */
1980static void pohmelfs_init_once(void *data)
1981{
1982 struct pohmelfs_inode *pi = data;
1983
1984 inode_init_once(&pi->vfs_inode);
1985}
1986
1987static int __init pohmelfs_init_inodecache(void)
1988{
1989 pohmelfs_inode_cache = kmem_cache_create("pohmelfs_inode_cache",
1990 sizeof(struct pohmelfs_inode),
1991 0, (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD),
1992 pohmelfs_init_once);
1993 if (!pohmelfs_inode_cache)
1994 return -ENOMEM;
1995
1996 return 0;
1997}
1998
1999static void pohmelfs_destroy_inodecache(void)
2000{
2001 kmem_cache_destroy(pohmelfs_inode_cache);
2002}
2003
2004static int __init init_pohmel_fs(void)
2005{
2006 int err;
2007
2008 err = pohmelfs_config_init();
2009 if (err)
2010 goto err_out_exit;
2011
2012 err = pohmelfs_init_inodecache();
2013 if (err)
2014 goto err_out_config_exit;
2015
2016 err = pohmelfs_mcache_init();
2017 if (err)
2018 goto err_out_destroy;
2019
2020 err = netfs_trans_init();
2021 if (err)
2022 goto err_out_mcache_exit;
2023
2024 err = register_filesystem(&pohmel_fs_type);
2025 if (err)
2026 goto err_out_trans;
2027
2028 return 0;
2029
2030err_out_trans:
2031 netfs_trans_exit();
2032err_out_mcache_exit:
2033 pohmelfs_mcache_exit();
2034err_out_destroy:
2035 pohmelfs_destroy_inodecache();
2036err_out_config_exit:
2037 pohmelfs_config_exit();
2038err_out_exit:
2039 return err;
2040}
2041
2042static void __exit exit_pohmel_fs(void)
2043{
2044 unregister_filesystem(&pohmel_fs_type);
2045 pohmelfs_destroy_inodecache();
2046 pohmelfs_mcache_exit();
2047 pohmelfs_config_exit();
2048 netfs_trans_exit();
2049}
2050
2051module_init(init_pohmel_fs);
2052module_exit(exit_pohmel_fs);
2053
2054MODULE_LICENSE("GPL");
2055MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
2056MODULE_DESCRIPTION("Pohmel filesystem");
diff --git a/drivers/staging/pohmelfs/lock.c b/drivers/staging/pohmelfs/lock.c
new file mode 100644
index 00000000000..6710114cd42
--- /dev/null
+++ b/drivers/staging/pohmelfs/lock.c
@@ -0,0 +1,182 @@
1/*
2 * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
3 * All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/module.h>
17#include <linux/backing-dev.h>
18#include <linux/fs.h>
19#include <linux/fsnotify.h>
20#include <linux/mempool.h>
21
22#include "netfs.h"
23
24static int pohmelfs_send_lock_trans(struct pohmelfs_inode *pi,
25 u64 id, u64 start, u32 size, int type)
26{
27 struct inode *inode = &pi->vfs_inode;
28 struct pohmelfs_sb *psb = POHMELFS_SB(inode->i_sb);
29 struct netfs_trans *t;
30 struct netfs_cmd *cmd;
31 int path_len, err;
32 void *data;
33 struct netfs_lock *l;
34 int isize = (type & POHMELFS_LOCK_GRAB) ? 0 : sizeof(struct netfs_inode_info);
35
36 err = pohmelfs_path_length(pi);
37 if (err < 0)
38 goto err_out_exit;
39
40 path_len = err;
41
42 err = -ENOMEM;
43 t = netfs_trans_alloc(psb, path_len + sizeof(struct netfs_lock) + isize,
44 NETFS_TRANS_SINGLE_DST, 0);
45 if (!t)
46 goto err_out_exit;
47
48 cmd = netfs_trans_current(t);
49 data = cmd + 1;
50
51 err = pohmelfs_construct_path_string(pi, data, path_len);
52 if (err < 0)
53 goto err_out_free;
54 path_len = err;
55
56 l = data + path_len;
57
58 l->start = start;
59 l->size = size;
60 l->type = type;
61 l->ino = pi->ino;
62
63 cmd->cmd = NETFS_LOCK;
64 cmd->start = 0;
65 cmd->id = id;
66 cmd->size = sizeof(struct netfs_lock) + path_len + isize;
67 cmd->ext = path_len;
68 cmd->csize = 0;
69
70 netfs_convert_cmd(cmd);
71 netfs_convert_lock(l);
72
73 if (isize) {
74 struct netfs_inode_info *info = (struct netfs_inode_info *)(l + 1);
75
76 info->mode = inode->i_mode;
77 info->nlink = inode->i_nlink;
78 info->uid = inode->i_uid;
79 info->gid = inode->i_gid;
80 info->blocks = inode->i_blocks;
81 info->rdev = inode->i_rdev;
82 info->size = inode->i_size;
83 info->version = inode->i_version;
84
85 netfs_convert_inode_info(info);
86 }
87
88 netfs_trans_update(cmd, t, path_len + sizeof(struct netfs_lock) + isize);
89
90 return netfs_trans_finish(t, psb);
91
92err_out_free:
93 netfs_trans_free(t);
94err_out_exit:
95 printk("%s: err: %d.\n", __func__, err);
96 return err;
97}
98
99int pohmelfs_data_lock(struct pohmelfs_inode *pi, u64 start, u32 size, int type)
100{
101 struct pohmelfs_sb *psb = POHMELFS_SB(pi->vfs_inode.i_sb);
102 struct pohmelfs_mcache *m;
103 int err = -ENOMEM;
104 struct iattr iattr;
105 struct inode *inode = &pi->vfs_inode;
106
107 dprintk("%s: %p: ino: %llu, start: %llu, size: %u, "
108 "type: %d, locked as: %d, owned: %d.\n",
109 __func__, &pi->vfs_inode, pi->ino,
110 start, size, type, pi->lock_type,
111 !!test_bit(NETFS_INODE_OWNED, &pi->state));
112
113 if (!pohmelfs_need_lock(pi, type))
114 return 0;
115
116 m = pohmelfs_mcache_alloc(psb, start, size, NULL);
117 if (IS_ERR(m))
118 return PTR_ERR(m);
119
120 err = pohmelfs_send_lock_trans(pi, m->gen, start, size,
121 type | POHMELFS_LOCK_GRAB);
122 if (err)
123 goto err_out_put;
124
125 err = wait_for_completion_timeout(&m->complete, psb->mcache_timeout);
126 if (err)
127 err = m->err;
128 else
129 err = -ETIMEDOUT;
130
131 if (err) {
132 printk("%s: %p: ino: %llu, mgen: %llu, start: %llu, size: %u, err: %d.\n",
133 __func__, &pi->vfs_inode, pi->ino, m->gen, start, size, err);
134 }
135
136 if (err && (err != -ENOENT))
137 goto err_out_put;
138
139 if (!err) {
140 netfs_convert_inode_info(&m->info);
141
142 iattr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_SIZE | ATTR_ATIME;
143 iattr.ia_mode = m->info.mode;
144 iattr.ia_uid = m->info.uid;
145 iattr.ia_gid = m->info.gid;
146 iattr.ia_size = m->info.size;
147 iattr.ia_atime = CURRENT_TIME;
148
149 dprintk("%s: %p: ino: %llu, mgen: %llu, start: %llu, isize: %llu -> %llu.\n",
150 __func__, &pi->vfs_inode, pi->ino, m->gen, start, inode->i_size, m->info.size);
151
152 err = pohmelfs_setattr_raw(inode, &iattr);
153 if (!err) {
154 struct dentry *dentry = d_find_alias(inode);
155 if (dentry) {
156 fsnotify_change(dentry, iattr.ia_valid);
157 dput(dentry);
158 }
159 }
160 }
161
162 pi->lock_type = type;
163 set_bit(NETFS_INODE_OWNED, &pi->state);
164
165 pohmelfs_mcache_put(psb, m);
166
167 return 0;
168
169err_out_put:
170 pohmelfs_mcache_put(psb, m);
171 return err;
172}
173
174int pohmelfs_data_unlock(struct pohmelfs_inode *pi, u64 start, u32 size, int type)
175{
176 dprintk("%s: %p: ino: %llu, start: %llu, size: %u, type: %d.\n",
177 __func__, &pi->vfs_inode, pi->ino, start, size, type);
178 pi->lock_type = 0;
179 clear_bit(NETFS_INODE_REMOTE_DIR_SYNCED, &pi->state);
180 clear_bit(NETFS_INODE_OWNED, &pi->state);
181 return pohmelfs_send_lock_trans(pi, pi->ino, start, size, type);
182}
diff --git a/drivers/staging/pohmelfs/mcache.c b/drivers/staging/pohmelfs/mcache.c
new file mode 100644
index 00000000000..e22665cdd16
--- /dev/null
+++ b/drivers/staging/pohmelfs/mcache.c
@@ -0,0 +1,171 @@
1/*
2 * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
3 * All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/module.h>
17#include <linux/slab.h>
18#include <linux/mempool.h>
19
20#include "netfs.h"
21
22static struct kmem_cache *pohmelfs_mcache_cache;
23static mempool_t *pohmelfs_mcache_pool;
24
25static inline int pohmelfs_mcache_cmp(u64 gen, u64 new)
26{
27 if (gen < new)
28 return 1;
29 if (gen > new)
30 return -1;
31 return 0;
32}
33
34struct pohmelfs_mcache *pohmelfs_mcache_search(struct pohmelfs_sb *psb, u64 gen)
35{
36 struct rb_root *root = &psb->mcache_root;
37 struct rb_node *n = root->rb_node;
38 struct pohmelfs_mcache *tmp, *ret = NULL;
39 int cmp;
40
41 while (n) {
42 tmp = rb_entry(n, struct pohmelfs_mcache, mcache_entry);
43
44 cmp = pohmelfs_mcache_cmp(tmp->gen, gen);
45 if (cmp < 0)
46 n = n->rb_left;
47 else if (cmp > 0)
48 n = n->rb_right;
49 else {
50 ret = tmp;
51 pohmelfs_mcache_get(ret);
52 break;
53 }
54 }
55
56 return ret;
57}
58
59static int pohmelfs_mcache_insert(struct pohmelfs_sb *psb, struct pohmelfs_mcache *m)
60{
61 struct rb_root *root = &psb->mcache_root;
62 struct rb_node **n = &root->rb_node, *parent = NULL;
63 struct pohmelfs_mcache *ret = NULL, *tmp;
64 int cmp;
65
66 while (*n) {
67 parent = *n;
68
69 tmp = rb_entry(parent, struct pohmelfs_mcache, mcache_entry);
70
71 cmp = pohmelfs_mcache_cmp(tmp->gen, m->gen);
72 if (cmp < 0)
73 n = &parent->rb_left;
74 else if (cmp > 0)
75 n = &parent->rb_right;
76 else {
77 ret = tmp;
78 break;
79 }
80 }
81
82 if (ret)
83 return -EEXIST;
84
85 rb_link_node(&m->mcache_entry, parent, n);
86 rb_insert_color(&m->mcache_entry, root);
87
88 return 0;
89}
90
91static int pohmelfs_mcache_remove(struct pohmelfs_sb *psb, struct pohmelfs_mcache *m)
92{
93 if (m && m->mcache_entry.rb_parent_color) {
94 rb_erase(&m->mcache_entry, &psb->mcache_root);
95 m->mcache_entry.rb_parent_color = 0;
96 return 1;
97 }
98 return 0;
99}
100
101void pohmelfs_mcache_remove_locked(struct pohmelfs_sb *psb, struct pohmelfs_mcache *m)
102{
103 mutex_lock(&psb->mcache_lock);
104 pohmelfs_mcache_remove(psb, m);
105 mutex_unlock(&psb->mcache_lock);
106}
107
108struct pohmelfs_mcache *pohmelfs_mcache_alloc(struct pohmelfs_sb *psb, u64 start,
109 unsigned int size, void *data)
110{
111 struct pohmelfs_mcache *m;
112 int err = -ENOMEM;
113
114 m = mempool_alloc(pohmelfs_mcache_pool, GFP_KERNEL);
115 if (!m)
116 goto err_out_exit;
117
118 init_completion(&m->complete);
119 m->err = 0;
120 atomic_set(&m->refcnt, 1);
121 m->data = data;
122 m->start = start;
123 m->size = size;
124 m->gen = atomic_long_inc_return(&psb->mcache_gen);
125
126 mutex_lock(&psb->mcache_lock);
127 err = pohmelfs_mcache_insert(psb, m);
128 mutex_unlock(&psb->mcache_lock);
129 if (err)
130 goto err_out_free;
131
132 return m;
133
134err_out_free:
135 mempool_free(m, pohmelfs_mcache_pool);
136err_out_exit:
137 return ERR_PTR(err);
138}
139
140void pohmelfs_mcache_free(struct pohmelfs_sb *psb, struct pohmelfs_mcache *m)
141{
142 pohmelfs_mcache_remove_locked(psb, m);
143
144 mempool_free(m, pohmelfs_mcache_pool);
145}
146
147int __init pohmelfs_mcache_init(void)
148{
149 pohmelfs_mcache_cache = kmem_cache_create("pohmelfs_mcache_cache",
150 sizeof(struct pohmelfs_mcache),
151 0, (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD), NULL);
152 if (!pohmelfs_mcache_cache)
153 goto err_out_exit;
154
155 pohmelfs_mcache_pool = mempool_create_slab_pool(256, pohmelfs_mcache_cache);
156 if (!pohmelfs_mcache_pool)
157 goto err_out_free;
158
159 return 0;
160
161err_out_free:
162 kmem_cache_destroy(pohmelfs_mcache_cache);
163err_out_exit:
164 return -ENOMEM;
165}
166
167void pohmelfs_mcache_exit(void)
168{
169 mempool_destroy(pohmelfs_mcache_pool);
170 kmem_cache_destroy(pohmelfs_mcache_cache);
171}
diff --git a/drivers/staging/pohmelfs/net.c b/drivers/staging/pohmelfs/net.c
new file mode 100644
index 00000000000..b2e91862208
--- /dev/null
+++ b/drivers/staging/pohmelfs/net.c
@@ -0,0 +1,1209 @@
1/*
2 * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
3 * All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/fsnotify.h>
17#include <linux/jhash.h>
18#include <linux/in.h>
19#include <linux/in6.h>
20#include <linux/kthread.h>
21#include <linux/pagemap.h>
22#include <linux/poll.h>
23#include <linux/slab.h>
24#include <linux/swap.h>
25#include <linux/syscalls.h>
26#include <linux/vmalloc.h>
27
28#include "netfs.h"
29
30/*
31 * Async machinery lives here.
32 * All commands being sent to server do _not_ require sync reply,
33 * instead, if it is really needed, like readdir or readpage, caller
34 * sleeps waiting for data, which will be placed into provided buffer
35 * and caller will be awakened.
36 *
37 * Every command response can come without some listener. For example
38 * readdir response will add new objects into cache without appropriate
39 * request from userspace. This is used in cache coherency.
40 *
41 * If object is not found for given data, it is discarded.
42 *
43 * All requests are received by dedicated kernel thread.
44 */
45
46/*
47 * Basic network sending/receiving functions.
48 * Blocked mode is used.
49 */
50static int netfs_data_recv(struct netfs_state *st, void *buf, u64 size)
51{
52 struct msghdr msg;
53 struct kvec iov;
54 int err;
55
56 BUG_ON(!size);
57
58 iov.iov_base = buf;
59 iov.iov_len = size;
60
61 msg.msg_iov = (struct iovec *)&iov;
62 msg.msg_iovlen = 1;
63 msg.msg_name = NULL;
64 msg.msg_namelen = 0;
65 msg.msg_control = NULL;
66 msg.msg_controllen = 0;
67 msg.msg_flags = MSG_DONTWAIT;
68
69 err = kernel_recvmsg(st->socket, &msg, &iov, 1, iov.iov_len,
70 msg.msg_flags);
71 if (err <= 0) {
72 printk("%s: failed to recv data: size: %llu, err: %d.\n", __func__, size, err);
73 if (err == 0)
74 err = -ECONNRESET;
75 }
76
77 return err;
78}
79
80static int pohmelfs_data_recv(struct netfs_state *st, void *data, unsigned int size)
81{
82 unsigned int revents = 0;
83 unsigned int err_mask = POLLERR | POLLHUP | POLLRDHUP;
84 unsigned int mask = err_mask | POLLIN;
85 int err = 0;
86
87 while (size && !err) {
88 revents = netfs_state_poll(st);
89
90 if (!(revents & mask)) {
91 DEFINE_WAIT(wait);
92
93 for (;;) {
94 prepare_to_wait(&st->thread_wait, &wait, TASK_INTERRUPTIBLE);
95 if (kthread_should_stop())
96 break;
97
98 revents = netfs_state_poll(st);
99
100 if (revents & mask)
101 break;
102
103 if (signal_pending(current))
104 break;
105
106 schedule();
107 continue;
108 }
109 finish_wait(&st->thread_wait, &wait);
110 }
111
112 err = 0;
113 netfs_state_lock(st);
114 if (st->socket && (st->read_socket == st->socket) && (revents & POLLIN)) {
115 err = netfs_data_recv(st, data, size);
116 if (err > 0) {
117 data += err;
118 size -= err;
119 err = 0;
120 } else if (err == 0)
121 err = -ECONNRESET;
122 }
123
124 if (revents & err_mask) {
125 printk("%s: revents: %x, socket: %p, size: %u, err: %d.\n",
126 __func__, revents, st->socket, size, err);
127 err = -ECONNRESET;
128 }
129 netfs_state_unlock(st);
130
131 if (err < 0) {
132 if (netfs_state_trylock_send(st)) {
133 netfs_state_exit(st);
134 err = netfs_state_init(st);
135 if (!err)
136 err = -EAGAIN;
137 netfs_state_unlock_send(st);
138 } else {
139 st->need_reset = 1;
140 }
141 }
142
143 if (kthread_should_stop())
144 err = -ENODEV;
145
146 if (err)
147 printk("%s: socket: %p, read_socket: %p, revents: %x, rev_error: %d, "
148 "should_stop: %d, size: %u, err: %d.\n",
149 __func__, st->socket, st->read_socket,
150 revents, revents & err_mask, kthread_should_stop(), size, err);
151 }
152
153 return err;
154}
155
156int pohmelfs_data_recv_and_check(struct netfs_state *st, void *data, unsigned int size)
157{
158 struct netfs_cmd *cmd = &st->cmd;
159 int err;
160
161 err = pohmelfs_data_recv(st, data, size);
162 if (err)
163 return err;
164
165 return pohmelfs_crypto_process_input_data(&st->eng, cmd->iv, data, NULL, size);
166}
167
168/*
169 * Polling machinery.
170 */
171
172struct netfs_poll_helper {
173 poll_table pt;
174 struct netfs_state *st;
175};
176
177static int netfs_queue_wake(wait_queue_t *wait, unsigned mode, int sync, void *key)
178{
179 struct netfs_state *st = container_of(wait, struct netfs_state, wait);
180
181 wake_up(&st->thread_wait);
182 return 1;
183}
184
185static void netfs_queue_func(struct file *file, wait_queue_head_t *whead,
186 poll_table *pt)
187{
188 struct netfs_state *st = container_of(pt, struct netfs_poll_helper, pt)->st;
189
190 st->whead = whead;
191 init_waitqueue_func_entry(&st->wait, netfs_queue_wake);
192 add_wait_queue(whead, &st->wait);
193}
194
195static void netfs_poll_exit(struct netfs_state *st)
196{
197 if (st->whead) {
198 remove_wait_queue(st->whead, &st->wait);
199 st->whead = NULL;
200 }
201}
202
203static int netfs_poll_init(struct netfs_state *st)
204{
205 struct netfs_poll_helper ph;
206
207 ph.st = st;
208 init_poll_funcptr(&ph.pt, &netfs_queue_func);
209
210 st->socket->ops->poll(NULL, st->socket, &ph.pt);
211 return 0;
212}
213
214/*
215 * Get response for readpage command. We search inode and page in its mapping
216 * and copy data into. If it was async request, then we queue page into shared
217 * data and wakeup listener, who will copy it to userspace.
218 *
219 * There is a work in progress of allowing to call copy_to_user() directly from
220 * async receiving kernel thread.
221 */
222static int pohmelfs_read_page_response(struct netfs_state *st)
223{
224 struct pohmelfs_sb *psb = st->psb;
225 struct netfs_cmd *cmd = &st->cmd;
226 struct inode *inode;
227 struct page *page;
228 int err = 0;
229
230 if (cmd->size > PAGE_CACHE_SIZE) {
231 err = -EINVAL;
232 goto err_out_exit;
233 }
234
235 inode = ilookup(st->psb->sb, cmd->id);
236 if (!inode) {
237 printk("%s: failed to find inode: id: %llu.\n", __func__, cmd->id);
238 err = -ENOENT;
239 goto err_out_exit;
240 }
241
242 page = find_get_page(inode->i_mapping, cmd->start >> PAGE_CACHE_SHIFT);
243 if (!page || !PageLocked(page)) {
244 printk("%s: failed to find/lock page: page: %p, id: %llu, start: %llu, index: %llu.\n",
245 __func__, page, cmd->id, cmd->start, cmd->start >> PAGE_CACHE_SHIFT);
246
247 while (cmd->size) {
248 unsigned int sz = min(cmd->size, st->size);
249
250 err = pohmelfs_data_recv(st, st->data, sz);
251 if (err)
252 break;
253
254 cmd->size -= sz;
255 }
256
257 err = -ENODEV;
258 if (page)
259 goto err_out_page_put;
260 goto err_out_put;
261 }
262
263 if (cmd->size) {
264 void *addr;
265
266 addr = kmap(page);
267 err = pohmelfs_data_recv(st, addr, cmd->size);
268 kunmap(page);
269
270 if (err)
271 goto err_out_page_unlock;
272 }
273
274 dprintk("%s: page: %p, start: %llu, size: %u, locked: %d.\n",
275 __func__, page, cmd->start, cmd->size, PageLocked(page));
276
277 SetPageChecked(page);
278 if ((psb->hash_string || psb->cipher_string) && psb->perform_crypto && cmd->size) {
279 err = pohmelfs_crypto_process_input_page(&st->eng, page, cmd->size, cmd->iv);
280 if (err < 0)
281 goto err_out_page_unlock;
282 } else {
283 SetPageUptodate(page);
284 unlock_page(page);
285 page_cache_release(page);
286 }
287
288 pohmelfs_put_inode(POHMELFS_I(inode));
289 wake_up(&st->psb->wait);
290
291 return 0;
292
293err_out_page_unlock:
294 SetPageError(page);
295 unlock_page(page);
296err_out_page_put:
297 page_cache_release(page);
298err_out_put:
299 pohmelfs_put_inode(POHMELFS_I(inode));
300err_out_exit:
301 wake_up(&st->psb->wait);
302 return err;
303}
304
305static int pohmelfs_check_name(struct pohmelfs_inode *parent, struct qstr *str,
306 struct netfs_inode_info *info)
307{
308 struct inode *inode;
309 struct pohmelfs_name *n;
310 int err = 0;
311 u64 ino = 0;
312
313 mutex_lock(&parent->offset_lock);
314 n = pohmelfs_search_hash(parent, str->hash);
315 if (n)
316 ino = n->ino;
317 mutex_unlock(&parent->offset_lock);
318
319 if (!ino)
320 goto out;
321
322 inode = ilookup(parent->vfs_inode.i_sb, ino);
323 if (!inode)
324 goto out;
325
326 dprintk("%s: parent: %llu, inode: %llu.\n", __func__, parent->ino, ino);
327
328 pohmelfs_fill_inode(inode, info);
329 pohmelfs_put_inode(POHMELFS_I(inode));
330 err = -EEXIST;
331out:
332 return err;
333}
334
335/*
336 * Readdir response from server. If special field is set, we wakeup
337 * listener (readdir() call), which will copy data to userspace.
338 */
339static int pohmelfs_readdir_response(struct netfs_state *st)
340{
341 struct inode *inode;
342 struct netfs_cmd *cmd = &st->cmd;
343 struct netfs_inode_info *info;
344 struct pohmelfs_inode *parent = NULL, *npi;
345 int err = 0, last = cmd->ext;
346 struct qstr str;
347
348 if (cmd->size > st->size)
349 return -EINVAL;
350
351 inode = ilookup(st->psb->sb, cmd->id);
352 if (!inode) {
353 printk("%s: failed to find inode: id: %llu.\n", __func__, cmd->id);
354 return -ENOENT;
355 }
356 parent = POHMELFS_I(inode);
357
358 if (!cmd->size && cmd->start) {
359 err = -cmd->start;
360 goto out;
361 }
362
363 if (cmd->size) {
364 char *name;
365
366 err = pohmelfs_data_recv_and_check(st, st->data, cmd->size);
367 if (err)
368 goto err_out_put;
369
370 info = (struct netfs_inode_info *)(st->data);
371
372 name = (char *)(info + 1);
373 str.len = cmd->size - sizeof(struct netfs_inode_info) - 1 - cmd->cpad;
374 name[str.len] = 0;
375 str.name = name;
376 str.hash = jhash(str.name, str.len, 0);
377
378 netfs_convert_inode_info(info);
379
380 if (parent) {
381 err = pohmelfs_check_name(parent, &str, info);
382 if (err) {
383 if (err == -EEXIST)
384 err = 0;
385 goto out;
386 }
387 }
388
389 info->ino = cmd->start;
390 if (!info->ino)
391 info->ino = pohmelfs_new_ino(st->psb);
392
393 dprintk("%s: parent: %llu, ino: %llu, name: '%s', hash: %x, len: %u, mode: %o.\n",
394 __func__, parent->ino, info->ino, str.name, str.hash, str.len,
395 info->mode);
396
397 npi = pohmelfs_new_inode(st->psb, parent, &str, info, 0);
398 if (IS_ERR(npi)) {
399 err = PTR_ERR(npi);
400
401 if (err != -EEXIST)
402 goto err_out_put;
403 } else {
404 struct dentry *dentry, *alias, *pd;
405
406 set_bit(NETFS_INODE_REMOTE_SYNCED, &npi->state);
407 clear_bit(NETFS_INODE_OWNED, &npi->state);
408
409 pd = d_find_alias(&parent->vfs_inode);
410 if (pd) {
411 str.hash = full_name_hash(str.name, str.len);
412 dentry = d_alloc(pd, &str);
413 if (dentry) {
414 alias = d_materialise_unique(dentry, &npi->vfs_inode);
415 if (alias)
416 dput(alias);
417 }
418
419 dput(dentry);
420 dput(pd);
421 }
422 }
423 }
424out:
425 if (last) {
426 set_bit(NETFS_INODE_REMOTE_DIR_SYNCED, &parent->state);
427 set_bit(NETFS_INODE_REMOTE_SYNCED, &parent->state);
428 wake_up(&st->psb->wait);
429 }
430 pohmelfs_put_inode(parent);
431
432 return err;
433
434err_out_put:
435 clear_bit(NETFS_INODE_REMOTE_DIR_SYNCED, &parent->state);
436 printk("%s: parent: %llu, ino: %llu, cmd_id: %llu.\n", __func__, parent->ino, cmd->start, cmd->id);
437 pohmelfs_put_inode(parent);
438 wake_up(&st->psb->wait);
439 return err;
440}
441
442/*
443 * Lookup command response.
444 * It searches for inode to be looked at (if it exists) and substitutes
445 * its inode information (size, permission, mode and so on), if inode does
446 * not exist, new one will be created and inserted into caches.
447 */
448static int pohmelfs_lookup_response(struct netfs_state *st)
449{
450 struct inode *inode = NULL;
451 struct netfs_cmd *cmd = &st->cmd;
452 struct netfs_inode_info *info;
453 struct pohmelfs_inode *parent = NULL, *npi;
454 int err = -EINVAL;
455 char *name;
456
457 inode = ilookup(st->psb->sb, cmd->id);
458 if (!inode) {
459 printk("%s: lookup response: id: %llu, start: %llu, size: %u.\n",
460 __func__, cmd->id, cmd->start, cmd->size);
461 err = -ENOENT;
462 goto err_out_exit;
463 }
464 parent = POHMELFS_I(inode);
465
466 if (!cmd->size) {
467 err = -cmd->start;
468 goto err_out_put;
469 }
470
471 if (cmd->size < sizeof(struct netfs_inode_info)) {
472 printk("%s: broken lookup response: id: %llu, start: %llu, size: %u.\n",
473 __func__, cmd->id, cmd->start, cmd->size);
474 err = -EINVAL;
475 goto err_out_put;
476 }
477
478 err = pohmelfs_data_recv_and_check(st, st->data, cmd->size);
479 if (err)
480 goto err_out_put;
481
482 info = (struct netfs_inode_info *)(st->data);
483 name = (char *)(info + 1);
484
485 netfs_convert_inode_info(info);
486
487 info->ino = cmd->start;
488 if (!info->ino)
489 info->ino = pohmelfs_new_ino(st->psb);
490
491 dprintk("%s: parent: %llu, ino: %llu, name: '%s', start: %llu.\n",
492 __func__, parent->ino, info->ino, name, cmd->start);
493
494 if (cmd->start)
495 npi = pohmelfs_new_inode(st->psb, parent, NULL, info, 0);
496 else {
497 struct qstr str;
498
499 str.name = name;
500 str.len = cmd->size - sizeof(struct netfs_inode_info) - 1 - cmd->cpad;
501 str.hash = jhash(name, str.len, 0);
502
503 npi = pohmelfs_new_inode(st->psb, parent, &str, info, 0);
504 }
505 if (IS_ERR(npi)) {
506 err = PTR_ERR(npi);
507
508 if (err != -EEXIST)
509 goto err_out_put;
510 } else {
511 set_bit(NETFS_INODE_REMOTE_SYNCED, &npi->state);
512 clear_bit(NETFS_INODE_OWNED, &npi->state);
513 }
514
515 clear_bit(NETFS_COMMAND_PENDING, &parent->state);
516 pohmelfs_put_inode(parent);
517
518 wake_up(&st->psb->wait);
519
520 return 0;
521
522err_out_put:
523 pohmelfs_put_inode(parent);
524err_out_exit:
525 clear_bit(NETFS_COMMAND_PENDING, &parent->state);
526 wake_up(&st->psb->wait);
527 printk("%s: inode: %p, id: %llu, start: %llu, size: %u, err: %d.\n",
528 __func__, inode, cmd->id, cmd->start, cmd->size, err);
529 return err;
530}
531
532/*
533 * Create response, just marks local inode as 'created', so that writeback
534 * for any of its children (or own) would not try to sync it again.
535 */
536static int pohmelfs_create_response(struct netfs_state *st)
537{
538 struct inode *inode;
539 struct netfs_cmd *cmd = &st->cmd;
540 struct pohmelfs_inode *pi;
541
542 inode = ilookup(st->psb->sb, cmd->id);
543 if (!inode) {
544 printk("%s: failed to find inode: id: %llu, start: %llu.\n",
545 __func__, cmd->id, cmd->start);
546 goto err_out_exit;
547 }
548
549 pi = POHMELFS_I(inode);
550
551 /*
552 * To lock or not to lock?
553 * We actually do not care if it races...
554 */
555 if (cmd->start)
556 make_bad_inode(inode);
557 set_bit(NETFS_INODE_REMOTE_SYNCED, &pi->state);
558
559 pohmelfs_put_inode(pi);
560
561 wake_up(&st->psb->wait);
562 return 0;
563
564err_out_exit:
565 wake_up(&st->psb->wait);
566 return -ENOENT;
567}
568
569/*
570 * Object remove response. Just says that remove request has been received.
571 * Used in cache coherency protocol.
572 */
573static int pohmelfs_remove_response(struct netfs_state *st)
574{
575 struct netfs_cmd *cmd = &st->cmd;
576 int err;
577
578 err = pohmelfs_data_recv_and_check(st, st->data, cmd->size);
579 if (err)
580 return err;
581
582 dprintk("%s: parent: %llu, path: '%s'.\n", __func__, cmd->id, (char *)st->data);
583
584 return 0;
585}
586
587/*
588 * Transaction reply processing.
589 *
590 * Find transaction based on its generation number, bump its reference counter,
591 * so that none could free it under us, drop from the trees and lists and
592 * drop reference counter. When it hits zero (when all destinations replied
593 * and all timeout handled by async scanning code), completion will be called
594 * and transaction will be freed.
595 */
596static int pohmelfs_transaction_response(struct netfs_state *st)
597{
598 struct netfs_trans_dst *dst;
599 struct netfs_trans *t = NULL;
600 struct netfs_cmd *cmd = &st->cmd;
601 short err = (signed)cmd->ext;
602
603 mutex_lock(&st->trans_lock);
604 dst = netfs_trans_search(st, cmd->start);
605 if (dst) {
606 netfs_trans_remove_nolock(dst, st);
607 t = dst->trans;
608 }
609 mutex_unlock(&st->trans_lock);
610
611 if (!t) {
612 printk("%s: failed to find transaction: start: %llu: id: %llu, size: %u, ext: %u.\n",
613 __func__, cmd->start, cmd->id, cmd->size, cmd->ext);
614 err = -EINVAL;
615 goto out;
616 }
617
618 t->result = err;
619 netfs_trans_drop_dst_nostate(dst);
620
621out:
622 wake_up(&st->psb->wait);
623 return err;
624}
625
626/*
627 * Inode metadata cache coherency message.
628 */
629static int pohmelfs_page_cache_response(struct netfs_state *st)
630{
631 struct netfs_cmd *cmd = &st->cmd;
632 struct inode *inode;
633
634 dprintk("%s: st: %p, id: %llu, start: %llu, size: %u.\n", __func__, st, cmd->id, cmd->start, cmd->size);
635
636 inode = ilookup(st->psb->sb, cmd->id);
637 if (!inode) {
638 printk("%s: failed to find inode: id: %llu.\n", __func__, cmd->id);
639 return -ENOENT;
640 }
641
642 set_bit(NETFS_INODE_NEED_FLUSH, &POHMELFS_I(inode)->state);
643 pohmelfs_put_inode(POHMELFS_I(inode));
644
645 return 0;
646}
647
648/*
649 * Root capabilities response: export statistics
650 * like used and available size, number of files and dirs,
651 * permissions.
652 */
653static int pohmelfs_root_cap_response(struct netfs_state *st)
654{
655 struct netfs_cmd *cmd = &st->cmd;
656 struct netfs_root_capabilities *cap;
657 struct pohmelfs_sb *psb = st->psb;
658
659 if (cmd->size != sizeof(struct netfs_root_capabilities)) {
660 psb->flags = EPROTO;
661 wake_up(&psb->wait);
662 return -EPROTO;
663 }
664
665 cap = st->data;
666
667 netfs_convert_root_capabilities(cap);
668
669 if (psb->total_size < cap->used + cap->avail)
670 psb->total_size = cap->used + cap->avail;
671 if (cap->avail)
672 psb->avail_size = cap->avail;
673 psb->state_flags = cap->flags;
674
675 if (psb->state_flags & POHMELFS_FLAGS_RO) {
676 psb->sb->s_flags |= MS_RDONLY;
677 printk(KERN_INFO "Mounting POHMELFS (%d) read-only.\n", psb->idx);
678 }
679
680 if (psb->state_flags & POHMELFS_FLAGS_XATTR)
681 printk(KERN_INFO "Mounting POHMELFS (%d) "
682 "with extended attributes support.\n", psb->idx);
683
684 if (atomic_long_read(&psb->total_inodes) <= 1)
685 atomic_long_set(&psb->total_inodes, cap->nr_files);
686
687 dprintk("%s: total: %llu, avail: %llu, flags: %llx, inodes: %llu.\n",
688 __func__, psb->total_size, psb->avail_size, psb->state_flags, cap->nr_files);
689
690 psb->flags = 0;
691 wake_up(&psb->wait);
692 return 0;
693}
694
695/*
696 * Crypto capabilities of the server, where it says that
697 * it supports or does not requested hash/cipher algorithms.
698 */
699static int pohmelfs_crypto_cap_response(struct netfs_state *st)
700{
701 struct netfs_cmd *cmd = &st->cmd;
702 struct netfs_crypto_capabilities *cap;
703 struct pohmelfs_sb *psb = st->psb;
704 int err = 0;
705
706 if (cmd->size != sizeof(struct netfs_crypto_capabilities)) {
707 psb->flags = EPROTO;
708 wake_up(&psb->wait);
709 return -EPROTO;
710 }
711
712 cap = st->data;
713
714 dprintk("%s: cipher '%s': %s, hash: '%s': %s.\n",
715 __func__,
716 psb->cipher_string, (cap->cipher_strlen) ? "SUPPORTED" : "NOT SUPPORTED",
717 psb->hash_string, (cap->hash_strlen) ? "SUPPORTED" : "NOT SUPPORTED");
718
719 if (!cap->hash_strlen) {
720 if (psb->hash_strlen && psb->crypto_fail_unsupported)
721 err = -ENOTSUPP;
722 psb->hash_strlen = 0;
723 kfree(psb->hash_string);
724 psb->hash_string = NULL;
725 }
726
727 if (!cap->cipher_strlen) {
728 if (psb->cipher_strlen && psb->crypto_fail_unsupported)
729 err = -ENOTSUPP;
730 psb->cipher_strlen = 0;
731 kfree(psb->cipher_string);
732 psb->cipher_string = NULL;
733 }
734
735 return err;
736}
737
738/*
739 * Capabilities handshake response.
740 */
741static int pohmelfs_capabilities_response(struct netfs_state *st)
742{
743 struct netfs_cmd *cmd = &st->cmd;
744 int err = 0;
745
746 err = pohmelfs_data_recv(st, st->data, cmd->size);
747 if (err)
748 return err;
749
750 switch (cmd->id) {
751 case POHMELFS_CRYPTO_CAPABILITIES:
752 return pohmelfs_crypto_cap_response(st);
753 case POHMELFS_ROOT_CAPABILITIES:
754 return pohmelfs_root_cap_response(st);
755 default:
756 break;
757 }
758 return -EINVAL;
759}
760
761/*
762 * Receiving extended attribute.
763 * Does not work properly if received size is more than requested one,
764 * it should not happen with current request/reply model though.
765 */
766static int pohmelfs_getxattr_response(struct netfs_state *st)
767{
768 struct pohmelfs_sb *psb = st->psb;
769 struct netfs_cmd *cmd = &st->cmd;
770 struct pohmelfs_mcache *m;
771 short error = (signed short)cmd->ext, err;
772 unsigned int sz, total_size;
773
774 m = pohmelfs_mcache_search(psb, cmd->id);
775
776 dprintk("%s: id: %llu, gen: %llu, err: %d.\n",
777 __func__, cmd->id, (m) ? m->gen : 0, error);
778
779 if (!m) {
780 printk("%s: failed to find getxattr cache entry: id: %llu.\n", __func__, cmd->id);
781 return -ENOENT;
782 }
783
784 if (cmd->size) {
785 sz = min_t(unsigned int, cmd->size, m->size);
786 err = pohmelfs_data_recv_and_check(st, m->data, sz);
787 if (err) {
788 error = err;
789 goto out;
790 }
791
792 m->size = sz;
793 total_size = cmd->size - sz;
794
795 while (total_size) {
796 sz = min(total_size, st->size);
797
798 err = pohmelfs_data_recv_and_check(st, st->data, sz);
799 if (err) {
800 error = err;
801 break;
802 }
803
804 total_size -= sz;
805 }
806 }
807
808out:
809 m->err = error;
810 complete(&m->complete);
811 pohmelfs_mcache_put(psb, m);
812
813 return error;
814}
815
816int pohmelfs_data_lock_response(struct netfs_state *st)
817{
818 struct pohmelfs_sb *psb = st->psb;
819 struct netfs_cmd *cmd = &st->cmd;
820 struct pohmelfs_mcache *m;
821 short err = (signed short)cmd->ext;
822 u64 id = cmd->id;
823
824 m = pohmelfs_mcache_search(psb, id);
825
826 dprintk("%s: id: %llu, gen: %llu, err: %d.\n",
827 __func__, cmd->id, (m) ? m->gen : 0, err);
828
829 if (!m) {
830 pohmelfs_data_recv(st, st->data, cmd->size);
831 printk("%s: failed to find data lock response: id: %llu.\n", __func__, cmd->id);
832 return -ENOENT;
833 }
834
835 if (cmd->size)
836 err = pohmelfs_data_recv_and_check(st, &m->info, cmd->size);
837
838 m->err = err;
839 complete(&m->complete);
840 pohmelfs_mcache_put(psb, m);
841
842 return err;
843}
844
845static void __inline__ netfs_state_reset(struct netfs_state *st)
846{
847 netfs_state_lock_send(st);
848 netfs_state_exit(st);
849 netfs_state_init(st);
850 netfs_state_unlock_send(st);
851}
852
853/*
854 * Main receiving function, called from dedicated kernel thread.
855 */
856static int pohmelfs_recv(void *data)
857{
858 int err = -EINTR;
859 struct netfs_state *st = data;
860 struct netfs_cmd *cmd = &st->cmd;
861
862 while (!kthread_should_stop()) {
863 /*
864 * If socket will be reset after this statement, then
865 * pohmelfs_data_recv() will just fail and loop will
866 * start again, so it can be done without any locks.
867 *
868 * st->read_socket is needed to prevents state machine
869 * breaking between this data reading and subsequent one
870 * in protocol specific functions during connection reset.
871 * In case of reset we have to read next command and do
872 * not expect data for old command to magically appear in
873 * new connection.
874 */
875 st->read_socket = st->socket;
876 err = pohmelfs_data_recv(st, cmd, sizeof(struct netfs_cmd));
877 if (err) {
878 msleep(1000);
879 continue;
880 }
881
882 netfs_convert_cmd(cmd);
883
884 dprintk("%s: cmd: %u, id: %llu, start: %llu, size: %u, "
885 "ext: %u, csize: %u, cpad: %u.\n",
886 __func__, cmd->cmd, cmd->id, cmd->start,
887 cmd->size, cmd->ext, cmd->csize, cmd->cpad);
888
889 if (cmd->csize) {
890 struct pohmelfs_crypto_engine *e = &st->eng;
891
892 if (unlikely(cmd->csize > e->size/2)) {
893 netfs_state_reset(st);
894 continue;
895 }
896
897 if (e->hash && unlikely(cmd->csize != st->psb->crypto_attached_size)) {
898 dprintk("%s: cmd: cmd: %u, id: %llu, start: %llu, size: %u, "
899 "csize: %u != digest size %u.\n",
900 __func__, cmd->cmd, cmd->id, cmd->start, cmd->size,
901 cmd->csize, st->psb->crypto_attached_size);
902 netfs_state_reset(st);
903 continue;
904 }
905
906 err = pohmelfs_data_recv(st, e->data, cmd->csize);
907 if (err) {
908 netfs_state_reset(st);
909 continue;
910 }
911
912#ifdef CONFIG_POHMELFS_DEBUG
913 {
914 unsigned int i;
915 unsigned char *hash = e->data;
916
917 dprintk("%s: received hash: ", __func__);
918 for (i = 0; i < cmd->csize; ++i)
919 printk("%02x ", hash[i]);
920
921 printk("\n");
922 }
923#endif
924 cmd->size -= cmd->csize;
925 }
926
927 /*
928 * This should catch protocol breakage and random garbage instead of commands.
929 */
930 if (unlikely((cmd->size > st->size) && (cmd->cmd != NETFS_XATTR_GET))) {
931 netfs_state_reset(st);
932 continue;
933 }
934
935 switch (cmd->cmd) {
936 case NETFS_READ_PAGE:
937 err = pohmelfs_read_page_response(st);
938 break;
939 case NETFS_READDIR:
940 err = pohmelfs_readdir_response(st);
941 break;
942 case NETFS_LOOKUP:
943 err = pohmelfs_lookup_response(st);
944 break;
945 case NETFS_CREATE:
946 err = pohmelfs_create_response(st);
947 break;
948 case NETFS_REMOVE:
949 err = pohmelfs_remove_response(st);
950 break;
951 case NETFS_TRANS:
952 err = pohmelfs_transaction_response(st);
953 break;
954 case NETFS_PAGE_CACHE:
955 err = pohmelfs_page_cache_response(st);
956 break;
957 case NETFS_CAPABILITIES:
958 err = pohmelfs_capabilities_response(st);
959 break;
960 case NETFS_LOCK:
961 err = pohmelfs_data_lock_response(st);
962 break;
963 case NETFS_XATTR_GET:
964 err = pohmelfs_getxattr_response(st);
965 break;
966 default:
967 printk("%s: wrong cmd: %u, id: %llu, start: %llu, size: %u, ext: %u.\n",
968 __func__, cmd->cmd, cmd->id, cmd->start, cmd->size, cmd->ext);
969 netfs_state_reset(st);
970 break;
971 }
972 }
973
974 while (!kthread_should_stop())
975 schedule_timeout_uninterruptible(msecs_to_jiffies(10));
976
977 return err;
978}
979
980int netfs_state_init(struct netfs_state *st)
981{
982 int err;
983 struct pohmelfs_ctl *ctl = &st->ctl;
984
985 err = sock_create(ctl->addr.sa_family, ctl->type, ctl->proto, &st->socket);
986 if (err) {
987 printk("%s: failed to create a socket: family: %d, type: %d, proto: %d, err: %d.\n",
988 __func__, ctl->addr.sa_family, ctl->type, ctl->proto, err);
989 goto err_out_exit;
990 }
991
992 st->socket->sk->sk_allocation = GFP_NOIO;
993 st->socket->sk->sk_sndtimeo = st->socket->sk->sk_rcvtimeo = msecs_to_jiffies(60000);
994
995 err = kernel_connect(st->socket, (struct sockaddr *)&ctl->addr, ctl->addrlen, 0);
996 if (err) {
997 printk("%s: failed to connect to server: idx: %u, err: %d.\n",
998 __func__, st->psb->idx, err);
999 goto err_out_release;
1000 }
1001 st->socket->sk->sk_sndtimeo = st->socket->sk->sk_rcvtimeo = msecs_to_jiffies(60000);
1002
1003 err = netfs_poll_init(st);
1004 if (err)
1005 goto err_out_release;
1006
1007 if (st->socket->ops->family == AF_INET) {
1008 struct sockaddr_in *sin = (struct sockaddr_in *)&ctl->addr;
1009 printk(KERN_INFO "%s: (re)connected to peer %pi4:%d.\n", __func__,
1010 &sin->sin_addr.s_addr, ntohs(sin->sin_port));
1011 } else if (st->socket->ops->family == AF_INET6) {
1012 struct sockaddr_in6 *sin = (struct sockaddr_in6 *)&ctl->addr;
1013 printk(KERN_INFO "%s: (re)connected to peer %pi6:%d", __func__,
1014 &sin->sin6_addr, ntohs(sin->sin6_port));
1015 }
1016
1017 return 0;
1018
1019err_out_release:
1020 sock_release(st->socket);
1021err_out_exit:
1022 st->socket = NULL;
1023 return err;
1024}
1025
1026void netfs_state_exit(struct netfs_state *st)
1027{
1028 if (st->socket) {
1029 netfs_poll_exit(st);
1030 st->socket->ops->shutdown(st->socket, 2);
1031
1032 if (st->socket->ops->family == AF_INET) {
1033 struct sockaddr_in *sin = (struct sockaddr_in *)&st->ctl.addr;
1034 printk(KERN_INFO "%s: disconnected from peer %pi4:%d.\n", __func__,
1035 &sin->sin_addr.s_addr, ntohs(sin->sin_port));
1036 } else if (st->socket->ops->family == AF_INET6) {
1037 struct sockaddr_in6 *sin = (struct sockaddr_in6 *)&st->ctl.addr;
1038 printk(KERN_INFO "%s: disconnected from peer %pi6:%d", __func__,
1039 &sin->sin6_addr, ntohs(sin->sin6_port));
1040 }
1041
1042 sock_release(st->socket);
1043 st->socket = NULL;
1044 st->read_socket = NULL;
1045 st->need_reset = 0;
1046 }
1047}
1048
1049int pohmelfs_state_init_one(struct pohmelfs_sb *psb, struct pohmelfs_config *conf)
1050{
1051 struct netfs_state *st = &conf->state;
1052 int err = -ENOMEM;
1053
1054 mutex_init(&st->__state_lock);
1055 mutex_init(&st->__state_send_lock);
1056 init_waitqueue_head(&st->thread_wait);
1057
1058 st->psb = psb;
1059 st->trans_root = RB_ROOT;
1060 mutex_init(&st->trans_lock);
1061
1062 st->size = psb->trans_data_size;
1063 st->data = kmalloc(st->size, GFP_KERNEL);
1064 if (!st->data)
1065 goto err_out_exit;
1066
1067 if (psb->perform_crypto) {
1068 err = pohmelfs_crypto_engine_init(&st->eng, psb);
1069 if (err)
1070 goto err_out_free_data;
1071 }
1072
1073 err = netfs_state_init(st);
1074 if (err)
1075 goto err_out_free_engine;
1076
1077 st->thread = kthread_run(pohmelfs_recv, st, "pohmelfs/%u", psb->idx);
1078 if (IS_ERR(st->thread)) {
1079 err = PTR_ERR(st->thread);
1080 goto err_out_netfs_exit;
1081 }
1082
1083 if (!psb->active_state)
1084 psb->active_state = conf;
1085
1086 dprintk("%s: conf: %p, st: %p, socket: %p.\n",
1087 __func__, conf, st, st->socket);
1088 return 0;
1089
1090err_out_netfs_exit:
1091 netfs_state_exit(st);
1092err_out_free_engine:
1093 pohmelfs_crypto_engine_exit(&st->eng);
1094err_out_free_data:
1095 kfree(st->data);
1096err_out_exit:
1097 return err;
1098
1099}
1100
1101void pohmelfs_state_flush_transactions(struct netfs_state *st)
1102{
1103 struct rb_node *rb_node;
1104 struct netfs_trans_dst *dst;
1105
1106 mutex_lock(&st->trans_lock);
1107 for (rb_node = rb_first(&st->trans_root); rb_node; ) {
1108 dst = rb_entry(rb_node, struct netfs_trans_dst, state_entry);
1109 rb_node = rb_next(rb_node);
1110
1111 dst->trans->result = -EINVAL;
1112 netfs_trans_remove_nolock(dst, st);
1113 netfs_trans_drop_dst_nostate(dst);
1114 }
1115 mutex_unlock(&st->trans_lock);
1116}
1117
1118static void pohmelfs_state_exit_one(struct pohmelfs_config *c)
1119{
1120 struct netfs_state *st = &c->state;
1121
1122 dprintk("%s: exiting, st: %p.\n", __func__, st);
1123 if (st->thread) {
1124 kthread_stop(st->thread);
1125 st->thread = NULL;
1126 }
1127
1128 netfs_state_lock_send(st);
1129 netfs_state_exit(st);
1130 netfs_state_unlock_send(st);
1131
1132 pohmelfs_state_flush_transactions(st);
1133
1134 pohmelfs_crypto_engine_exit(&st->eng);
1135 kfree(st->data);
1136
1137 kfree(c);
1138}
1139
1140/*
1141 * Initialize network stack. It searches for given ID in global
1142 * configuration table, this contains information of the remote server
1143 * (address (any supported by socket interface) and port, protocol and so on).
1144 */
1145int pohmelfs_state_init(struct pohmelfs_sb *psb)
1146{
1147 int err = -ENOMEM;
1148
1149 err = pohmelfs_copy_config(psb);
1150 if (err) {
1151 pohmelfs_state_exit(psb);
1152 return err;
1153 }
1154
1155 return 0;
1156}
1157
1158void pohmelfs_state_exit(struct pohmelfs_sb *psb)
1159{
1160 struct pohmelfs_config *c, *tmp;
1161
1162 list_for_each_entry_safe(c, tmp, &psb->state_list, config_entry) {
1163 list_del(&c->config_entry);
1164 pohmelfs_state_exit_one(c);
1165 }
1166}
1167
1168void pohmelfs_switch_active(struct pohmelfs_sb *psb)
1169{
1170 struct pohmelfs_config *c = psb->active_state;
1171
1172 if (!list_empty(&psb->state_list)) {
1173 if (c->config_entry.next != &psb->state_list) {
1174 psb->active_state = list_entry(c->config_entry.next,
1175 struct pohmelfs_config, config_entry);
1176 } else {
1177 psb->active_state = list_entry(psb->state_list.next,
1178 struct pohmelfs_config, config_entry);
1179 }
1180
1181 dprintk("%s: empty: %d, active %p -> %p.\n",
1182 __func__, list_empty(&psb->state_list), c,
1183 psb->active_state);
1184 } else
1185 psb->active_state = NULL;
1186}
1187
1188void pohmelfs_check_states(struct pohmelfs_sb *psb)
1189{
1190 struct pohmelfs_config *c, *tmp;
1191 LIST_HEAD(delete_list);
1192
1193 mutex_lock(&psb->state_lock);
1194 list_for_each_entry_safe(c, tmp, &psb->state_list, config_entry) {
1195 if (pohmelfs_config_check(c, psb->idx)) {
1196
1197 if (psb->active_state == c)
1198 pohmelfs_switch_active(psb);
1199 list_move(&c->config_entry, &delete_list);
1200 }
1201 }
1202 pohmelfs_copy_config(psb);
1203 mutex_unlock(&psb->state_lock);
1204
1205 list_for_each_entry_safe(c, tmp, &delete_list, config_entry) {
1206 list_del(&c->config_entry);
1207 pohmelfs_state_exit_one(c);
1208 }
1209}
diff --git a/drivers/staging/pohmelfs/netfs.h b/drivers/staging/pohmelfs/netfs.h
new file mode 100644
index 00000000000..985b6b755d5
--- /dev/null
+++ b/drivers/staging/pohmelfs/netfs.h
@@ -0,0 +1,919 @@
1/*
2 * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
3 * All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#ifndef __NETFS_H
17#define __NETFS_H
18
19#include <linux/types.h>
20#include <linux/connector.h>
21#include <linux/backing-dev.h>
22
23#define POHMELFS_CN_IDX 5
24#define POHMELFS_CN_VAL 0
25
26#define POHMELFS_CTLINFO_ACK 1
27#define POHMELFS_NOINFO_ACK 2
28
29#define POHMELFS_NULL_IDX 65535
30
31/*
32 * Network command structure.
33 * Will be extended.
34 */
35struct netfs_cmd {
36 __u16 cmd; /* Command number */
37 __u16 csize; /* Attached crypto information size */
38 __u16 cpad; /* Attached padding size */
39 __u16 ext; /* External flags */
40 __u32 size; /* Size of the attached data */
41 __u32 trans; /* Transaction id */
42 __u64 id; /* Object ID to operate on. Used for feedback.*/
43 __u64 start; /* Start of the object. */
44 __u64 iv; /* IV sequence */
45 __u8 data[0];
46};
47
48static inline void netfs_convert_cmd(struct netfs_cmd *cmd)
49{
50 cmd->id = __be64_to_cpu(cmd->id);
51 cmd->start = __be64_to_cpu(cmd->start);
52 cmd->iv = __be64_to_cpu(cmd->iv);
53 cmd->cmd = __be16_to_cpu(cmd->cmd);
54 cmd->ext = __be16_to_cpu(cmd->ext);
55 cmd->csize = __be16_to_cpu(cmd->csize);
56 cmd->cpad = __be16_to_cpu(cmd->cpad);
57 cmd->size = __be32_to_cpu(cmd->size);
58}
59
60#define NETFS_TRANS_SINGLE_DST (1<<0)
61
62enum {
63 NETFS_READDIR = 1, /* Read directory for given inode number */
64 NETFS_READ_PAGE, /* Read data page from the server */
65 NETFS_WRITE_PAGE, /* Write data page to the server */
66 NETFS_CREATE, /* Create directory entry */
67 NETFS_REMOVE, /* Remove directory entry */
68
69 NETFS_LOOKUP, /* Lookup single object */
70 NETFS_LINK, /* Create a link */
71 NETFS_TRANS, /* Transaction */
72 NETFS_OPEN, /* Open intent */
73 NETFS_INODE_INFO, /* Metadata cache coherency synchronization message */
74
75 NETFS_PAGE_CACHE, /* Page cache invalidation message */
76 NETFS_READ_PAGES, /* Read multiple contiguous pages in one go */
77 NETFS_RENAME, /* Rename object */
78 NETFS_CAPABILITIES, /* Capabilities of the client, for example supported crypto */
79 NETFS_LOCK, /* Distributed lock message */
80
81 NETFS_XATTR_SET, /* Set extended attribute */
82 NETFS_XATTR_GET, /* Get extended attribute */
83 NETFS_CMD_MAX
84};
85
86enum {
87 POHMELFS_FLAGS_ADD = 0, /* Network state control message for ADD */
88 POHMELFS_FLAGS_DEL, /* Network state control message for DEL */
89 POHMELFS_FLAGS_SHOW, /* Network state control message for SHOW */
90 POHMELFS_FLAGS_CRYPTO, /* Crypto data control message */
91 POHMELFS_FLAGS_MODIFY, /* Network state modification message */
92 POHMELFS_FLAGS_DUMP, /* Network state control message for SHOW ALL */
93 POHMELFS_FLAGS_FLUSH, /* Network state control message for FLUSH */
94};
95
96/*
97 * Always wanted to copy it from socket headers into public one,
98 * since they are __KERNEL__ protected there.
99 */
100#define _K_SS_MAXSIZE 128
101
102struct saddr {
103 unsigned short sa_family;
104 char addr[_K_SS_MAXSIZE];
105};
106
107enum {
108 POHMELFS_CRYPTO_HASH = 0,
109 POHMELFS_CRYPTO_CIPHER,
110};
111
112struct pohmelfs_crypto {
113 unsigned int idx; /* Config index */
114 unsigned short strlen; /* Size of the attached crypto string including 0-byte
115 * "cbc(aes)" for example */
116 unsigned short type; /* HMAC, cipher, both */
117 unsigned int keysize; /* Key size */
118 unsigned char data[0]; /* Algorithm string, key and IV */
119};
120
121#define POHMELFS_IO_PERM_READ (1<<0)
122#define POHMELFS_IO_PERM_WRITE (1<<1)
123
124/*
125 * Configuration command used to create table of different remote servers.
126 */
127struct pohmelfs_ctl {
128 __u32 idx; /* Config index */
129 __u32 type; /* Socket type */
130 __u32 proto; /* Socket protocol */
131 __u16 addrlen; /* Size of the address */
132 __u16 perm; /* IO permission */
133 __u16 prio; /* IO priority */
134 struct saddr addr; /* Remote server address */
135};
136
137/*
138 * Ack for userspace about requested command.
139 */
140struct pohmelfs_cn_ack {
141 struct cn_msg msg;
142 int error;
143 int msg_num;
144 int unused[3];
145 struct pohmelfs_ctl ctl;
146};
147
148/*
149 * Inode info structure used to sync with server.
150 * Check what stat() returns.
151 */
152struct netfs_inode_info {
153 unsigned int mode;
154 unsigned int nlink;
155 unsigned int uid;
156 unsigned int gid;
157 unsigned int blocksize;
158 unsigned int padding;
159 __u64 ino;
160 __u64 blocks;
161 __u64 rdev;
162 __u64 size;
163 __u64 version;
164};
165
166static inline void netfs_convert_inode_info(struct netfs_inode_info *info)
167{
168 info->mode = __cpu_to_be32(info->mode);
169 info->nlink = __cpu_to_be32(info->nlink);
170 info->uid = __cpu_to_be32(info->uid);
171 info->gid = __cpu_to_be32(info->gid);
172 info->blocksize = __cpu_to_be32(info->blocksize);
173 info->blocks = __cpu_to_be64(info->blocks);
174 info->rdev = __cpu_to_be64(info->rdev);
175 info->size = __cpu_to_be64(info->size);
176 info->version = __cpu_to_be64(info->version);
177 info->ino = __cpu_to_be64(info->ino);
178}
179
180/*
181 * Cache state machine.
182 */
183enum {
184 NETFS_COMMAND_PENDING = 0, /* Command is being executed */
185 NETFS_INODE_REMOTE_SYNCED, /* Inode was synced to server */
186 NETFS_INODE_REMOTE_DIR_SYNCED, /* Inode (directory) was synced from the server */
187 NETFS_INODE_OWNED, /* Inode is owned by given host */
188 NETFS_INODE_NEED_FLUSH, /* Inode has to be flushed to the server */
189};
190
191/*
192 * POHMELFS capabilities: information about supported
193 * crypto operations (hash/cipher, modes, key sizes and so on),
194 * root information (used/available size, number of objects, permissions)
195 */
196enum pohmelfs_capabilities {
197 POHMELFS_CRYPTO_CAPABILITIES = 0,
198 POHMELFS_ROOT_CAPABILITIES,
199};
200
201/* Read-only mount */
202#define POHMELFS_FLAGS_RO (1<<0)
203/* Extended attributes support on/off */
204#define POHMELFS_FLAGS_XATTR (1<<1)
205
206struct netfs_root_capabilities {
207 __u64 nr_files;
208 __u64 used, avail;
209 __u64 flags;
210};
211
212static inline void netfs_convert_root_capabilities(struct netfs_root_capabilities *cap)
213{
214 cap->nr_files = __cpu_to_be64(cap->nr_files);
215 cap->used = __cpu_to_be64(cap->used);
216 cap->avail = __cpu_to_be64(cap->avail);
217 cap->flags = __cpu_to_be64(cap->flags);
218}
219
220struct netfs_crypto_capabilities {
221 unsigned short hash_strlen; /* Hash string length, like "hmac(sha1) including 0 byte "*/
222 unsigned short cipher_strlen; /* Cipher string length with the same format */
223 unsigned int cipher_keysize; /* Cipher key size */
224};
225
226static inline void netfs_convert_crypto_capabilities(struct netfs_crypto_capabilities *cap)
227{
228 cap->hash_strlen = __cpu_to_be16(cap->hash_strlen);
229 cap->cipher_strlen = __cpu_to_be16(cap->cipher_strlen);
230 cap->cipher_keysize = __cpu_to_be32(cap->cipher_keysize);
231}
232
233enum pohmelfs_lock_type {
234 POHMELFS_LOCK_GRAB = (1<<15),
235
236 POHMELFS_READ_LOCK = 0,
237 POHMELFS_WRITE_LOCK,
238};
239
240struct netfs_lock {
241 __u64 start;
242 __u64 ino;
243 __u32 size;
244 __u32 type;
245};
246
247static inline void netfs_convert_lock(struct netfs_lock *lock)
248{
249 lock->start = __cpu_to_be64(lock->start);
250 lock->ino = __cpu_to_be64(lock->ino);
251 lock->size = __cpu_to_be32(lock->size);
252 lock->type = __cpu_to_be32(lock->type);
253}
254
255#ifdef __KERNEL__
256
257#include <linux/kernel.h>
258#include <linux/completion.h>
259#include <linux/rbtree.h>
260#include <linux/net.h>
261#include <linux/poll.h>
262
263/*
264 * Private POHMELFS cache of objects in directory.
265 */
266struct pohmelfs_name {
267 struct rb_node hash_node;
268
269 struct list_head sync_create_entry;
270
271 u64 ino;
272
273 u32 hash;
274 u32 mode;
275 u32 len;
276
277 char *data;
278};
279
280/*
281 * POHMELFS inode. Main object.
282 */
283struct pohmelfs_inode {
284 struct list_head inode_entry; /* Entry in superblock list.
285 * Objects which are not bound to dentry require to be dropped
286 * in ->put_super()
287 */
288 struct rb_root hash_root; /* The same, but indexed by name hash and len */
289 struct mutex offset_lock; /* Protect both above trees */
290
291 struct list_head sync_create_list; /* List of created but not yet synced to the server children */
292
293 unsigned int drop_count;
294
295 int lock_type; /* How this inode is locked: read or write */
296
297 int error; /* Transaction error for given inode */
298
299 long state; /* State machine above */
300
301 u64 ino; /* Inode number */
302 u64 total_len; /* Total length of all children names, used to create offsets */
303
304 struct inode vfs_inode;
305};
306
307struct netfs_trans;
308typedef int (*netfs_trans_complete_t)(struct page **pages, unsigned int page_num,
309 void *private, int err);
310
311struct netfs_state;
312struct pohmelfs_sb;
313
314struct netfs_trans {
315 /*
316 * Transaction header and attached contiguous data live here.
317 */
318 struct iovec iovec;
319
320 /*
321 * Pages attached to transaction.
322 */
323 struct page **pages;
324
325 /*
326 * List and protecting lock for transaction destination
327 * network states.
328 */
329 spinlock_t dst_lock;
330 struct list_head dst_list;
331
332 /*
333 * Number of users for given transaction.
334 * For example each network state attached to transaction
335 * via dst_list increases it.
336 */
337 atomic_t refcnt;
338
339 /*
340 * Number of pages attached to given transaction.
341 * Some slots in above page array can be NULL, since
342 * for example page can be under writeback already,
343 * so we skip it in this transaction.
344 */
345 unsigned int page_num;
346
347 /*
348 * Transaction flags: single dst or broadcast and so on.
349 */
350 unsigned int flags;
351
352 /*
353 * Size of the data, which can be placed into
354 * iovec.iov_base area.
355 */
356 unsigned int total_size;
357
358 /*
359 * Number of pages to be sent to remote server.
360 * Usually equal to above page_num, but in case of partial
361 * writeback it can accumulate only pages already completed
362 * previous writeback.
363 */
364 unsigned int attached_pages;
365
366 /*
367 * Attached number of bytes in all above pages.
368 */
369 unsigned int attached_size;
370
371 /*
372 * Unique transacton generation number.
373 * Used as identity in the network state tree of transactions.
374 */
375 unsigned int gen;
376
377 /*
378 * Transaction completion status.
379 */
380 int result;
381
382 /*
383 * Superblock this transaction belongs to
384 */
385 struct pohmelfs_sb *psb;
386
387 /*
388 * Crypto engine, which processed this transaction.
389 * Can be not NULL only if crypto engine holds encrypted pages.
390 */
391 struct pohmelfs_crypto_engine *eng;
392
393 /* Private data */
394 void *private;
395
396 /* Completion callback, invoked just before transaction is destroyed */
397 netfs_trans_complete_t complete;
398};
399
400static inline int netfs_trans_cur_len(struct netfs_trans *t)
401{
402 return (signed)(t->total_size - t->iovec.iov_len);
403}
404
405static inline void *netfs_trans_current(struct netfs_trans *t)
406{
407 return t->iovec.iov_base + t->iovec.iov_len;
408}
409
410struct netfs_trans *netfs_trans_alloc(struct pohmelfs_sb *psb, unsigned int size,
411 unsigned int flags, unsigned int nr);
412void netfs_trans_free(struct netfs_trans *t);
413int netfs_trans_finish(struct netfs_trans *t, struct pohmelfs_sb *psb);
414int netfs_trans_finish_send(struct netfs_trans *t, struct pohmelfs_sb *psb);
415
416static inline void netfs_trans_reset(struct netfs_trans *t)
417{
418 t->complete = NULL;
419}
420
421struct netfs_trans_dst {
422 struct list_head trans_entry;
423 struct rb_node state_entry;
424
425 unsigned long send_time;
426
427 /*
428 * Times this transaction was resent to its old or new,
429 * depending on flags, destinations. When it reaches maximum
430 * allowed number, specified in superblock->trans_retries,
431 * transaction will be freed with ETIMEDOUT error.
432 */
433 unsigned int retries;
434
435 struct netfs_trans *trans;
436 struct netfs_state *state;
437};
438
439struct netfs_trans_dst *netfs_trans_search(struct netfs_state *st, unsigned int gen);
440void netfs_trans_drop_dst(struct netfs_trans_dst *dst);
441void netfs_trans_drop_dst_nostate(struct netfs_trans_dst *dst);
442void netfs_trans_drop_trans(struct netfs_trans *t, struct netfs_state *st);
443void netfs_trans_drop_last(struct netfs_trans *t, struct netfs_state *st);
444int netfs_trans_resend(struct netfs_trans *t, struct pohmelfs_sb *psb);
445int netfs_trans_remove_nolock(struct netfs_trans_dst *dst, struct netfs_state *st);
446
447int netfs_trans_init(void);
448void netfs_trans_exit(void);
449
450struct pohmelfs_crypto_engine {
451 u64 iv; /* Crypto IV for current operation */
452 unsigned long timeout; /* Crypto waiting timeout */
453 unsigned int size; /* Size of crypto scratchpad */
454 void *data; /* Temporal crypto scratchpad */
455 /*
456 * Crypto operations performed on objects.
457 */
458 struct crypto_hash *hash;
459 struct crypto_ablkcipher *cipher;
460
461 struct pohmelfs_crypto_thread *thread; /* Crypto thread which hosts this engine */
462
463 struct page **pages;
464 unsigned int page_num;
465};
466
467struct pohmelfs_crypto_thread {
468 struct list_head thread_entry;
469
470 struct task_struct *thread;
471 struct pohmelfs_sb *psb;
472
473 struct pohmelfs_crypto_engine eng;
474
475 struct netfs_trans *trans;
476
477 wait_queue_head_t wait;
478 int error;
479
480 unsigned int size;
481 struct page *page;
482};
483
484void pohmelfs_crypto_thread_make_ready(struct pohmelfs_crypto_thread *th);
485
486/*
487 * Network state, attached to one server.
488 */
489struct netfs_state {
490 struct mutex __state_lock; /* Can not allow to use the same socket simultaneously */
491 struct mutex __state_send_lock;
492 struct netfs_cmd cmd; /* Cached command */
493 struct netfs_inode_info info; /* Cached inode info */
494
495 void *data; /* Cached some data */
496 unsigned int size; /* Size of that data */
497
498 struct pohmelfs_sb *psb; /* Superblock */
499
500 struct task_struct *thread; /* Async receiving thread */
501
502 /* Waiting/polling machinery */
503 wait_queue_t wait;
504 wait_queue_head_t *whead;
505 wait_queue_head_t thread_wait;
506
507 struct mutex trans_lock;
508 struct rb_root trans_root;
509
510 struct pohmelfs_ctl ctl; /* Remote peer */
511
512 struct socket *socket; /* Socket object */
513 struct socket *read_socket; /* Cached pointer to socket object.
514 * Used to determine if between lock drops socket was changed.
515 * Never used to read data or any kind of access.
516 */
517 /*
518 * Crypto engines to process incoming data.
519 */
520 struct pohmelfs_crypto_engine eng;
521
522 int need_reset;
523};
524
525int netfs_state_init(struct netfs_state *st);
526void netfs_state_exit(struct netfs_state *st);
527
528static inline void netfs_state_lock_send(struct netfs_state *st)
529{
530 mutex_lock(&st->__state_send_lock);
531}
532
533static inline int netfs_state_trylock_send(struct netfs_state *st)
534{
535 return mutex_trylock(&st->__state_send_lock);
536}
537
538static inline void netfs_state_unlock_send(struct netfs_state *st)
539{
540 BUG_ON(!mutex_is_locked(&st->__state_send_lock));
541
542 mutex_unlock(&st->__state_send_lock);
543}
544
545static inline void netfs_state_lock(struct netfs_state *st)
546{
547 mutex_lock(&st->__state_lock);
548}
549
550static inline void netfs_state_unlock(struct netfs_state *st)
551{
552 BUG_ON(!mutex_is_locked(&st->__state_lock));
553
554 mutex_unlock(&st->__state_lock);
555}
556
557static inline unsigned int netfs_state_poll(struct netfs_state *st)
558{
559 unsigned int revents = POLLHUP | POLLERR;
560
561 netfs_state_lock(st);
562 if (st->socket)
563 revents = st->socket->ops->poll(NULL, st->socket, NULL);
564 netfs_state_unlock(st);
565
566 return revents;
567}
568
569struct pohmelfs_config;
570
571struct pohmelfs_sb {
572 struct rb_root mcache_root;
573 struct mutex mcache_lock;
574 atomic_long_t mcache_gen;
575 unsigned long mcache_timeout;
576
577 unsigned int idx;
578
579 unsigned int trans_retries;
580
581 atomic_t trans_gen;
582
583 unsigned int crypto_attached_size;
584 unsigned int crypto_align_size;
585
586 unsigned int crypto_fail_unsupported;
587
588 unsigned int crypto_thread_num;
589 struct list_head crypto_active_list, crypto_ready_list;
590 struct mutex crypto_thread_lock;
591
592 unsigned int trans_max_pages;
593 unsigned long trans_data_size;
594 unsigned long trans_timeout;
595
596 unsigned long drop_scan_timeout;
597 unsigned long trans_scan_timeout;
598
599 unsigned long wait_on_page_timeout;
600
601 struct list_head flush_list;
602 struct list_head drop_list;
603 spinlock_t ino_lock;
604 u64 ino;
605
606 /*
607 * Remote nodes POHMELFS connected to.
608 */
609 struct list_head state_list;
610 struct mutex state_lock;
611
612 /*
613 * Currently active state to request data from.
614 */
615 struct pohmelfs_config *active_state;
616
617
618 wait_queue_head_t wait;
619
620 /*
621 * Timed checks: stale transactions, inodes to be freed and so on.
622 */
623 struct delayed_work dwork;
624 struct delayed_work drop_dwork;
625
626 struct super_block *sb;
627
628 struct backing_dev_info bdi;
629
630 /*
631 * Algorithm strings.
632 */
633 char *hash_string;
634 char *cipher_string;
635
636 u8 *hash_key;
637 u8 *cipher_key;
638
639 /*
640 * Algorithm string lengths.
641 */
642 unsigned int hash_strlen;
643 unsigned int cipher_strlen;
644 unsigned int hash_keysize;
645 unsigned int cipher_keysize;
646
647 /*
648 * Controls whether to perfrom crypto processing or not.
649 */
650 int perform_crypto;
651
652 /*
653 * POHMELFS statistics.
654 */
655 u64 total_size;
656 u64 avail_size;
657 atomic_long_t total_inodes;
658
659 /*
660 * Xattr support, read-only and so on.
661 */
662 u64 state_flags;
663
664 /*
665 * Temporary storage to detect changes in the wait queue.
666 */
667 long flags;
668};
669
670static inline void netfs_trans_update(struct netfs_cmd *cmd,
671 struct netfs_trans *t, unsigned int size)
672{
673 unsigned int sz = ALIGN(size, t->psb->crypto_align_size);
674
675 t->iovec.iov_len += sizeof(struct netfs_cmd) + sz;
676 cmd->cpad = __cpu_to_be16(sz - size);
677}
678
679static inline struct pohmelfs_sb *POHMELFS_SB(struct super_block *sb)
680{
681 return sb->s_fs_info;
682}
683
684static inline struct pohmelfs_inode *POHMELFS_I(struct inode *inode)
685{
686 return container_of(inode, struct pohmelfs_inode, vfs_inode);
687}
688
689static inline u64 pohmelfs_new_ino(struct pohmelfs_sb *psb)
690{
691 u64 ino;
692
693 spin_lock(&psb->ino_lock);
694 ino = psb->ino++;
695 spin_unlock(&psb->ino_lock);
696
697 return ino;
698}
699
700static inline void pohmelfs_put_inode(struct pohmelfs_inode *pi)
701{
702 struct pohmelfs_sb *psb = POHMELFS_SB(pi->vfs_inode.i_sb);
703
704 spin_lock(&psb->ino_lock);
705 list_move_tail(&pi->inode_entry, &psb->drop_list);
706 pi->drop_count++;
707 spin_unlock(&psb->ino_lock);
708}
709
710struct pohmelfs_config {
711 struct list_head config_entry;
712
713 struct netfs_state state;
714};
715
716struct pohmelfs_config_group {
717 /*
718 * Entry in the global config group list.
719 */
720 struct list_head group_entry;
721
722 /*
723 * Index of the current group.
724 */
725 unsigned int idx;
726 /*
727 * Number of config_list entries in this group entry.
728 */
729 unsigned int num_entry;
730 /*
731 * Algorithm strings.
732 */
733 char *hash_string;
734 char *cipher_string;
735
736 /*
737 * Algorithm string lengths.
738 */
739 unsigned int hash_strlen;
740 unsigned int cipher_strlen;
741
742 /*
743 * Key and its size.
744 */
745 unsigned int hash_keysize;
746 unsigned int cipher_keysize;
747 u8 *hash_key;
748 u8 *cipher_key;
749
750 /*
751 * List of config entries (network state info) for given idx.
752 */
753 struct list_head config_list;
754};
755
756int __init pohmelfs_config_init(void);
757void pohmelfs_config_exit(void);
758int pohmelfs_copy_config(struct pohmelfs_sb *psb);
759int pohmelfs_copy_crypto(struct pohmelfs_sb *psb);
760int pohmelfs_config_check(struct pohmelfs_config *config, int idx);
761int pohmelfs_state_init_one(struct pohmelfs_sb *psb, struct pohmelfs_config *conf);
762
763extern const struct file_operations pohmelfs_dir_fops;
764extern const struct inode_operations pohmelfs_dir_inode_ops;
765
766int pohmelfs_state_init(struct pohmelfs_sb *psb);
767void pohmelfs_state_exit(struct pohmelfs_sb *psb);
768void pohmelfs_state_flush_transactions(struct netfs_state *st);
769
770void pohmelfs_fill_inode(struct inode *inode, struct netfs_inode_info *info);
771
772void pohmelfs_name_del(struct pohmelfs_inode *parent, struct pohmelfs_name *n);
773void pohmelfs_free_names(struct pohmelfs_inode *parent);
774struct pohmelfs_name *pohmelfs_search_hash(struct pohmelfs_inode *pi, u32 hash);
775
776void pohmelfs_inode_del_inode(struct pohmelfs_sb *psb, struct pohmelfs_inode *pi);
777
778struct pohmelfs_inode *pohmelfs_create_entry_local(struct pohmelfs_sb *psb,
779 struct pohmelfs_inode *parent, struct qstr *str, u64 start, int mode);
780
781int pohmelfs_write_create_inode(struct pohmelfs_inode *pi);
782
783int pohmelfs_write_inode_create(struct inode *inode, struct netfs_trans *trans);
784int pohmelfs_remove_child(struct pohmelfs_inode *parent, struct pohmelfs_name *n);
785
786struct pohmelfs_inode *pohmelfs_new_inode(struct pohmelfs_sb *psb,
787 struct pohmelfs_inode *parent, struct qstr *str,
788 struct netfs_inode_info *info, int link);
789
790int pohmelfs_setattr(struct dentry *dentry, struct iattr *attr);
791int pohmelfs_setattr_raw(struct inode *inode, struct iattr *attr);
792
793int pohmelfs_meta_command(struct pohmelfs_inode *pi, unsigned int cmd_op, unsigned int flags,
794 netfs_trans_complete_t complete, void *priv, u64 start);
795int pohmelfs_meta_command_data(struct pohmelfs_inode *pi, u64 id, unsigned int cmd_op, char *addon,
796 unsigned int flags, netfs_trans_complete_t complete, void *priv, u64 start);
797
798void pohmelfs_check_states(struct pohmelfs_sb *psb);
799void pohmelfs_switch_active(struct pohmelfs_sb *psb);
800
801int pohmelfs_construct_path_string(struct pohmelfs_inode *pi, void *data, int len);
802int pohmelfs_path_length(struct pohmelfs_inode *pi);
803
804struct pohmelfs_crypto_completion {
805 struct completion complete;
806 int error;
807};
808
809int pohmelfs_trans_crypt(struct netfs_trans *t, struct pohmelfs_sb *psb);
810void pohmelfs_crypto_exit(struct pohmelfs_sb *psb);
811int pohmelfs_crypto_init(struct pohmelfs_sb *psb);
812
813int pohmelfs_crypto_engine_init(struct pohmelfs_crypto_engine *e, struct pohmelfs_sb *psb);
814void pohmelfs_crypto_engine_exit(struct pohmelfs_crypto_engine *e);
815
816int pohmelfs_crypto_process_input_data(struct pohmelfs_crypto_engine *e, u64 iv,
817 void *data, struct page *page, unsigned int size);
818int pohmelfs_crypto_process_input_page(struct pohmelfs_crypto_engine *e,
819 struct page *page, unsigned int size, u64 iv);
820
821static inline u64 pohmelfs_gen_iv(struct netfs_trans *t)
822{
823 u64 iv = t->gen;
824
825 iv <<= 32;
826 iv |= ((unsigned long)t) & 0xffffffff;
827
828 return iv;
829}
830
831int pohmelfs_data_lock(struct pohmelfs_inode *pi, u64 start, u32 size, int type);
832int pohmelfs_data_unlock(struct pohmelfs_inode *pi, u64 start, u32 size, int type);
833int pohmelfs_data_lock_response(struct netfs_state *st);
834
835static inline int pohmelfs_need_lock(struct pohmelfs_inode *pi, int type)
836{
837 if (test_bit(NETFS_INODE_OWNED, &pi->state)) {
838 if (type == pi->lock_type)
839 return 0;
840 if ((type == POHMELFS_READ_LOCK) && (pi->lock_type == POHMELFS_WRITE_LOCK))
841 return 0;
842 }
843
844 if (!test_bit(NETFS_INODE_REMOTE_SYNCED, &pi->state))
845 return 0;
846
847 return 1;
848}
849
850int __init pohmelfs_mcache_init(void);
851void pohmelfs_mcache_exit(void);
852
853/* #define CONFIG_POHMELFS_DEBUG */
854
855#ifdef CONFIG_POHMELFS_DEBUG
856#define dprintka(f, a...) printk(f, ##a)
857#define dprintk(f, a...) printk("%d: " f, task_pid_vnr(current), ##a)
858#else
859#define dprintka(f, a...) do {} while (0)
860#define dprintk(f, a...) do {} while (0)
861#endif
862
863static inline void netfs_trans_get(struct netfs_trans *t)
864{
865 atomic_inc(&t->refcnt);
866}
867
868static inline void netfs_trans_put(struct netfs_trans *t)
869{
870 if (atomic_dec_and_test(&t->refcnt)) {
871 dprintk("%s: t: %p, gen: %u, err: %d.\n",
872 __func__, t, t->gen, t->result);
873 if (t->complete)
874 t->complete(t->pages, t->page_num,
875 t->private, t->result);
876 netfs_trans_free(t);
877 }
878}
879
880struct pohmelfs_mcache {
881 struct rb_node mcache_entry;
882 struct completion complete;
883
884 atomic_t refcnt;
885
886 u64 gen;
887
888 void *data;
889 u64 start;
890 u32 size;
891 int err;
892
893 struct netfs_inode_info info;
894};
895
896struct pohmelfs_mcache *pohmelfs_mcache_alloc(struct pohmelfs_sb *psb, u64 start,
897 unsigned int size, void *data);
898void pohmelfs_mcache_free(struct pohmelfs_sb *psb, struct pohmelfs_mcache *m);
899struct pohmelfs_mcache *pohmelfs_mcache_search(struct pohmelfs_sb *psb, u64 gen);
900void pohmelfs_mcache_remove_locked(struct pohmelfs_sb *psb, struct pohmelfs_mcache *m);
901
902static inline void pohmelfs_mcache_get(struct pohmelfs_mcache *m)
903{
904 atomic_inc(&m->refcnt);
905}
906
907static inline void pohmelfs_mcache_put(struct pohmelfs_sb *psb,
908 struct pohmelfs_mcache *m)
909{
910 if (atomic_dec_and_test(&m->refcnt))
911 pohmelfs_mcache_free(psb, m);
912}
913
914/*#define POHMELFS_TRUNCATE_ON_INODE_FLUSH
915 */
916
917#endif /* __KERNEL__*/
918
919#endif /* __NETFS_H */
diff --git a/drivers/staging/pohmelfs/path_entry.c b/drivers/staging/pohmelfs/path_entry.c
new file mode 100644
index 00000000000..400a9fc386a
--- /dev/null
+++ b/drivers/staging/pohmelfs/path_entry.c
@@ -0,0 +1,120 @@
1/*
2 * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
3 * All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/module.h>
17#include <linux/fs.h>
18#include <linux/ktime.h>
19#include <linux/fs_struct.h>
20#include <linux/pagemap.h>
21#include <linux/writeback.h>
22#include <linux/mount.h>
23#include <linux/mm.h>
24
25#include "netfs.h"
26
27#define UNHASHED_OBSCURE_STRING_SIZE sizeof(" (deleted)")
28
29/*
30 * Create path from root for given inode.
31 * Path is formed as set of stuctures, containing name of the object
32 * and its inode data (mode, permissions and so on).
33 */
34int pohmelfs_construct_path_string(struct pohmelfs_inode *pi, void *data, int len)
35{
36 struct path path;
37 struct dentry *d;
38 char *ptr;
39 int err = 0, strlen, reduce = 0;
40
41 d = d_find_alias(&pi->vfs_inode);
42 if (!d) {
43 printk("%s: no alias, list_empty: %d.\n", __func__, list_empty(&pi->vfs_inode.i_dentry));
44 return -ENOENT;
45 }
46
47 spin_lock(&current->fs->lock);
48 path.mnt = mntget(current->fs->root.mnt);
49 spin_unlock(&current->fs->lock);
50
51 path.dentry = d;
52
53 if (!IS_ROOT(d) && d_unhashed(d))
54 reduce = 1;
55
56 ptr = d_path(&path, data, len);
57 if (IS_ERR(ptr)) {
58 err = PTR_ERR(ptr);
59 goto out;
60 }
61
62 if (reduce && len >= UNHASHED_OBSCURE_STRING_SIZE) {
63 char *end = data + len - UNHASHED_OBSCURE_STRING_SIZE;
64 *end = '\0';
65 }
66
67 strlen = len - (ptr - (char *)data);
68 memmove(data, ptr, strlen);
69 ptr = data;
70
71 err = strlen;
72
73 dprintk("%s: dname: '%s', len: %u, maxlen: %u, name: '%s', strlen: %d.\n",
74 __func__, d->d_name.name, d->d_name.len, len, ptr, strlen);
75
76out:
77 dput(d);
78 mntput(path.mnt);
79
80 return err;
81}
82
83int pohmelfs_path_length(struct pohmelfs_inode *pi)
84{
85 struct dentry *d, *root, *first;
86 int len;
87 unsigned seq;
88
89 first = d_find_alias(&pi->vfs_inode);
90 if (!first) {
91 dprintk("%s: ino: %llu, mode: %o.\n", __func__, pi->ino, pi->vfs_inode.i_mode);
92 return -ENOENT;
93 }
94
95 spin_lock(&current->fs->lock);
96 root = dget(current->fs->root.dentry);
97 spin_unlock(&current->fs->lock);
98
99rename_retry:
100 len = 1; /* Root slash */
101 d = first;
102 seq = read_seqbegin(&rename_lock);
103 rcu_read_lock();
104
105 if (!IS_ROOT(d) && d_unhashed(d))
106 len += UNHASHED_OBSCURE_STRING_SIZE; /* Obscure " (deleted)" string */
107
108 while (d && d != root && !IS_ROOT(d)) {
109 len += d->d_name.len + 1; /* Plus slash */
110 d = d->d_parent;
111 }
112 rcu_read_unlock();
113 if (read_seqretry(&rename_lock, seq))
114 goto rename_retry;
115
116 dput(root);
117 dput(first);
118
119 return len + 1; /* Including zero-byte */
120}
diff --git a/drivers/staging/pohmelfs/trans.c b/drivers/staging/pohmelfs/trans.c
new file mode 100644
index 00000000000..36a25358256
--- /dev/null
+++ b/drivers/staging/pohmelfs/trans.c
@@ -0,0 +1,706 @@
1/*
2 * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
3 * All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/module.h>
17#include <linux/crypto.h>
18#include <linux/fs.h>
19#include <linux/jhash.h>
20#include <linux/hash.h>
21#include <linux/ktime.h>
22#include <linux/mempool.h>
23#include <linux/mm.h>
24#include <linux/mount.h>
25#include <linux/pagemap.h>
26#include <linux/parser.h>
27#include <linux/poll.h>
28#include <linux/swap.h>
29#include <linux/slab.h>
30#include <linux/statfs.h>
31#include <linux/writeback.h>
32
33#include "netfs.h"
34
35static struct kmem_cache *netfs_trans_dst;
36static mempool_t *netfs_trans_dst_pool;
37
38static void netfs_trans_init_static(struct netfs_trans *t, int num, int size)
39{
40 t->page_num = num;
41 t->total_size = size;
42 atomic_set(&t->refcnt, 1);
43
44 spin_lock_init(&t->dst_lock);
45 INIT_LIST_HEAD(&t->dst_list);
46}
47
48static int netfs_trans_send_pages(struct netfs_trans *t, struct netfs_state *st)
49{
50 int err = 0;
51 unsigned int i, attached_pages = t->attached_pages, ci;
52 struct msghdr msg;
53 struct page **pages = (t->eng)?t->eng->pages:t->pages;
54 struct page *p;
55 unsigned int size;
56
57 msg.msg_name = NULL;
58 msg.msg_namelen = 0;
59 msg.msg_control = NULL;
60 msg.msg_controllen = 0;
61 msg.msg_flags = MSG_WAITALL | MSG_MORE;
62
63 ci = 0;
64 for (i=0; i<t->page_num; ++i) {
65 struct page *page = pages[ci];
66 struct netfs_cmd cmd;
67 struct iovec io;
68
69 p = t->pages[i];
70
71 if (!p)
72 continue;
73
74 size = page_private(p);
75
76 io.iov_base = &cmd;
77 io.iov_len = sizeof(struct netfs_cmd);
78
79 cmd.cmd = NETFS_WRITE_PAGE;
80 cmd.ext = 0;
81 cmd.id = 0;
82 cmd.size = size;
83 cmd.start = p->index;
84 cmd.start <<= PAGE_CACHE_SHIFT;
85 cmd.csize = 0;
86 cmd.cpad = 0;
87 cmd.iv = pohmelfs_gen_iv(t);
88
89 netfs_convert_cmd(&cmd);
90
91 msg.msg_iov = &io;
92 msg.msg_iovlen = 1;
93 msg.msg_flags = MSG_WAITALL | MSG_MORE;
94
95 err = kernel_sendmsg(st->socket, &msg, (struct kvec *)msg.msg_iov, 1, sizeof(struct netfs_cmd));
96 if (err <= 0) {
97 printk("%s: %d/%d failed to send transaction header: t: %p, gen: %u, err: %d.\n",
98 __func__, i, t->page_num, t, t->gen, err);
99 if (err == 0)
100 err = -ECONNRESET;
101 goto err_out;
102 }
103
104 msg.msg_flags = MSG_WAITALL | (attached_pages == 1 ? 0 :
105 MSG_MORE);
106
107 err = kernel_sendpage(st->socket, page, 0, size, msg.msg_flags);
108 if (err <= 0) {
109 printk("%s: %d/%d failed to send transaction page: t: %p, gen: %u, size: %u, err: %d.\n",
110 __func__, i, t->page_num, t, t->gen, size, err);
111 if (err == 0)
112 err = -ECONNRESET;
113 goto err_out;
114 }
115
116 dprintk("%s: %d/%d sent t: %p, gen: %u, page: %p/%p, size: %u.\n",
117 __func__, i, t->page_num, t, t->gen, page, p, size);
118
119 err = 0;
120 attached_pages--;
121 if (!attached_pages)
122 break;
123 ci++;
124
125 continue;
126
127err_out:
128 printk("%s: t: %p, gen: %u, err: %d.\n", __func__, t, t->gen, err);
129 netfs_state_exit(st);
130 break;
131 }
132
133 return err;
134}
135
136int netfs_trans_send(struct netfs_trans *t, struct netfs_state *st)
137{
138 int err;
139 struct msghdr msg;
140
141 BUG_ON(!t->iovec.iov_len);
142 BUG_ON(t->iovec.iov_len > 1024*1024*1024);
143
144 netfs_state_lock_send(st);
145 if (!st->socket) {
146 err = netfs_state_init(st);
147 if (err)
148 goto err_out_unlock_return;
149 }
150
151 msg.msg_iov = &t->iovec;
152 msg.msg_iovlen = 1;
153 msg.msg_name = NULL;
154 msg.msg_namelen = 0;
155 msg.msg_control = NULL;
156 msg.msg_controllen = 0;
157 msg.msg_flags = MSG_WAITALL;
158
159 if (t->attached_pages)
160 msg.msg_flags |= MSG_MORE;
161
162 err = kernel_sendmsg(st->socket, &msg, (struct kvec *)msg.msg_iov, 1, t->iovec.iov_len);
163 if (err <= 0) {
164 printk("%s: failed to send contig transaction: t: %p, gen: %u, size: %zu, err: %d.\n",
165 __func__, t, t->gen, t->iovec.iov_len, err);
166 if (err == 0)
167 err = -ECONNRESET;
168 goto err_out_unlock_return;
169 }
170
171 dprintk("%s: sent %s transaction: t: %p, gen: %u, size: %zu, page_num: %u.\n",
172 __func__, (t->page_num)?"partial":"full",
173 t, t->gen, t->iovec.iov_len, t->page_num);
174
175 err = 0;
176 if (t->attached_pages)
177 err = netfs_trans_send_pages(t, st);
178
179err_out_unlock_return:
180
181 if (st->need_reset)
182 netfs_state_exit(st);
183
184 netfs_state_unlock_send(st);
185
186 dprintk("%s: t: %p, gen: %u, err: %d.\n",
187 __func__, t, t->gen, err);
188
189 t->result = err;
190 return err;
191}
192
193static inline int netfs_trans_cmp(unsigned int gen, unsigned int new)
194{
195 if (gen < new)
196 return 1;
197 if (gen > new)
198 return -1;
199 return 0;
200}
201
202struct netfs_trans_dst *netfs_trans_search(struct netfs_state *st, unsigned int gen)
203{
204 struct rb_root *root = &st->trans_root;
205 struct rb_node *n = root->rb_node;
206 struct netfs_trans_dst *tmp, *ret = NULL;
207 struct netfs_trans *t;
208 int cmp;
209
210 while (n) {
211 tmp = rb_entry(n, struct netfs_trans_dst, state_entry);
212 t = tmp->trans;
213
214 cmp = netfs_trans_cmp(t->gen, gen);
215 if (cmp < 0)
216 n = n->rb_left;
217 else if (cmp > 0)
218 n = n->rb_right;
219 else {
220 ret = tmp;
221 break;
222 }
223 }
224
225 return ret;
226}
227
228static int netfs_trans_insert(struct netfs_trans_dst *ndst, struct netfs_state *st)
229{
230 struct rb_root *root = &st->trans_root;
231 struct rb_node **n = &root->rb_node, *parent = NULL;
232 struct netfs_trans_dst *ret = NULL, *tmp;
233 struct netfs_trans *t = NULL, *new = ndst->trans;
234 int cmp;
235
236 while (*n) {
237 parent = *n;
238
239 tmp = rb_entry(parent, struct netfs_trans_dst, state_entry);
240 t = tmp->trans;
241
242 cmp = netfs_trans_cmp(t->gen, new->gen);
243 if (cmp < 0)
244 n = &parent->rb_left;
245 else if (cmp > 0)
246 n = &parent->rb_right;
247 else {
248 ret = tmp;
249 break;
250 }
251 }
252
253 if (ret) {
254 printk("%s: exist: old: gen: %u, flags: %x, send_time: %lu, "
255 "new: gen: %u, flags: %x, send_time: %lu.\n",
256 __func__, t->gen, t->flags, ret->send_time,
257 new->gen, new->flags, ndst->send_time);
258 return -EEXIST;
259 }
260
261 rb_link_node(&ndst->state_entry, parent, n);
262 rb_insert_color(&ndst->state_entry, root);
263 ndst->send_time = jiffies;
264
265 return 0;
266}
267
268int netfs_trans_remove_nolock(struct netfs_trans_dst *dst, struct netfs_state *st)
269{
270 if (dst && dst->state_entry.rb_parent_color) {
271 rb_erase(&dst->state_entry, &st->trans_root);
272 dst->state_entry.rb_parent_color = 0;
273 return 1;
274 }
275 return 0;
276}
277
278static int netfs_trans_remove_state(struct netfs_trans_dst *dst)
279{
280 int ret;
281 struct netfs_state *st = dst->state;
282
283 mutex_lock(&st->trans_lock);
284 ret = netfs_trans_remove_nolock(dst, st);
285 mutex_unlock(&st->trans_lock);
286
287 return ret;
288}
289
290/*
291 * Create new destination for given transaction associated with given network state.
292 * Transaction's reference counter is bumped and will be dropped when either
293 * reply is received or when async timeout detection task will fail resending
294 * and drop transaction.
295 */
296static int netfs_trans_push_dst(struct netfs_trans *t, struct netfs_state *st)
297{
298 struct netfs_trans_dst *dst;
299 int err;
300
301 dst = mempool_alloc(netfs_trans_dst_pool, GFP_KERNEL);
302 if (!dst)
303 return -ENOMEM;
304
305 dst->retries = 0;
306 dst->send_time = 0;
307 dst->state = st;
308 dst->trans = t;
309 netfs_trans_get(t);
310
311 mutex_lock(&st->trans_lock);
312 err = netfs_trans_insert(dst, st);
313 mutex_unlock(&st->trans_lock);
314
315 if (err)
316 goto err_out_free;
317
318 spin_lock(&t->dst_lock);
319 list_add_tail(&dst->trans_entry, &t->dst_list);
320 spin_unlock(&t->dst_lock);
321
322 return 0;
323
324err_out_free:
325 t->result = err;
326 netfs_trans_put(t);
327 mempool_free(dst, netfs_trans_dst_pool);
328 return err;
329}
330
331static void netfs_trans_free_dst(struct netfs_trans_dst *dst)
332{
333 netfs_trans_put(dst->trans);
334 mempool_free(dst, netfs_trans_dst_pool);
335}
336
337static void netfs_trans_remove_dst(struct netfs_trans_dst *dst)
338{
339 if (netfs_trans_remove_state(dst))
340 netfs_trans_free_dst(dst);
341}
342
343/*
344 * Drop destination transaction entry when we know it.
345 */
346void netfs_trans_drop_dst(struct netfs_trans_dst *dst)
347{
348 struct netfs_trans *t = dst->trans;
349
350 spin_lock(&t->dst_lock);
351 list_del_init(&dst->trans_entry);
352 spin_unlock(&t->dst_lock);
353
354 netfs_trans_remove_dst(dst);
355}
356
357/*
358 * Drop destination transaction entry when we know it and when we
359 * already removed dst from state tree.
360 */
361void netfs_trans_drop_dst_nostate(struct netfs_trans_dst *dst)
362{
363 struct netfs_trans *t = dst->trans;
364
365 spin_lock(&t->dst_lock);
366 list_del_init(&dst->trans_entry);
367 spin_unlock(&t->dst_lock);
368
369 netfs_trans_free_dst(dst);
370}
371
372/*
373 * This drops destination transaction entry from appropriate network state
374 * tree and drops related reference counter. It is possible that transaction
375 * will be freed here if its reference counter hits zero.
376 * Destination transaction entry will be freed.
377 */
378void netfs_trans_drop_trans(struct netfs_trans *t, struct netfs_state *st)
379{
380 struct netfs_trans_dst *dst, *tmp, *ret = NULL;
381
382 spin_lock(&t->dst_lock);
383 list_for_each_entry_safe(dst, tmp, &t->dst_list, trans_entry) {
384 if (dst->state == st) {
385 ret = dst;
386 list_del(&dst->trans_entry);
387 break;
388 }
389 }
390 spin_unlock(&t->dst_lock);
391
392 if (ret)
393 netfs_trans_remove_dst(ret);
394}
395
396/*
397 * This drops destination transaction entry from appropriate network state
398 * tree and drops related reference counter. It is possible that transaction
399 * will be freed here if its reference counter hits zero.
400 * Destination transaction entry will be freed.
401 */
402void netfs_trans_drop_last(struct netfs_trans *t, struct netfs_state *st)
403{
404 struct netfs_trans_dst *dst, *tmp, *ret;
405
406 spin_lock(&t->dst_lock);
407 ret = list_entry(t->dst_list.prev, struct netfs_trans_dst, trans_entry);
408 if (ret->state != st) {
409 ret = NULL;
410 list_for_each_entry_safe(dst, tmp, &t->dst_list, trans_entry) {
411 if (dst->state == st) {
412 ret = dst;
413 list_del_init(&dst->trans_entry);
414 break;
415 }
416 }
417 } else {
418 list_del(&ret->trans_entry);
419 }
420 spin_unlock(&t->dst_lock);
421
422 if (ret)
423 netfs_trans_remove_dst(ret);
424}
425
426static int netfs_trans_push(struct netfs_trans *t, struct netfs_state *st)
427{
428 int err;
429
430 err = netfs_trans_push_dst(t, st);
431 if (err)
432 return err;
433
434 err = netfs_trans_send(t, st);
435 if (err)
436 goto err_out_free;
437
438 if (t->flags & NETFS_TRANS_SINGLE_DST)
439 pohmelfs_switch_active(st->psb);
440
441 return 0;
442
443err_out_free:
444 t->result = err;
445 netfs_trans_drop_last(t, st);
446
447 return err;
448}
449
450int netfs_trans_finish_send(struct netfs_trans *t, struct pohmelfs_sb *psb)
451{
452 struct pohmelfs_config *c;
453 int err = -ENODEV;
454 struct netfs_state *st;
455#if 0
456 dprintk("%s: t: %p, gen: %u, size: %u, page_num: %u, active: %p.\n",
457 __func__, t, t->gen, t->iovec.iov_len, t->page_num, psb->active_state);
458#endif
459 mutex_lock(&psb->state_lock);
460 list_for_each_entry(c, &psb->state_list, config_entry) {
461 st = &c->state;
462
463 if (t->flags & NETFS_TRANS_SINGLE_DST) {
464 if (!(st->ctl.perm & POHMELFS_IO_PERM_READ))
465 continue;
466 } else {
467 if (!(st->ctl.perm & POHMELFS_IO_PERM_WRITE))
468 continue;
469 }
470
471 if (psb->active_state && (psb->active_state->state.ctl.prio >= st->ctl.prio) &&
472 (t->flags & NETFS_TRANS_SINGLE_DST))
473 st = &psb->active_state->state;
474
475 err = netfs_trans_push(t, st);
476 if (!err && (t->flags & NETFS_TRANS_SINGLE_DST))
477 break;
478 }
479
480 mutex_unlock(&psb->state_lock);
481#if 0
482 dprintk("%s: fully sent t: %p, gen: %u, size: %u, page_num: %u, err: %d.\n",
483 __func__, t, t->gen, t->iovec.iov_len, t->page_num, err);
484#endif
485 if (err)
486 t->result = err;
487 return err;
488}
489
490int netfs_trans_finish(struct netfs_trans *t, struct pohmelfs_sb *psb)
491{
492 int err;
493 struct netfs_cmd *cmd = t->iovec.iov_base;
494
495 t->gen = atomic_inc_return(&psb->trans_gen);
496
497 cmd->size = t->iovec.iov_len - sizeof(struct netfs_cmd) +
498 t->attached_size + t->attached_pages * sizeof(struct netfs_cmd);
499 cmd->cmd = NETFS_TRANS;
500 cmd->start = t->gen;
501 cmd->id = 0;
502
503 if (psb->perform_crypto) {
504 cmd->ext = psb->crypto_attached_size;
505 cmd->csize = psb->crypto_attached_size;
506 }
507
508 dprintk("%s: t: %u, size: %u, iov_len: %zu, attached_size: %u, attached_pages: %u.\n",
509 __func__, t->gen, cmd->size, t->iovec.iov_len, t->attached_size, t->attached_pages);
510 err = pohmelfs_trans_crypt(t, psb);
511 if (err) {
512 t->result = err;
513 netfs_convert_cmd(cmd);
514 dprintk("%s: trans: %llu, crypto_attached_size: %u, attached_size: %u, attached_pages: %d, trans_size: %u, err: %d.\n",
515 __func__, cmd->start, psb->crypto_attached_size, t->attached_size, t->attached_pages, cmd->size, err);
516 }
517 netfs_trans_put(t);
518 return err;
519}
520
521/*
522 * Resend transaction to remote server(s).
523 * If new servers were added into superblock, we can try to send data
524 * to them too.
525 *
526 * It is called under superblock's state_lock, so we can safely
527 * dereference psb->state_list. Also, transaction's reference counter is
528 * bumped, so it can not go away under us, thus we can safely access all
529 * its members. State is locked.
530 *
531 * This function returns 0 if transaction was successfully sent to at
532 * least one destination target.
533 */
534int netfs_trans_resend(struct netfs_trans *t, struct pohmelfs_sb *psb)
535{
536 struct netfs_trans_dst *dst;
537 struct netfs_state *st;
538 struct pohmelfs_config *c;
539 int err, exist, error = -ENODEV;
540
541 list_for_each_entry(c, &psb->state_list, config_entry) {
542 st = &c->state;
543
544 exist = 0;
545 spin_lock(&t->dst_lock);
546 list_for_each_entry(dst, &t->dst_list, trans_entry) {
547 if (st == dst->state) {
548 exist = 1;
549 break;
550 }
551 }
552 spin_unlock(&t->dst_lock);
553
554 if (exist) {
555 if (!(t->flags & NETFS_TRANS_SINGLE_DST) ||
556 (c->config_entry.next == &psb->state_list)) {
557 dprintk("%s: resending st: %p, t: %p, gen: %u.\n",
558 __func__, st, t, t->gen);
559 err = netfs_trans_send(t, st);
560 if (!err)
561 error = 0;
562 }
563 continue;
564 }
565
566 dprintk("%s: pushing/resending st: %p, t: %p, gen: %u.\n",
567 __func__, st, t, t->gen);
568 err = netfs_trans_push(t, st);
569 if (err)
570 continue;
571 error = 0;
572 if (t->flags & NETFS_TRANS_SINGLE_DST)
573 break;
574 }
575
576 t->result = error;
577 return error;
578}
579
580void *netfs_trans_add(struct netfs_trans *t, unsigned int size)
581{
582 struct iovec *io = &t->iovec;
583 void *ptr;
584
585 if (size > t->total_size) {
586 ptr = ERR_PTR(-EINVAL);
587 goto out;
588 }
589
590 if (io->iov_len + size > t->total_size) {
591 dprintk("%s: too big size t: %p, gen: %u, iov_len: %zu, size: %u, total: %u.\n",
592 __func__, t, t->gen, io->iov_len, size, t->total_size);
593 ptr = ERR_PTR(-E2BIG);
594 goto out;
595 }
596
597 ptr = io->iov_base + io->iov_len;
598 io->iov_len += size;
599
600out:
601 dprintk("%s: t: %p, gen: %u, size: %u, total: %zu.\n",
602 __func__, t, t->gen, size, io->iov_len);
603 return ptr;
604}
605
606void netfs_trans_free(struct netfs_trans *t)
607{
608 if (t->eng)
609 pohmelfs_crypto_thread_make_ready(t->eng->thread);
610 kfree(t);
611}
612
613struct netfs_trans *netfs_trans_alloc(struct pohmelfs_sb *psb, unsigned int size,
614 unsigned int flags, unsigned int nr)
615{
616 struct netfs_trans *t;
617 unsigned int num, cont, pad, size_no_trans;
618 unsigned int crypto_added = 0;
619 struct netfs_cmd *cmd;
620
621 if (psb->perform_crypto)
622 crypto_added = psb->crypto_attached_size;
623
624 /*
625 * |sizeof(struct netfs_trans)|
626 * |sizeof(struct netfs_cmd)| - transaction header
627 * |size| - buffer with requested size
628 * |padding| - crypto padding, zero bytes
629 * |nr * sizeof(struct page *)| - array of page pointers
630 *
631 * Overall size should be less than PAGE_SIZE for guaranteed allocation.
632 */
633
634 cont = size;
635 size = ALIGN(size, psb->crypto_align_size);
636 pad = size - cont;
637
638 size_no_trans = size + sizeof(struct netfs_cmd) * 2 + crypto_added;
639
640 cont = sizeof(struct netfs_trans) + size_no_trans;
641
642 num = (PAGE_SIZE - cont)/sizeof(struct page *);
643
644 if (nr > num)
645 nr = num;
646
647 t = kzalloc(cont + nr*sizeof(struct page *), GFP_NOIO);
648 if (!t)
649 goto err_out_exit;
650
651 t->iovec.iov_base = (void *)(t + 1);
652 t->pages = (struct page **)(t->iovec.iov_base + size_no_trans);
653
654 /*
655 * Reserving space for transaction header.
656 */
657 t->iovec.iov_len = sizeof(struct netfs_cmd) + crypto_added;
658
659 netfs_trans_init_static(t, nr, size_no_trans);
660
661 t->flags = flags;
662 t->psb = psb;
663
664 cmd = (struct netfs_cmd *)t->iovec.iov_base;
665
666 cmd->size = size;
667 cmd->cpad = pad;
668 cmd->csize = crypto_added;
669
670 dprintk("%s: t: %p, gen: %u, size: %u, padding: %u, align_size: %u, flags: %x, "
671 "page_num: %u, base: %p, pages: %p.\n",
672 __func__, t, t->gen, size, pad, psb->crypto_align_size, flags, nr,
673 t->iovec.iov_base, t->pages);
674
675 return t;
676
677err_out_exit:
678 return NULL;
679}
680
681int netfs_trans_init(void)
682{
683 int err = -ENOMEM;
684
685 netfs_trans_dst = kmem_cache_create("netfs_trans_dst", sizeof(struct netfs_trans_dst),
686 0, 0, NULL);
687 if (!netfs_trans_dst)
688 goto err_out_exit;
689
690 netfs_trans_dst_pool = mempool_create_slab_pool(256, netfs_trans_dst);
691 if (!netfs_trans_dst_pool)
692 goto err_out_free;
693
694 return 0;
695
696err_out_free:
697 kmem_cache_destroy(netfs_trans_dst);
698err_out_exit:
699 return err;
700}
701
702void netfs_trans_exit(void)
703{
704 mempool_destroy(netfs_trans_dst_pool);
705 kmem_cache_destroy(netfs_trans_dst);
706}