a.v0 = v0; 
sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg){	struct sn_hwperf_ioctl_args a;	struct cpuinfo_ia64 *cdata;	struct sn_hwperf_object_info *objs;	struct sn_hwperf_object_info *cpuobj;	struct sn_hwperf_op_info op_info;	void *p = NULL;	int nobj;	char slice;	int node;	int r;	int v0;	int i;	int j;	unlock_kernel();	/* only user requests are allowed here */	if ((op & SN_HWPERF_OP_MASK) < 10) {		r = -EINVAL;		goto error;	}	r = copy_from_user(&a, (const void __user *)arg,		sizeof(struct sn_hwperf_ioctl_args));	if (r != 0) {		r = -EFAULT;		goto error;	}	/*	 * Allocate memory to hold a kernel copy of the user buffer. The	 * buffer contents are either copied in or out (or both) of user	 * space depending on the flags encoded in the requested operation.	 */	if (a.ptr) {		p = vmalloc(a.sz);		if (!p) {			r = -ENOMEM;			goto error;		}	}	if (op & SN_HWPERF_OP_MEM_COPYIN) {		r = copy_from_user(p, (const void __user *)a.ptr, a.sz);		if (r != 0) {			r = -EFAULT;			goto error;		}	}	switch (op) {	case SN_HWPERF_GET_CPU_INFO:		if (a.sz == sizeof(u64)) {			/* special case to get size needed */			*(u64 *) p = (u64) num_online_cpus() *				sizeof(struct sn_hwperf_object_info);		} else		if (a.sz < num_online_cpus() * sizeof(struct sn_hwperf_object_info)) {			r = -ENOMEM;			goto error;		} else		if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) {			memset(p, 0, a.sz);			for (i = 0; i < nobj; i++) {				node = sn_hwperf_obj_to_cnode(objs + i);				for_each_online_cpu(j) {					if (node != cpu_to_node(j))						continue;					cpuobj = (struct sn_hwperf_object_info *) p + j;					slice = 'a' + cpuid_to_slice(j);					cdata = cpu_data(j);					cpuobj->id = j;					snprintf(cpuobj->name,						 sizeof(cpuobj->name),						 "CPU %luMHz %s",						 cdata->proc_freq / 1000000,						 cdata->vendor);					snprintf(cpuobj->location,						 sizeof(cpuobj->location),						 "%s%c", objs[i].location,						 slice);				}			}			vfree(objs);		}		break;	case SN_HWPERF_GET_NODE_NASID:		if (a.sz != sizeof(u64) ||		   (node = a.arg) < 0 || node >= numionodes) {			r = -EINVAL;			goto error;		}		*(u64 *)p = (u64)cnodeid_to_nasid(node);		break;	case SN_HWPERF_GET_OBJ_NODE:		if (a.sz != sizeof(u64) || a.arg < 0) {			r = -EINVAL;			goto error;		}		if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) {			if (a.arg >= nobj) {				r = -EINVAL;				vfree(objs);				goto error;			}			if (objs[(i = a.arg)].id != a.arg) {				for (i = 0; i < nobj; i++) {					if (objs[i].id == a.arg)						break;				}			}			if (i == nobj) {				r = -EINVAL;				vfree(objs);				goto error;			}			*(u64 *)p = (u64)sn_hwperf_obj_to_cnode(objs + i);			vfree(objs);		}		break;	case SN_HWPERF_GET_MMRS:	case SN_HWPERF_SET_MMRS:	case SN_HWPERF_OBJECT_DISTANCE:		op_info.p = p;		op_info.a = &a;		op_info.v0 = &v0;		op_info.op = op;		r = sn_hwperf_op_cpu(&op_info);		if (r) {			r = sn_hwperf_map_err(r);			goto error;		}		break;	default:		/* all other ops are a direct SAL call */		r = ia64_sn_hwperf_op(sn_hwperf_master_nasid, op,			      a.arg, a.sz, (u64) p, 0, 0, &v0);		if (r) {			r = sn_hwperf_map_err(r);			goto error;		}		a.v0 = v0;		break;	}	if (op & SN_HWPERF_OP_MEM_COPYOUT) {		r = copy_to_user((void __user *)a.ptr, p, a.sz);		if (r != 0) {			r = -EFAULT;			goto error;		}	}error:	vfree(p);	lock_kernel();	return r;}
10457	/local/tlutelli/issta_data/temp/c/2005_temp/2005/10457/4a5c13c7eb0d55bfd2cf3100c55f1e3d8df37576/sn_hwperf.c/buggy/arch/ia64/sn/kernel/sn2/sn_hwperf.c