📄 ref.c
字号:
return 0;}intfusion_ref_watch (FusionDev *dev, int id, int call_id, int call_arg){ int ret; FusionRef *ref; ret = lock_ref (dev, false, id, &ref); if (ret) return ret; if (ref->pid != current->pid) { unlock_ref (ref); return -EACCES; } if (ref->global + ref->local == 0) { unlock_ref (ref); return -EIO; } if (ref->watched) { unlock_ref (ref); return -EBUSY; } ref->watched = true; ref->call_id = call_id; ref->call_arg = call_arg; wake_up_interruptible_all (&ref->wait); unlock_ref (ref); return 0;}intfusion_ref_inherit (FusionDev *dev, int id, int from_id){ int ret; FusionRef *ref; FusionRef *from = NULL; ret = lookup_ref (dev, false, id, &ref); if (ret) return ret; if (down_interruptible (&ref->lock)) { up (&dev->ref.lock); return -EINTR; } ret = -EBUSY; if (ref->inherited) goto out; ret = lock_ref (dev, true, from_id, &from); if (ret) goto out; ret = add_inheritor( ref, from ); if (ret) goto out; ret = propagate_local( dev, ref, from->local ); if (ret) goto out; ref->inherited = from;out: if (from) unlock_ref (from); unlock_ref (ref); up (&dev->ref.lock); return ret;}intfusion_ref_destroy (FusionDev *dev, int id){ int ret; FusionRef *ref; ret = lookup_ref (dev, false, id, &ref); if (ret) return ret; if (down_interruptible (&ref->lock)) { up (&dev->ref.lock); return -EINTR; } drop_inheritors( dev, ref ); if (ref->inherited) remove_inheritor( ref, ref->inherited ); fusion_list_remove (&dev->ref.list, &ref->link); wake_up_interruptible_all (&ref->wait); up (&dev->ref.lock); free_all_local (ref); up (&ref->lock); kfree (ref); return 0;}voidfusion_ref_clear_all_local (FusionDev *dev, int fusion_id){ FusionLink *l; down (&dev->ref.lock); fusion_list_foreach (l, dev->ref.list) { FusionRef *ref = (FusionRef *) l; clear_local (dev, ref, fusion_id); } up (&dev->ref.lock);}/******************************************************************************/static intlookup_ref (FusionDev *dev, bool locked, int id, FusionRef **ret_ref){ FusionLink *l; if (!locked && down_interruptible (&dev->ref.lock)) return -EINTR; fusion_list_foreach (l, dev->ref.list) { FusionRef *ref = (FusionRef *) l; if (ref->id == id) { *ret_ref = ref; return 0; } } if (!locked) up (&dev->ref.lock); return -EINVAL;}static intlock_ref (FusionDev *dev, bool locked, int id, FusionRef **ret_ref){ int ret; FusionRef *ref; ret = lookup_ref (dev, locked, id, &ref); if (ret) return ret; if (ref) { fusion_list_move_to_front (&dev->ref.list, &ref->link); if (down_interruptible (&ref->lock)) { if (!locked) up (&dev->ref.lock); return -EINTR; } if (!locked) up (&dev->ref.lock); } *ret_ref = ref; return 0;}static voidunlock_ref (FusionRef *ref){ up (&ref->lock);}static intadd_local (FusionRef *ref, int fusion_id, int add){ FusionLink *l; LocalRef *local; fusion_list_foreach (l, ref->local_refs) { local = (LocalRef *) l; if (local->fusion_id == fusion_id) { fusion_list_move_to_front( &ref->local_refs, l ); if (local->refs + add < 0) return -EIO; local->refs += add; return 0; } } local = kmalloc (sizeof(LocalRef), GFP_KERNEL); if (!local) return -ENOMEM; local->fusion_id = fusion_id; local->refs = add; fusion_list_prepend (&ref->local_refs, &local->link); return 0;}static voidclear_local (FusionDev *dev, FusionRef *ref, int fusion_id){ FusionLink *l; down (&ref->lock); if (ref->locked == fusion_id) { ref->locked = 0; wake_up_interruptible_all (&ref->wait); } fusion_list_foreach (l, ref->local_refs) { LocalRef *local = (LocalRef *) l; if (local->fusion_id == fusion_id) { if (local->refs) propagate_local( dev, ref, - local->refs ); fusion_list_remove( &ref->local_refs, l ); kfree (l); break; } } up (&ref->lock);}static voidfree_all_local (FusionRef *ref){ FusionLink *l = ref->local_refs; while (l) { FusionLink *next = l->next; kfree (l); l = next; } ref->local_refs = NULL;}static voidnotify_ref (FusionDev *dev, FusionRef *ref){ if (ref->watched) { FusionCallExecute execute; execute.call_id = ref->call_id; execute.call_arg = ref->call_arg; execute.call_ptr = NULL; fusion_call_execute (dev, 0, &execute); } else wake_up_interruptible_all (&ref->wait);}static intpropagate_local( FusionDev *dev, FusionRef *ref, int diff ){ FusionLink *l; /* Recurse into inheritors. */ fusion_list_foreach (l, ref->inheritors) { FusionRef *inheritor = ((Inheritor*) l)->ref; if (down_interruptible( &inheritor->lock )) { printk( KERN_ERR "fusion_ref: propagate_local() interrupted!\n" ); //return -EINTR; } propagate_local( dev, inheritor, diff ); up( &inheritor->lock ); } /* Apply difference. */ ref->local += diff; /* Notify zero count. */ if (ref->local + ref->global == 0) notify_ref( dev, ref ); return 0;}static intadd_inheritor(FusionRef *ref, FusionRef *from){ Inheritor *inheritor; inheritor = kmalloc (sizeof(Inheritor), GFP_KERNEL); if (!inheritor) return -ENOMEM; inheritor->ref = ref; fusion_list_prepend( &from->inheritors, &inheritor->link ); return 0;}static voidremove_inheritor(FusionRef *ref, FusionRef *from){ FusionLink *l; down( &from->lock ); fusion_list_foreach (l, from->inheritors) { Inheritor *inheritor = (Inheritor*) l; if (inheritor->ref == ref) { fusion_list_remove( &from->inheritors, &inheritor->link ); kfree( l ); break; } } up( &from->lock );}static voiddrop_inheritors( FusionDev *dev, FusionRef *ref ){ FusionLink *l = ref->inheritors; while (l) { FusionLink *next = l->next; FusionRef *inheritor = ((Inheritor*) l)->ref; if (down_interruptible( &inheritor->lock )) { printk( KERN_ERR "fusion_ref: drop_inheritors() interrupted!\n" ); //return; } propagate_local( dev, inheritor, - ref->local ); inheritor->inherited = NULL; up( &inheritor->lock ); kfree (l); l = next; } ref->inheritors = NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -