diff options
| author | Manfred Spraul <manfred@colorfullife.com> | 2008-07-25 04:48:04 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-25 13:53:42 -0400 |
| commit | 4daa28f6d8f5cda8ea0f55048e3c8811c384cbdd (patch) | |
| tree | 934bfbd7932a18da8295d9e21727985d1ea16311 | |
| parent | 00c2bf85d8febfcfddde63822043462b026134ff (diff) | |
ipc/sem.c: convert undo structures to struct list_head
The undo structures contain two linked lists, the attached patch replaces
them with generic struct list_head lists.
[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: Manfred Spraul <manfred@colorfullife.com>
Cc: Nadia Derbey <Nadia.Derbey@bull.net>
Cc: Pierre Peiffer <peifferp@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | include/linux/sem.h | 12 | ||||
| -rw-r--r-- | ipc/sem.c | 163 |
2 files changed, 95 insertions, 80 deletions
diff --git a/include/linux/sem.h b/include/linux/sem.h index c8eaad9e4b72..6a1af1b49a13 100644 --- a/include/linux/sem.h +++ b/include/linux/sem.h | |||
| @@ -95,7 +95,7 @@ struct sem_array { | |||
| 95 | struct sem *sem_base; /* ptr to first semaphore in array */ | 95 | struct sem *sem_base; /* ptr to first semaphore in array */ |
| 96 | struct sem_queue *sem_pending; /* pending operations to be processed */ | 96 | struct sem_queue *sem_pending; /* pending operations to be processed */ |
| 97 | struct sem_queue **sem_pending_last; /* last pending operation */ | 97 | struct sem_queue **sem_pending_last; /* last pending operation */ |
| 98 | struct sem_undo *undo; /* undo requests on this array */ | 98 | struct list_head list_id; /* undo requests on this array */ |
| 99 | unsigned long sem_nsems; /* no. of semaphores in array */ | 99 | unsigned long sem_nsems; /* no. of semaphores in array */ |
| 100 | }; | 100 | }; |
| 101 | 101 | ||
| @@ -118,8 +118,8 @@ struct sem_queue { | |||
| 118 | * when the process exits. | 118 | * when the process exits. |
| 119 | */ | 119 | */ |
| 120 | struct sem_undo { | 120 | struct sem_undo { |
| 121 | struct sem_undo * proc_next; /* next entry on this process */ | 121 | struct list_head list_proc; /* per-process list: all undos from one process */ |
| 122 | struct sem_undo * id_next; /* next entry on this semaphore set */ | 122 | struct list_head list_id; /* per semaphore array list: all undos for one array */ |
| 123 | int semid; /* semaphore set identifier */ | 123 | int semid; /* semaphore set identifier */ |
| 124 | short * semadj; /* array of adjustments, one per semaphore */ | 124 | short * semadj; /* array of adjustments, one per semaphore */ |
| 125 | }; | 125 | }; |
| @@ -128,9 +128,9 @@ struct sem_undo { | |||
| 128 | * that may be shared among all a CLONE_SYSVSEM task group. | 128 | * that may be shared among all a CLONE_SYSVSEM task group. |
| 129 | */ | 129 | */ |
| 130 | struct sem_undo_list { | 130 | struct sem_undo_list { |
| 131 | atomic_t refcnt; | 131 | atomic_t refcnt; |
| 132 | spinlock_t lock; | 132 | spinlock_t lock; |
| 133 | struct sem_undo *proc_list; | 133 | struct list_head list_proc; |
| 134 | }; | 134 | }; |
| 135 | 135 | ||
| 136 | struct sysv_sem { | 136 | struct sysv_sem { |
| @@ -274,7 +274,7 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params) | |||
| 274 | sma->sem_base = (struct sem *) &sma[1]; | 274 | sma->sem_base = (struct sem *) &sma[1]; |
| 275 | /* sma->sem_pending = NULL; */ | 275 | /* sma->sem_pending = NULL; */ |
| 276 | sma->sem_pending_last = &sma->sem_pending; | 276 | sma->sem_pending_last = &sma->sem_pending; |
| 277 | /* sma->undo = NULL; */ | 277 | INIT_LIST_HEAD(&sma->list_id); |
| 278 | sma->sem_nsems = nsems; | 278 | sma->sem_nsems = nsems; |
| 279 | sma->sem_ctime = get_seconds(); | 279 | sma->sem_ctime = get_seconds(); |
| 280 | sem_unlock(sma); | 280 | sem_unlock(sma); |
| @@ -536,7 +536,8 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) | |||
| 536 | * (They will be freed without any further action in exit_sem() | 536 | * (They will be freed without any further action in exit_sem() |
| 537 | * or during the next semop.) | 537 | * or during the next semop.) |
| 538 | */ | 538 | */ |
| 539 | for (un = sma->undo; un; un = un->id_next) | 539 | assert_spin_locked(&sma->sem_perm.lock); |
| 540 | list_for_each_entry(un, &sma->list_id, list_id) | ||
| 540 | un->semid = -1; | 541 | un->semid = -1; |
| 541 | 542 | ||
| 542 | /* Wake up all pending processes and let them fail with EIDRM. */ | 543 | /* Wake up all pending processes and let them fail with EIDRM. */ |
| @@ -763,9 +764,12 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, | |||
| 763 | 764 | ||
| 764 | for (i = 0; i < nsems; i++) | 765 | for (i = 0; i < nsems; i++) |
| 765 | sma->sem_base[i].semval = sem_io[i]; | 766 | sma->sem_base[i].semval = sem_io[i]; |
| 766 | for (un = sma->undo; un; un = un->id_next) | 767 | |
| 768 | assert_spin_locked(&sma->sem_perm.lock); | ||
| 769 | list_for_each_entry(un, &sma->list_id, list_id) { | ||
| 767 | for (i = 0; i < nsems; i++) | 770 | for (i = 0; i < nsems; i++) |
| 768 | un->semadj[i] = 0; | 771 | un->semadj[i] = 0; |
| 772 | } | ||
| 769 | sma->sem_ctime = get_seconds(); | 773 | sma->sem_ctime = get_seconds(); |
| 770 | /* maybe some queued-up processes were waiting for this */ | 774 | /* maybe some queued-up processes were waiting for this */ |
| 771 | update_queue(sma); | 775 | update_queue(sma); |
| @@ -797,12 +801,15 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, | |||
| 797 | { | 801 | { |
| 798 | int val = arg.val; | 802 | int val = arg.val; |
| 799 | struct sem_undo *un; | 803 | struct sem_undo *un; |
| 804 | |||
| 800 | err = -ERANGE; | 805 | err = -ERANGE; |
| 801 | if (val > SEMVMX || val < 0) | 806 | if (val > SEMVMX || val < 0) |
| 802 | goto out_unlock; | 807 | goto out_unlock; |
| 803 | 808 | ||
| 804 | for (un = sma->undo; un; un = un->id_next) | 809 | assert_spin_locked(&sma->sem_perm.lock); |
| 810 | list_for_each_entry(un, &sma->list_id, list_id) | ||
| 805 | un->semadj[semnum] = 0; | 811 | un->semadj[semnum] = 0; |
| 812 | |||
| 806 | curr->semval = val; | 813 | curr->semval = val; |
| 807 | curr->sempid = task_tgid_vnr(current); | 814 | curr->sempid = task_tgid_vnr(current); |
| 808 | sma->sem_ctime = get_seconds(); | 815 | sma->sem_ctime = get_seconds(); |
| @@ -952,6 +959,8 @@ static inline int get_undo_list(struct sem_undo_list **undo_listp) | |||
| 952 | return -ENOMEM; | 959 | return -ENOMEM; |
| 953 | spin_lock_init(&undo_list->lock); | 960 | spin_lock_init(&undo_list->lock); |
| 954 | atomic_set(&undo_list->refcnt, 1); | 961 | atomic_set(&undo_list->refcnt, 1); |
| 962 | INIT_LIST_HEAD(&undo_list->list_proc); | ||
| 963 | |||
| 955 | current->sysvsem.undo_list = undo_list; | 964 | current->sysvsem.undo_list = undo_list; |
| 956 | } | 965 | } |
| 957 | *undo_listp = undo_list; | 966 | *undo_listp = undo_list; |
| @@ -960,25 +969,30 @@ static inline int get_undo_list(struct sem_undo_list **undo_listp) | |||
| 960 | 969 | ||
| 961 | static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid) | 970 | static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid) |
| 962 | { | 971 | { |
| 963 | struct sem_undo **last, *un; | 972 | struct sem_undo *walk, *tmp; |
| 964 | 973 | ||
| 965 | last = &ulp->proc_list; | 974 | assert_spin_locked(&ulp->lock); |
| 966 | un = *last; | 975 | list_for_each_entry_safe(walk, tmp, &ulp->list_proc, list_proc) { |
| 967 | while(un != NULL) { | 976 | if (walk->semid == semid) |
| 968 | if(un->semid==semid) | 977 | return walk; |
| 969 | break; | 978 | if (walk->semid == -1) { |
| 970 | if(un->semid==-1) { | 979 | list_del(&walk->list_proc); |
| 971 | *last=un->proc_next; | 980 | kfree(walk); |
| 972 | kfree(un); | ||
| 973 | } else { | ||
| 974 | last=&un->proc_next; | ||
| 975 | } | 981 | } |
| 976 | un=*last; | ||
| 977 | } | 982 | } |
| 978 | return un; | 983 | return NULL; |
| 979 | } | 984 | } |
| 980 | 985 | ||
| 981 | static struct sem_undo *find_undo(struct ipc_namespace *ns, int semid) | 986 | /** |
| 987 | * find_alloc_undo - Lookup (and if not present create) undo array | ||
| 988 | * @ns: namespace | ||
| 989 | * @semid: semaphore array id | ||
| 990 | * | ||
| 991 | * The function looks up (and if not present creates) the undo structure. | ||
| 992 | * The size of the undo structure depends on the size of the semaphore | ||
| 993 | * array, thus the alloc path is not that straightforward. | ||
| 994 | */ | ||
| 995 | static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid) | ||
| 982 | { | 996 | { |
| 983 | struct sem_array *sma; | 997 | struct sem_array *sma; |
| 984 | struct sem_undo_list *ulp; | 998 | struct sem_undo_list *ulp; |
| @@ -997,6 +1011,7 @@ static struct sem_undo *find_undo(struct ipc_namespace *ns, int semid) | |||
| 997 | goto out; | 1011 | goto out; |
| 998 | 1012 | ||
| 999 | /* no undo structure around - allocate one. */ | 1013 | /* no undo structure around - allocate one. */ |
| 1014 | /* step 1: figure out the size of the semaphore array */ | ||
| 1000 | sma = sem_lock_check(ns, semid); | 1015 | sma = sem_lock_check(ns, semid); |
| 1001 | if (IS_ERR(sma)) | 1016 | if (IS_ERR(sma)) |
| 1002 | return ERR_PTR(PTR_ERR(sma)); | 1017 | return ERR_PTR(PTR_ERR(sma)); |
| @@ -1004,15 +1019,19 @@ static struct sem_undo *find_undo(struct ipc_namespace *ns, int semid) | |||
| 1004 | nsems = sma->sem_nsems; | 1019 | nsems = sma->sem_nsems; |
| 1005 | sem_getref_and_unlock(sma); | 1020 | sem_getref_and_unlock(sma); |
| 1006 | 1021 | ||
| 1022 | /* step 2: allocate new undo structure */ | ||
| 1007 | new = kzalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL); | 1023 | new = kzalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL); |
| 1008 | if (!new) { | 1024 | if (!new) { |
| 1009 | sem_putref(sma); | 1025 | sem_putref(sma); |
| 1010 | return ERR_PTR(-ENOMEM); | 1026 | return ERR_PTR(-ENOMEM); |
| 1011 | } | 1027 | } |
| 1012 | new->semadj = (short *) &new[1]; | ||
| 1013 | new->semid = semid; | ||
| 1014 | 1028 | ||
| 1029 | /* step 3: Acquire the lock on the undo list pointer */ | ||
| 1015 | spin_lock(&ulp->lock); | 1030 | spin_lock(&ulp->lock); |
| 1031 | |||
