diff options
Diffstat (limited to 'dev.c')
-rw-r--r-- | dev.c | 72 |
1 files changed, 63 insertions, 9 deletions
@@ -33,6 +33,10 @@ static struct mog_dev *mog_dev_new(struct mog_svc *svc, uint32_t mog_devid) dev->st_dev = sb.st_dev; mog_ioq_init(&dev->fsckq, svc, 1); mog_ioq_init(&dev->ioq, svc, svc->thr_per_dev); + dev->usage_txt = 0; + dev->usage_len = 0; + dev->usage_mtime = 0; + CHECK(int, 0, pthread_mutex_init(&dev->usage_lock, NULL)); return dev; } @@ -108,8 +112,7 @@ bool mog_dev_cmp(const void *a, const void *b) } static int -emit_usage( -const struct mog_dev *dev, struct mog_svc *svc, int fd, struct statvfs *v) +emit_usage(struct mog_dev *dev, struct mog_svc *svc, int fd, struct statvfs *v) { int rc = -1; unsigned long long available = v->f_bavail; @@ -129,6 +132,7 @@ const struct mog_dev *dev, struct mog_svc *svc, int fd, struct statvfs *v) me = mog_mnt_acquire(dev->st_dev); if (me) { + char *usage_txt; static const char usage_fmt[] = "available: %llu\n" "device: %s\n" @@ -139,14 +143,34 @@ const struct mog_dev *dev, struct mog_svc *svc, int fd, struct statvfs *v) "used: %llu\n"; errno = 0; - rc = dprintf(fd, usage_fmt, + rc = asprintf(&usage_txt, usage_fmt, available, me->me_devname, svc->docroot, (unsigned)dev->devid, now, total, use, used); + if (rc > 0) { + char *old_usage; + + CHECK(int, 0, pthread_mutex_lock(&dev->usage_lock)); + old_usage = dev->usage_txt; + dev->usage_txt = usage_txt; + dev->usage_len = rc; + dev->usage_mtime = (time_t)now; + CHECK(int, 0, pthread_mutex_unlock(&dev->usage_lock)); + + free(old_usage); + if (fd >= 0) { + ssize_t w = write(fd, usage_txt, rc); + + if (w >= 0 && w != rc) + errno = ENOSPC; + else if (w < 0) + rc = -1; + } + } PRESERVE_ERRNO( mog_mnt_release(me) ); if (rc < 0 || errno == ENOSPC) { PRESERVE_ERRNO(do { - syslog(LOG_ERR, "dprintf(%s/dev%u/usage): %m", + syslog(LOG_ERR, "write(%s/dev%u/usage): %m", svc->docroot, (unsigned)dev->devid); } while (0)); } @@ -159,12 +183,32 @@ const struct mog_dev *dev, struct mog_svc *svc, int fd, struct statvfs *v) return rc; } -int mog_dev_mkusage(const struct mog_dev *dev, struct mog_svc *svc) +static void +dev_usage_update(struct mog_dev *dev, struct mog_svc *svc, struct statvfs *v) +{ + if (mog_statvfs(svc, dev, v) < 0) { + syslog(LOG_ERR, "statvfs error: %s/dev%u/usage (%m)", + svc->docroot, (unsigned)dev->devid); + return; + } + (void)emit_usage(dev, svc, -1, v); +} + +void +mog_dev_usage_update(struct mog_dev *dev, struct mog_svc *svc) +{ + struct statvfs v; + + dev_usage_update(dev, svc, &v); +} + +int mog_dev_mkusage(struct mog_dev *dev, struct mog_svc *svc) { struct statvfs v; char *usage_path; char *tmp_path; int fd = -1; + struct stat sb; if (!svc->mgmt_mfd) return 0; @@ -174,6 +218,17 @@ int mog_dev_mkusage(const struct mog_dev *dev, struct mog_svc *svc) (unsigned)dev->devid); return 0; } + + /* + * allow chmod 0000 on devNNN/usage files to prevent us from + * overwriting them + */ + if (mog_stat(svc, usage_path, &sb) == 0 && + ((sb.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) == 0)) { + dev_usage_update(dev, svc, &v); + tmp_path = 0; + goto out; + } if (asprintf(&tmp_path, "%s.%x", usage_path, (unsigned)getpid()) < 0) { syslog(LOG_ERR, "error generating path: /dev%u/usage.%u (%m)", (unsigned)dev->devid, (unsigned)getpid()); @@ -186,14 +241,11 @@ int mog_dev_mkusage(const struct mog_dev *dev, struct mog_svc *svc) errno = 0; fd = mog_open_put(svc, tmp_path, O_EXCL|O_CREAT); if (fd < 0) { - if (mog_open_expire_retry(svc)) - fd = mog_open_put(svc, tmp_path, O_EXCL|O_CREAT); - } - if (fd < 0) { PRESERVE_ERRNO(do { syslog(LOG_ERR, "open(%s%s): %m", svc->docroot, tmp_path); } while (0)); + dev_usage_update(dev, svc, &v); goto out; } if (fstatvfs(fd, &v) < 0) { @@ -252,6 +304,8 @@ void mog_dev_free(void *ptr) mog_ioq_destroy(&dev->fsckq); mog_ioq_destroy(&dev->ioq); + free(dev->usage_txt); + CHECK(int, 0, pthread_mutex_destroy(&dev->usage_lock)); free(dev); } |