summaryrefslogtreecommitdiff
path: root/release/src/linux/linux/include/linux/intermezzo_fs.h
blob: 3553aa77bccaa734ee3ca3cd8b001962fefe5d0b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
 * vim:expandtab:shiftwidth=8:tabstop=8:
 *
 *  Copyright (C) 2001, 2002 Cluster File Systems, Inc.
 *  Copyright (C) 2001 Tacitus Systems, Inc.
 *  Copyright (C) 2000 Stelias Computing, Inc.
 *  Copyright (C) 2000 Red Hat, Inc.
 *  Copyright (C) 2000 TurboLinux, Inc.
 *  Copyright (C) 2000 Los Alamos National Laboratory.
 *
 *   This file is part of InterMezzo, http://www.inter-mezzo.org.
 *
 *   InterMezzo is free software; you can redistribute it and/or
 *   modify it under the terms of version 2 of the GNU General Public
 *   License as published by the Free Software Foundation.
 *
 *   InterMezzo is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with InterMezzo; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#ifndef __INTERMEZZO_FS_H_
#define __INTERMEZZO_FS_H_ 1

#include <linux/intermezzo_lib.h>
#include <linux/intermezzo_idl.h>


#ifdef __KERNEL__
typedef __u8 uuid_t[16];
#else
# include <uuid/uuid.h>
#endif

struct lento_vfs_context {
        __u64 kml_offset;
        __u64 updated_time;
        __u64 remote_ino;
        __u64 remote_generation;
        __u32 slot_offset;
        __u32 recno;
        __u32 flags;
        uuid_t uuid;
        struct presto_version remote_version;
};

static inline int izo_ioctl_is_invalid(struct izo_ioctl_data *data);

#ifdef __KERNEL__
# include <linux/smp.h>
# include <linux/fsfilter.h>
# include <linux/slab.h>
# include <linux/vmalloc.h>
# include <linux/smp_lock.h>

/* fixups for fs.h */
# ifndef fs_down
#  define fs_down(sem) down(sem)
# endif

# ifndef fs_up
#  define fs_up(sem) up(sem)
# endif

# define KML_IDLE                        0
# define KML_DECODE                      1
# define KML_OPTIMIZE                    2
# define KML_REINT                       3

# define KML_OPEN_REINT                  0x0100
# define KML_REINT_BEGIN                 0x0200
# define KML_BACKFETCH                   0x0400
# define KML_REINT_END                   0x0800
# define KML_CLOSE_REINT                 0x1000
# define KML_REINT_MAXBUF                (64 * 1024)

# define CACHE_CLIENT_RO       0x4
# define CACHE_LENTO_RO        0x8

/* global variables */
extern int presto_debug;
extern int presto_print_entry;
extern long presto_kmemory;
extern long presto_vmemory;

# define PRESTO_DEBUG
# ifdef PRESTO_DEBUG
/* debugging masks */
#  define D_SUPER       1
#  define D_INODE       2
#  define D_FILE        4
#  define D_CACHE       8  /* cache debugging */
#  define D_MALLOC     16  /* print malloc, de-alloc information */
#  define D_JOURNAL    32
#  define D_UPCALL     64  /* up and downcall debugging */
#  define D_PSDEV     128
#  define D_PIOCTL    256
#  define D_SPECIAL   512
#  define D_TIMING   1024
#  define D_DOWNCALL 2048
#  define D_KML      4096
#  define D_FSDATA   8192

#  define CDEBUG(mask, format, a...)                                    \
        do {                                                            \
                if (presto_debug & mask) {                              \
                        printk("(%s:%s,l. %d %d): " format, __FILE__,   \
                               __FUNCTION__, __LINE__, current->pid     \
                               , ## a);                                 \
                }                                                       \
        } while (0)

#define CERROR(format, a...)                                            \
do {                                                                    \
        printk("(%s:%s,l. %d %d): " format, __FILE__, __FUNCTION__,     \
               __LINE__, current->pid , ## a);                          \
} while (0)

#  define ENTRY                                                         \
        if (presto_print_entry)                                         \
                printk("Process %d entered %s\n", current->pid, __FUNCTION__)

#  define EXIT                                                          \
        if (presto_print_entry)                                         \
                printk("Process %d leaving %s at %d\n", current->pid,   \
                       __FUNCTION__, __LINE__)

#  define presto_kmem_inc(ptr, size) presto_kmemory += (size)
#  define presto_kmem_dec(ptr, size) presto_kmemory -= (size)
#  define presto_vmem_inc(ptr, size) presto_vmemory += (size)
#  define presto_vmem_dec(ptr, size) presto_vmemory -= (size)
# else /* !PRESTO_DEBUG */
#  define CDEBUG(mask, format, a...) do {} while (0)
#  define ENTRY do {} while (0)
#  define EXIT do {} while (0)
#  define presto_kmem_inc(ptr, size) do {} while (0)
#  define presto_kmem_dec(ptr, size) do {} while (0)
#  define presto_vmem_inc(ptr, size) do {} while (0)
#  define presto_vmem_dec(ptr, size) do {} while (0)
# endif /* PRESTO_DEBUG */


struct run_ctxt {
        struct vfsmount *pwdmnt;
        struct dentry   *pwd;
        struct vfsmount *rootmnt;
        struct dentry   *root;
        uid_t            fsuid;
        gid_t            fsgid;
        mm_segment_t     fs;
	int              ngroups;
	gid_t	         groups[NGROUPS];

};

static inline void push_ctxt(struct run_ctxt *save, struct run_ctxt *new)
{
        int i;
        save->fs = get_fs();
        save->pwd = dget(current->fs->pwd);
        save->pwdmnt = mntget(current->fs->pwdmnt);
        save->fsgid = current->fsgid;
        save->fsuid = current->fsuid;
        save->root = current->fs->root;
        save->rootmnt = current->fs->rootmnt;
        save->ngroups = current->ngroups;
        for (i = 0; i< current->ngroups; i++) 
                save->groups[i] = current->groups[i];

        set_fs(new->fs);
        lock_kernel();
        set_fs_pwd(current->fs, new->pwdmnt, new->pwd);
        if (new->root)
                set_fs_root(current->fs, new->rootmnt, new->root);
        unlock_kernel();
        current->fsuid = new->fsuid;
        current->fsgid = new->fsgid;
        if (new->ngroups > 0) {
                current->ngroups = new->ngroups;
                for (i = 0; i< new->ngroups; i++) 
                        current->groups[i] = new->groups[i];
        }
        
}

static inline void pop_ctxt(struct run_ctxt *saved)
{
        int i;

        set_fs(saved->fs);
        lock_kernel();
        set_fs_pwd(current->fs, saved->pwdmnt, saved->pwd);
        if (saved->root)
                set_fs_root(current->fs, saved->rootmnt, saved->root);
        unlock_kernel();
        current->fsuid = saved->fsuid;
        current->fsgid = saved->fsgid;
        current->ngroups = saved->ngroups;
        for (i = 0; i< saved->ngroups; i++) 
                current->groups[i] = saved->groups[i];

        mntput(saved->pwdmnt);
        dput(saved->pwd);
}

static inline struct presto_dentry_data *presto_d2d(struct dentry *dentry)
{
        return (struct presto_dentry_data *)(dentry->d_fsdata);
}

struct presto_cache {
        spinlock_t          cache_lock;
        loff_t              cache_reserved;
        struct  vfsmount   *cache_vfsmount;
        struct super_block *cache_sb;
        struct  dentry     *cache_root;
        struct list_head    cache_chain; /* for the dev/cache hash */

        int   cache_flags;

        kdev_t cache_dev;            /* underlying block device */

        char *cache_type;            /* filesystem type of cache */
        struct filter_fs *cache_filter;

        struct upc_channel *cache_psdev;  /* points to channel used */
        struct list_head cache_channel_list; 
        struct list_head cache_fset_list; /* filesets mounted in cache */
};

struct presto_log_fd {
        rwlock_t         fd_lock;
        loff_t           fd_offset;  /* offset where next record should go */
        struct file    *fd_file;
        int             fd_truncating;
        unsigned int   fd_recno;   /* last recno written */
        struct list_head  fd_reservations;
};

/* file sets */
# define CHUNK_BITS  16

struct presto_file_set {
        struct list_head fset_list;
        struct presto_log_fd fset_kml;
        struct presto_log_fd fset_lml;
        struct presto_log_fd fset_rcvd;
        struct list_head *fset_clients;  /* cache of clients */
        struct dentry *fset_dentry;
        struct vfsmount *fset_mnt;
        struct presto_cache *fset_cache;

        unsigned int fset_lento_recno;  /* last recno mentioned to lento */
        loff_t fset_lento_off;    /* last offset mentioned to lento */
        loff_t fset_kml_logical_off; /* logical offset of kml file byte 0 */
        char * fset_name;

        int fset_flags;
        int fset_chunkbits;
        char *fset_reint_buf; /* temporary buffer holds kml during reint */

        spinlock_t fset_permit_lock;
        int fset_permit_count;
        int fset_permit_upcall_count;
        /* This queue is used both for processes waiting for the kernel to give
         * up the permit as well as processes waiting for the kernel to be given
         * the permit, depending on the state of FSET_HASPERMIT. */
        wait_queue_head_t fset_permit_queue;

        loff_t  fset_file_maxio;  /* writing more than this causes a close */
        unsigned long int kml_truncate_size;
};

/* This is the default number of bytes written before a close is recorded*/
#define FSET_DEFAULT_MAX_FILEIO (1024<<10)

struct dentry *presto_tmpfs_ilookup(struct inode *dir, struct dentry *dentry, 
                                    ino_t ino, unsigned int generation);
struct dentry *presto_iget_ilookup(struct inode *dir, struct dentry *dentry, 
                                    ino_t ino, unsigned int generation);
struct dentry *presto_add_ilookup_dentry(struct dentry *parent,
                                         struct dentry *real);

struct journal_ops {
        int (*tr_all_data)(struct inode *);
        loff_t (*tr_avail)(struct presto_cache *fset, struct super_block *);
        void *(*tr_start)(struct presto_file_set *, struct inode *, int op);
        void (*tr_commit)(struct presto_file_set *, void *handle);
        void (*tr_journal_data)(struct inode *);
        struct dentry *(*tr_ilookup)(struct inode *dir, struct dentry *dentry, ino_t ino, unsigned int generation);
        struct dentry *(*tr_add_ilookup)(struct dentry *parent, struct dentry *real);
};

extern struct journal_ops presto_ext2_journal_ops;
extern struct journal_ops presto_ext3_journal_ops;
extern struct journal_ops presto_tmpfs_journal_ops;
extern struct journal_ops presto_xfs_journal_ops;
extern struct journal_ops presto_reiserfs_journal_ops;
extern struct journal_ops presto_obdfs_journal_ops;

# define LENTO_FL_KML            0x0001
# define LENTO_FL_EXPECT         0x0002
# define LENTO_FL_VFSCHECK       0x0004
# define LENTO_FL_JUSTLOG        0x0008
# define LENTO_FL_WRITE_KML      0x0010
# define LENTO_FL_CANCEL_LML     0x0020
# define LENTO_FL_WRITE_EXPECT   0x0040
# define LENTO_FL_IGNORE_TIME    0x0080
# define LENTO_FL_TOUCH_PARENT   0x0100
# define LENTO_FL_TOUCH_NEWOBJ   0x0200
# define LENTO_FL_SET_DDFILEID   0x0400

struct presto_cache *presto_get_cache(struct inode *inode);
int presto_sprint_mounts(char *buf, int buflen, int minor);
struct presto_file_set *presto_fset(struct dentry *de);
int presto_journal(struct dentry *dentry, char *buf, size_t size);
int presto_fwrite(struct file *file, const char *str, int len, loff_t *off);
int presto_ispresto(struct inode *);

/* super.c */
extern struct file_system_type presto_fs_type;
extern int init_intermezzo_fs(void);

/* fileset.c */
extern int izo_prepare_fileset(struct dentry *root, char *fsetname);
char * izo_make_path(struct presto_file_set *fset, char *name);
struct file *izo_fset_open(struct presto_file_set *fset, char *name, int flags, int mode);

/* psdev.c */
int izo_psdev_get_free_channel(void);
int presto_psdev_init(void);
int izo_psdev_setpid(int minor);
extern void presto_psdev_cleanup(void);
inline int presto_lento_up(int minor);
int izo_psdev_setchannel(struct file *file, int fd);

/* inode.c */
extern struct super_operations presto_super_ops;
void presto_set_ops(struct inode *inode, struct  filter_fs *filter);

/* dcache.c */
void presto_frob_dop(struct dentry *de);
char *presto_path(struct dentry *dentry, struct dentry *root,
                  char *buffer, int buflen);
inline struct presto_dentry_data *izo_alloc_ddata(void);
int presto_set_dd(struct dentry *);
int presto_init_ddata_cache(void);
void presto_cleanup_ddata_cache(void);
extern struct dentry_operations presto_dentry_ops;

/* dir.c */
extern struct inode_operations presto_dir_iops;
extern struct inode_operations presto_file_iops;
extern struct inode_operations presto_sym_iops;
extern struct file_operations presto_dir_fops;
extern struct file_operations presto_file_fops;
extern struct file_operations presto_sym_fops;
int presto_setattr(struct dentry *de, struct iattr *iattr);
int presto_settime(struct presto_file_set *fset, struct dentry *newobj,
                   struct dentry *parent, struct dentry *target,
                   struct lento_vfs_context *ctx, int valid);
int presto_ioctl(struct inode *inode, struct file *file,
                 unsigned int cmd, unsigned long arg);

extern int presto_ilookup_uid;
# define PRESTO_ILOOKUP_MAGIC "...ino:"
# define PRESTO_ILOOKUP_SEP ':'
int izo_dentry_is_ilookup(struct dentry *, ino_t *id, unsigned int *generation);
struct dentry *presto_lookup(struct inode * dir, struct dentry *dentry);

struct presto_dentry_data {
        int dd_count; /* how mnay dentries are using this dentry */
        struct presto_file_set *dd_fset;
        struct dentry *dd_inodentry; 
        loff_t dd_kml_offset;
        int dd_flags;
        __u64 remote_ino;
        __u64 remote_generation;
};

struct presto_file_data {
        int fd_do_lml;
        loff_t fd_lml_offset;
        size_t fd_bytes_written;
        /* authorization related data of file at open time */
        uid_t fd_uid;
        gid_t fd_gid;
        mode_t fd_mode;
        /* identification data of calling process */
        uid_t fd_fsuid;
        gid_t fd_fsgid;
        int fd_ngroups;
        gid_t fd_groups[NGROUPS_MAX];
        /* information how to complete the close operation */
        struct lento_vfs_context fd_info;
        struct presto_version fd_version;
};

/* presto.c and Lento::Downcall */

int presto_walk(const char *name, struct nameidata *nd);
int izo_clear_fsetroot(struct dentry *dentry);
int izo_clear_all_fsetroots(struct presto_cache *cache);
int presto_get_kmlsize(char *path, __u64 *size);
int presto_get_lastrecno(char *path, off_t *size);
int presto_set_fsetroot(struct dentry *dentry, char *fsetname,
                       unsigned int flags);
int presto_set_fsetroot_from_ioc(struct dentry *dentry, char *fsetname,
                                 unsigned int flags);
inline int presto_is_read_only(struct presto_file_set *);
int presto_truncate_lml(struct presto_file_set *fset);
int lento_write_lml(char *path,
                     __u64 remote_ino,
                     __u32 remote_generation,
                     __u32 remote_version,
                    struct presto_version *remote_file_version);
int lento_complete_closes(char *path);
inline int presto_f2m(struct presto_file_set *fset);
int presto_prep(struct dentry *, struct presto_cache **,
                       struct presto_file_set **);
/* cache.c */
extern struct presto_cache *presto_cache_init(void);
extern inline void presto_cache_add(struct presto_cache *cache, kdev_t dev);
extern inline void presto_cache_init_hash(void);

struct presto_cache *presto_cache_find(kdev_t dev);

#define PRESTO_REQLOW  (3 * 4096)
#define PRESTO_REQHIGH (6 * 4096)
void presto_release_space(struct presto_cache *cache, loff_t req);
int presto_reserve_space(struct presto_cache *cache, loff_t req);

#define PRESTO_DATA             0x00000002 /* cached data is valid */
#define PRESTO_ATTR             0x00000004 /* attributes cached */
#define PRESTO_DONT_JOURNAL     0x00000008 /* things like .intermezzo/ */

struct presto_file_set *presto_path2fileset(const char *name);
int izo_revoke_permit(struct dentry *, uuid_t uuid);
int presto_chk(struct dentry *dentry, int flag);
void presto_set(struct dentry *dentry, int flag);
int presto_get_permit(struct inode *inode);
int presto_put_permit(struct inode *inode);
int presto_set_max_kml_size(const char *path, unsigned long max_size);
int izo_mark_dentry(struct dentry *dentry, int and, int or, int *res);
int izo_mark_cache(struct dentry *dentry, int and_bits, int or_bits, int *);
int izo_mark_fset(struct dentry *dentry, int and_bits, int or_bits, int *);
void presto_getversion(struct presto_version *pv, struct inode *inode);
int presto_i2m(struct inode *inode);
int presto_c2m(struct presto_cache *cache);


/* file.c */
int izo_purge_file(struct presto_file_set *fset, char *file);
int presto_adjust_lml(struct file *file, struct lento_vfs_context *info);

/* journal.c */
struct rec_info {
        loff_t offset;
        int size;
        int recno;
        int is_kml;
};

void presto_trans_commit(struct presto_file_set *fset, void *handle);
void *presto_trans_start(struct presto_file_set *fset, struct inode *inode,
                         int op);
int presto_fread(struct file *file, char *str, int len, loff_t *off);
int presto_clear_lml_close(struct presto_file_set *fset,
                           loff_t  lml_offset);
int presto_complete_lml(struct presto_file_set *fset);
int presto_read_kml_logical_offset(struct rec_info *recinfo,
                                   struct presto_file_set *fset);
int presto_write_kml_logical_offset(struct presto_file_set *fset);
struct file *presto_copy_kml_tail(struct presto_file_set *fset,
                                  unsigned long int start);
int presto_finish_kml_truncate(struct presto_file_set *fset,
                               unsigned long int offset);
int izo_lookup_file(struct presto_file_set *fset, char *path,
                    struct nameidata *nd);
int izo_do_truncate(struct presto_file_set *fset, struct dentry *dentry,
                    loff_t length,  loff_t size_check);
int izo_log_close(struct presto_log_fd *logfd);
struct file *izo_log_open(struct presto_file_set *fset, char *name, int flags);
int izo_init_kml_file(struct presto_file_set *, struct presto_log_fd *);
int izo_init_lml_file(struct presto_file_set *, struct presto_log_fd *);
int izo_init_last_rcvd_file(struct presto_file_set *, struct presto_log_fd *);

/* vfs.c */

/* Extra data needed in the KML for rollback operations; this structure is
 * passed around during the KML-writing process. */
struct izo_rollback_data {
        __u32 rb_mode;
        __u32 rb_rdev;
        __u64 rb_uid;
        __u64 rb_gid;
};

int presto_write_last_rcvd(struct rec_info *recinfo,
                           struct presto_file_set *fset,
                           struct lento_vfs_context *info);
void izo_get_rollback_data(struct inode *inode, struct izo_rollback_data *rb);
int presto_do_close(struct presto_file_set *fset, struct file *file);
int presto_do_setattr(struct presto_file_set *fset, struct dentry *dentry,
                      struct iattr *iattr, struct lento_vfs_context *info);
int presto_do_create(struct presto_file_set *fset, struct dentry *dir,
                     struct dentry *dentry, int mode,
                     struct lento_vfs_context *info);
int presto_do_link(struct presto_file_set *fset, struct dentry *dir,
                   struct dentry *old_dentry, struct dentry *new_dentry,
                   struct lento_vfs_context *info);
int presto_do_unlink(struct presto_file_set *fset, struct dentry *dir,
                     struct dentry *dentry, struct lento_vfs_context *info);
int presto_do_symlink(struct presto_file_set *fset, struct dentry *dir,
                      struct dentry *dentry, const char *name,
                      struct lento_vfs_context *info);
int presto_do_mkdir(struct presto_file_set *fset, struct dentry *dir,
                    struct dentry *dentry, int mode,
                    struct lento_vfs_context *info);
int presto_do_rmdir(struct presto_file_set *fset, struct dentry *dir,
                    struct dentry *dentry, struct lento_vfs_context *info);
int presto_do_mknod(struct presto_file_set *fset, struct dentry *dir,
                    struct dentry *dentry, int mode, dev_t dev,
                    struct lento_vfs_context *info);
int do_rename(struct presto_file_set *fset, struct dentry *old_dir,
              struct dentry *old_dentry, struct dentry *new_dir,
              struct dentry *new_dentry, struct lento_vfs_context *info);
int presto_do_statfs (struct presto_file_set *fset,
                      struct statfs * buf);

int lento_setattr(const char *name, struct iattr *iattr,
                  struct lento_vfs_context *info);
int lento_create(const char *name, int mode, struct lento_vfs_context *info);
int lento_link(const char *oldname, const char *newname,
               struct lento_vfs_context *info);
int lento_unlink(const char *name, struct lento_vfs_context *info);
int lento_symlink(const char *oldname,const char *newname,
                  struct lento_vfs_context *info);
int lento_mkdir(const char *name, int mode, struct lento_vfs_context *info);
int lento_rmdir(const char *name, struct lento_vfs_context *info);
int lento_mknod(const char *name, int mode, dev_t dev,
                struct lento_vfs_context *info);
int lento_rename(const char *oldname, const char *newname,
                 struct lento_vfs_context *info);
int lento_iopen(const char *name, ino_t ino, unsigned int generation,int flags);

/* journal.c */

#define JOURNAL_PAGE_SZ  PAGE_SIZE

__inline__ int presto_no_journal(struct presto_file_set *fset);
int journal_fetch(int minor);
int presto_log(struct presto_file_set *fset, struct rec_info *rec,
               const char *buf, size_t size,
               const char *string1, int len1, 
               const char *string2, int len2,
               const char *string3, int len3);
int presto_get_fileid(int minor, struct presto_file_set *fset,
                      struct dentry *dentry);
int presto_journal_setattr(struct rec_info *rec, struct presto_file_set *fset,
                           struct dentry *dentry, struct presto_version *old_ver,
                           struct izo_rollback_data *, struct iattr *iattr);
int presto_journal_create(struct rec_info *rec, struct presto_file_set *fset,
                          struct dentry *dentry,
                          struct presto_version *tgt_dir_ver,
                          struct presto_version *new_file_ver, int mode);
int presto_journal_link(struct rec_info *rec, struct presto_file_set *fset,
                        struct dentry *src, struct dentry *tgt,
                        struct presto_version *tgt_dir_ver,
                        struct presto_version *new_link_ver);
int presto_journal_unlink(struct rec_info *rec, struct presto_file_set *fset,
                          struct dentry *dir,
                          struct presto_version *tgt_dir_ver,
                          struct presto_version *old_file_ver,
                          struct izo_rollback_data *, struct dentry *dentry,
                          char *old_target, int old_targetlen);
int presto_journal_symlink(struct rec_info *rec, struct presto_file_set *fset,
                           struct dentry *dentry, const char *target,
                           struct presto_version *tgt_dir_ver,
                           struct presto_version *new_link_ver);
int presto_journal_mkdir(struct rec_info *rec, struct presto_file_set *fset,
                         struct dentry *dentry,
                         struct presto_version *tgt_dir_ver,
                         struct presto_version *new_dir_ver, int mode);
int presto_journal_rmdir(struct rec_info *rec, struct presto_file_set *fset,
                         struct dentry *dentry,
                         struct presto_version *tgt_dir_ver,
                         struct presto_version *old_dir_ver,
                         struct izo_rollback_data *, int len, const char *name);
int presto_journal_mknod(struct rec_info *rec, struct presto_file_set *fset,
                         struct dentry *dentry,
                         struct presto_version *tgt_dir_ver,
                         struct presto_version *new_node_ver, int mode,
                         int dmajor, int dminor);
int presto_journal_rename(struct rec_info *rec, struct presto_file_set *fset,
                          struct dentry *src, struct dentry *tgt,
                          struct presto_version *src_dir_ver,
                          struct presto_version *tgt_dir_ver);
int presto_journal_open(struct rec_info *, struct presto_file_set *,
                        struct dentry *, struct presto_version *old_ver);
int presto_journal_close(struct rec_info *rec, struct presto_file_set *,
                         struct file *, struct dentry *,
                         struct presto_version *old_file_ver,
                         struct presto_version *new_file_ver);
int presto_write_lml_close(struct rec_info *rec,
                           struct presto_file_set *fset, 
                           struct file *file,
                           __u64 remote_ino,
                           __u64 remote_generation,
                           struct presto_version *remote_version,
                           struct presto_version *new_file_ver);
void presto_log_op(void *data, int len);
loff_t presto_kml_offset(struct presto_file_set *fset);

/* upcall.c */
#define SYNCHRONOUS 0
#define ASYNCHRONOUS 1
/* asynchronous calls */
int izo_upc_kml(int minor, __u64 offset, __u32 first_recno, __u64 length,
                __u32 last_recno, char *fsetname);
int izo_upc_kml_truncate(int minor, __u64 length, __u32 last_recno,
                         char *fsetname);
int izo_upc_go_fetch_kml(int minor, char *fsetname, uuid_t uuid, __u64 kmlsize);
int izo_upc_backfetch(int minor, char *path, char *fileset, 
                      struct lento_vfs_context *);

/* synchronous calls */
int izo_upc_get_fileid(int minor, __u32 reclen, char *rec, 
                       __u32 pathlen, char *path, char *fsetname);
int izo_upc_permit(int minor, struct dentry *, __u32 pathlen, char *path,
                   char *fset);
int izo_upc_open(int minor, __u32 pathlen, char *path, char *fsetname, 
                 struct lento_vfs_context *info);
int izo_upc_connect(int minor, __u64 ip_address, __u64 port, __u8 uuid[16],
                    int client_flag);
int izo_upc_revoke_permit(int minor, char *fsetname, uuid_t uuid);
int izo_upc_set_kmlsize(int minor, char *fsetname, uuid_t uuid, __u64 kmlsize);
int izo_upc_client_make_branch(int minor, char *fsetname);
int izo_upc_server_make_branch(int minor, char *fsetname);
int izo_upc_branch_undo(int minor, char *fsetname, char *branchname);
int izo_upc_branch_redo(int minor, char *fsetname, char *branchname);
int izo_upc_repstatus(int minor,  char * fsetname, struct izo_rcvd_rec *lr_server);

/* general mechanism */
int izo_upc_upcall(int minor, int *size, struct izo_upcall_hdr *, int async);

/* replicator.c */
int izo_repstatus(struct presto_file_set *fset, __u64 client_kmlsize, 
                  struct izo_rcvd_rec *lr_client, struct izo_rcvd_rec *lr_server);
int izo_rep_cache_init(struct presto_file_set *);
loff_t izo_rcvd_get(struct izo_rcvd_rec *, struct presto_file_set *, char *uuid);
loff_t izo_rcvd_write(struct presto_file_set *, struct izo_rcvd_rec *);
loff_t izo_rcvd_upd_remote(struct presto_file_set *fset, char * uuid,  __u64 remote_recno,
                           __u64 remote_offset);

/* sysctl.c */
int init_intermezzo_sysctl(void);
void cleanup_intermezzo_sysctl(void);

/* ext_attr.c */
/* We will be more tolerant than the default ea patch with attr name sizes and
 * the size of value. If these come via VFS from the default ea patches, the
 * corresponding character strings will be truncated anyway. During journalling- * we journal length for both name and value. See journal_set_ext_attr.
 */
#define PRESTO_EXT_ATTR_NAME_MAX 128
#define PRESTO_EXT_ATTR_VALUE_MAX 8192

#define PRESTO_ALLOC(ptr, size)                                         \
do {                                                                    \
        long s = (size);                                                \
        (ptr) = kmalloc(s, GFP_KERNEL);                                 \
        if ((ptr) == NULL)                                              \
                CERROR("IZO: out of memory at %s:%d (trying to "        \
                       "allocate %ld)\n", __FILE__, __LINE__, s);       \
        else {                                                          \
                presto_kmem_inc((ptr), s);                              \
                memset((ptr), 0, s);                                    \
        }                                                               \
        CDEBUG(D_MALLOC, "kmalloced: %ld at %p (tot %ld).\n",           \
               s, (ptr), presto_kmemory);                               \
} while (0)

#define PRESTO_FREE(ptr, size)                                          \
do {                                                                    \
        long s = (size);                                                \
        if ((ptr) == NULL) {                                            \
                CERROR("IZO: free NULL pointer (%ld bytes) at "         \
                       "%s:%d\n", s, __FILE__, __LINE__);               \
                break;                                                  \
        }                                                               \
        kfree(ptr);                                                     \
        CDEBUG(D_MALLOC, "kfreed: %ld at %p (tot %ld).\n",              \
               s, (ptr), presto_kmemory);                               \
        presto_kmem_dec((ptr), s);                                      \
} while (0)

static inline int dentry_name_cmp(struct dentry *dentry, char *name)
{
        return (strlen(name) == dentry->d_name.len &&
                memcmp(name, dentry->d_name.name, dentry->d_name.len) == 0);
}

static inline char *strdup(char *str)
{
        char *tmp;
        tmp = kmalloc(strlen(str) + 1, GFP_KERNEL);
        if (tmp)
                memcpy(tmp, str, strlen(str) + 1);
               
        return tmp;
}

/* buffer MUST be at least the size of izo_ioctl_hdr */
static inline int izo_ioctl_getdata(char *buf, char *end, void *arg)
{
        struct izo_ioctl_hdr *hdr;
        struct izo_ioctl_data *data;
        int err;
        ENTRY;

        hdr = (struct izo_ioctl_hdr *)buf;
        data = (struct izo_ioctl_data *)buf;

        err = copy_from_user(buf, (void *)arg, sizeof(*hdr));
        if ( err ) {
                EXIT;
                return err;
        }

        if (hdr->ioc_version != IZO_IOCTL_VERSION) {
                CERROR("IZO: version mismatch kernel vs application\n");
                return -EINVAL;
        }

        if (hdr->ioc_len + buf >= end) {
                CERROR("IZO: user buffer exceeds kernel buffer\n");
                return -EINVAL;
        }

        if (hdr->ioc_len < sizeof(struct izo_ioctl_data)) {
                CERROR("IZO: user buffer too small for ioctl\n");
                return -EINVAL;
        }

        err = copy_from_user(buf, (void *)arg, hdr->ioc_len);
        if ( err ) {
                EXIT;
                return err;
        }

        if (izo_ioctl_is_invalid(data)) {
                CERROR("IZO: ioctl not correctly formatted\n");
                return -EINVAL;
        }

        if (data->ioc_inllen1) {
                data->ioc_inlbuf1 = &data->ioc_bulk[0];
        }

        if (data->ioc_inllen2) {
                data->ioc_inlbuf2 = &data->ioc_bulk[0] +
                        size_round(data->ioc_inllen1);
        }

        EXIT;
        return 0;
}

# define MYPATHLEN(buffer, path) ((buffer) + PAGE_SIZE - (path))

# define free kfree
# define malloc(a) kmalloc(a, GFP_KERNEL)
# define printf printk
int kml_reint_rec(struct file *dir, struct izo_ioctl_data *data);
int izo_get_fileid(struct file *dir, struct izo_ioctl_data *data);
int izo_set_fileid(struct file *dir, struct izo_ioctl_data *data);

#else /* __KERNEL__ */
# include <stdlib.h>
# include <stdio.h>
# include <sys/types.h>
# include <sys/ioctl.h>
# include <string.h>

# define printk printf
# ifndef CERROR
#   define CERROR printf
# endif
# define kmalloc(a,b) malloc(a)

void init_fsreintdata (void);
int kml_fsreint(struct kml_rec *rec, char *basedir);
int kml_iocreint(__u32 size, char *ptr, __u32 offset, int dird,
                 uuid_t uuid, __u32 generate_kml);

static inline int izo_ioctl_packlen(struct izo_ioctl_data *data);

static inline void izo_ioctl_init(struct izo_ioctl_data *data)
{
        memset(data, 0, sizeof(*data));
        data->ioc_len = sizeof(*data);
        data->ioc_version = IZO_IOCTL_VERSION;
}

static inline int
izo_ioctl_pack(struct izo_ioctl_data *data, char **pbuf, int max)
{
        char *ptr;
        struct izo_ioctl_data *overlay;
        data->ioc_len = izo_ioctl_packlen(data);
        data->ioc_version = IZO_IOCTL_VERSION;

        if (*pbuf && izo_ioctl_packlen(data) > max)
                return 1;
        if (*pbuf == NULL)
                *pbuf = malloc(data->ioc_len);
        if (*pbuf == NULL)
                return 1;
        overlay = (struct izo_ioctl_data *)*pbuf;
        memcpy(*pbuf, data, sizeof(*data));

        ptr = overlay->ioc_bulk;
        if (data->ioc_inlbuf1)
                LOGL(data->ioc_inlbuf1, data->ioc_inllen1, ptr);
        if (data->ioc_inlbuf2)
                LOGL(data->ioc_inlbuf2, data->ioc_inllen2, ptr);
        if (izo_ioctl_is_invalid(overlay))
                return 1;

        return 0;
}

#endif /* __KERNEL__*/

#define IZO_ERROR_NAME 1
#define IZO_ERROR_UPDATE 2
#define IZO_ERROR_DELETE 3
#define IZO_ERROR_RENAME 4

static inline char *izo_error(int err)
{
#ifndef __KERNEL__
        if (err <= 0)
                return strerror(-err);
#endif
        switch (err) {
        case IZO_ERROR_NAME:
                return "InterMezzo name/name conflict";
        case IZO_ERROR_UPDATE:
                return "InterMezzo update/update conflict";
        case IZO_ERROR_DELETE:
                return "InterMezzo update/delete conflict";
        case IZO_ERROR_RENAME:
                return "InterMezzo rename/rename conflict";
        }
        return "Unknown InterMezzo error";
}

static inline int izo_ioctl_packlen(struct izo_ioctl_data *data)
{
        int len = sizeof(struct izo_ioctl_data);
        len += size_round(data->ioc_inllen1);
        len += size_round(data->ioc_inllen2);
        return len;
}

static inline int izo_ioctl_is_invalid(struct izo_ioctl_data *data)
{
        if (data->ioc_len > (1<<30)) {
                CERROR("IZO ioctl: ioc_len larger than 1<<30\n");
                return 1;
        }
        if (data->ioc_inllen1 > (1<<30)) {
                CERROR("IZO ioctl: ioc_inllen1 larger than 1<<30\n");
                return 1;
        }
        if (data->ioc_inllen2 > (1<<30)) {
                CERROR("IZO ioctl: ioc_inllen2 larger than 1<<30\n");
                return 1;
        }
        if (data->ioc_inlbuf1 && !data->ioc_inllen1) {
                CERROR("IZO ioctl: inlbuf1 pointer but 0 length\n");
                return 1;
        }
        if (data->ioc_inlbuf2 && !data->ioc_inllen2) {
                CERROR("IZO ioctl: inlbuf2 pointer but 0 length\n");
                return 1;
        }
        if (data->ioc_pbuf1 && !data->ioc_plen1) {
                CERROR("IZO ioctl: pbuf1 pointer but 0 length\n");
                return 1;
        }
        if (data->ioc_pbuf2 && !data->ioc_plen2) {
                CERROR("IZO ioctl: pbuf2 pointer but 0 length\n");
                return 1;
        }
        if (izo_ioctl_packlen(data) != data->ioc_len ) {
                CERROR("IZO ioctl: packlen exceeds ioc_len\n");
                return 1;
        }
        if (data->ioc_inllen1 &&
            data->ioc_bulk[data->ioc_inllen1 - 1] != '\0') {
                CERROR("IZO ioctl: inlbuf1 not 0 terminated\n");
                return 1;
        }
        if (data->ioc_inllen2 &&
            data->ioc_bulk[size_round(data->ioc_inllen1) + data->ioc_inllen2
                           - 1] != '\0') {
                CERROR("IZO ioctl: inlbuf2 not 0 terminated\n");
                return 1;
        }
        return 0;
}

/* kml_unpack.c */
char *kml_print_rec(struct kml_rec *rec, int brief);
int kml_unpack(struct kml_rec *rec, char **buf, char *end);

#endif