cregit-Linux how code gets into the kernel

Release 4.10 fs/omfs/dir.c

Directory: fs/omfs
/*
 * OMFS (as used by RIO Karma) directory operations.
 * Copyright (C) 2005 Bob Copeland <me@bobcopeland.com>
 * Released under GPL v2.
 */

#include <linux/fs.h>
#include <linux/ctype.h>
#include <linux/buffer_head.h>
#include "omfs.h"


static int omfs_hash(const char *name, int namelen, int mod) { int i, hash = 0; for (i = 0; i < namelen; i++) hash ^= tolower(name[i]) << (i % 24); return hash % mod; }

Contributors

PersonTokensPropCommitsCommitProp
bob copelandbob copeland58100.00%1100.00%
Total58100.00%1100.00%

/* * Finds the bucket for a given name and reads the containing block; * *ofs is set to the offset of the first list entry. */
static struct buffer_head *omfs_get_bucket(struct inode *dir, const char *name, int namelen, int *ofs) { int nbuckets = (dir->i_size - OMFS_DIR_START)/8; int bucket = omfs_hash(name, namelen, nbuckets); *ofs = OMFS_DIR_START + bucket * 8; return omfs_bread(dir->i_sb, dir->i_ino); }

Contributors

PersonTokensPropCommitsCommitProp
bob copelandbob copeland71100.00%2100.00%
Total71100.00%2100.00%


static struct buffer_head *omfs_scan_list(struct inode *dir, u64 block, const char *name, int namelen, u64 *prev_block) { struct buffer_head *bh; struct omfs_inode *oi; int err = -ENOENT; *prev_block = ~0; while (block != ~0) { bh = omfs_bread(dir->i_sb, block); if (!bh) { err = -EIO; goto err; } oi = (struct omfs_inode *) bh->b_data; if (omfs_is_bad(OMFS_SB(dir->i_sb), &oi->i_head, block)) { brelse(bh); goto err; } if (strncmp(oi->i_name, name, namelen) == 0) return bh; *prev_block = block; block = be64_to_cpu(oi->i_sibling); brelse(bh); } err: return ERR_PTR(err); }

Contributors

PersonTokensPropCommitsCommitProp
bob copelandbob copeland170100.00%2100.00%
Total170100.00%2100.00%


static struct buffer_head *omfs_find_entry(struct inode *dir, const char *name, int namelen) { struct buffer_head *bh; int ofs; u64 block, dummy; bh = omfs_get_bucket(dir, name, namelen, &ofs); if (!bh) return ERR_PTR(-EIO); block = be64_to_cpu(*((__be64 *) &bh->b_data[ofs])); brelse(bh); return omfs_scan_list(dir, block, name, namelen, &dummy); }

Contributors

PersonTokensPropCommitsCommitProp
bob copelandbob copeland100100.00%1100.00%
Total100100.00%1100.00%


int omfs_make_empty(struct inode *inode, struct super_block *sb) { struct omfs_sb_info *sbi = OMFS_SB(sb); struct buffer_head *bh; struct omfs_inode *oi; bh = omfs_bread(sb, inode->i_ino); if (!bh) return -ENOMEM; memset(bh->b_data, 0, sizeof(struct omfs_inode)); if (S_ISDIR(inode->i_mode)) { memset(&bh->b_data[OMFS_DIR_START], 0xff, sbi->s_sys_blocksize - OMFS_DIR_START); } else omfs_make_empty_table(bh, OMFS_EXTENT_START); oi = (struct omfs_inode *) bh->b_data; oi->i_head.h_self = cpu_to_be64(inode->i_ino); oi->i_sibling = ~cpu_to_be64(0ULL); mark_buffer_dirty(bh); brelse(bh); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
bob copelandbob copeland14996.13%250.00%
al viroal viro31.94%125.00%
harvey harrisonharvey harrison31.94%125.00%
Total155100.00%4100.00%


static int omfs_add_link(struct dentry *dentry, struct inode *inode) { struct inode *dir = d_inode(dentry->d_parent); const char *name = dentry->d_name.name; int namelen = dentry->d_name.len; struct omfs_inode *oi; struct buffer_head *bh; u64 block; __be64 *entry; int ofs; /* just prepend to head of queue in proper bucket */ bh = omfs_get_bucket(dir, name, namelen, &ofs); if (!bh) goto out; entry = (__be64 *) &bh->b_data[ofs]; block = be64_to_cpu(*entry); *entry = cpu_to_be64(inode->i_ino); mark_buffer_dirty(bh); brelse(bh); /* now set the sibling and parent pointers on the new inode */ bh = omfs_bread(dir->i_sb, inode->i_ino); if (!bh) goto out; oi = (struct omfs_inode *) bh->b_data; memcpy(oi->i_name, name, namelen); memset(oi->i_name + namelen, 0, OMFS_NAMELEN - namelen); oi->i_sibling = cpu_to_be64(block); oi->i_parent = cpu_to_be64(dir->i_ino); mark_buffer_dirty(bh); brelse(bh); dir->i_ctime = current_time(dir); /* mark affected inodes dirty to rebuild checksums */ mark_inode_dirty(dir); mark_inode_dirty(inode); return 0; out: return -ENOMEM; }

Contributors

PersonTokensPropCommitsCommitProp
bob copelandbob copeland24497.21%250.00%
deepa dinamanideepa dinamani41.59%125.00%
david howellsdavid howells31.20%125.00%
Total251100.00%4100.00%


static int omfs_delete_entry(struct dentry *dentry) { struct inode *dir = d_inode(dentry->d_parent); struct inode *dirty; const char *name = dentry->d_name.name; int namelen = dentry->d_name.len; struct omfs_inode *oi; struct buffer_head *bh, *bh2; __be64 *entry, next; u64 block, prev; int ofs; int err = -ENOMEM; /* delete the proper node in the bucket's linked list */ bh = omfs_get_bucket(dir, name, namelen, &ofs); if (!bh) goto out; entry = (__be64 *) &bh->b_data[ofs]; block = be64_to_cpu(*entry); bh2 = omfs_scan_list(dir, block, name, namelen, &prev); if (IS_ERR(bh2)) { err = PTR_ERR(bh2); goto out_free_bh; } oi = (struct omfs_inode *) bh2->b_data; next = oi->i_sibling; brelse(bh2); if (prev != ~0) { /* found in middle of list, get list ptr */ brelse(bh); bh = omfs_bread(dir->i_sb, prev); if (!bh) goto out; oi = (struct omfs_inode *) bh->b_data; entry = &oi->i_sibling; } *entry = next; mark_buffer_dirty(bh); if (prev != ~0) { dirty = omfs_iget(dir->i_sb, prev); if (!IS_ERR(dirty)) { mark_inode_dirty(dirty); iput(dirty); } } err = 0; out_free_bh: brelse(bh); out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
bob copelandbob copeland29899.00%266.67%
david howellsdavid howells31.00%133.33%
Total301100.00%3100.00%


static int omfs_dir_is_empty(struct inode *inode) { int nbuckets = (inode->i_size - OMFS_DIR_START) / 8; struct buffer_head *bh; u64 *ptr; int i; bh = omfs_bread(inode->i_sb, inode->i_ino); if (!bh) return 0; ptr = (u64 *) &bh->b_data[OMFS_DIR_START]; for (i = 0; i < nbuckets; i++, ptr++) if (*ptr != ~0) break; brelse(bh); return *ptr != ~0; }

Contributors

PersonTokensPropCommitsCommitProp
bob copelandbob copeland108100.00%2100.00%
Total108100.00%2100.00%


static int omfs_remove(struct inode *dir, struct dentry *dentry) { struct inode *inode = d_inode(dentry); int ret; if (S_ISDIR(inode->i_mode) && !omfs_dir_is_empty(inode)) return -ENOTEMPTY; ret = omfs_delete_entry(dentry); if (ret) return ret; clear_nlink(inode); mark_inode_dirty(inode); mark_inode_dirty(dir); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
bob copelandbob copeland4758.75%125.00%
al viroal viro2936.25%125.00%
david howellsdavid howells33.75%125.00%
sage weilsage weil11.25%125.00%
Total80100.00%4100.00%


static int omfs_add_node(struct inode *dir, struct dentry *dentry, umode_t mode) { int err; struct inode *inode = omfs_new_inode(dir, mode); if (IS_ERR(inode)) return PTR_ERR(inode); err = omfs_make_empty(inode, dir->i_sb); if (err) goto out_free_inode; err = omfs_add_link(dentry, inode); if (err) goto out_free_inode; d_instantiate(dentry, inode); return 0; out_free_inode: iput(inode); return err; }

Contributors

PersonTokensPropCommitsCommitProp
bob copelandbob copeland10099.01%150.00%
al viroal viro10.99%150.00%
Total101100.00%2100.00%


static int omfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { return omfs_add_node(dir, dentry, mode | S_IFDIR); }

Contributors

PersonTokensPropCommitsCommitProp
bob copelandbob copeland3096.77%150.00%
al viroal viro13.23%150.00%
Total31100.00%2100.00%


static int omfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) { return omfs_add_node(dir, dentry, mode | S_IFREG); }

Contributors

PersonTokensPropCommitsCommitProp
bob copelandbob copeland3191.18%133.33%
al viroal viro38.82%266.67%
Total34100.00%3100.00%


static struct dentry *omfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { struct buffer_head *bh; struct inode *inode = NULL; if (dentry->d_name.len > OMFS_NAMELEN) return ERR_PTR(-ENAMETOOLONG); bh = omfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len); if (!IS_ERR(bh)) { struct omfs_inode *oi = (struct omfs_inode *)bh->b_data; ino_t ino = be64_to_cpu(oi->i_head.h_self); brelse(bh); inode = omfs_iget(dir->i_sb, ino); if (IS_ERR(inode)) return ERR_CAST(inode); } d_add(dentry, inode); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
bob copelandbob copeland14297.93%150.00%
al viroal viro32.07%150.00%
Total145100.00%2100.00%

/* sanity check block's self pointer */
int omfs_is_bad(struct omfs_sb_info *sbi, struct omfs_header *header, u64 fsblock) { int is_bad; u64 ino = be64_to_cpu(header->h_self); is_bad = ((ino != fsblock) || (ino < sbi->s_root_ino) || (ino > sbi->s_num_blocks)); if (is_bad) printk(KERN_WARNING "omfs: bad hash chain detected\n"); return is_bad; }

Contributors

PersonTokensPropCommitsCommitProp
bob copelandbob copeland70100.00%1100.00%
Total70100.00%1100.00%


static bool omfs_fill_chain(struct inode *dir, struct dir_context *ctx, u64 fsblock, int hindex) { /* follow chain in this bucket */ while (fsblock != ~0) { struct buffer_head *bh = omfs_bread(dir->i_sb, fsblock); struct omfs_inode *oi; u64 self; unsigned char d_type; if (!bh) return true; oi = (struct omfs_inode *) bh->b_data; if (omfs_is_bad(OMFS_SB(dir->i_sb), &oi->i_head, fsblock)) { brelse(bh); return true; } self = fsblock; fsblock = be64_to_cpu(oi->i_sibling); /* skip visited nodes */ if (hindex) { hindex--; brelse(bh); continue; } d_type = (oi->i_type == OMFS_DIR) ? DT_DIR : DT_REG; if (!dir_emit(ctx, oi->i_name, strnlen(oi->i_name, OMFS_NAMELEN), self, d_type)) { brelse(bh); return false; } brelse(bh); ctx->pos++; } return true; }

Contributors

PersonTokensPropCommitsCommitProp
bob copelandbob copeland14573.60%250.00%
al viroal viro5226.40%250.00%
Total197100.00%4100.00%


static int omfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, unsigned int flags) { struct inode *new_inode = d_inode(new_dentry); struct inode *old_inode = d_inode(old_dentry); int err; if (flags & ~RENAME_NOREPLACE) return -EINVAL; if (new_inode) { /* overwriting existing file/dir */ err = omfs_remove(new_dir, new_dentry); if (err) goto out; } /* since omfs locates files by name, we need to unlink _before_ * adding the new link or we won't find the old one */ err = omfs_delete_entry(old_dentry); if (err) goto out; mark_inode_dirty(old_dir); err = omfs_add_link(new_dentry, old_inode); if (err) goto out; old_inode->i_ctime = current_time(old_inode); mark_inode_dirty(old_inode); out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
bob copelandbob copeland10573.94%114.29%
miklos szeredimiklos szeredi1510.56%114.29%
al viroal viro128.45%342.86%
david howellsdavid howells64.23%114.29%
deepa dinamanideepa dinamani42.82%114.29%
Total142100.00%7100.00%


static int omfs_readdir(struct file *file, struct dir_context *ctx) { struct inode *dir = file_inode(file); struct buffer_head *bh; __be64 *p; unsigned int hchain, hindex; int nbuckets; if (ctx->pos >> 32) return -EINVAL; if (ctx->pos < 1 << 20) { if (!dir_emit_dots(file, ctx)) return 0; ctx->pos = 1 << 20; } nbuckets = (dir->i_size - OMFS_DIR_START) / 8; /* high 12 bits store bucket + 1 and low 20 bits store hash index */ hchain = (ctx->pos >> 20) - 1; hindex = ctx->pos & 0xfffff; bh = omfs_bread(dir->i_sb, dir->i_ino); if (!bh) return -EINVAL; p = (__be64 *)(bh->b_data + OMFS_DIR_START) + hchain; for (; hchain < nbuckets; hchain++) { __u64 fsblock = be64_to_cpu(*p++); if (!omfs_fill_chain(dir, ctx, fsblock, hindex)) break; hindex = 0; ctx->pos = (hchain+2) << 20; } brelse(bh); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
bob copelandbob copeland15570.14%250.00%
al viroal viro6629.86%250.00%
Total221100.00%4100.00%

const struct inode_operations omfs_dir_inops = { .lookup = omfs_lookup, .mkdir = omfs_mkdir, .rename = omfs_rename, .create = omfs_create, .unlink = omfs_remove, .rmdir = omfs_remove, }; const struct file_operations omfs_dir_operations = { .read = generic_read_dir, .iterate_shared = omfs_readdir, .llseek = generic_file_llseek, };

Overall Contributors

PersonTokensPropCommitsCommitProp
bob copelandbob copeland208790.39%28.70%
al viroal viro1737.49%1356.52%
david howellsdavid howells150.65%14.35%
miklos szeredimiklos szeredi150.65%14.35%
deepa dinamanideepa dinamani80.35%14.35%
christoph hellwigchristoph hellwig50.22%14.35%
harvey harrisonharvey harrison30.13%14.35%
alexey dobriyanalexey dobriyan20.09%28.70%
sage weilsage weil10.04%14.35%
Total2309100.00%23100.00%
Directory: fs/omfs
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.