aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorManfred Spraul <manfred@colorfullife.com>2008-07-25 04:48:04 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-25 13:53:42 -0400
commit4daa28f6d8f5cda8ea0f55048e3c8811c384cbdd (patch)
tree934bfbd7932a18da8295d9e21727985d1ea16311 /ipc
parent00c2bf85d8febfcfddde63822043462b026134ff (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>
Diffstat (limited to 'ipc')
-rw-r--r--ipc/sem.c163
1 files changed, 89 insertions, 74 deletions
diff --git a/ipc/sem.c b/ipc/sem.c
index e9418df5ff3e..4f26c7157356 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -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
961static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid) 970static 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
981static 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 */
995static 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
1032 /* step 4: check for races: someone else allocated the undo struct,
1033 * semaphore array was destroyed.
1034 */
1016 un = lookup_undo(ulp, semid); 1035 un = lookup_undo(ulp, semid);
1017 if (un) { 1036 if (un) {
1018 spin_unlock(&ulp->lock); 1037 spin_unlock(&ulp->lock);
@@ -1028,13 +1047,17 @@ static struct sem_undo *find_undo(struct ipc_namespace *ns, int semid)
1028 un = ERR_PTR(-EIDRM); 1047 un = ERR_PTR(-EIDRM);
1029 goto out; 1048 goto out;
1030 } 1049 }
1031 new->proc_next = ulp->proc_list; 1050 /* step 5: initialize & link new undo structure */
1032 ulp->proc_list = new; 1051 new->semadj = (short *) &new[1];
1033 new->id_next = sma->undo; 1052 new->semid = semid;
1034 sma->undo = new; 1053 assert_spin_locked(&ulp->lock);
1054 list_add(&new->list_proc, &ulp->list_proc);
1055 assert_spin_locked(&sma->sem_perm.lock);
1056 list_add(&new->list_id, &sma->list_id);
1057
1035 sem_unlock(sma); 1058 sem_unlock(sma);
1036 un = new;
1037 spin_unlock(&ulp->lock); 1059 spin_unlock(&ulp->lock);
1060 un = new;
1038out: 1061out:
1039 return un; 1062 return un;
1040} 1063}
@@ -1090,9 +1113,8 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops,
1090 alter = 1; 1113 alter = 1;
1091 } 1114 }
1092 1115
1093retry_undos:
1094 if (undos) { 1116 if (undos) {
1095 un = find_undo(ns, semid); 1117 un = find_alloc_undo(ns, semid);
1096 if (IS_ERR(un)) { 1118 if (IS_ERR(un)) {
1097 error = PTR_ERR(un); 1119 error = PTR_ERR(un);
1098 goto out_free; 1120 goto out_free;
@@ -1107,14 +1129,14 @@ retry_undos:
1107 } 1129 }
1108 1130
1109 /* 1131 /*