aboutsummaryrefslogtreecommitdiffstats
path: root/init
Commit message (Expand)AuthorAge
* Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-2.6Linus Torvalds2008-03-04
|\
| * sysfs: CONFIG_SYSFS_DEPRECATED fixIngo Molnar2008-03-04
| * driver core: fix up Kconfig text for CONFIG_SYSFS_DEPRECATEDGreg Kroah-Hartman2008-03-04
* | Memory controller: rename to Memory Resource ControllerBalbir Singh2008-03-04
* | Fix "Malformed early option 'loglevel'"Alex Riesen2008-03-04
|/
* cgroup memory controller: document huge memory/cache overhead in KconfigAndi Kleen2008-02-23
* Use struct path in fs_structJan Blunck2008-02-15
* sched: rt-group: make rt groups scheduling configurablePeter Zijlstra2008-02-13
* kbuild: fix make V=1Sam Ravnborg2008-02-11
* x86: DEBUG_PAGEALLOC: enable after mem_init()Thomas Gleixner2008-02-09
* brk: help text typo fixIngo Molnar2008-02-09
* kbuild: silence CHK/UPD messages according to $(quiet)Mike Frysinger2008-02-09
* Convert loglevel-related kernel boot parameters to early_paramYinghai Lu2008-02-08
* start the global /sbin/init with 0,0 special pidsOleg Nesterov2008-02-08
* teach set_special_pids() to use struct pidOleg Nesterov2008-02-08
* namespaces: cleanup the code managed with PID_NS optionPavel Emelyanov2008-02-08
* namespaces: cleanup the code managed with the USER_NS optionPavel Emelyanov2008-02-08
* namespaces: move the IPC namespace under IPC_NS optionPavel Emelyanov2008-02-08
* namespaces: move the UTS namespace under UTS_NS optionPavel Emelyanov2008-02-08
* namespaces: add the NAMESPACES config optionPavel Emelyanov2008-02-08
* Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/...Linus Torvalds2008-02-07
|\
| * ACPI: basic initramfs DSDT override supportMarkus Gaugusch2008-02-06
* | Memory controller: cgroups setupBalbir Singh2008-02-07
* | Memory controller: resource countersPavel Emelianov2008-02-07
|/
* Merge git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86Linus Torvalds2008-02-06
|\
| * brk randomization: introduce CONFIG_COMPAT_BRKIngo Molnar2008-02-06
* | calibrate_delay() must be __cpuinitAdrian Bunk2008-02-06
* | Remove superfluous checks for CONFIG_BLK_DEV_INITRD from initramfs.cRobert P. J. Day2008-02-06
* | proper prototype for get_filesystem_list()Adrian Bunk2008-02-06
* | proper prototype for signals_init()Adrian Bunk2008-02-06
* | read_current_timer() cleanupsAndrew Morton2008-02-06
|/
* slob: correct Kconfig descriptionMatt Mackall2008-02-05
* maps4: make page monitoring /proc file optionalMatt Mackall2008-02-05
* timerfd: un-break CONFIG_TIMERFDDavide Libenzi2008-02-05
* Move Kconfig.instrumentation to arch/Kconfig and init/KconfigMathieu Desnoyers2008-02-03
* Create arch/KconfigMathieu Desnoyers2008-02-03
* RCU: add help text for "RCU implementation type"Paul E. McKenney2008-01-31
* x86: do not PSE on CONFIG_DEBUG_PAGEALLOC=yIngo Molnar2008-01-30
* x86/non-x86: percpu, node ids, apic ids x86.git fixupMike Travis2008-01-30
* x86: optimize lock prefix switching to run less frequentlyAndi Kleen2008-01-30
* percpu: use a kconfig variable to signal arch specific percpu setuptravis@sgi.com2008-01-30
* kconfig: use environment optionRoman Zippel2008-01-28
* sh: syscall audit support.Yuichi Nakamura2008-01-27
* Preempt-RCU: implementationPaul E. McKenney2008-01-25
* cpu-hotplug: refcount based cpu hotplugGautham R Shenoy2008-01-25
* Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmo...Linus Torvalds2008-01-25
|\
| * security: remove security_sb_post_mountroot hookH. Peter Anvin2008-01-24
* | sysfs: make SYSFS_DEPRECATED depend on SYSFSRandy Dunlap2008-01-24
* | Driver core: convert block from raw kobjects to core devicesKay Sievers2008-01-24
|/
* Unify /proc/slabinfo configurationLinus Torvalds2008-01-02
if (cpos >= emi->ei_cpos && cpos < range) { list_move(&emi->ei_list, &em->em_list); *ret_emi = emi; break; } } } static int ocfs2_extent_map_lookup(struct inode *inode, unsigned int cpos, unsigned int *phys, unsigned int *len, unsigned int *flags) { unsigned int coff; struct ocfs2_inode_info *oi = OCFS2_I(inode); struct ocfs2_extent_map_item *emi; spin_lock(&oi->ip_lock); __ocfs2_extent_map_lookup(&oi->ip_extent_map, cpos, &emi); if (emi) { coff = cpos - emi->ei_cpos; *phys = emi->ei_phys + coff; if (len) *len = emi->ei_clusters - coff; if (flags) *flags = emi->ei_flags; } spin_unlock(&oi->ip_lock); if (emi == NULL) return -ENOENT; return 0; } /* * Forget about all clusters equal to or greater than cpos. */ void ocfs2_extent_map_trunc(struct inode *inode, unsigned int cpos) { struct ocfs2_extent_map_item *emi, *n; struct ocfs2_inode_info *oi = OCFS2_I(inode); struct ocfs2_extent_map *em = &oi->ip_extent_map; LIST_HEAD(tmp_list); unsigned int range; spin_lock(&oi->ip_lock); list_for_each_entry_safe(emi, n, &em->em_list, ei_list) { if (emi->ei_cpos >= cpos) { /* Full truncate of this record. */ list_move(&emi->ei_list, &tmp_list); BUG_ON(em->em_num_items == 0); em->em_num_items--; continue; } range = emi->ei_cpos + emi->ei_clusters; if (range > cpos) { /* Partial truncate */ emi->ei_clusters = cpos - emi->ei_cpos; } } spin_unlock(&oi->ip_lock); list_for_each_entry_safe(emi, n, &tmp_list, ei_list) { list_del(&emi->ei_list); kfree(emi); } } /* * Is any part of emi2 contained within emi1 */ static int ocfs2_ei_is_contained(struct ocfs2_extent_map_item *emi1, struct ocfs2_extent_map_item *emi2) { unsigned int range1, range2; /* * Check if logical start of emi2 is inside emi1 */ range1 = emi1->ei_cpos + emi1->ei_clusters; if (emi2->ei_cpos >= emi1->ei_cpos && emi2->ei_cpos < range1) return 1; /* * Check if logical end of emi2 is inside emi1 */ range2 = emi2->ei_cpos + emi2->ei_clusters; if (range2 > emi1->ei_cpos && range2 <= range1) return 1; return 0; } static void ocfs2_copy_emi_fields(struct ocfs2_extent_map_item *dest, struct ocfs2_extent_map_item *src) { dest->ei_cpos = src->ei_cpos; dest->ei_phys = src->ei_phys; dest->ei_clusters = src->ei_clusters; dest->ei_flags = src->ei_flags; } /* * Try to merge emi with ins. Returns 1 if merge succeeds, zero * otherwise. */ static int ocfs2_try_to_merge_extent_map(struct ocfs2_extent_map_item *emi, struct ocfs2_extent_map_item *ins) { /* * Handle contiguousness */ if (ins->ei_phys == (emi->ei_phys + emi->ei_clusters) && ins->ei_cpos == (emi->ei_cpos + emi->ei_clusters) && ins->ei_flags == emi->ei_flags) { emi->ei_clusters += ins->ei_clusters; return 1; } else if ((ins->ei_phys + ins->ei_clusters) == emi->ei_phys && (ins->ei_cpos + ins->ei_clusters) == emi->ei_phys && ins->ei_flags == emi->ei_flags) { emi->ei_phys = ins->ei_phys; emi->ei_cpos = ins->ei_cpos; emi->ei_clusters += ins->ei_clusters; return 1; } /* * Overlapping extents - this shouldn't happen unless we've * split an extent to change it's flags. That is exceedingly * rare, so there's no sense in trying to optimize it yet. */ if (ocfs2_ei_is_contained(emi, ins) || ocfs2_ei_is_contained(ins, emi)) { ocfs2_copy_emi_fields(emi, ins); return 1; } /* No merge was possible. */ return 0; } /* * In order to reduce complexity on the caller, this insert function * is intentionally liberal in what it will accept. * * The only rule is that the truncate call *must* be used whenever * records have been deleted. This avoids inserting overlapping * records with different physical mappings. */ void ocfs2_extent_map_insert_rec(struct inode *inode, struct ocfs2_extent_rec *rec) { struct ocfs2_inode_info *oi = OCFS2_I(inode); struct ocfs2_extent_map *em = &oi->ip_extent_map; struct ocfs2_extent_map_item *emi, *new_emi = NULL; struct ocfs2_extent_map_item ins; ins.ei_cpos = le32_to_cpu(rec->e_cpos); ins.ei_phys = ocfs2_blocks_to_clusters(inode->i_sb, le64_to_cpu(rec->e_blkno)); ins.ei_clusters = le16_to_cpu(rec->e_leaf_clusters); ins.ei_flags = rec->e_flags; search: spin_lock(&oi->ip_lock); list_for_each_entry(emi, &em->em_list, ei_list) { if (ocfs2_try_to_merge_extent_map(emi, &ins)) { list_move(&emi->ei_list, &em->em_list); spin_unlock(&oi->ip_lock); goto out; } } /* * No item could be merged. * * Either allocate and add a new item, or overwrite the last recently * inserted. */ if (em->em_num_items < OCFS2_MAX_EXTENT_MAP_ITEMS) { if (new_emi == NULL) { spin_unlock(&oi->ip_lock); new_emi = kmalloc(sizeof(*new_emi), GFP_NOFS); if (new_emi == NULL) goto out; goto search; } ocfs2_copy_emi_fields(new_emi, &ins); list_add(&new_emi->ei_list, &em->em_list); em->em_num_items++; new_emi = NULL; } else { BUG_ON(list_empty(&em->em_list) || em->em_num_items == 0); emi = list_entry(em->em_list.prev, struct ocfs2_extent_map_item, ei_list); list_move(&emi->ei_list, &em->em_list); ocfs2_copy_emi_fields(emi, &ins); } spin_unlock(&oi->ip_lock); out: if (new_emi) kfree(new_emi); } /* * Return the 1st index within el which contains an extent start * larger than v_cluster. */ static int ocfs2_search_for_hole_index(struct ocfs2_extent_list *el, u32 v_cluster) { int i; struct ocfs2_extent_rec *rec; for(i = 0; i < le16_to_cpu(el->l_next_free_rec); i++) { rec = &el->l_recs[i]; if (v_cluster < le32_to_cpu(rec->e_cpos)) break; } return i; } /* * Figure out the size of a hole which starts at v_cluster within the given * extent list. * * If there is no more allocation past v_cluster, we return the maximum * cluster size minus v_cluster. * * If we have in-inode extents, then el points to the dinode list and * eb_bh is NULL. Otherwise, eb_bh should point to the extent block * containing el. */ static int ocfs2_figure_hole_clusters(struct inode *inode, struct ocfs2_extent_list *el, struct buffer_head *eb_bh, u32 v_cluster, u32 *num_clusters) { int ret, i; struct buffer_head *next_eb_bh = NULL; struct ocfs2_extent_block *eb, *next_eb; i = ocfs2_search_for_hole_index(el, v_cluster); if (i == le16_to_cpu(el->l_next_free_rec) && eb_bh) { eb = (struct ocfs2_extent_block *)eb_bh->b_data; /* * Check the next leaf for any extents. */ if (le64_to_cpu(eb->h_next_leaf_blk) == 0ULL) goto no_more_extents; ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), le64_to_cpu(eb->h_next_leaf_blk), &next_eb_bh, OCFS2_BH_CACHED, inode); if (ret) { mlog_errno(ret); goto out; } next_eb = (struct ocfs2_extent_block *)next_eb_bh->b_data; if (!OCFS2_IS_VALID_EXTENT_BLOCK(next_eb)) { ret = -EROFS; OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, next_eb); goto out; } el = &next_eb->h_list; i = ocfs2_search_for_hole_index(el, v_cluster); } no_more_extents: if (i == le16_to_cpu(el->l_next_free_rec)) { /* * We're at the end of our existing allocation. Just * return the maximum number of clusters we could * possibly allocate. */ *num_clusters = UINT_MAX - v_cluster; } else { *num_clusters = le32_to_cpu(el->l_recs[i].e_cpos) - v_cluster; } ret = 0; out: brelse(next_eb_bh); return ret; } int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, u32 *p_cluster, u32 *num_clusters, unsigned int *extent_flags) { int ret, i; unsigned int flags = 0; struct buffer_head *di_bh = NULL; struct buffer_head *eb_bh = NULL; struct ocfs2_dinode *di; struct ocfs2_extent_block *eb; struct ocfs2_extent_list *el; struct ocfs2_extent_rec *rec; u32 coff; if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { ret = -ERANGE; mlog_errno(ret); goto out; } ret = ocfs2_extent_map_lookup(inode, v_cluster, p_cluster, num_clusters, extent_flags); if (ret == 0) goto out; ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno, &di_bh, OCFS2_BH_CACHED, inode); if (ret) { mlog_errno(ret); goto out; } di = (struct ocfs2_dinode *) di_bh->b_data; el = &di->id2.i_list; if (el->l_tree_depth) { ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh); if (ret) { mlog_errno(ret); goto out; } eb = (struct ocfs2_extent_block *) eb_bh->b_data; el = &eb->h_list; if (el->l_tree_depth) { ocfs2_error(inode->i_sb, "Inode %lu has non zero tree depth in " "leaf block %llu\n", inode->i_ino, (unsigned long long)eb_bh->b_blocknr); ret = -EROFS; goto out; } } i = ocfs2_search_extent_list(el, v_cluster); if (i == -1) { /* * A hole was found. Return some canned values that * callers can key on. If asked for, num_clusters will * be populated with the size of the hole. */ *p_cluster = 0; if (num_clusters) { ret = ocfs2_figure_hole_clusters(inode, el, eb_bh, v_cluster, num_clusters); if (ret) { mlog_errno(ret); goto out; } } } else { rec = &el->l_recs[i]; BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos)); if (!rec->e_blkno) { ocfs2_error(inode->i_sb, "Inode %lu has bad extent " "record (%u, %u, 0)", inode->i_ino, le32_to_cpu(rec->e_cpos), ocfs2_rec_clusters(el, rec)); ret = -EROFS; goto out; } coff = v_cluster - le32_to_cpu(rec->e_cpos); *p_cluster = ocfs2_blocks_to_clusters(inode->i_sb, le64_to_cpu(rec->e_blkno)); *p_cluster = *p_cluster + coff; if (num_clusters) *num_clusters = ocfs2_rec_clusters(el, rec) - coff; flags = rec->e_flags; ocfs2_extent_map_insert_rec(inode, rec); } if (extent_flags) *extent_flags = flags; out: brelse(di_bh); brelse(eb_bh); return ret; } /* * This expects alloc_sem to be held. The allocation cannot change at * all while the map is in the process of being updated. */ int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno, u64 *ret_count, unsigned int *extent_flags) { int ret; int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); u32 cpos, num_clusters, p_cluster; u64 boff = 0; cpos = ocfs2_blocks_to_clusters(inode->i_sb, v_blkno); ret = ocfs2_get_clusters(inode, cpos, &p_cluster, &num_clusters, extent_flags); if (ret) { mlog_errno(ret); goto out; } /* * p_cluster == 0 indicates a hole. */ if (p_cluster) { boff = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster); boff += (v_blkno & (u64)(bpc - 1)); } *p_blkno = boff; if (ret_count) { *ret_count = ocfs2_clusters_to_blocks(inode->i_sb, num_clusters); *ret_count -= v_blkno & (u64)(bpc - 1); } out: return ret; }