📄 ext3-mballoc2-2.6-fc5.patch
字号:
++ /* drop non-allocated, but dquote'd blocks */+ J_ASSERT(*len >= ac.ac_b_ex.fe_len);+ DQUOT_FREE_BLOCK(inode, *len - ac.ac_b_ex.fe_len);++ *len = ac.ac_b_ex.fe_len;+ J_ASSERT(*len > 0);+ J_ASSERT(block != 0);+ goto out;++out_err:+ /* if we've already allocated something, roll it back */+ if (ac.ac_status == AC_STATUS_FOUND) {+ /* FIXME: free blocks here */+ }++ DQUOT_FREE_BLOCK(inode, *len);+ brelse(bitmap_bh);+ *errp = err;+ block = 0;+out:+ if (ac.ac_buddy_page)+ page_cache_release(ac.ac_buddy_page);+ if (ac.ac_bitmap_page)+ page_cache_release(ac.ac_bitmap_page);++ if (!(flags & EXT3_MB_HINT_RESERVED)) {+ /* block wasn't reserved before and we reserved it+ * at the beginning of allocation. it doesn't matter+ * whether we allocated anything or we failed: time+ * to release reservation. NOTE: because I expect+ * any multiblock request from delayed allocation+ * path only, here is single block always */+ ext3_mb_release_blocks(sb, 1);+ }++ if (unlikely(ext3_mb_stats) && ac.ac_g_ex.fe_len > 1) {+ atomic_inc(&sbi->s_bal_reqs);+ atomic_add(*len, &sbi->s_bal_allocated);+ if (*len >= ac.ac_g_ex.fe_len)+ atomic_inc(&sbi->s_bal_success);+ atomic_add(ac.ac_found, &sbi->s_bal_ex_scanned);+ if (ac.ac_g_ex.fe_start == ac.ac_b_ex.fe_start &&+ ac.ac_g_ex.fe_group == ac.ac_b_ex.fe_group)+ atomic_inc(&sbi->s_bal_goals);+ if (ac.ac_found > ext3_mb_max_to_scan)+ atomic_inc(&sbi->s_bal_breaks);+ }++ ext3_mb_store_history(sb, inode->i_ino, &ac);++ return block;+}+EXPORT_SYMBOL(ext3_mb_new_blocks);++#ifdef EXT3_MB_HISTORY+struct ext3_mb_proc_session {+ struct ext3_mb_history *history;+ struct super_block *sb;+ int start;+ int max;+};++static void *ext3_mb_history_skip_empty(struct ext3_mb_proc_session *s,+ struct ext3_mb_history *hs,+ int first)+{+ if (hs == s->history + s->max)+ hs = s->history;+ if (!first && hs == s->history + s->start)+ return NULL;+ while (hs->goal.fe_len == 0) {+ hs++;+ if (hs == s->history + s->max)+ hs = s->history;+ if (hs == s->history + s->start)+ return NULL;+ }+ return hs;+}++static void *ext3_mb_seq_history_start(struct seq_file *seq, loff_t *pos)+{+ struct ext3_mb_proc_session *s = seq->private;+ struct ext3_mb_history *hs;+ int l = *pos;++ if (l == 0)+ return SEQ_START_TOKEN;+ hs = ext3_mb_history_skip_empty(s, s->history + s->start, 1);+ if (!hs)+ return NULL;+ while (--l && (hs = ext3_mb_history_skip_empty(s, ++hs, 0)) != NULL);+ return hs;+}++static void *ext3_mb_seq_history_next(struct seq_file *seq, void *v, loff_t *pos)+{+ struct ext3_mb_proc_session *s = seq->private;+ struct ext3_mb_history *hs = v;++ ++*pos;+ if (v == SEQ_START_TOKEN)+ return ext3_mb_history_skip_empty(s, s->history + s->start, 1);+ else+ return ext3_mb_history_skip_empty(s, ++hs, 0);+}++static int ext3_mb_seq_history_show(struct seq_file *seq, void *v)+{+ struct ext3_mb_history *hs = v;+ char buf[20], buf2[20];++ if (v == SEQ_START_TOKEN) {+ seq_printf(seq, "%-5s %-8s %-17s %-17s %-5s %-5s %-2s %-5s %-5s %-6s\n",+ "pid", "inode", "goal", "result", "found", "grps", "cr",+ "merge", "tail", "broken");+ return 0;+ }++ sprintf(buf, "%u/%u/%u", hs->goal.fe_group,+ hs->goal.fe_start, hs->goal.fe_len);+ sprintf(buf2, "%u/%u/%u", hs->result.fe_group,+ hs->result.fe_start, hs->result.fe_len);+ seq_printf(seq, "%-5u %-8u %-17s %-17s %-5u %-5u %-2u %-5s %-5u %-6u\n",+ hs->pid, hs->ino, buf, buf2, hs->found, hs->groups,+ hs->cr, hs->merged ? "M" : "", hs->tail,+ hs->buddy ? 1 << hs->buddy : 0);+ return 0;+}++static void ext3_mb_seq_history_stop(struct seq_file *seq, void *v)+{+}++static struct seq_operations ext3_mb_seq_history_ops = {+ .start = ext3_mb_seq_history_start,+ .next = ext3_mb_seq_history_next,+ .stop = ext3_mb_seq_history_stop,+ .show = ext3_mb_seq_history_show,+};++static int ext3_mb_seq_history_open(struct inode *inode, struct file *file)+{+ struct super_block *sb = PDE(inode)->data;+ struct ext3_sb_info *sbi = EXT3_SB(sb);+ struct ext3_mb_proc_session *s;+ int rc, size;++ s = kmalloc(sizeof(*s), GFP_KERNEL);+ if (s == NULL)+ return -EIO;+ size = sizeof(struct ext3_mb_history) * sbi->s_mb_history_max;+ s->history = kmalloc(size, GFP_KERNEL);+ if (s->history == NULL) {+ kfree(s);+ return -EIO;+ }++ spin_lock(&sbi->s_mb_history_lock);+ memcpy(s->history, sbi->s_mb_history, size);+ s->max = sbi->s_mb_history_max;+ s->start = sbi->s_mb_history_cur % s->max;+ spin_unlock(&sbi->s_mb_history_lock);++ rc = seq_open(file, &ext3_mb_seq_history_ops);+ if (rc == 0) {+ struct seq_file *m = (struct seq_file *)file->private_data;+ m->private = s;+ } else {+ kfree(s->history);+ kfree(s);+ }+ return rc;++}++static int ext3_mb_seq_history_release(struct inode *inode, struct file *file)+{+ struct seq_file *seq = (struct seq_file *)file->private_data;+ struct ext3_mb_proc_session *s = seq->private;+ kfree(s->history);+ kfree(s);+ return seq_release(inode, file);+}++static struct file_operations ext3_mb_seq_history_fops = {+ .owner = THIS_MODULE,+ .open = ext3_mb_seq_history_open,+ .read = seq_read,+ .llseek = seq_lseek,+ .release = ext3_mb_seq_history_release,+};++static void *ext3_mb_seq_groups_start(struct seq_file *seq, loff_t *pos)+{+ struct super_block *sb = seq->private;+ struct ext3_sb_info *sbi = EXT3_SB(sb);+ long group;++ if (*pos < 0 || *pos >= sbi->s_groups_count)+ return NULL;++ group = *pos + 1;+ return (void *) group;+}++static void *ext3_mb_seq_groups_next(struct seq_file *seq, void *v, loff_t *pos)+{+ struct super_block *sb = seq->private;+ struct ext3_sb_info *sbi = EXT3_SB(sb);+ long group;++ ++*pos;+ if (*pos < 0 || *pos >= sbi->s_groups_count)+ return NULL;+ group = *pos + 1;+ return (void *) group;;+}++static int ext3_mb_seq_groups_show(struct seq_file *seq, void *v)+{+ struct super_block *sb = seq->private;+ long group = (long) v, i;+ struct sg {+ struct ext3_group_info info;+ unsigned short counters[16];+ } sg;++ group--;+ if (group == 0)+ seq_printf(seq, "#%-5s: %-5s %-5s %-5s [ %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s ]\n",+ "group", "free", "frags", "first", "2^0", "2^1", "2^2",+ "2^3", "2^4", "2^5", "2^6", "2^7", "2^8", "2^9", "2^10",+ "2^11", "2^12", "2^13");++ i = (sb->s_blocksize_bits + 2) * sizeof(sg.info.bb_counters[0]) ++ sizeof(struct ext3_group_info);+ ext3_lock_group(sb, group);+ memcpy(&sg, EXT3_GROUP_INFO(sb, group), i);+ ext3_unlock_group(sb, group);++ if (EXT3_MB_GRP_NEED_INIT(&sg.info))+ return 0;++ seq_printf(seq, "#%-5lu: %-5u %-5u %-5u [", group, sg.info.bb_free,+ sg.info.bb_fragments, sg.info.bb_first_free);+ for (i = 0; i <= 13; i++)+ seq_printf(seq, " %-5u", i <= sb->s_blocksize_bits + 1 ?+ sg.info.bb_counters[i] : 0);+ seq_printf(seq, " ]\n");++ return 0;+}++static void ext3_mb_seq_groups_stop(struct seq_file *seq, void *v)+{+}++static struct seq_operations ext3_mb_seq_groups_ops = {+ .start = ext3_mb_seq_groups_start,+ .next = ext3_mb_seq_groups_next,+ .stop = ext3_mb_seq_groups_stop,+ .show = ext3_mb_seq_groups_show,+};++static int ext3_mb_seq_groups_open(struct inode *inode, struct file *file)+{+ struct super_block *sb = PDE(inode)->data;+ int rc;++ rc = seq_open(file, &ext3_mb_seq_groups_ops);+ if (rc == 0) {+ struct seq_file *m = (struct seq_file *)file->private_data;+ m->private = sb;+ }+ return rc;++}++static struct file_operations ext3_mb_seq_groups_fops = {+ .owner = THIS_MODULE,+ .open = ext3_mb_seq_groups_open,+ .read = seq_read,+ .llseek = seq_lseek,+ .release = seq_release,+};++static void ext3_mb_history_release(struct super_block *sb)+{+ struct ext3_sb_info *sbi = EXT3_SB(sb);+ char name[64];++ snprintf(name, sizeof(name) - 1, "%s", bdevname(sb->s_bdev, name));+ remove_proc_entry("mb_groups", sbi->s_mb_proc);+ remove_proc_entry("mb_history", sbi->s_mb_proc);+ remove_proc_entry(name, proc_root_ext3);++ if (sbi->s_mb_history)+ kfree(sbi->s_mb_history);+}++static void ext3_mb_history_init(struct super_block *sb)+{+ struct ext3_sb_info *sbi = EXT3_SB(sb);+ char name[64];+ int i;++ snprintf(name, sizeof(name) - 1, "%s", bdevname(sb->s_bdev, name));+ sbi->s_mb_proc = proc_mkdir(name, proc_root_ext3);+ if (sbi->s_mb_proc != NULL) {+ struct proc_dir_entry *p;+ p = create_proc_entry("mb_history", S_IRUGO, sbi->s_mb_proc);+ if (p) {+ p->proc_fops = &ext3_mb_seq_history_fops;+ p->data = sb;+ }+ p = create_proc_entry("mb_groups", S_IRUGO, sbi->s_mb_proc);+ if (p) {+ p->proc_fops = &ext3_mb_seq_groups_fops;+ p->data = sb;+ }+ }++ sbi->s_mb_history_max = 1000;+ sbi->s_mb_history_cur = 0;+ spin_lock_init(&sbi->s_mb_history_lock);+ i = sbi->s_mb_history_max * sizeof(struct ext3_mb_history);+ sbi->s_mb_history = kmalloc(i, GFP_KERNEL);+ if (likely(sbi->s_mb_history != NULL))+ memset(sbi->s_mb_history, 0, i);+ /* if we can't allocate history, then we simple won't use it */+}++static void+ext3_mb_store_history(struct super_block *sb, unsigned ino,+ struct ext3_allocation_context *ac)+{+ struct ext3_sb_info *sbi = EXT3_SB(sb);+ struct ext3_mb_history h;++ if (unlikely(sbi->s_mb_history == NULL))+ return;++ h.pid = current->pid;+ h.ino = ino;+ h.goal = ac->ac_g_ex;+ h.result = ac->ac_b_ex;+ h.found = ac->ac_found;+ h.cr = ac->ac_criteria;+ h.groups = ac->ac_groups_scanned;+ h.tail = ac->ac_tail;+ h.buddy = ac->ac_buddy;+ h.merged = 0;+ if (ac->ac_g_ex.fe_start == ac->ac_b_ex.fe_start &&+ ac->ac_g_ex.fe_group == ac->ac_b_ex.fe_group)+ h.merged = 1;++ spin_lock(&sbi->s_mb_history_lock);+ memcpy(sbi->s_mb_history + sbi->s_mb_history_cur, &h, sizeof(h));+ if (++sbi->s_mb_history_cur >= sbi->s_mb_history_max)+ sbi->s_mb_history_cur = 0;+ spin_unlock(&sbi->s_mb_history_lock);+}++#else+#define ext3_mb_history_release(sb)+#define ext3_mb_history_init(sb)+#endif++int ext3_mb_init_backend(struct super_block *sb)+{+ struct ext3_sb_info *sbi = EXT3_SB(sb);+ int i, j, len, metalen;+ int num_meta_group_infos =+ (sbi->s_groups_count + EXT3_DESC_PER_BLOCK(sb) - 1) >>+ EXT3_DESC_PER_BLOCK_BITS(sb);+ struct ext3_group_info **meta_group_info;++ /* An 8TB filesystem with 64-bit pointers requires a 4096 byte+ * kmalloc. A 128kb malloc should suffice for a 256TB filesystem.+ * So a two level scheme suffices for now. */+ sbi->s_group_info = kmalloc(sizeof(*sbi->s_group_info) *+ num_meta_group_infos, GFP_KERNEL);+ if (sbi->s_group_info == NULL) {+ printk(KERN_ERR "EXT3-fs: can't allocate buddy meta group\n");+ return -ENOMEM;+ }+ sbi->s_buddy_cache = new_inode(sb);+ if (sbi->s_buddy_cache == NULL) {+ printk(KERN_ERR "EXT3-fs: can't get new inode\n");+ goto err_freesgi;+ }++ metalen = sizeof(*meta_group_info) << EXT3_DESC_PER_BLOCK_BITS(sb);+ for (i = 0; i < num_meta_group_infos; i++) {+ if ((i + 1) == num_meta_group_infos)+ metalen = sizeof(*meta_group_info) *+ (sbi->s_groups_count -+ (i << EXT3_DESC_PER_BLOCK_BITS(sb)));+ meta_group_info = kmalloc(metalen, GFP_KERNEL);+ if (meta_group_info == NULL) {+ printk(KERN_ERR "EXT3-fs: can't allocate mem for a "+ "buddy group\n");+ goto err_freemeta;+ }+ sbi->s_group_info[i] = meta_group_info;+ }++ /*+ * calculate needed size. if change bb_counters size,+ * don't forget about ext3_mb_generate_buddy()+ */+ len = sizeof(struct ext3_group_info);+ len += sizeof(unsigned short) * (sb->s_blocksize_bits + 2);+ for (i = 0; i < sbi->s_groups_count; i++) {+ struct ext3_group_desc * desc;++ meta_group_info =+ sbi->s_group_info[i >> EXT3_DESC_PER_BLOCK_BITS(sb)];+ j = i & (EXT3_DESC_PER_BLOCK(sb) - 1);++ meta_group_info[j] = kmalloc(len, GFP_KERNEL);+ if (meta_group_info[j] == NULL) {+ printk(KERN_ERR "EXT3-fs: can't allocate buddy mem\n");+ i--;+ goto err_freebuddy;+ }+ desc = ext3_get_group_desc(sb, i, NULL);+ if (desc == NULL) {+ printk(KERN_ERR"EXT3-fs: can't read descriptor %u\n",i);+ goto err_freebuddy;+ }+ memset(meta_group_info[j], 0, len);+ set_bit(EXT3_GROUP_INFO_NEED_INIT_BIT,+ &meta_group_info[j]->bb_state);+ meta_group_info[j]->bb_free =+ le16_to_cpu(desc->bg_free_blocks_count);+ }++ return 0;++err_freebuddy:+ while (i >= 0) {+ kfree(EXT3_GROUP_INFO(sb, i));+ i--;+ }+ i = num_meta_group_infos;+err_freemeta:+ while (--i >= 0)+ kfree(sbi->s_group_info[i]);+ iput(sbi->s_buddy_cache);+err_freesgi:+ kfree(sbi->s_group_info);+ return -ENOMEM;+}++int ext3_mb_init(struct super_block *sb, int needs_recovery)+{+ struct ext3_sb_info *sbi = EXT3_SB(sb);+ struct inode *root = sb->s_root->d_inode;+ unsigned i, offset, max;+ struct dentry *dentry;++ if (!test_opt(sb, MBALLOC))+ return 0;++ i = (sb->s_blocksize_bits + 2) * sizeof(unsigned short);++ sbi->s_mb_offsets = kmalloc(i, GFP_KERNEL);+ if (sbi->s_mb_offsets == NULL) {+ clear_opt(sbi->s_mount_opt, MBALLOC);+ return -ENOMEM;+ }+ sbi->s_mb_maxs = kmalloc(i, GFP_KERNEL);+ if (sbi->s_mb_maxs == NULL) {+ clear_opt(sbi->s_mount_opt, MBALLOC);+ kfree(sbi->s_mb_maxs);+ return -ENOMEM;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -