On 07/13/2010 09:00 AM, Brian King wrote: > On 07/12/2010 10:42 AM, Nathan Fontenot wrote: >> @@ -123,13 +130,20 @@ >> static ssize_t show_mem_removable(struct sys_device *dev, >> struct sysdev_attribute *attr, char *buf) >> { >> - unsigned long start_pfn; >> - int ret; >> - struct memory_block *mem = >> - container_of(dev, struct memory_block, sysdev); >> + struct list_head *pos, *tmp; >> + struct memory_block *mem; >> + int ret = 1; >> + >> + mem = container_of(dev, struct memory_block, sysdev); >> + list_for_each_safe(pos, tmp, &mem->sections) { >> + struct memory_block_section *mbs; >> + unsigned long start_pfn; >> + >> + mbs = list_entry(pos, struct memory_block_section, next); >> + start_pfn = section_nr_to_pfn(mbs->phys_index); >> + ret &= is_mem_section_removable(start_pfn, PAGES_PER_SECTION); >> + } > > I don't see you deleting anyting from the list in this loop. Why do you need > to use list_for_each_safe? That won't protect you if someone else is messing > with the list.
Yes, Kame pointed this out too. I think I'll need to update the patches to always take the mutex when walking the list and use list_for_each_entry > >> >> - start_pfn = section_nr_to_pfn(mem->phys_index); >> - ret = is_mem_section_removable(start_pfn, PAGES_PER_SECTION); >> return sprintf(buf, "%d\n", ret); >> } >> > > >> @@ -238,19 +252,40 @@ >> static int memory_block_change_state(struct memory_block *mem, >> unsigned long to_state, unsigned long from_state_req) >> { >> + struct memory_block_section *mbs; >> + struct list_head *pos; >> int ret = 0; >> + >> mutex_lock(&mem->state_mutex); >> >> - if (mem->state != from_state_req) { >> - ret = -EINVAL; >> - goto out; >> + list_for_each(pos, &mem->sections) { >> + mbs = list_entry(pos, struct memory_block_section, next); >> + >> + if (mbs->state != from_state_req) >> + continue; >> + >> + ret = memory_block_action(mbs, to_state); >> + if (ret) >> + break; >> + } > > Would it be better here to loop through all the sections and ensure they > are in the proper state first before starting to change the state of any > of them? Then you could easily return -EINVAL if one or more is in > the incorrect state and wouldn't need to the code below. The code below is needed in cases where the add/remove of one of the memory_block_sections fails. The code can then return all of the memory_block_sections in the memory_block to the original state. > >> + if (ret) { >> + list_for_each(pos, &mem->sections) { >> + mbs = list_entry(pos, struct memory_block_section, >> + next); >> + >> + if (mbs->state == from_state_req) >> + continue; >> + >> + if (memory_block_action(mbs, to_state)) >> + printk(KERN_ERR "Could not re-enable memory " >> + "section %lx\n", mbs->phys_index); >> + } >> } >> >> - ret = memory_block_action(mem, to_state); >> if (!ret) >> mem->state = to_state; >> >> -out: >> mutex_unlock(&mem->state_mutex); >> return ret; >> } > > >> @@ -498,19 +496,97 @@ >> >> return mem; >> } >> +static int add_mem_block_section(struct memory_block *mem, >> + int section_nr, unsigned long state) >> +{ >> + struct memory_block_section *mbs; >> + >> + mbs = kzalloc(sizeof(*mbs), GFP_KERNEL); >> + if (!mbs) >> + return -ENOMEM; >> + >> + mbs->phys_index = section_nr; >> + mbs->state = state; >> + >> + list_add(&mbs->next, &mem->sections); > > I don't think there is sufficient protection for this list. Don't we > need to be holding a lock of some sort when adding/deleting/iterating > through this list? You're right. we should be holding the mutex. I think there are a couple other places that I missed with this. I'll fix it for a v2 of the patches. > >> + return 0; >> +} > _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev