diff options
author | jhb <jhb@FreeBSD.org> | 2008-08-01 20:39:18 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2008-08-01 20:39:18 +0000 |
commit | fb79f73c28253a3656f0acb17ecf928ba367b468 (patch) | |
tree | 1d8b3f40879015f9f10c45a2dd1b58949476abbb /sys/dev | |
parent | 1df9b1f27f0a861fcc8e3335144fb3a775effaf8 (diff) | |
download | FreeBSD-src-fb79f73c28253a3656f0acb17ecf928ba367b468.zip FreeBSD-src-fb79f73c28253a3656f0acb17ecf928ba367b468.tar.gz |
- Use an sx lock to serialize writes since they update the checksum.
- Remove D_NEEDGIANT as the rtc drivers already have their own locks, so
this doesn't need Giant.
MFC after: 1 week
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/nvram/nvram.c | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/sys/dev/nvram/nvram.c b/sys/dev/nvram/nvram.c index 12b6cd4..164287e 100644 --- a/sys/dev/nvram/nvram.c +++ b/sys/dev/nvram/nvram.c @@ -31,7 +31,9 @@ #include <sys/kernel.h> #include <sys/conf.h> #include <sys/fcntl.h> +#include <sys/lock.h> #include <sys/proc.h> +#include <sys/sx.h> #include <sys/uio.h> #include <sys/module.h> @@ -63,10 +65,10 @@ static d_read_t nvram_read; static d_write_t nvram_write; static struct cdev *nvram_dev; +static struct sx nvram_lock; static struct cdevsw nvram_cdevsw = { .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, .d_open = nvram_open, .d_read = nvram_read, .d_write = nvram_write, @@ -113,18 +115,24 @@ nvram_write(struct cdev *dev, struct uio *uio, int flags) int i; uint16_t sum; + sx_xlock(&nvram_lock); + /* Assert that we understand the existing checksum first! */ sum = rtcin(NVRAM_FIRST + CKSUM_MSB) << 8 | rtcin(NVRAM_FIRST + CKSUM_LSB); for (i = CKSUM_FIRST; i <= CKSUM_LAST; i++) sum -= rtcin(NVRAM_FIRST + i); - if (sum != 0) + if (sum != 0) { + sx_xunlock(&nvram_lock); return (EIO); + } /* Bring in user data and write */ while (uio->uio_resid > 0 && error == 0) { nv_off = uio->uio_offset + NVRAM_FIRST; - if (nv_off < NVRAM_FIRST || nv_off >= NVRAM_LAST) + if (nv_off < NVRAM_FIRST || nv_off >= NVRAM_LAST) { + sx_xunlock(&nvram_lock); return (0); /* Signal EOF */ + } /* Single byte at a time */ error = uiomove(&v, 1, uio); writertc(nv_off, v); @@ -135,6 +143,7 @@ nvram_write(struct cdev *dev, struct uio *uio, int flags) sum += rtcin(NVRAM_FIRST + i); writertc(NVRAM_FIRST + CKSUM_MSB, sum >> 8); writertc(NVRAM_FIRST + CKSUM_LSB, sum); + sx_xunlock(&nvram_lock); return (error); } @@ -143,12 +152,14 @@ nvram_modevent(module_t mod __unused, int type, void *data __unused) { switch (type) { case MOD_LOAD: + sx_init(&nvram_lock, "nvram"); nvram_dev = make_dev(&nvram_cdevsw, 0, UID_ROOT, GID_KMEM, 0640, "nvram"); break; case MOD_UNLOAD: case MOD_SHUTDOWN: destroy_dev(nvram_dev); + sx_destroy(&nvram_lock); break; default: return (EOPNOTSUPP); |