0001
0002
0003
0004
0005
0006
0007 #include <linux/fs.h>
0008 #include <linux/ctype.h>
0009 #include <linux/buffer_head.h>
0010 #include "omfs.h"
0011
0012 static int omfs_hash(const char *name, int namelen, int mod)
0013 {
0014 int i, hash = 0;
0015 for (i = 0; i < namelen; i++)
0016 hash ^= tolower(name[i]) << (i % 24);
0017 return hash % mod;
0018 }
0019
0020
0021
0022
0023
0024 static struct buffer_head *omfs_get_bucket(struct inode *dir,
0025 const char *name, int namelen, int *ofs)
0026 {
0027 int nbuckets = (dir->i_size - OMFS_DIR_START)/8;
0028 int bucket = omfs_hash(name, namelen, nbuckets);
0029
0030 *ofs = OMFS_DIR_START + bucket * 8;
0031 return omfs_bread(dir->i_sb, dir->i_ino);
0032 }
0033
0034 static struct buffer_head *omfs_scan_list(struct inode *dir, u64 block,
0035 const char *name, int namelen,
0036 u64 *prev_block)
0037 {
0038 struct buffer_head *bh;
0039 struct omfs_inode *oi;
0040 int err = -ENOENT;
0041 *prev_block = ~0;
0042
0043 while (block != ~0) {
0044 bh = omfs_bread(dir->i_sb, block);
0045 if (!bh) {
0046 err = -EIO;
0047 goto err;
0048 }
0049
0050 oi = (struct omfs_inode *) bh->b_data;
0051 if (omfs_is_bad(OMFS_SB(dir->i_sb), &oi->i_head, block)) {
0052 brelse(bh);
0053 goto err;
0054 }
0055
0056 if (strncmp(oi->i_name, name, namelen) == 0)
0057 return bh;
0058
0059 *prev_block = block;
0060 block = be64_to_cpu(oi->i_sibling);
0061 brelse(bh);
0062 }
0063 err:
0064 return ERR_PTR(err);
0065 }
0066
0067 static struct buffer_head *omfs_find_entry(struct inode *dir,
0068 const char *name, int namelen)
0069 {
0070 struct buffer_head *bh;
0071 int ofs;
0072 u64 block, dummy;
0073
0074 bh = omfs_get_bucket(dir, name, namelen, &ofs);
0075 if (!bh)
0076 return ERR_PTR(-EIO);
0077
0078 block = be64_to_cpu(*((__be64 *) &bh->b_data[ofs]));
0079 brelse(bh);
0080
0081 return omfs_scan_list(dir, block, name, namelen, &dummy);
0082 }
0083
0084 int omfs_make_empty(struct inode *inode, struct super_block *sb)
0085 {
0086 struct omfs_sb_info *sbi = OMFS_SB(sb);
0087 struct buffer_head *bh;
0088 struct omfs_inode *oi;
0089
0090 bh = omfs_bread(sb, inode->i_ino);
0091 if (!bh)
0092 return -ENOMEM;
0093
0094 memset(bh->b_data, 0, sizeof(struct omfs_inode));
0095
0096 if (S_ISDIR(inode->i_mode)) {
0097 memset(&bh->b_data[OMFS_DIR_START], 0xff,
0098 sbi->s_sys_blocksize - OMFS_DIR_START);
0099 } else
0100 omfs_make_empty_table(bh, OMFS_EXTENT_START);
0101
0102 oi = (struct omfs_inode *) bh->b_data;
0103 oi->i_head.h_self = cpu_to_be64(inode->i_ino);
0104 oi->i_sibling = ~cpu_to_be64(0ULL);
0105
0106 mark_buffer_dirty(bh);
0107 brelse(bh);
0108 return 0;
0109 }
0110
0111 static int omfs_add_link(struct dentry *dentry, struct inode *inode)
0112 {
0113 struct inode *dir = d_inode(dentry->d_parent);
0114 const char *name = dentry->d_name.name;
0115 int namelen = dentry->d_name.len;
0116 struct omfs_inode *oi;
0117 struct buffer_head *bh;
0118 u64 block;
0119 __be64 *entry;
0120 int ofs;
0121
0122
0123 bh = omfs_get_bucket(dir, name, namelen, &ofs);
0124 if (!bh)
0125 goto out;
0126
0127 entry = (__be64 *) &bh->b_data[ofs];
0128 block = be64_to_cpu(*entry);
0129 *entry = cpu_to_be64(inode->i_ino);
0130 mark_buffer_dirty(bh);
0131 brelse(bh);
0132
0133
0134 bh = omfs_bread(dir->i_sb, inode->i_ino);
0135 if (!bh)
0136 goto out;
0137
0138 oi = (struct omfs_inode *) bh->b_data;
0139 memcpy(oi->i_name, name, namelen);
0140 memset(oi->i_name + namelen, 0, OMFS_NAMELEN - namelen);
0141 oi->i_sibling = cpu_to_be64(block);
0142 oi->i_parent = cpu_to_be64(dir->i_ino);
0143 mark_buffer_dirty(bh);
0144 brelse(bh);
0145
0146 dir->i_ctime = current_time(dir);
0147
0148
0149 mark_inode_dirty(dir);
0150 mark_inode_dirty(inode);
0151 return 0;
0152 out:
0153 return -ENOMEM;
0154 }
0155
0156 static int omfs_delete_entry(struct dentry *dentry)
0157 {
0158 struct inode *dir = d_inode(dentry->d_parent);
0159 struct inode *dirty;
0160 const char *name = dentry->d_name.name;
0161 int namelen = dentry->d_name.len;
0162 struct omfs_inode *oi;
0163 struct buffer_head *bh, *bh2;
0164 __be64 *entry, next;
0165 u64 block, prev;
0166 int ofs;
0167 int err = -ENOMEM;
0168
0169
0170 bh = omfs_get_bucket(dir, name, namelen, &ofs);
0171 if (!bh)
0172 goto out;
0173
0174 entry = (__be64 *) &bh->b_data[ofs];
0175 block = be64_to_cpu(*entry);
0176
0177 bh2 = omfs_scan_list(dir, block, name, namelen, &prev);
0178 if (IS_ERR(bh2)) {
0179 err = PTR_ERR(bh2);
0180 goto out_free_bh;
0181 }
0182
0183 oi = (struct omfs_inode *) bh2->b_data;
0184 next = oi->i_sibling;
0185 brelse(bh2);
0186
0187 if (prev != ~0) {
0188
0189 brelse(bh);
0190 bh = omfs_bread(dir->i_sb, prev);
0191 if (!bh)
0192 goto out;
0193
0194 oi = (struct omfs_inode *) bh->b_data;
0195 entry = &oi->i_sibling;
0196 }
0197
0198 *entry = next;
0199 mark_buffer_dirty(bh);
0200
0201 if (prev != ~0) {
0202 dirty = omfs_iget(dir->i_sb, prev);
0203 if (!IS_ERR(dirty)) {
0204 mark_inode_dirty(dirty);
0205 iput(dirty);
0206 }
0207 }
0208
0209 err = 0;
0210 out_free_bh:
0211 brelse(bh);
0212 out:
0213 return err;
0214 }
0215
0216 static int omfs_dir_is_empty(struct inode *inode)
0217 {
0218 int nbuckets = (inode->i_size - OMFS_DIR_START) / 8;
0219 struct buffer_head *bh;
0220 u64 *ptr;
0221 int i;
0222
0223 bh = omfs_bread(inode->i_sb, inode->i_ino);
0224
0225 if (!bh)
0226 return 0;
0227
0228 ptr = (u64 *) &bh->b_data[OMFS_DIR_START];
0229
0230 for (i = 0; i < nbuckets; i++, ptr++)
0231 if (*ptr != ~0)
0232 break;
0233
0234 brelse(bh);
0235 return *ptr != ~0;
0236 }
0237
0238 static int omfs_remove(struct inode *dir, struct dentry *dentry)
0239 {
0240 struct inode *inode = d_inode(dentry);
0241 int ret;
0242
0243
0244 if (S_ISDIR(inode->i_mode) &&
0245 !omfs_dir_is_empty(inode))
0246 return -ENOTEMPTY;
0247
0248 ret = omfs_delete_entry(dentry);
0249 if (ret)
0250 return ret;
0251
0252 clear_nlink(inode);
0253 mark_inode_dirty(inode);
0254 mark_inode_dirty(dir);
0255 return 0;
0256 }
0257
0258 static int omfs_add_node(struct inode *dir, struct dentry *dentry, umode_t mode)
0259 {
0260 int err;
0261 struct inode *inode = omfs_new_inode(dir, mode);
0262
0263 if (IS_ERR(inode))
0264 return PTR_ERR(inode);
0265
0266 err = omfs_make_empty(inode, dir->i_sb);
0267 if (err)
0268 goto out_free_inode;
0269
0270 err = omfs_add_link(dentry, inode);
0271 if (err)
0272 goto out_free_inode;
0273
0274 d_instantiate(dentry, inode);
0275 return 0;
0276
0277 out_free_inode:
0278 iput(inode);
0279 return err;
0280 }
0281
0282 static int omfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
0283 struct dentry *dentry, umode_t mode)
0284 {
0285 return omfs_add_node(dir, dentry, mode | S_IFDIR);
0286 }
0287
0288 static int omfs_create(struct user_namespace *mnt_userns, struct inode *dir,
0289 struct dentry *dentry, umode_t mode, bool excl)
0290 {
0291 return omfs_add_node(dir, dentry, mode | S_IFREG);
0292 }
0293
0294 static struct dentry *omfs_lookup(struct inode *dir, struct dentry *dentry,
0295 unsigned int flags)
0296 {
0297 struct buffer_head *bh;
0298 struct inode *inode = NULL;
0299
0300 if (dentry->d_name.len > OMFS_NAMELEN)
0301 return ERR_PTR(-ENAMETOOLONG);
0302
0303 bh = omfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len);
0304 if (!IS_ERR(bh)) {
0305 struct omfs_inode *oi = (struct omfs_inode *)bh->b_data;
0306 ino_t ino = be64_to_cpu(oi->i_head.h_self);
0307 brelse(bh);
0308 inode = omfs_iget(dir->i_sb, ino);
0309 } else if (bh != ERR_PTR(-ENOENT)) {
0310 inode = ERR_CAST(bh);
0311 }
0312 return d_splice_alias(inode, dentry);
0313 }
0314
0315
0316 int omfs_is_bad(struct omfs_sb_info *sbi, struct omfs_header *header,
0317 u64 fsblock)
0318 {
0319 int is_bad;
0320 u64 ino = be64_to_cpu(header->h_self);
0321 is_bad = ((ino != fsblock) || (ino < sbi->s_root_ino) ||
0322 (ino > sbi->s_num_blocks));
0323
0324 if (is_bad)
0325 printk(KERN_WARNING "omfs: bad hash chain detected\n");
0326
0327 return is_bad;
0328 }
0329
0330 static bool omfs_fill_chain(struct inode *dir, struct dir_context *ctx,
0331 u64 fsblock, int hindex)
0332 {
0333
0334 while (fsblock != ~0) {
0335 struct buffer_head *bh = omfs_bread(dir->i_sb, fsblock);
0336 struct omfs_inode *oi;
0337 u64 self;
0338 unsigned char d_type;
0339
0340 if (!bh)
0341 return true;
0342
0343 oi = (struct omfs_inode *) bh->b_data;
0344 if (omfs_is_bad(OMFS_SB(dir->i_sb), &oi->i_head, fsblock)) {
0345 brelse(bh);
0346 return true;
0347 }
0348
0349 self = fsblock;
0350 fsblock = be64_to_cpu(oi->i_sibling);
0351
0352
0353 if (hindex) {
0354 hindex--;
0355 brelse(bh);
0356 continue;
0357 }
0358
0359 d_type = (oi->i_type == OMFS_DIR) ? DT_DIR : DT_REG;
0360
0361 if (!dir_emit(ctx, oi->i_name,
0362 strnlen(oi->i_name, OMFS_NAMELEN),
0363 self, d_type)) {
0364 brelse(bh);
0365 return false;
0366 }
0367 brelse(bh);
0368 ctx->pos++;
0369 }
0370 return true;
0371 }
0372
0373 static int omfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
0374 struct dentry *old_dentry, struct inode *new_dir,
0375 struct dentry *new_dentry, unsigned int flags)
0376 {
0377 struct inode *new_inode = d_inode(new_dentry);
0378 struct inode *old_inode = d_inode(old_dentry);
0379 int err;
0380
0381 if (flags & ~RENAME_NOREPLACE)
0382 return -EINVAL;
0383
0384 if (new_inode) {
0385
0386 err = omfs_remove(new_dir, new_dentry);
0387 if (err)
0388 goto out;
0389 }
0390
0391
0392
0393 err = omfs_delete_entry(old_dentry);
0394 if (err)
0395 goto out;
0396
0397 mark_inode_dirty(old_dir);
0398 err = omfs_add_link(new_dentry, old_inode);
0399 if (err)
0400 goto out;
0401
0402 old_inode->i_ctime = current_time(old_inode);
0403 mark_inode_dirty(old_inode);
0404 out:
0405 return err;
0406 }
0407
0408 static int omfs_readdir(struct file *file, struct dir_context *ctx)
0409 {
0410 struct inode *dir = file_inode(file);
0411 struct buffer_head *bh;
0412 __be64 *p;
0413 unsigned int hchain, hindex;
0414 int nbuckets;
0415
0416 if (ctx->pos >> 32)
0417 return -EINVAL;
0418
0419 if (ctx->pos < 1 << 20) {
0420 if (!dir_emit_dots(file, ctx))
0421 return 0;
0422 ctx->pos = 1 << 20;
0423 }
0424
0425 nbuckets = (dir->i_size - OMFS_DIR_START) / 8;
0426
0427
0428 hchain = (ctx->pos >> 20) - 1;
0429 hindex = ctx->pos & 0xfffff;
0430
0431 bh = omfs_bread(dir->i_sb, dir->i_ino);
0432 if (!bh)
0433 return -EINVAL;
0434
0435 p = (__be64 *)(bh->b_data + OMFS_DIR_START) + hchain;
0436
0437 for (; hchain < nbuckets; hchain++) {
0438 __u64 fsblock = be64_to_cpu(*p++);
0439 if (!omfs_fill_chain(dir, ctx, fsblock, hindex))
0440 break;
0441 hindex = 0;
0442 ctx->pos = (hchain+2) << 20;
0443 }
0444 brelse(bh);
0445 return 0;
0446 }
0447
0448 const struct inode_operations omfs_dir_inops = {
0449 .lookup = omfs_lookup,
0450 .mkdir = omfs_mkdir,
0451 .rename = omfs_rename,
0452 .create = omfs_create,
0453 .unlink = omfs_remove,
0454 .rmdir = omfs_remove,
0455 };
0456
0457 const struct file_operations omfs_dir_operations = {
0458 .read = generic_read_dir,
0459 .iterate_shared = omfs_readdir,
0460 .llseek = generic_file_llseek,
0461 };