proc_to_write.dtype = PROV_DIST_PROCESS;
proc_to_write.pd_phook = p;
err = prov_analyzer_pawrite(&proc_to_write, args, pos, &pa, 1);
如上,这是do_paread中的语句。当前进程封装为prov_dist_obj结构体。args是buf以及长度,pos是偏移,这两个感觉是用不到的。pa是prov_addition结构体。
开始分析:
int prov_analyzer_pawrite (struct prov_dist_obj * dobj,
struct prov_arguments * args,
loff_t *pos,
struct prov_addition ** in_additions,
const unsigned num_in_additions) {
struct prov_addition ** out_additions = NULL;
unsigned num_additions = 0;
int ret = 0;
ret = do_analysis(in_additions, num_in_additions, /*分析层进行分析,去循环,去重复*/
&out_additions, &num_additions);
if (ret < 0) {
printk(KERN_ERR "PASS:(%s) do analysis failed %d\n",
__FUNCTION__, ret);
goto out;
}
ret = prov_dist_pawrite(dobj, args, pos, out_additions, num_additions); /*交给Distributor层*/
if (num_additions) {
free_prov_addition_array(out_additions, num_additions);
}
out:
return ret;
}
Distributor层代码好多。。。。参数的意思基本不变。
int prov_dist_pawrite(struct prov_dist_obj * dobj,
struct prov_arguments * args,
loff_t * pos,
struct prov_addition ** additions,
const unsigned num_additions) {
struct prov_obj_ref src_obj;
struct prov_dist_info * dinfo;
struct prov_array out_array;
struct inode * inode = NULL;
struct file * f = NULL;
version_t version;
int i = 0;
int ret = 0;
prov_array_init(&out_array); /*初始化一个prov_array结构,里面是2个数和一个void类型的指针的指针*/
/* set the inode and file */
if (dobj->dtype == PROV_DIST_INODE) {
inode = dobj->pd_inode;
} else if (dobj->dtype == PROV_DIST_FILE) {
f = dobj->pd_file;
inode = f->f_path.dentry->d_inode;
}
if (!current->t_hook) { /*当前进程无hook的话,只写数据*/
/* current process doesn't have a hook, so go out. XXX this
* should have been filtered out at the observer, but I can't
* understand this */
if (f) {
/* but we have a file to write data to, so do that before we go */
if (args->arg_type == NON_UIO_BASED) {
if ((args->buf == NULL) && (args->buflen == 0) && (pos == NULL)) {
/*
* This is us, during an mmap write. For an mmap
* write, we need to add a record to the
* distributor/analyzer indicating that it wrote the
* file. To get that effect, we make this dummy read
* call with everything set to NULL or 0 (depending on
* its type) from the obvserver.
*/
} else {
ret = vfs_write(f, args->buf, args->buflen, pos);
}
} else {
ret = vfs_writev(f, args->vec, args->vlen, pos);
}
}
goto out;
}
/* set up for converting */
src_obj.rtype = PROV_PROCESS;
src_obj.pr_phook = current->t_hook;
/* then get the version out */
dinfo = get_dist_info(&src_obj);
if (IS_ERR(dinfo)) {
ret = PTR_ERR(dinfo);
printk (KERN_ERR "PASS:(%s) error dist info %d\n",
__FUNCTION__, ret);
goto out;
}
version = dinfo->version;
put_dist_info(&src_obj);
/* now process the additions. The src_obj is used to convert any
records that have CONVERT_REFER_SRC in them */
ret = process_prov_additions(additions, num_additions, &src_obj, /*见下文吧*/
version, &out_array);
if (ret < 0) {
printk (KERN_ERR "PASS:(%s) processing additions %d\n",
__FUNCTION__, ret);
goto out_free;
}
if (out_array.num > 1024) {
printk("number of elements %u\n", out_array.num);
}
switch(dobj->dtype) {
case PROV_DIST_PROCESS: /*如果是进程,就跳出,返回*/
/* do nothing */
break;
case PROV_DIST_INODE:
case PROV_DIST_FILE:
if (!is_pass_file(inode)) {
if (args->arg_type == NON_UIO_BASED) {
if ((args->buf == NULL) && (args->buflen == 0) && (pos == NULL)) {
/*
* This is us, during an mmap write. For an mmap
* write, we need to add a record to the
* distributor/analyzer indicating that it wrote the
* file. To get that effect, we make this dummy read
* call with everything set to NULL or 0 (depending on
* its type) from the obvserver.
*/
} else {
ret = vfs_write(f, args->buf, args->buflen, pos);
}
} else {
ret = vfs_writev(f, args->vec, args->vlen, pos);
}
if (ret < 0) {
printk (KERN_ERR "PASS:(%s) error vfs_writing %d\n",
__FUNCTION__, ret);
}
} else {
/*
* Write the provenance to the file system. Note that we
* actually need to sort all the records by their volume
* and then write the provenance volume by volume.
*/
struct prov_addition ** additions = (struct prov_addition **) out_array.data;
if (args->arg_type == NON_UIO_BASED) {
ret = inode->i_prov_hook->pi_ops->pi_pawrite(inode, f, args->buf,
args->buflen, pos,
additions,
out_array.num);
} else {
ret = inode->i_prov_hook->pi_ops->pi_pawritev(inode, f, args->vec,
args->vlen, pos,
additions,
out_array.num);
}
if (ret < 0) {
printk (KERN_ERR "PASS:(%s) pawrite failed %d\n",
__FUNCTION__, ret);
}
}
break;
}
out_free:
/* free the records, if any */
for (i = 0; i < out_array.num; ++i) {
free_prov_addition(out_array.data[i]); out_array.data[i] = NULL;
}
prov_array_cleanup(&out_array);
out:
return ret;
}
参数:&prov_addition 个数为1 进程的obj 进程dinfo中的版本 prov_array
static int
process_prov_additions(struct prov_addition ** in_additions,
const unsigned num_additions,
struct prov_obj_ref * src_obj,
version_t version,
struct prov_array * out_array) {
struct prov_addition * pa = NULL;
int ret = 0;
int i = 0;
for (i = 0; i < num_additions; ++i) {
if (!is_obj_pass_file(&in_additions[i]->pa_target)) { /*在这里,target是上文中的进程,所以不是pass file*/
ret = convert_and_add_prov_addition_to_object(in_additions[i], /*注意prov_dist_info结构中的list*/
src_obj,
version);
if (ret < 0) {
printk(KERN_ERR "PASS:%s failed to convert_add_prov_addition"
"[%d]: %d\n", __FUNCTION__, i, ret);
}
/* we're done with this non-pass record and we can move on
* to the next element in the in_additions array */
continue;
}
/* record i is a pass volume provenance record */
switch (in_additions[i]->pa_precord.pp_value.pv_type) {
case PROV_TYPE_NIL:
switch (in_additions[i]->pa_conversion) {
case PROV_CONVERT_NONE:
pa = copy_prov_addition(in_additions[i]);
break;
case PROV_CONVERT_REFER_SRC:
pa = convert_and_flush_phony_obj(&in_additions[i]->pa_target,
PROV_TYPE_OBJECTVERSION,
in_additions[i]->pa_precord.pp_attribute,
src_obj, version, out_array);
break;
case PROV_CONVERT_REFER_DST:
BUG(); /* xxx; we don't know how to handle this yet */
break;
}
break;
case PROV_TYPE_OBJECT:
case PROV_TYPE_OBJECTVERSION:
if (is_obj_pass_file(&in_additions[i]->pa_precord.pp_value.pv_obj)){
/* if the prov record points to a pass file, then we
* can just make a copy of the object */
pa = copy_prov_addition(in_additions[i]);
} else {
/* else we convert the non-pass object to its phony */
pa = convert_and_flush_phony_obj(&in_additions[i]->pa_target,
in_additions[i]->pa_precord.pp_value.pv_type,
in_additions[i]->pa_precord.pp_attribute,
&in_additions[i]->pa_precord.pp_value.pv_obj,
in_additions[i]->pa_precord.pp_value.pv_version,
out_array);
}
break;
default:
pa = copy_prov_addition(in_additions[i]);
break;
}
if (IS_ERR(pa)) {
/* print and error message and continue with the other guys */
ret = PTR_ERR(pa);
printk(KERN_ERR "PASS (%s): failed process addition %d:%d\n",
__FUNCTION__, i, ret);
} else {
ret = prov_array_add(out_array, pa, NULL); /*将pa放入array中*/
if (ret < 0) {
//printk("freeing %s:%p\n", __FUNCTION__, pa);
free_prov_addition(pa);
printk(KERN_ERR "PASS (%s): failed to add addition %d:%d\n",
__FUNCTION__, i, ret);
goto err;
}
}
}
goto out;
err:
for (i = 0; i < out_array->num; ++i) {
//printk("freeing %s:%p\n", __FUNCTION__, out_array->additions[i]);
free_prov_addition(out_array->data[i]);
out_array->data[i] = NULL;
}
prov_array_cleanup(out_array);
out:
return ret;
}