--- /dev/null 2007-08-05 21:14:35.622844160 +0200 +++ linux-2.6.21logfs/fs/logfs/logfs.h 2007-08-08 03:02:00.000000000 +0200 @@ -0,0 +1,445 @@ +/* + * fs/logfs/logfs.h + * + * As should be obvious for Linux kernel code, license is GPLv2 + * + * Copyright (c) 2005-2007 Joern Engel <joern@xxxxxxxxx> + * + * Private header for logfs. + */ +#ifndef fs_logfs_logfs_h +#define fs_logfs_logfs_h + +#define __CHECK_ENDIAN__ + + +#include <linux/crc32.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/logfs.h> +#include <linux/pagemap.h> + + +/* + * There is no generic kernel btree library yet. When such a thing gets + * introduced, this definition and the corresponding source file should + * get removed. + */ +struct btree_head { + struct btree_node *node; + int height; + void *null_ptr; +}; + + +static inline void build_bug_on_needs_a_function(void) +{ + BUILD_BUG_ON(sizeof(struct logfs_object_header) != LOGFS_HEADERSIZE); + BUILD_BUG_ON(sizeof(struct logfs_segment_header) + != LOGFS_SEGMENT_HEADERSIZE); +} + + +/* FIXME: This should really be somewhere in the 64bit area. */ +#define LOGFS_LINK_MAX (1<<30) + + +/* + * Private errno for accessed beyond end-of-file. Only used internally to + * logfs. If this ever gets exposed to userspace or even other parts of the + * kernel, it is a bug. 256 was chosen as a number sufficiently above all + * used errno #defines. + * + * It can be argued that this is a hack and should be replaced with something + * else. My last attempt to do this failed spectacularly and there are more + * urgent problems that users actually care about. This will remain for the + * moment. Patches are wellcome, of course. + */ +#define EOF (512) + + +/* Read-only filesystem */ +#define LOGFS_SB_FLAG_RO 1 + + +/** + * struct logfs_area - area management information + * + * @a_sb: the superblock this area belongs to + * @a_is_open: 1 if the area is currently open, else 0 + * @a_segno: segment number of area + * @a_used_bytes: number of used bytes + * @a_ops: area operations (either journal or ostore) + * @a_wbuf: write buffer + * @a_erase_count: erase count + * @a_level: GC level + */ +struct logfs_area { /* a segment open for writing */ + struct super_block *a_sb; + int a_is_open; + u32 a_segno; + u32 a_used_bytes; + const struct logfs_area_ops *a_ops; + void *a_wbuf; + u32 a_erase_count; + u8 a_level; +}; + + +/** + * struct logfs_area_ops - area operations + * + * @get_free_segment: fill area->ofs with the offset of a free segment + * @get_erase_count: fill area->erase_count (needs area->ofs) + * @erase_segment: erase and setup segment + * @finish_area: flush buffers, etc. + */ +struct logfs_area_ops { + void (*get_free_segment)(struct logfs_area *area); + void (*get_erase_count)(struct logfs_area *area); + int (*erase_segment)(struct logfs_area *area); + void (*finish_area)(struct logfs_area *area); +}; + + +/** + * struct logfs_device_ops - device access operations + * + * @read: read from the device + * @write: write to the device + * @erase: erase part of the device + */ +struct logfs_device_ops { + int (*read)(struct super_block *sb, loff_t ofs, size_t len, void *buf); + int (*write)(struct super_block *sb, loff_t ofs, size_t len, void *buf); + int (*erase)(struct super_block *sb, loff_t ofs, size_t len); + void (*sync)(struct super_block *sb); +}; + + +/** + * struct gc_candidate - "candidate" segment to be garbage collected next + * + * @list: list (either free of low) + * @erase_count: erase count of segment + * @valid: number of valid bytes + * @write_time: GEC at time of writing + * @segno: segment number + * @level: segment level + * + * Candidates can be on two lists. The free list contains electees rather + * than candidates - segments that no longer contain any valid data. The + * low list contains candidates to be picked for GC. It should be kept + * short. It is not required to always pick a perfect candidate. In the + * worst case GC will have to move more data than absolutely necessary. + */ +struct gc_candidate { + struct list_head list; + u32 erase_count; + u32 valid; + u64 write_time; + u32 segno; + u8 level; +}; + + +/** + * struct logfs_journal_entry - temporary structure used during journal scan + * + * @used: + * @version: normalized version + * @len: length + * @offset: offset + */ +struct logfs_journal_entry { + int used; + s16 version; + u16 len; + u64 offset; +}; + + +enum transaction_state { + CREATE_1 = 1, + CREATE_2, + UNLINK_1, + UNLINK_2, + CROSS_RENAME_1, + CROSS_RENAME_2, + TARGET_RENAME_1, + TARGET_RENAME_2, + TARGET_RENAME_3 +}; + + +/** + * struct logfs_transaction - essential fields to support atomic dirops + * + * @ino: target inode + * @dir: inode of directory containing dentry + * @pos: pos of dentry in directory + */ +struct logfs_transaction { + enum transaction_state state; + u64 ino; + u64 dir; + u64 pos; +}; + + +struct logfs_super { + struct mtd_info *s_mtd; /* underlying device */ + struct block_device *s_bdev; /* underlying device */ + int s_sync; /* sync on next io? */ + const struct logfs_device_ops *s_devops;/* device access */ + struct inode *s_master_inode; /* ifile */ + long s_flags; + /* dir.c fields */ + struct mutex s_dirop_mutex; /* for creat/unlink/rename */ + u64 s_victim_ino; /* used for atomic dir-ops */ + u64 s_rename_dir; /* source directory ino */ + u64 s_rename_pos; /* position of source dd */ + /* gc.c fields */ + long s_segsize; /* size of a segment */ + int s_segshift; /* log2 of segment size */ + long s_no_segs; /* segments on device */ + long s_no_blocks; /* blocks per segment */ + long s_writesize; /* minimum write size */ + int s_writeshift; /* log2 of write size */ + u64 s_size; /* filesystem size */ + struct logfs_area *s_area[LOGFS_NO_AREAS]; /* open segment array */ + u64 s_gec; /* global erase count */ + u64 s_sweeper; /* current sweeper pos */ + u8 s_ifile_levels; /* max level of ifile */ + u8 s_iblock_levels; /* max level of regular files */ + u8 s_data_levels; /* # of segments to leaf block*/ + u8 s_total_levels; /* sum of above three */ + struct list_head s_free_list; /* 100% free segments */ + struct list_head s_low_list; /* low-resistance segments */ + int s_free_count; /* # of 100% free segments */ + int s_low_count; /* # of low-resistance segs */ + struct btree_head s_reserved_segments; /* sb, journal, bad, etc. */ + /* inode.c fields */ + spinlock_t s_ino_lock; /* lock s_last_ino on 32bit */ + u64 s_last_ino; /* highest ino used */ + struct list_head s_freeing_list; /* inodes being freed */ + /* journal.c fields */ + struct mutex s_journal_mutex; + void *s_je; /* journal entry to compress */ + void *s_compressed_je; /* block to write to journal */ + u64 s_journal_seg[LOGFS_JOURNAL_SEGS]; /* journal segments */ + u32 s_journal_ec[LOGFS_JOURNAL_SEGS]; /* journal erasecounts */ + u64 s_last_version; + struct logfs_area *s_journal_area; /* open journal segment */ + struct logfs_journal_entry s_retired[JE_LAST+1]; /* for journal scan */ + struct logfs_journal_entry s_speculative[JE_LAST+1]; /* dito */ + struct logfs_journal_entry s_first; /* dito */ + int s_sum_index; /* for the 12 summaries */ + __be32 *s_bb_array; /* bad segments */ + /* readwrite.c fields */ + struct mutex s_r_mutex; + struct mutex s_w_mutex; + __be64 *s_rblock; + __be64 *s_wblock[LOGFS_MAX_LEVELS]; + u64 s_free_bytes; /* number of free bytes */ + u64 s_used_bytes; /* number of bytes used */ + u64 s_gc_reserve; + u64 s_root_reserve; + u32 s_bad_segments; /* number of bad segments */ +}; + + +/** + * struct logfs_inode - in-memory inode + * + * @vfs_inode: struct inode + * @li_data: data pointers + * @li_used_bytes: number of used bytes + * @li_freeing_list: used to track inodes currently being freed + * @li_flags: inode flags + */ +struct logfs_inode { + struct inode vfs_inode; + u64 li_data[LOGFS_EMBEDDED_FIELDS]; + u64 li_used_bytes; + struct list_head li_freeing_list; + struct logfs_transaction *li_transaction; + u32 li_flags; + u8 li_height; +}; + + +#define journal_for_each(__i) for (__i=0; __i<LOGFS_JOURNAL_SEGS; __i++) + + +/* compr.c */ +int logfs_compress(void *in, void *out, size_t inlen, size_t outlen); +int logfs_uncompress(void *in, void *out, size_t inlen, size_t outlen); +int __init logfs_compr_init(void); +void __exit logfs_compr_exit(void); + + +/* dir.c */ +extern const struct inode_operations logfs_dir_iops; +extern const struct file_operations logfs_dir_fops; +int logfs_replay_journal(struct super_block *sb); + + +/* file.c */ +extern const struct inode_operations logfs_reg_iops; +extern const struct file_operations logfs_reg_fops; +extern const struct address_space_operations logfs_reg_aops; +int logfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg); +int logfs_fsync(struct file *file, struct dentry *dentry, int datasync); + + +/* gc.c */ +void logfs_gc_pass(struct super_block *sb); +int logfs_init_gc(struct logfs_super *super); +void logfs_cleanup_gc(struct logfs_super *super); + + +/* inode.c */ +extern const struct super_operations logfs_super_operations; +struct inode *logfs_iget(struct super_block *sb, ino_t ino, int *cookie); +void logfs_iput(struct inode *inode, int cookie); +struct inode *logfs_new_inode(struct inode *dir, int mode); +struct inode *logfs_new_meta_inode(struct super_block *sb, u64 ino); +int logfs_init_inode_cache(void); +void logfs_destroy_inode_cache(void); +int __logfs_write_inode(struct inode *inode, int lock); +void __logfs_destroy_inode(struct inode *inode); + + +/* journal.c */ +int logfs_write_anchor(struct inode *inode); +int logfs_init_journal(struct super_block *sb); +void logfs_cleanup_journal(struct super_block *sb); + + +/* memtree.c */ +void btree_init(struct btree_head *head); +void *btree_lookup(struct btree_head *head, long val); +int btree_insert(struct btree_head *head, long val, void *ptr); +int btree_remove(struct btree_head *head, long val); + + +/* readwrite.c */ +int logfs_inode_read(struct inode *inode, void *buf, size_t n, loff_t _pos); +int logfs_inode_write(struct inode *inode, const void *buf, size_t n, + loff_t pos, int lock, struct logfs_transaction *ta); +int logfs_readpage_nolock(struct page *page); +int logfs_write_buf(struct inode *inode, pgoff_t index, void *buf, int lock, + struct logfs_transaction *ta); +int logfs_delete(struct inode *inode, pgoff_t index, + struct logfs_transaction *ta); +int logfs_rewrite_block(struct inode *inode, pgoff_t index, u64 ofs, int level); +int logfs_is_valid_block(struct super_block *sb, u64 ofs, u64 ino, u64 pos); +void logfs_truncate(struct inode *inode); +u64 logfs_seek_data(struct inode *inode, u64 pos); +int logfs_init_rw(struct logfs_super *super); +void logfs_cleanup_rw(struct logfs_super *super); + +/* segment.c */ +int logfs_erase_segment(struct super_block *sb, u32 ofs); +int wbuf_read(struct super_block *sb, u64 ofs, size_t len, void *buf); +int logfs_segment_read(struct inode *inode, void *buf, u64 ofs, u64 pos, + u8 level); +s64 logfs_segment_write(struct inode *inode, void *buf, u64 pos, int level, + int alloc); +int logfs_segment_delete(struct inode *inode, u64 ofs, u64 pos, int level); +void logfs_set_blocks(struct inode *inode, u64 no); +void logfs_buf_write(struct logfs_area *area, u64 ofs, void *data, size_t len); + +/* area handling */ +int logfs_init_areas(struct super_block *sb); +void logfs_cleanup_areas(struct logfs_super *super); +int logfs_open_area(struct logfs_area *area); +void logfs_close_area(struct logfs_area *area); + +/* super.c */ +void logfs_crash_dump(struct super_block *sb); +void *memchr_inv(const void *s, int c, size_t n); +int logfs_statfs(struct dentry *dentry, struct kstatfs *stats); + + +/* progs/fsck.c */ +#ifdef CONFIG_LOGFS_FSCK +int logfs_fsck(struct super_block *sb); +#else +static inline int logfs_fsck(struct super_block *sb) +{ + return 0; +} +#endif + + +/* progs/mkfs.c */ +int logfs_mkfs(struct super_block *sb, struct logfs_disk_super *ds); + + +#define LOGFS_BUG(sb) do { \ + struct super_block *__sb = sb; \ + logfs_crash_dump(__sb); \ + logfs_super(__sb)->s_flags |= LOGFS_SB_FLAG_RO; \ + BUG(); \ +} while(0) + +#define LOGFS_BUG_ON(condition, sb) \ + do { if (unlikely((condition)!=0)) LOGFS_BUG((sb)); } while(0) + + +static inline struct logfs_super *logfs_super(struct super_block *sb) +{ + return sb->s_fs_info; +} + +static inline struct logfs_inode *logfs_inode(struct inode *inode) +{ + return container_of(inode, struct logfs_inode, vfs_inode); +} + + +static inline __be32 logfs_crc32(void *data, size_t len, size_t skip) +{ + return cpu_to_be32(crc32(~0, data+skip, len-skip)); +} + + +static inline u8 logfs_type(struct inode *inode) +{ + return (inode->i_mode >> 12) & 15; +} + + +static inline pgoff_t logfs_index(struct super_block *sb, u64 pos) +{ + return pos >> sb->s_blocksize_bits; +} + + +static inline u64 logfs_block_ofs(struct super_block *sb, u32 segno, + u32 blockno) +{ + return (segno << logfs_super(sb)->s_segshift) + + (blockno << sb->s_blocksize_bits); +} + + +static inline u64 dev_ofs(struct super_block *sb, u32 segno, u32 ofs) +{ + return ((u64)segno << logfs_super(sb)->s_segshift) + ofs; +} + + +static inline int device_read(struct super_block *sb, u32 segno, u32 ofs, + size_t len, void *buf) +{ + struct logfs_super *super = logfs_super(sb); + + return super->s_devops->read(sb, dev_ofs(sb, segno, ofs), len, buf); +} + + +#endif - To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html