/* * fs/logfs/readwrite.c * * As should be obvious for Linux kernel code, license is GPLv2 * * Copyright (c) 2005-2008 Joern Engel <joern@logfs.org> * * * Actually contains five sets of very similar functions: * read read blocks from a file * seek_hole find next hole * seek_data find next data block * valid check whether a block still belongs to a file * write write blocks to a file * delete delete a block (for directories and ifile) * rewrite move existing blocks of a file to a new location (gc helper) * truncate truncate a file */#include "logfs.h"#include <linux/sched.h>#include <linux/slab.h> static u64 adjust_bix(u64 bix, level_t level){ switch (level) { case 0: return bix; case LEVEL(1): return max_t(u64, bix, I0_BLOCKS); case LEVEL(2): return max_t(u64, bix, I1_BLOCKS); case LEVEL(3): return max_t(u64, bix, I2_BLOCKS); case LEVEL(4): return max_t(u64, bix, I3_BLOCKS); case LEVEL(5): return max_t(u64, bix, I4_BLOCKS); default: WARN_ON(1); return bix; }} static inline u64 maxbix(u8 height){ return 1ULL << (LOGFS_BLOCK_BITS * height);} /** * The inode address space is cut in two halves. Lower half belongs to data * pages, upper half to indirect blocks. If the high bit (INDIRECT_BIT) is * set, the actual block index (bix) and level can be derived from the page * index. * * The lowest three bits of the block index are set to 0 after packing and * unpacking. Since the lowest n bits (9 for 4KiB blocksize) are ignored * anyway this is harmless. */#define ARCH_SHIFT (BITS_PER_LONG - 32)#define INDIRECT_BIT (0x80000000UL << ARCH_SHIFT)#define LEVEL_SHIFT (28 + ARCH_SHIFT)static inline pgoff_t first_indirect_block(void){ return INDIRECT_BIT | (1ULL << LEVEL_SHIFT);} pgoff_t logfs_pack_index(u64 bix, level_t level){ pgoff_t index; BUG_ON(bix >= INDIRECT_BIT); if (level == 0) return bix; index = INDIRECT_BIT; index |= (__force long)level << LEVEL_SHIFT; index |= bix >> ((__force u8)level * LOGFS_BLOCK_BITS); return index;} void logfs_unpack_index(pgoff_t index, u64 *bix, level_t *level){ u8 __level; if (!(index & INDIRECT_BIT)) { *bix = index; *level = 0; return; } __level = (index & ~INDIRECT_BIT) >> LEVEL_SHIFT; *level = LEVEL(__level); *bix = (index << (__level * LOGFS_BLOCK_BITS)) & ~INDIRECT_BIT; *bix = adjust_bix(*bix, *level); return;}#undef ARCH_SHIFT#undef INDIRECT_BIT#undef LEVEL_SHIFT /* * Time is stored as nanoseconds since the epoch. */static struct timespec be64_to_timespec(__be64 betime){ return ns_to_timespec(be64_to_cpu(betime));} static __be64 timespec_to_be64(struct timespec tsp){ return cpu_to_be64((u64)tsp.tv_sec * NSEC_PER_SEC + tsp.tv_nsec);} static void logfs_disk_to_inode(struct logfs_disk_inode *di, struct inode*inode){ struct logfs_inode *li = logfs_inode(inode); int i; inode->i_mode = be16_to_cpu(di->di_mode); li->li_height = di->di_height; li->li_flags = be32_to_cpu(di->di_flags); i_uid_write(inode, be32_to_cpu(di->di_uid)); i_gid_write(inode, be32_to_cpu(di->di_gid)); inode->i_size = be64_to_cpu(di->di_size); logfs_set_blocks(inode, be64_to_cpu(di->di_used_bytes)); inode->i_atime = be64_to_timespec(di->di_atime); inode->i_ctime = be64_to_timespec(di->di_ctime); inode->i_mtime = be64_to_timespec(di->di_mtime); set_nlink(inode, be32_to_cpu(di->di_refcount)); inode->i_generation = be32_to_cpu(di->di_generation); switch (inode->i_mode & S_IFMT) { case S_IFSOCK: /* fall through */ case S_IFBLK: /* fall through */ case S_IFCHR: /* fall through */ case S_IFIFO: inode->i_rdev = be64_to_cpu(di->di_data[0]); break; case S_IFDIR: /* fall through */ case S_IFREG: /* fall through */ case S_IFLNK: for (i = 0; i < LOGFS_EMBEDDED_FIELDS; i++) li->li_data[i] = be64_to_cpu(di->di_data[i]); break; default: BUG(); }} static void logfs_inode_to_disk(struct inode *inode, struct logfs_disk_inode*di){ struct logfs_inode *li = logfs_inode(inode); int i; di->di_mode = cpu_to_be16(inode->i_mode); di->di_height = li->li_height; di->di_pad = 0; di->di_flags = cpu_to_be32(li->li_flags); di->di_uid = cpu_to_be32(i_uid_read(inode)); di->di_gid = cpu_to_be32(i_gid_read(inode)); di->di_size = cpu_to_be64(i_size_read(inode)); di->di_used_bytes = cpu_to_be64(li->li_used_bytes); di->di_atime = timespec_to_be64(inode->i_atime); di->di_ctime = timespec_to_be64(inode->i_ctime); di->di_mtime = timespec_to_be64(inode->i_mtime); di->di_refcount = cpu_to_be32(inode->i_nlink); di->di_generation = cpu_to_be32(inode->i_generation); switch (inode->i_mode & S_IFMT) { case S_IFSOCK: /* fall through */ case S_IFBLK: /* fall through */ case S_IFCHR: /* fall through */ case S_IFIFO: di->di_data[0] = cpu_to_be64(inode->i_rdev); break; case S_IFDIR: /* fall through */ case S_IFREG: /* fall through */ case S_IFLNK: for (i = 0; i < LOGFS_EMBEDDED_FIELDS; i++) di->di_data[i] = cpu_to_be64(li->li_data[i]); break; default: BUG(); }} static void __logfs_set_blocks(struct inode *inode){ struct super_block *sb = inode->i_sb; struct logfs_inode *li = logfs_inode(inode); inode->i_blocks = ULONG_MAX; if (li->li_used_bytes >> sb->s_blocksize_bits < ULONG_MAX) inode->i_blocks = ALIGN(li->li_used_bytes, 512) >> 9;} void logfs_set_blocks(struct inode *inode, u64 bytes){ struct logfs_inode *li = logfs_inode(inode); li->li_used_bytes = bytes; __logfs_set_blocks(inode);} static void prelock_page(struct super_block *sb, struct page *page, int lock){ struct logfs_super *super = logfs_super(sb); BUG_ON(!PageLocked(page)); if (lock) { BUG_ON(PagePreLocked(page)); SetPagePreLocked(page); } else { /* We are in GC path. */ if (PagePreLocked(page)) super->s_lock_count++; else SetPagePreLocked(page); }} static void preunlock_page(struct super_block *sb, struct page *page, int lock){ struct logfs_super *super = logfs_super(sb); BUG_ON(!PageLocked(page)); if (lock) ClearPagePreLocked(page); else { /* We are in GC path. */ BUG_ON(!PagePreLocked(page)); if (super->s_lock_count) super->s_lock_count--; else ClearPagePreLocked(page); }} /* * Logfs is prone to an AB-BA deadlock where one task tries to acquire * s_write_mutex with a locked page and GC tries to get that page while holding * s_write_mutex. * To solve this issue logfs will ignore the page lock iff the page in question * is waiting for s_write_mutex. We annotate this fact by setting PG_pre_locked * in addition to PG_locked. */void logfs_get_wblocks(struct super_block *sb, struct page *page, int lock){ struct logfs_super *super = logfs_super(sb); if (page) prelock_page(sb, page, lock); if (lock) { mutex_lock(&super->s_write_mutex); logfs_gc_pass(sb); /* FIXME: We also have to check for shadowed space * and mempool fill grade */ }} void logfs_put_wblocks(struct super_block *sb, struct page *page, int lock){ struct logfs_super *super = logfs_super(sb); if (page) preunlock_page(sb, page, lock); /* Order matters - we must clear PG_pre_locked before releasing * s_write_mutex or we could race against another task. */ if (lock) mutex_unlock(&super->s_write_mutex);} static struct page *logfs_get_read_page(struct inode *inode, u64 bix, level_t level){ return find_or_create_page(inode->i_mapping, logfs_pack_index(bix, level), GFP_NOFS);} static void logfs_put_read_page(struct page *page){ unlock_page(page); page_cache_release(page);} static void logfs_lock_write_page(struct page *page){ int loop = 0; while (unlikely(!trylock_page(page))) { if (loop++ > 0x1000) { /* Has been observed once so far... */ printk(KERN_ERR "stack at %p\n", &loop); BUG(); } if (PagePreLocked(page)) { /* Holder of page lock is waiting for us, it * is safe to use this page. */ break; } /* Some other process has this page locked and has * nothing to do with us. Wait for it to finish. */ schedule(); } BUG_ON(!PageLocked(page));} static struct page *logfs_get_write_page(struct inode *inode, u64 bix, level_t level){ struct address_space *mapping = inode->i_mapping; pgoff_t index = logfs_pack_index(bix, level); struct page *page; int err; repeat: page = find_get_page(mapping, index); if (!page) { page = __page_cache_alloc(GFP_NOFS); if (!page) return NULL; err = add_to_page_cache_lru(page, mapping, index, GFP_NOFS); if (unlikely(err)) { page_cache_release(page); if (err == -EEXIST) goto repeat; return NULL; } } else logfs_lock_write_page(page); BUG_ON(!PageLocked(page)); return page;} static void logfs_unlock_write_page(struct page *page){ if (!PagePreLocked(page)) unlock_page(page);} static void logfs_put_write_page(struct page *page){ logfs_unlock_write_page(page); page_cache_release(page);} static struct page *logfs_get_page(struct inode *inode, u64 bix, level_t level, int rw){ if (rw == READ) return logfs_get_read_page(inode, bix, level); else return logfs_get_write_page(inode, bix, level);} static void logfs_put_page(struct page *page, int rw){ if (rw == READ) logfs_put_read_page(page); else logfs_put_write_page(page);} static unsigned long __get_bits(u64 val, int skip, int no){ u64 ret = val; ret >>= skip * no; ret <<= 64 - no; ret >>= 64 - no; return ret;} static unsigned long get_bits(u64 val, level_t skip){ return __get_bits(val, (__force int)skip, LOGFS_BLOCK_BITS);} static inline void init_shadow_tree(struct super_block *sb, struct shadow_tree *tree){ struct logfs_super *super = logfs_super(sb); btree_init_mempool64(&tree->new, super->s_btree_pool); btree_init_mempool64(&tree->old, super->s_btree_pool);} static void indirect_write_block(struct logfs_block *block){ struct page *page; struct inode *inode; int ret; page = block->page; inode = page->mapping->host; logfs_lock_write_page(page); ret = logfs_write_buf(inode, page, 0); logfs_unlock_write_page(page); /* * This needs some rework. Unless you want your filesystem to run * completely synchronously (you don't), the filesystem will always * report writes as 'successful' before the actual work has been * done. The actual work gets done here and this is where any errors * will show up. And there isn't much we can do about it, really. * * Some attempts to fix the errors (move from bad blocks, retry io,...) * have already been done, so anything left should be either a broken * device or a bug somewhere in logfs itself. Being relatively new, * the odds currently favor a bug, so for now the line below isn't * entirely tasteles. */ BUG_ON(ret);} static void inode_write_block(struct logfs_block *block){ struct inode *inode; int ret; inode = block->inode; if (inode->i_ino == LOGFS_INO_MASTER) logfs_write_anchor(inode->i_sb); else { ret = __logfs_write_inode(inode, NULL, 0); /* see indirect_write_block comment */ BUG_ON(ret); }} /* * This silences a false, yet annoying gcc warning. I hate it when my editor * jumps into bitops.h each time I recompile this file. * TODO: Complain to gcc folks about this and upgrade compiler. */static unsigned long fnb(const unsigned long *addr, unsigned long size, unsigned long offset){ return find_next_bit(addr, size, offset);} static __be64 inode_val0(struct inode *inode){ struct logfs_inode *li = logfs_inode(inode); u64 val; /* * Explicit shifting generates good code, but must match the format * of the structure. Add some paranoia just in case. */ BUILD_BUG_ON(offsetof(struct logfs_disk_inode, di_mode) != 0); BUILD_BUG_ON(offsetof(struct logfs_disk_inode, di_height) != 2); BUILD_BUG_ON(offsetof(struct logfs_disk_inode, di_flags) != 4); val = (u64)inode->i_mode << 48 | (u64)li->li_height << 40 | (u64)li->li_flags; return cpu_to_be64(val);} static int inode_write_alias(struct super_block *sb, struct logfs_block *block, write_alias_t *write_one_alias){ struct inode *inode = block->inode; struct logfs_inode *li = logfs_inode(inode); unsigned long pos; u64 ino , bix; __be64 val; level_t level; int err; for (pos = 0; ; pos++) { pos = fnb(block->alias_map, LOGFS_BLOCK_FACTOR, pos); if (pos >= LOGFS_EMBEDDED_FIELDS + INODE_POINTER_OFS) return 0; switch (pos) { case INODE_HEIGHT_OFS: val = inode_val0(inode); break; case INODE_USED_OFS: val = cpu_to_be64(li->li_used_bytes); break; case INODE_SIZE_OFS: val = cpu_to_be64(i_size_read(inode)); break; case INODE_POINTER_OFS ... INODE_POINTER_OFS + LOGFS_EMBEDDED_FIELDS - 1: val = cpu_to_be64(li->li_data[pos - INODE_POINTER_OFS]); break; default: BUG(); } ino = LOGFS_INO_MASTER; bix = inode->i_ino; level = LEVEL(0); err = write_one_alias(sb, ino, bix, level, pos, val); if (err) return err; }Lines 1–500 of 2299. Load more
/* * fs/logfs/readwrite.c * * As should be obvious for Linux kernel code, license is GPLv2 * * Copyright (c) 2005-2008 Joern Engel <joern@logfs.org> * * * Actually contains five sets of very similar functions: * read read blocks from a file * seek_hole find next hole * seek_data find next data block * valid check whether a block still belongs to a file * write write blocks to a file * delete delete a block (for directories and ifile) * rewrite move existing blocks of a file to a new location (gc helper) * truncate truncate a file */ #include "logfs.h" #include <linux/sched.h> #include <linux/slab.h> static u64 adjust_bix(u64 bix, level_t level) { switch (level) { case 0: return bix; case LEVEL(1): return max_t(u64, bix, I0_BLOCKS); case LEVEL(2): return max_t(u64, bix, I1_BLOCKS); case LEVEL(3): return max_t(u64, bix, I2_BLOCKS); case LEVEL(4): return max_t(u64, bix, I3_BLOCKS); case LEVEL(5): return max_t(u64, bix, I4_BLOCKS); default: WARN_ON(1); return bix; } } static inline u64 maxbix(u8 height) { return 1ULL << (LOGFS_BLOCK_BITS * height); } /** * The inode address space is cut in two halves. Lower half belongs to data * pages, upper half to indirect blocks. If the high bit (INDIRECT_BIT) is * set, the actual block index (bix) and level can be derived from the page * index. * * The lowest three bits of the block index are set to 0 after packing and * unpacking. Since the lowest n bits (9 for 4KiB blocksize) are ignored * anyway this is harmless. */ #define ARCH_SHIFT (BITS_PER_LONG - 32) #define INDIRECT_BIT (0x80000000UL << ARCH_SHIFT) #define LEVEL_SHIFT (28 + ARCH_SHIFT) static inline pgoff_t first_indirect_block(void) { return INDIRECT_BIT | (1ULL << LEVEL_SHIFT); } pgoff_t logfs_pack_index(u64 bix, level_t level) { pgoff_t index; BUG_ON(bix >= INDIRECT_BIT); if (level == 0) return bix; index = INDIRECT_BIT; index |= (__force long)level << LEVEL_SHIFT; index |= bix >> ((__force u8)level * LOGFS_BLOCK_BITS); return index; } void logfs_unpack_index(pgoff_t index, u64 *bix, level_t *level) { u8 __level; if (!(index & INDIRECT_BIT)) { *bix = index; *level = 0; return; } __level = (index & ~INDIRECT_BIT) >> LEVEL_SHIFT; *level = LEVEL(__level); *bix = (index << (__level * LOGFS_BLOCK_BITS)) & ~INDIRECT_BIT; *bix = adjust_bix(*bix, *level); return; } #undef ARCH_SHIFT #undef INDIRECT_BIT #undef LEVEL_SHIFT /* * Time is stored as nanoseconds since the epoch. */ static struct timespec be64_to_timespec(__be64 betime) { return ns_to_timespec(be64_to_cpu(betime)); } static __be64 timespec_to_be64(struct timespec tsp) { return cpu_to_be64((u64)tsp.tv_sec * NSEC_PER_SEC + tsp.tv_nsec); } static void logfs_disk_to_inode(struct logfs_disk_inode *di, struct inode*inode) { struct logfs_inode *li = logfs_inode(inode); int i; inode->i_mode = be16_to_cpu(di->di_mode); li->li_height = di->di_height; li->li_flags = be32_to_cpu(di->di_flags); i_uid_write(inode, be32_to_cpu(di->di_uid)); i_gid_write(inode, be32_to_cpu(di->di_gid)); inode->i_size = be64_to_cpu(di->di_size); logfs_set_blocks(inode, be64_to_cpu(di->di_used_bytes)); inode->i_atime = be64_to_timespec(di->di_atime); inode->i_ctime = be64_to_timespec(di->di_ctime); inode->i_mtime = be64_to_timespec(di->di_mtime); set_nlink(inode, be32_to_cpu(di->di_refcount)); inode->i_generation = be32_to_cpu(di->di_generation); switch (inode->i_mode & S_IFMT) { case S_IFSOCK: /* fall through */ case S_IFBLK: /* fall through */ case S_IFCHR: /* fall through */ case S_IFIFO: inode->i_rdev = be64_to_cpu(di->di_data[0]); break; case S_IFDIR: /* fall through */ case S_IFREG: /* fall through */ case S_IFLNK: for (i = 0; i < LOGFS_EMBEDDED_FIELDS; i++) li->li_data[i] = be64_to_cpu(di->di_data[i]); break; default: BUG(); } } static void logfs_inode_to_disk(struct inode *inode, struct logfs_disk_inode*di) { struct logfs_inode *li = logfs_inode(inode); int i; di->di_mode = cpu_to_be16(inode->i_mode); di->di_height = li->li_height; di->di_pad = 0; di->di_flags = cpu_to_be32(li->li_flags); di->di_uid = cpu_to_be32(i_uid_read(inode)); di->di_gid = cpu_to_be32(i_gid_read(inode)); di->di_size = cpu_to_be64(i_size_read(inode)); di->di_used_bytes = cpu_to_be64(li->li_used_bytes); di->di_atime = timespec_to_be64(inode->i_atime); di->di_ctime = timespec_to_be64(inode->i_ctime); di->di_mtime = timespec_to_be64(inode->i_mtime); di->di_refcount = cpu_to_be32(inode->i_nlink); di->di_generation = cpu_to_be32(inode->i_generation); switch (inode->i_mode & S_IFMT) { case S_IFSOCK: /* fall through */ case S_IFBLK: /* fall through */ case S_IFCHR: /* fall through */ case S_IFIFO: di->di_data[0] = cpu_to_be64(inode->i_rdev); break; case S_IFDIR: /* fall through */ case S_IFREG: /* fall through */ case S_IFLNK: for (i = 0; i < LOGFS_EMBEDDED_FIELDS; i++) di->di_data[i] = cpu_to_be64(li->li_data[i]); break; default: BUG(); } } static void __logfs_set_blocks(struct inode *inode) { struct super_block *sb = inode->i_sb; struct logfs_inode *li = logfs_inode(inode); inode->i_blocks = ULONG_MAX; if (li->li_used_bytes >> sb->s_blocksize_bits < ULONG_MAX) inode->i_blocks = ALIGN(li->li_used_bytes, 512) >> 9; } void logfs_set_blocks(struct inode *inode, u64 bytes) { struct logfs_inode *li = logfs_inode(inode); li->li_used_bytes = bytes; __logfs_set_blocks(inode); } static void prelock_page(struct super_block *sb, struct page *page, int lock) { struct logfs_super *super = logfs_super(sb); BUG_ON(!PageLocked(page)); if (lock) { BUG_ON(PagePreLocked(page)); SetPagePreLocked(page); } else { /* We are in GC path. */ if (PagePreLocked(page)) super->s_lock_count++; else SetPagePreLocked(page); } } static void preunlock_page(struct super_block *sb, struct page *page, int lock) { struct logfs_super *super = logfs_super(sb); BUG_ON(!PageLocked(page)); if (lock) ClearPagePreLocked(page); else { /* We are in GC path. */ BUG_ON(!PagePreLocked(page)); if (super->s_lock_count) super->s_lock_count--; else ClearPagePreLocked(page); } } /* * Logfs is prone to an AB-BA deadlock where one task tries to acquire * s_write_mutex with a locked page and GC tries to get that page while holding * s_write_mutex. * To solve this issue logfs will ignore the page lock iff the page in question * is waiting for s_write_mutex. We annotate this fact by setting PG_pre_locked * in addition to PG_locked. */ void logfs_get_wblocks(struct super_block *sb, struct page *page, int lock) { struct logfs_super *super = logfs_super(sb); if (page) prelock_page(sb, page, lock); if (lock) { mutex_lock(&super->s_write_mutex); logfs_gc_pass(sb); /* FIXME: We also have to check for shadowed space * and mempool fill grade */ } } void logfs_put_wblocks(struct super_block *sb, struct page *page, int lock) { struct logfs_super *super = logfs_super(sb); if (page) preunlock_page(sb, page, lock); /* Order matters - we must clear PG_pre_locked before releasing * s_write_mutex or we could race against another task. */ if (lock) mutex_unlock(&super->s_write_mutex); } static struct page *logfs_get_read_page(struct inode *inode, u64 bix, level_t level) { return find_or_create_page(inode->i_mapping, logfs_pack_index(bix, level), GFP_NOFS); } static void logfs_put_read_page(struct page *page) { unlock_page(page); page_cache_release(page); } static void logfs_lock_write_page(struct page *page) { int loop = 0; while (unlikely(!trylock_page(page))) { if (loop++ > 0x1000) { /* Has been observed once so far... */ printk(KERN_ERR "stack at %p\n", &loop); BUG(); } if (PagePreLocked(page)) { /* Holder of page lock is waiting for us, it * is safe to use this page. */ break; } /* Some other process has this page locked and has * nothing to do with us. Wait for it to finish. */ schedule(); } BUG_ON(!PageLocked(page)); } static struct page *logfs_get_write_page(struct inode *inode, u64 bix, level_t level) { struct address_space *mapping = inode->i_mapping; pgoff_t index = logfs_pack_index(bix, level); struct page *page; int err; repeat: page = find_get_page(mapping, index); if (!page) { page = __page_cache_alloc(GFP_NOFS); if (!page) return NULL; err = add_to_page_cache_lru(page, mapping, index, GFP_NOFS); if (unlikely(err)) { page_cache_release(page); if (err == -EEXIST) goto repeat; return NULL; } } else logfs_lock_write_page(page); BUG_ON(!PageLocked(page)); return page; } static void logfs_unlock_write_page(struct page *page) { if (!PagePreLocked(page)) unlock_page(page); } static void logfs_put_write_page(struct page *page) { logfs_unlock_write_page(page); page_cache_release(page); } static struct page *logfs_get_page(struct inode *inode, u64 bix, level_t level, int rw) { if (rw == READ) return logfs_get_read_page(inode, bix, level); else return logfs_get_write_page(inode, bix, level); } static void logfs_put_page(struct page *page, int rw) { if (rw == READ) logfs_put_read_page(page); else logfs_put_write_page(page); } static unsigned long __get_bits(u64 val, int skip, int no) { u64 ret = val; ret >>= skip * no; ret <<= 64 - no; ret >>= 64 - no; return ret; } static unsigned long get_bits(u64 val, level_t skip) { return __get_bits(val, (__force int)skip, LOGFS_BLOCK_BITS); } static inline void init_shadow_tree(struct super_block *sb, struct shadow_tree *tree) { struct logfs_super *super = logfs_super(sb); btree_init_mempool64(&tree->new, super->s_btree_pool); btree_init_mempool64(&tree->old, super->s_btree_pool); } static void indirect_write_block(struct logfs_block *block) { struct page *page; struct inode *inode; int ret; page = block->page; inode = page->mapping->host; logfs_lock_write_page(page); ret = logfs_write_buf(inode, page, 0); logfs_unlock_write_page(page); /* * This needs some rework. Unless you want your filesystem to run * completely synchronously (you don't), the filesystem will always * report writes as 'successful' before the actual work has been * done. The actual work gets done here and this is where any errors * will show up. And there isn't much we can do about it, really. * * Some attempts to fix the errors (move from bad blocks, retry io,...) * have already been done, so anything left should be either a broken * device or a bug somewhere in logfs itself. Being relatively new, * the odds currently favor a bug, so for now the line below isn't * entirely tasteles. */ BUG_ON(ret); } static void inode_write_block(struct logfs_block *block) { struct inode *inode; int ret; inode = block->inode; if (inode->i_ino == LOGFS_INO_MASTER) logfs_write_anchor(inode->i_sb); else { ret = __logfs_write_inode(inode, NULL, 0); /* see indirect_write_block comment */ BUG_ON(ret); } } /* * This silences a false, yet annoying gcc warning. I hate it when my editor * jumps into bitops.h each time I recompile this file. * TODO: Complain to gcc folks about this and upgrade compiler. */ static unsigned long fnb(const unsigned long *addr, unsigned long size, unsigned long offset) { return find_next_bit(addr, size, offset); } static __be64 inode_val0(struct inode *inode) { struct logfs_inode *li = logfs_inode(inode); u64 val; /* * Explicit shifting generates good code, but must match the format * of the structure. Add some paranoia just in case. */ BUILD_BUG_ON(offsetof(struct logfs_disk_inode, di_mode) != 0); BUILD_BUG_ON(offsetof(struct logfs_disk_inode, di_height) != 2); BUILD_BUG_ON(offsetof(struct logfs_disk_inode, di_flags) != 4); val = (u64)inode->i_mode << 48 | (u64)li->li_height << 40 | (u64)li->li_flags; return cpu_to_be64(val); } static int inode_write_alias(struct super_block *sb, struct logfs_block *block, write_alias_t *write_one_alias) { struct inode *inode = block->inode; struct logfs_inode *li = logfs_inode(inode); unsigned long pos; u64 ino , bix; __be64 val; level_t level; int err; for (pos = 0; ; pos++) { pos = fnb(block->alias_map, LOGFS_BLOCK_FACTOR, pos); if (pos >= LOGFS_EMBEDDED_FIELDS + INODE_POINTER_OFS) return 0; switch (pos) { case INODE_HEIGHT_OFS: val = inode_val0(inode); break; case INODE_USED_OFS: val = cpu_to_be64(li->li_used_bytes); break; case INODE_SIZE_OFS: val = cpu_to_be64(i_size_read(inode)); break; case INODE_POINTER_OFS ... INODE_POINTER_OFS + LOGFS_EMBEDDED_FIELDS - 1: val = cpu_to_be64(li->li_data[pos - INODE_POINTER_OFS]); break; default: BUG(); } ino = LOGFS_INO_MASTER; bix = inode->i_ino; level = LEVEL(0); err = write_one_alias(sb, ino, bix, level, pos, val); if (err) return err; }