[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH 3/3] Xen physical cpus interface (V2)



Konrad Rzeszutek Wilk wrote:
>> +static void pcpu_sys_remove(struct pcpu *pcpu)
>> +{
>> +    struct device *dev;
>> +
>> +    if (!pcpu)
>> +            return;
>> +
>> +    dev = &pcpu->dev;
>> +    if (dev->id)
>> +            device_remove_file(dev, &dev_attr_online);
>> +
>> +    device_unregister(dev);
>> +}
>> +
>> +static void free_pcpu(struct pcpu *pcpu)
> 
> 1) So this isn't just freeing the PCPU, it also unregisters
> the SysFS.
> 
> As such you should call this differently:
> 
> unregister_and_free(struct pcpu *pcpu)

Fine, rename 2 funcs:
init_pcpu --> int_and_register_pcpu
free_pcpu --> unregister_and_free_pcpu

> 
> or do the unregistration part seperatly.
> 
> 2) But there is also another issue - a possiblity of race.
> 
> The user might be running:
> while (true)
> do
>  echo 1 > online
>  echo 0 > online
> done
> 
> and the the sync_pcpu will end up calling pcpu_sys_remove and
> free the pcpu. The SysFS aren't deleted until all of the

No race here. echo x > online would not change cpu present map.

> object references (kref's) have been put. So when you get to
> 'kfree(pcpu)' you might be still holding a reference (meaning
> the user is doing 'echo 0 > online') and crash.
> 
> I think you need to hold the mutex in the store_online() function
> (not good), or better yet, make a device_release function
> that will be called when the last kref has been put.
> 
> 
> 3) Third the name. These functions all depend on the mutex lock being
> held. As such add a postfix to the name of the function of
> "_locked" or a prefix of "__' so it is known that the caller holds
> the mutex.

OK, add _locked postfix to these functions.

Thanks,
Jinsong

> 
>> +{
>> +    if (!pcpu)
>> +            return;
>> +
>> +    pcpu_sys_remove(pcpu);
>> +
>> +    list_del(&pcpu->list);
>> +    kfree(pcpu);
>> +}
>> +
>> +static int pcpu_sys_create(struct pcpu *pcpu)
>> +{
>> +    struct device *dev;
>> +    int err = -EINVAL;
>> +
>> +    if (!pcpu)
>> +            return err;
>> +
>> +    dev = &pcpu->dev;
>> +    dev->bus = &xen_pcpu_subsys;
>> +    dev->id = pcpu->cpu_id;
>> +
>> +    err = device_register(dev);
>> +    if (err)
>> +            return err;
>> +
>> +    /*
>> +     * Xen never offline cpu0 due to several restrictions
>> +     * and assumptions. This basically doesn't add a sys control
>> +     * to user, one cannot attempt to offline BSP.
>> +     */
>> +    if (dev->id) {
>> +            err = device_create_file(dev, &dev_attr_online); +              
>> if (err) {
>> +                    device_unregister(dev);
>> +                    return err;
>> +            }
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static struct pcpu *init_pcpu(struct xenpf_pcpuinfo *info) +{
>> +    struct pcpu *pcpu;
>> +    int err;
>> +
>> +    if (info->flags & XEN_PCPU_FLAGS_INVALID)
>> +            return ERR_PTR(-ENODEV);
>> +
>> +    pcpu = kzalloc(sizeof(struct pcpu), GFP_KERNEL);
>> +    if (!pcpu)
>> +            return ERR_PTR(-ENOMEM);
>> +
>> +    INIT_LIST_HEAD(&pcpu->list);
>> +    pcpu->cpu_id = info->xen_cpuid;
>> +    pcpu->flags = info->flags;
>> +
>> +    err = pcpu_sys_create(pcpu);
>> +    if (err) {
>> +            pr_warning(XEN_PCPU "Failed to register pcpu%u\n", +            
>>           
>> info->xen_cpuid); +          kfree(pcpu);
>> +            return ERR_PTR(-ENOENT);
>> +    }
>> +
>> +    /* Need hold on xen_pcpu_lock before pcpu list manipulations */
>> +    list_add_tail(&pcpu->list, &xen_pcpus);
>> +    return pcpu;
>> +}
>> +
>> +/*
>> + * Caller should hold the xen_pcpu_lock
>> + */
>> +static int sync_pcpu(uint32_t cpu, uint32_t *max_cpu) +{
>> +    int ret;
>> +    struct pcpu *pcpu = NULL;
>> +    struct xenpf_pcpuinfo *info;
>> +    struct xen_platform_op op = {
>> +            .cmd                   = XENPF_get_cpuinfo,
>> +            .interface_version     = XENPF_INTERFACE_VERSION,
>> +            .u.pcpu_info.xen_cpuid = cpu,
>> +    };
>> +
>> +    ret = HYPERVISOR_dom0_op(&op);
>> +    if (ret)
>> +            return ret;
>> +
>> +    info = &op.u.pcpu_info;
>> +    if (max_cpu)
>> +            *max_cpu = info->max_present;
>> +
>> +    pcpu = get_pcpu(cpu);
>> +
>> +    if (info->flags & XEN_PCPU_FLAGS_INVALID) {
>> +            /* The pcpu has been removed */
>> +            if (pcpu)
>> +                    free_pcpu(pcpu);
>> +            return 0;
>> +    }
>> +
>> +    if (!pcpu) {
>> +            pcpu = init_pcpu(info);
>> +            if (IS_ERR_OR_NULL(pcpu))
>> +                    return -ENODEV;
>> +    } else
>> +            pcpu_online_status(info, pcpu);
>> +
>> +    return 0;
>> +}
>> +
>> +/*
>> + * Sync dom0's pcpu information with xen hypervisor's + */
>> +static int xen_sync_pcpus(void)
>> +{
>> +    /*
>> +     * Boot cpu always have cpu_id 0 in xen
>> +     */
>> +    uint32_t cpu = 0, max_cpu = 0;
>> +    int err = 0;
>> +    struct list_head *cur, *tmp;
>> +    struct pcpu *pcpu;
>> +
>> +    mutex_lock(&xen_pcpu_lock);
>> +
>> +    while (!err && (cpu <= max_cpu)) {
>> +            err = sync_pcpu(cpu, &max_cpu);
>> +            cpu++;
>> +    }
>> +
>> +    if (err) {
>> +            list_for_each_safe(cur, tmp, &xen_pcpus) {
>> +                    pcpu = list_entry(cur, struct pcpu, list);
>> +                    free_pcpu(pcpu);
>> +            }
>> +    }
>> +
>> +    mutex_unlock(&xen_pcpu_lock);
>> +
>> +    return err;
>> +}
>> +
>> +static void xen_pcpu_work_fn(struct work_struct *work) +{
>> +    xen_sync_pcpus();
>> +}
>> +static DECLARE_WORK(xen_pcpu_work, xen_pcpu_work_fn); +
>> +static irqreturn_t xen_pcpu_interrupt(int irq, void *dev_id) +{
>> +    schedule_work(&xen_pcpu_work);
>> +    return IRQ_HANDLED;
>> +}
>> +
>> +static int __init xen_pcpu_init(void)
>> +{
>> +    int irq, ret;
>> +
>> +    if (!xen_initial_domain())
>> +            return -ENODEV;
>> +
>> +    irq = bind_virq_to_irqhandler(VIRQ_PCPU_STATE, 0,
>> +                                  xen_pcpu_interrupt, 0,
>> +                                  "xen-pcpu", NULL);
>> +    if (irq < 0) {
>> +            pr_warning(XEN_PCPU "Failed to bind pcpu virq\n"); +            
>> return irq;
>> +    }
>> +
>> +    ret = subsys_system_register(&xen_pcpu_subsys, NULL); + if (ret) {
>> +            pr_warning(XEN_PCPU "Failed to register pcpu subsys\n"); +      
>>         goto
>> err1; +      }
>> +
>> +    ret = xen_sync_pcpus();
>> +    if (ret) {
>> +            pr_warning(XEN_PCPU "Failed to sync pcpu info\n"); +            
>> goto err2;
>> +    }
>> +
>> +    return 0;
>> +
>> +err2:
>> +    bus_unregister(&xen_pcpu_subsys);
>> +err1:
>> +    unbind_from_irqhandler(irq, NULL);
>> +    return ret;
>> +}
>> +arch_initcall(xen_pcpu_init);
>> diff --git a/include/xen/interface/platform.h
>> b/include/xen/interface/platform.h index 486653f..61fa661 100644 ---
>> a/include/xen/interface/platform.h +++
>> b/include/xen/interface/platform.h @@ -314,6 +314,13 @@ struct
>>  xenpf_pcpuinfo { };
>>  DEFINE_GUEST_HANDLE_STRUCT(xenpf_pcpuinfo);
>> 
>> +#define XENPF_cpu_online    56
>> +#define XENPF_cpu_offline   57
>> +struct xenpf_cpu_ol {
>> +    uint32_t cpuid;
>> +};
>> +DEFINE_GUEST_HANDLE_STRUCT(xenpf_cpu_ol);
>> +
>>  struct xen_platform_op {
>>      uint32_t cmd;
>>      uint32_t interface_version; /* XENPF_INTERFACE_VERSION */
>> @@ -330,6 +337,7 @@ struct xen_platform_op {
>>              struct xenpf_getidletime       getidletime;
>>              struct xenpf_set_processor_pminfo set_pminfo;
>>              struct xenpf_pcpuinfo          pcpu_info;
>> +            struct xenpf_cpu_ol            cpu_ol;
>>              uint8_t                        pad[128];
>>      } u;
>>  };
>> diff --git a/include/xen/interface/xen.h
>> b/include/xen/interface/xen.h 
>> index a890804..0801468 100644
>> --- a/include/xen/interface/xen.h
>> +++ b/include/xen/interface/xen.h
>> @@ -80,6 +80,7 @@
>>  #define VIRQ_CONSOLE    2  /* (DOM0) Bytes received on emergency
>>  console. */ #define VIRQ_DOM_EXC    3  /* (DOM0) Exceptional event
>>  for some domain.   */ #define VIRQ_DEBUGGER   6  /* (DOM0) A domain
>> has paused for debugging.   */ +#define VIRQ_PCPU_STATE 9  /* (DOM0)
>> PCPU state changed                   */ 
>> 
>>  /* Architecture-specific VIRQ definitions. */
>>  #define VIRQ_ARCH_0    16
>> --
>> 1.7.1


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.