/* tid is the actual task/thread id (née pid, stored as ->pid), pid/tgid is that 2.6 thread group id crap (stored as ->tgid) */ asmlinkage long sys_vperfctr_open(int tid, int creat) { struct file *filp; struct task_struct *tsk; struct vperfctr *perfctr; int err; int fd; if (!vperfctr_fs_init_done()) return -ENODEV; filp = vperfctr_get_filp(); if (!filp) return -ENOMEM; err = fd = get_unused_fd(); if (err < 0) goto err_filp; perfctr = NULL; if (creat) { perfctr = get_empty_vperfctr(); /* may sleep */ if (IS_ERR(perfctr)) { err = PTR_ERR(perfctr); goto err_fd; } } tsk = current; if (tid != 0 && tid != tsk->pid) { /* remote? */ // tasklist_lock is to access the linked list of task_struct structures exclusively read_lock(&tasklist_lock); //tsk = find_task_by_pid(tid); tsk = find_task_by_pid_ns(tid, current->nsproxy->pid_ns); if (tsk) get_task_struct(tsk); read_unlock(&tasklist_lock); err = -ESRCH; if (!tsk) goto err_perfctr; err = ptrace_check_attach(tsk, 0); if (err < 0) goto err_tsk; } if (creat) { /* check+install must be atomic to prevent remote-control races */ task_lock(tsk); if (!tsk->thread.perfctr) { perfctr->owner = tsk; tsk->thread.perfctr = perfctr; err = 0; } else err = -EEXIST; task_unlock(tsk); if (err) goto err_tsk; } else { perfctr = tsk->thread.perfctr; /* XXX: Old API needed to allow NULL perfctr here. Do we want to keep or change that rule? */ } filp->private_data = perfctr; if (perfctr) atomic_inc(&perfctr->count); if (tsk != current) put_task_struct(tsk); #if 0 if (perfctr) { printk ("sys_vperfctr_open(): fd = %d, perfctr is NOT null\n", fd); } else { printk ("sys_vperfctr_open(): fd = %d, perfctr is null\n", fd); } #endif fd_install(fd, filp); return fd; err_tsk: if (tsk != current) put_task_struct(tsk); err_perfctr: if (perfctr) /* can only occur if creat != 0 */ put_vperfctr(perfctr); err_fd: put_unused_fd(fd); err_filp: fput(filp); return err; }
/* tid is the actual task/thread id (née pid, stored as ->pid), pid/tgid is that 2.6 thread group id crap (stored as ->tgid) */ int vperfctr_attach(int tid, int creat) { struct file *filp; struct task_struct *tsk; struct vperfctr *perfctr; int err; int fd; filp = vperfctr_get_filp(); if (!filp) return -ENOMEM; err = fd = get_unused_fd(); if (err < 0) goto err_filp; perfctr = NULL; if (creat) { perfctr = get_empty_vperfctr(); /* may sleep */ if (IS_ERR(perfctr)) { err = PTR_ERR(perfctr); goto err_fd; } } tsk = current; if (tid != 0 && tid != task_pid_vnr(tsk)) { /* remote? */ vperfctr_lock_find_task_by_vpid(); tsk = find_task_by_vpid(tid); if (tsk) get_task_struct(tsk); vperfctr_unlock_find_task_by_vpid(); err = -ESRCH; if (!tsk) goto err_perfctr; err = ptrace_check_attach(tsk, 0); if (err < 0) goto err_tsk; } if (creat) { /* check+install must be atomic to prevent remote-control races */ vperfctr_task_lock(tsk); if (!tsk->thread.perfctr) { perfctr->owner = tsk; tsk->thread.perfctr = perfctr; err = 0; } else err = -EEXIST; vperfctr_task_unlock(tsk); if (err) goto err_tsk; } else { perfctr = tsk->thread.perfctr; /* PERFCTR_ABI and PERFCTR_INFO don't need the perfctr. Hence no non-NULL check here. */ } filp->private_data = perfctr; if (perfctr) atomic_inc(&perfctr->count); if (tsk != current) put_task_struct(tsk); fd_install(fd, filp); return fd; err_tsk: if (tsk != current) put_task_struct(tsk); err_perfctr: if (perfctr) /* can only occur if creat != 0 */ put_vperfctr(perfctr); err_fd: put_unused_fd(fd); err_filp: fput(filp); return err; }