Re: [patch] POSIX advisory mode lock panic fix by Dfly

看板DFBSD_submit作者時間21年前 (2004/04/21 13:01), 編輯推噓0(000)
留言0則, 0人參與, 最新討論串5/17 (看更多)
This is a multi-part message in MIME format. --------------080201000002010903040002 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit Matthew Dillon wrote: > Sometimes these things just fall into place, other times they are > predetermined to be ugly no matter what you do :-). > > If its going to be ugly it is best to put the ugliness all in one place. > So, for example, it is generally better to pass the governing structure > to a wrapper procedure with ugly insides then it is to strew 'pp' all over > the source file. Sometimes special cases prevent it from working out, > and sometimes things just fall into place and you get an elegant solution. > > -Matt Well here's my pre-bedtime attempt at fixing sys/, anyway. I'm going to be gone for the next 8 hours, but please let me know what you think of this new version. (Note: it's not guaranteed to work ;)). I'll comment it tomorrow :). --Devon --------------080201000002010903040002 Content-Type: text/plain; name="lockfix-sys.dfly.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="lockfix-sys.dfly.patch" diff -ur sys/kern/kern_lockf.c sys_lockfix/kern/kern_lockf.c --- sys/kern/kern_lockf.c Tue Apr 20 21:38:13 2004 +++ sys_lockfix/kern/kern_lockf.c Tue Apr 20 22:51:14 2004 @@ -51,6 +51,7 @@ #include <sys/fcntl.h> #include <sys/lockf.h> +#include <sys/resourcevar.h> /* * This variable controls the maximum number of processes that will @@ -80,12 +81,58 @@ struct lockf *, int, struct lockf ***, struct lockf **); static struct lockf * lf_getblock (struct lockf *); +struct lockf *lf_alloc (int, caddr_t); static int lf_getlock (struct lockf *, struct flock *); +static int lf_res_exceeded (struct proc *); static int lf_setlock (struct lockf *); -static void lf_split (struct lockf *, struct lockf *); +static int lf_split (struct lockf *, struct lockf *); +static void lf_free (struct lockf *); static void lf_wakelock (struct lockf *); /* + * Allocate space for a struct lockf and upgrade the user/process lock count + */ +struct lockf * +lf_alloc(int flags, caddr_t id) { + struct lockf *lock; + + if ((flags & F_POSIX) != 0) + incposixlockcnt((struct proc *)id); + + MALLOC(lock, struct lockf *, sizeof *lock, M_LOCKF, M_WAITOK); + return (lock); +} + +/* + * Free memory allocated for a struct lockf and decrement the user/process + * lock count. + */ +static void +lf_free (struct lockf *lock) +{ + + if ((lock->lf_flags & F_POSIX) != 0) + decposixlockcnt((struct proc *)lock->lf_id); + + free(lock, M_LOCKF) + return; +} + +/* + * Determine if the user has exceeded their allowed POSIX locks + */ +static int +lf_res_exceeded (struct proc *p) +{ + struct uidinfo *ui = p->p_ucred->cr_uidinfo; + + if (ui->ui_posixlocks > p->p_rlimit[RLIMIT_POSIXLOCK].rlim_max) + return (-1); + + return 0; +} + +/* * Advisory record locking support */ int @@ -147,7 +194,7 @@ /* * Create the lockf structure */ - MALLOC(lock, struct lockf *, sizeof *lock, M_LOCKF, M_WAITOK); + lock = lf_alloc(ap->a_flags, ap->a_id); lock->lf_start = start; lock->lf_end = end; lock->lf_id = ap->a_id; @@ -162,20 +209,23 @@ */ switch(ap->a_op) { case F_SETLK: - return (lf_setlock(lock)); + if (lf_res_exceeded((struct proc *)ap->a_id) != 0) + return (lf_setlock(lock)); + else + return (ENOLCK); case F_UNLCK: error = lf_clearlock(lock); - FREE(lock, M_LOCKF); + lf_free(lock); return (error); case F_GETLK: error = lf_getlock(lock, fl); - FREE(lock, M_LOCKF); + lf_free(lock); return (error); default: - free(lock, M_LOCKF); + lf_free(lock); return (EINVAL); } /* NOTREACHED */ @@ -207,7 +257,7 @@ * Free the structure and return if nonblocking. */ if ((lock->lf_flags & F_WAIT) == 0) { - FREE(lock, M_LOCKF); + lf_free(lock); return (EAGAIN); } /* @@ -238,7 +288,7 @@ break; wproc = (struct proc *)waitblock->lf_id; if (wproc == (struct proc *)lock->lf_id) { - free(lock, M_LOCKF); + lf_free(lock); return (EDEADLK); } } @@ -280,7 +330,7 @@ lock->lf_next = NOLOCKF; } if (error) { - free(lock, M_LOCKF); + lf_free(lock); return (error); } } @@ -325,7 +375,7 @@ overlap->lf_type == F_WRLCK) lf_wakelock(overlap); overlap->lf_type = lock->lf_type; - FREE(lock, M_LOCKF); + lf_free(lock); lock = overlap; /* for debug output below */ break; @@ -334,7 +384,7 @@ * Check for common starting point and different types. */ if (overlap->lf_type == lock->lf_type) { - free(lock, M_LOCKF); + lf_free(lock); lock = overlap; /* for debug output below */ break; } @@ -342,8 +392,12 @@ *prev = lock; lock->lf_next = overlap; overlap->lf_start = lock->lf_end + 1; - } else - lf_split(overlap, lock); + } else { + error = lf_split(overlap, lock); + if (error) + return (error); + } + lf_wakelock(overlap); break; @@ -375,7 +429,7 @@ needtolink = 0; } else *prev = overlap->lf_next; - free(overlap, M_LOCKF); + lf_free(overlap); continue; case 4: /* overlap starts before lock */ @@ -447,7 +501,7 @@ case 1: /* overlap == lock */ *prev = overlap->lf_next; - FREE(overlap, M_LOCKF); + lf_free(overlap); break; case 2: /* overlap contains lock: split it */ @@ -455,14 +509,16 @@ overlap->lf_start = unlock->lf_end + 1; break; } - lf_split(overlap, unlock); + error = lf_split(overlap, unlock); + if (error) + return (error); overlap->lf_next = unlock->lf_next; break; case 3: /* lock contains overlap */ *prev = overlap->lf_next; lf = overlap->lf_next; - free(overlap, M_LOCKF); + lf_free(overlap); continue; case 4: /* overlap starts before lock */ @@ -662,7 +718,7 @@ * Split a lock and a contained region into * two or three locks as necessary. */ -static void +static int lf_split(lock1, lock2) struct lockf *lock1; struct lockf *lock2; @@ -681,19 +737,23 @@ if (lock1->lf_start == lock2->lf_start) { lock1->lf_start = lock2->lf_end + 1; lock2->lf_next = lock1; - return; + return (0); } if (lock1->lf_end == lock2->lf_end) { lock1->lf_end = lock2->lf_start - 1; lock2->lf_next = lock1->lf_next; lock1->lf_next = lock2; - return; + return (0); } + + if (lf_res_exceeded((struct proc *)lock1->lf_id) != 0) + return (ENOLCK); + + splitlock = lf_alloc(lock1->lf_flags, lock1->lf_id); /* * Make a new lock consisting of the last part of * the encompassing lock */ - MALLOC(splitlock, struct lockf *, sizeof *splitlock, M_LOCKF, M_WAITOK); bcopy((caddr_t)lock1, (caddr_t)splitlock, sizeof *splitlock); splitlock->lf_start = lock2->lf_end + 1; TAILQ_INIT(&splitlock->lf_blkhd); @@ -704,6 +764,7 @@ splitlock->lf_next = lock1->lf_next; lock2->lf_next = splitlock; lock1->lf_next = lock2; + return (0); } /* diff -ur sys/kern/kern_mib.c sys_lockfix/kern/kern_mib.c --- sys/kern/kern_mib.c Tue Apr 20 21:38:13 2004 +++ sys_lockfix/kern/kern_mib.c Tue Apr 20 21:40:14 2004 @@ -47,6 +47,7 @@ #include <sys/sysctl.h> #include <sys/proc.h> #include <sys/jail.h> +#include <sys/fcntl.h> #include <machine/smp.h> SYSCTL_NODE(, 0, sysctl, CTLFLAG_RW, 0, @@ -101,6 +102,9 @@ SYSCTL_INT(_kern, KERN_MAXPROCPERUID, maxprocperuid, CTLFLAG_RW, &maxprocperuid, 0, "Maximum processes allowed per userid"); + +SYSCTL_INT(_kern, KERN_MAXPOSIXLOCKPERUID, maxposixlocksperuid, CTLFLAG_RW, + &maxposixlocksperuid, 0, "Maximum number of POSIX-type locks per user id"); SYSCTL_INT(_kern, OID_AUTO, maxusers, CTLFLAG_RD, &maxusers, 0, "Hint for kernel tuning"); diff -ur sys/kern/kern_prot.c sys_lockfix/kern/kern_prot.c --- sys/kern/kern_prot.c Tue Apr 20 21:38:13 2004 +++ sys_lockfix/kern/kern_prot.c Tue Apr 20 21:40:14 2004 @@ -1108,8 +1108,10 @@ cr = cratom(&p->p_ucred); (void)chgproccnt(cr->cr_ruidinfo, -1, 0); + (void)chgposixlockcnt(p, -(p->p_numposixlocks), 0); /* It is assumed that pcred is not shared between processes */ cr->cr_ruid = ruid; uireplace(&cr->cr_ruidinfo, uifind(ruid)); (void)chgproccnt(cr->cr_ruidinfo, 1, 0); + (void)chgposixlockcnt(p, p->p_numposixlocks, 0); } diff -ur sys/kern/kern_resource.c sys_lockfix/kern/kern_resource.c --- sys/kern/kern_resource.c Tue Apr 20 21:38:13 2004 +++ sys_lockfix/kern/kern_resource.c Tue Apr 20 22:48:13 2004 @@ -46,6 +46,7 @@ #include <sys/systm.h> #include <sys/sysproto.h> #include <sys/file.h> +#include <sys/fcntl.h> #include <sys/kern_syscall.h> #include <sys/kernel.h> #include <sys/resourcevar.h> @@ -387,6 +388,12 @@ if (limp->rlim_max < 1) limp->rlim_max = 1; break; + case RLIMIT_POSIXLOCK: + if (limp->rlim_cur > maxposixlocksperuid) + limp->rlim_cur = maxposixlocksperuid; + if (limp->lim_max > maxposixlocksperuid) + limp->rlim_max = maxposixlocksperuid; + break; } *alimp = *limp; return (0); @@ -626,6 +633,38 @@ if (uip->ui_proccnt < 0) printf("negative proccnt for uid = %d\n", uip->ui_uid); return (1); +} + +/* + * Increment the count associated with the number of POSIX locks + * in use by a user and process at any given time. + */ +void +incposixlockcnt (struct proc *p) +{ + struct uidinfo *uip = pp->p_ucred->cr_uidinfo; + + uip->ui_posixlocks++; + p->p_posixlocks++; + return; +} + +/* + * Increment the count associated with the number of POSIX locks + * in use by a user and process at any given time. + */ +void +decposixlockcnt (struct proc *p) +{ + struct uidinfo *uip = pp->p_ucred->cr_uidinfo; + + uip->ui_posixlocks--; + KASSERT(uip->ui_advlocks < 0, ("Negative number of POSIX locks held by + user.")); + p->p_posixlocks--; + KASSERT(pp->p_numposixlocks < 0, ("Negative number of POSIX locks held + by process.")); + return; } /* diff -ur sys/kern/subr_param.c sys_lockfix/kern/subr_param.c --- sys/kern/subr_param.c Tue Apr 20 21:38:13 2004 +++ sys_lockfix/kern/subr_param.c Tue Apr 20 21:40:14 2004 @@ -66,6 +66,9 @@ #ifndef NSFBUFS #define NSFBUFS (512 + maxusers * 16) #endif +#ifndef MAXPOSIXLOCKSPERUID +#define MAXPOSIXLOCKSPERUID (maxusers * 64) /* Should be a safe value */ +#endif int hz; int stathz; @@ -77,6 +80,7 @@ int maxprocperuid; /* max # of procs per user */ int maxfiles; /* sys. wide open files limit */ int maxfilesperproc; /* per-proc open files limit */ +int maxposixlocksperuid; /* max # POSIX locks per uid */ int ncallout; /* maximum # of timer events */ int mbuf_wait = 32; /* mbuf sleep time in ticks */ int nbuf; @@ -122,6 +126,8 @@ #endif TUNABLE_INT_FETCH("kern.maxbcache", &maxbcache); + maxposixlocksperuid = MAXPOSIXLOCKSPERUID; + TUNABLE_INT_FETCH("kern.maxposixlocksperuid", &maxposixlocksperuid); maxtsiz = MAXTSIZ; TUNABLE_QUAD_FETCH("kern.maxtsiz", &maxtsiz); dfldsiz = DFLDSIZ; diff -ur sys/sys/fcntl.h sys_lockfix/sys/fcntl.h --- sys/sys/fcntl.h Tue Apr 20 21:38:12 2004 +++ sys_lockfix/sys/fcntl.h Tue Apr 20 21:40:14 2004 @@ -223,4 +223,8 @@ __END_DECLS #endif +#ifdef _KERNEL +extern int maxposixlocksperuid; +#endif + #endif /* !_SYS_FCNTL_H_ */ Only in sys_lockfix/sys: fcntl.h.orig diff -ur sys/sys/proc.h sys_lockfix/sys/proc.h --- sys/sys/proc.h Tue Apr 20 21:38:12 2004 +++ sys_lockfix/sys/proc.h Tue Apr 20 22:51:53 2004 @@ -235,6 +235,7 @@ struct thread *p_thread; /* temporarily embed thread struct in proc */ struct upcall *p_upcall; /* USERLAND POINTER! registered upcall */ struct sched *p_sched; /* work-in-progress / Peter Kadau */ + int p_posixlocks /* number of POSIX locks */ }; #if defined(_KERNEL) Only in sys_lockfix/sys: proc.h.orig diff -ur sys/sys/resource.h sys_lockfix/sys/resource.h --- sys/sys/resource.h Tue Apr 20 21:38:12 2004 +++ sys_lockfix/sys/resource.h Tue Apr 20 21:40:14 2004 @@ -90,8 +90,9 @@ #define RLIMIT_NOFILE 8 /* number of open files */ #define RLIMIT_SBSIZE 9 /* maximum size of all socket buffers */ #define RLIMIT_VMEM 10 /* virtual process size (inclusive of mmap) */ +#define RLIMIT_POSIXLOCK 11 /* maximum number of POSIX locks per user */ -#define RLIM_NLIMITS 11 /* number of resource limits */ +#define RLIM_NLIMITS 12 /* number of resource limits */ #define RLIM_INFINITY ((rlim_t)(((u_quad_t)1 << 63) - 1)) @@ -113,6 +114,7 @@ "nofile", "sbsize", "vmem", + "posixlock", }; #endif Only in sys_lockfix/sys: resource.h.orig diff -ur sys/sys/resourcevar.h sys_lockfix/sys/resourcevar.h --- sys/sys/resourcevar.h Tue Apr 20 21:38:12 2004 +++ sys_lockfix/sys/resourcevar.h Tue Apr 20 22:52:11 2004 @@ -95,6 +95,7 @@ long ui_proccnt; /* number of processes */ uid_t ui_uid; /* uid */ int ui_ref; /* reference count */ + int ui_numposixlocks; /* number of POSIX locks */ struct varsymset ui_varsymset; /* variant symlinks */ }; @@ -107,6 +108,7 @@ void calcru (struct proc *p, struct timeval *up, struct timeval *sp, struct timeval *ip); int chgproccnt (struct uidinfo *uip, int diff, int max); +int chgposixlockcnt (struct proc *p, int diff, int max); int chgsbsize (struct uidinfo *uip, u_long *hiwat, u_long to, rlim_t max); int fuswintr (void *base); struct plimit *limcopy (struct plimit *lim); Only in sys_lockfix/sys: resourcevar.h.orig diff -ur sys/sys/sysctl.h sys_lockfix/sys/sysctl.h --- sys/sys/sysctl.h Tue Apr 20 21:38:12 2004 +++ sys_lockfix/sys/sysctl.h Tue Apr 20 21:40:14 2004 @@ -342,6 +342,7 @@ #define KERN_USRSTACK 33 /* int: address of USRSTACK */ #define KERN_LOGSIGEXIT 34 /* int: do we log sigexit procs? */ #define KERN_MAXID 35 /* number of valid kern ids */ +#define KERN_MAXPOSIXLOCKSPERUID 36 /* int: max POSIX locks per uid */ #define CTL_KERN_NAMES { \ { 0, 0 }, \ @@ -373,6 +374,7 @@ { "bootfile", CTLTYPE_STRING }, \ { "maxfilesperproc", CTLTYPE_INT }, \ { "maxprocperuid", CTLTYPE_INT }, \ + { "maxposixlocksperuid", CTLTYPE_INT }, \ { "dumpdev", CTLTYPE_STRUCT }, /* we lie; don't print as int */ \ { "ipc", CTLTYPE_NODE }, \ { "dummy", CTLTYPE_INT }, \ Only in sys_lockfix/sys: sysctl.h.orig --------------080201000002010903040002--
文章代碼(AID): #10XW0J00 (DFBSD_submit)
討論串 (同標題文章)
文章代碼(AID): #10XW0J00 (DFBSD_submit)