* [PATCH] serve /dev*/usage requests from memory
@ 2018-11-27 9:59 Eric Wong
2018-11-28 0:19 ` Eric Wong
2018-12-07 23:56 ` [PATCH 2/1] http_parser: workaround parsing OOM in Ragel 6.10 Eric Wong
0 siblings, 2 replies; 3+ messages in thread
From: Eric Wong @ 2018-11-27 9:59 UTC (permalink / raw)
To: cmogstored-public
Filesystems may become unwritable and out-of-date "usage" files
will cause trackers to see out-of-date information.
We still write to the filesystem by default for compatibility
with existing HTTP servers. However, giving the "usage" file a
0000 mode will prevent cmogstored from overwriting it. This
allows admins to also reduce wear on storage devices:
chmod 0000 $mogroot/dev*/usage
---
cmogstored.h | 12 ++++--
dev.c | 70 +++++++++++++++++++++++++++----
fs.c | 13 ++++++
fs.h | 2 +
http.c | 32 ++++++++-------
http_get.c | 93 ++++++++++++++++++++++++++++++++++++++----
http_parser.rl | 10 +++--
test/cmogstored-cfg.rb | 4 +-
test/http-parser-1.c | 35 ++++++++++++++++
9 files changed, 233 insertions(+), 38 deletions(-)
diff --git a/cmogstored.h b/cmogstored.h
index db87ac0..61a7ffc 100644
--- a/cmogstored.h
+++ b/cmogstored.h
@@ -109,6 +109,10 @@ struct mog_wbuf;
struct mog_dev {
dev_t st_dev;
uint32_t devid;
+ pthread_mutex_t usage_lock; /* protects usage_txt */
+ unsigned usage_len;
+ char *usage_txt;
+ time_t usage_mtime;
struct mog_ioq ioq; /* normal requests */
struct mog_ioq fsckq; /* low-priority for MogileFS fsck */
};
@@ -206,8 +210,9 @@ struct mog_http {
unsigned has_range:1; /* for GET */
unsigned bad_range:1;
unsigned skip_rbuf_defer:1;
+ unsigned usage_txt:1;
enum mog_chunk_state chunk_state:2;
- unsigned unused_padding:2;
+ unsigned unused_padding:1;
uint8_t path_tip;
uint8_t path_end;
uint16_t line_end;
@@ -374,7 +379,7 @@ void mog_set_maxconns(unsigned long);
/* svc.c */
struct mog_svc *mog_svc_new(const char *docroot);
-typedef int (*mog_scandev_cb)(const struct mog_dev *, struct mog_svc *);
+typedef int (*mog_scandev_cb)(struct mog_dev *, struct mog_svc *);
size_t mog_svc_each(Hash_processor processor, void *data);
void mog_svc_upgrade_prepare(void);
bool mog_svc_start_each(void *svc_ptr, void *have_mgmt_ptr);
@@ -385,12 +390,13 @@ bool mog_svc_atfork_child(void *svc_ptr, void *parent);
/* dev.c */
struct mog_dev *mog_dev_for(struct mog_svc *, uint32_t mog_devid, bool update);
-int mog_dev_mkusage(const struct mog_dev *, struct mog_svc *);
+int mog_dev_mkusage(struct mog_dev *, struct mog_svc *);
size_t mog_dev_hash(const void *, size_t tablesize);
bool mog_dev_cmp(const void *a, const void *b);
void mog_dev_free(void *devptr);
bool mog_dev_user_rescale_i(void *devp, void *svcp);
bool mog_dev_requeue_prepare(void *devp, void *ign);
+void mog_dev_usage_update(struct mog_dev *, struct mog_svc *);
/* valid_path.rl */
int mog_valid_path(const char *buf, size_t len);
diff --git a/dev.c b/dev.c
index 4cb15d2..40ddeb7 100644
--- a/dev.c
+++ b/dev.c
@@ -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());
@@ -185,15 +240,12 @@ 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) {
diff --git a/fs.c b/fs.c
index 1c51977..a0f1147 100644
--- a/fs.c
+++ b/fs.c
@@ -126,3 +126,16 @@ int mog_mkdir(struct mog_svc *svc, const char *path, mode_t mode)
return mkdir(fspath, mode);
}
#endif /* !HAVE_MKDIRAT */
+
+int mog_statvfs(struct mog_svc *svc, struct mog_dev *dev, struct statvfs *v)
+{
+ char fspath[MY_PATHMAX];
+ int rc = snprintf(fspath, sizeof(fspath), "%s/dev%u",
+ svc->docroot, dev->devid);
+
+ if (rc <= 0) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ return statvfs(fspath, v);
+}
diff --git a/fs.h b/fs.h
index 19d3961..63e16e8 100644
--- a/fs.h
+++ b/fs.h
@@ -45,3 +45,5 @@ int mog_open_read(struct mog_svc *svc, const char *path);
#ifdef O_CLOEXEC
void mog_cloexec_works(void);
#endif
+
+int mog_statvfs(struct mog_svc *, struct mog_dev *, struct statvfs *);
diff --git a/http.c b/http.c
index 1061e63..e685273 100644
--- a/http.c
+++ b/http.c
@@ -447,25 +447,29 @@ void mog_httpget_post_accept(int fd, struct mog_accept *ac,
*/
char *mog_http_path(struct mog_http *http, char *buf)
{
- char *path = buf + http->_p.path_tip;
- size_t len = http->_p.path_end - http->_p.path_tip;
-
- assert(http->_p.path_end > http->_p.path_tip
- && "bad HTTP path from parser");
-
- if (! mog_valid_path(path, len))
+ if (http->_p.usage_txt) {
+ errno = EACCES;
return NULL;
+ } else {
+ char *path = buf + http->_p.path_tip;
+ size_t len = http->_p.path_end - http->_p.path_tip;
- if (http->_p.http_method == MOG_HTTP_METHOD_PUT) {
- if (!mog_valid_put_path(path, len)) {
- errno = EINVAL;
+ assert(http->_p.path_end > http->_p.path_tip
+ && "bad HTTP path from parser");
+
+ if (! mog_valid_path(path, len))
return NULL;
- }
- }
- path[len] = '\0';
+ if (http->_p.http_method == MOG_HTTP_METHOD_PUT) {
+ if (!mog_valid_put_path(path, len)) {
+ errno = EINVAL;
+ return NULL;
+ }
+ }
- return path;
+ path[len] = '\0';
+ return path;
+ }
}
diff --git a/http_get.c b/http_get.c
index 154d8c5..1af4fd2 100644
--- a/http_get.c
+++ b/http_get.c
@@ -47,6 +47,16 @@ static ssize_t linux_sendfile(int sockfd, int filefd, off_t *off, size_t count)
#define ERR416 "416 Requested Range Not Satisfiable"
+static void
+http_hdr_prepare(char **buf, char **modified, size_t *len, time_t *mtime)
+{
+ /* single buffer so we can use MSG_MORE */
+ *buf = mog_fsbuf_get(len);
+ *modified = *buf + *len / 2;
+ assert((*len / 2) > MOG_HTTPDATE_CAPA && "fsbuf too small");
+ mog_http_date(*modified, MOG_HTTPDATE_CAPA, mtime);
+}
+
/*
* TODO: refactor this
*
@@ -58,18 +68,13 @@ static ssize_t linux_sendfile(int sockfd, int filefd, off_t *off, size_t count)
static off_t http_get_resp_hdr(struct mog_fd *mfd, struct stat *sb)
{
struct mog_http *http = &mfd->as.http;
- char *modified;
- char *buf;
+ char *buf, *modified;
size_t len;
struct mog_now *now = mog_now();
long long count;
int rc;
- /* single buffer so we can use MSG_MORE */
- buf = mog_fsbuf_get(&len);
- modified = buf + len / 2;
- assert((len / 2) > MOG_HTTPDATE_CAPA && "fsbuf too small");
- mog_http_date(modified, MOG_HTTPDATE_CAPA, &sb->st_mtime);
+ http_hdr_prepare(&buf, &modified, &len, &sb->st_mtime);
/* validate ranges */
if (http->_p.has_range) {
@@ -194,14 +199,86 @@ bad_range:
return (off_t)count;
}
+static void emit_dev_usage(struct mog_fd *mfd)
+{
+ struct mog_http *http = &mfd->as.http;
+ struct mog_dev *dev = mog_dev_for(http->svc, http->_p.mog_devid, false);
+ void *ok = NULL;
+
+ if (dev) {
+ char *buf, *modified;
+ size_t len, ilen;
+ struct mog_now *now;
+ int rc;
+ bool retried = false;
+ struct iovec iov;
+
+retry:
+ now = mog_now();
+ CHECK(int, 0, pthread_mutex_lock(&dev->usage_lock));
+ ok = dev->usage_txt;
+ if (!ok) {
+ if (retried)
+ goto out_unlock;
+ retried = true;
+ CHECK(int, 0, pthread_mutex_unlock(&dev->usage_lock));
+ mog_dev_usage_update(dev, http->svc);
+ goto retry;
+ }
+
+ http_hdr_prepare(&buf, &modified, &len,
+ &dev->usage_mtime);
+ ilen = len;
+ rc = snprintf(buf, len,
+ "HTTP/1.1 200 OK\r\n"
+ "Date: %s\r\n"
+ "Last-Modified: %s\r\n"
+ "Content-Length: %u\r\n"
+ "Content-Type: text/plain\r\n"
+ "Accept-Ranges: bytes\r\n"
+ "Connection: %s\r\n"
+ "\r\n",
+ now->httpdate,
+ modified,
+ dev->usage_len,
+ http->_p.persistent ? "keep-alive" : "close");
+
+ ok = NULL;
+ if (rc > 0) {
+ len -= rc;
+ if (http->_p.http_method == MOG_HTTP_METHOD_HEAD) {
+ ok = iov.iov_base = buf;
+ iov.iov_len = rc;
+ } else if (len >= dev->usage_len && len < ilen) {
+ memcpy(buf + rc, dev->usage_txt,
+ dev->usage_len);
+ ok = iov.iov_base = buf;
+ iov.iov_len = rc + dev->usage_len;
+ }
+ }
+out_unlock:
+ CHECK(int, 0, pthread_mutex_unlock(&dev->usage_lock));
+ if (ok)
+ http->wbuf = mog_trywritev(mfd->fd, &iov, 1);
+ }
+ if (!dev || !ok)
+ mog_http_resp(mfd, "404 Not Found", true);
+}
+
void mog_http_get_open(struct mog_fd *mfd, char *buf)
{
struct mog_http *http = &mfd->as.http;
struct stat sb;
struct mog_file *file = NULL;
- char *path = mog_http_path(http, buf);
+ char *path;
off_t len;
+ if (http->_p.usage_txt) {
+ emit_dev_usage(mfd);
+ return;
+ }
+
+ path = mog_http_path(http, buf);
if (!path) goto forbidden; /* path traversal attack */
assert(http->forward == NULL && "already have http->forward");
assert(path[0] == '/' && "bad path");
diff --git a/http_parser.rl b/http_parser.rl
index 300b571..ae4217a 100644
--- a/http_parser.rl
+++ b/http_parser.rl
@@ -48,12 +48,16 @@ static char *skip_header(struct mog_http *http, char *buf, const char *pe)
DELETE = "DELETE "> { http->_p.http_method = MOG_HTTP_METHOD_DELETE; };
MKCOL = "MKCOL "> { http->_p.http_method = MOG_HTTP_METHOD_MKCOL; };
+ mog_fs_path = (mog_path) > { http->_p.path_tip = to_u8(fpc - buf); }
+ # TODO: maybe folks use query string/fragments for logging...
+ (" HTTP/1.") > { http->_p.path_end = to_u8(fpc - buf); };
+
+ usage_path = ('/' devid "usage HTTP/1.") @ { http->_p.usage_txt = 1; };
+
# no HTTP/0.9 for now, sorry (not :P)
req_line = (HEAD|GET|PUT|DELETE|MKCOL)
("http://" [^/]+)?
- '/'*(mog_path) > { http->_p.path_tip = to_u8(fpc - buf); }
- # TODO: maybe folks use query string/fragments for logging...
- (" HTTP/1.") > { http->_p.path_end = to_u8(fpc - buf); }
+ '/'*(usage_path | mog_fs_path)
('0'|'1'> { http->_p.persistent = 1; }) '\r'LF;
content_length = "Content-Length:"i sep
diff --git a/test/cmogstored-cfg.rb b/test/cmogstored-cfg.rb
index 07dfc6a..7cb862e 100644
--- a/test/cmogstored-cfg.rb
+++ b/test/cmogstored-cfg.rb
@@ -367,7 +367,9 @@ class TestCmogstoredConfig < Test::Unit::TestCase
get_client
Net::HTTP.start(@host, @port) do |http|
resp = http.request(Net::HTTP::Get.new("/dev666/usage"))
- assert_kind_of Net::HTTPNotFound, resp
+ assert_kind_of Net::HTTPOK, resp
+ assert resp.body.size > 0
+ assert ! File.exist?("#@tmpdir/dev666/usage")
resp = http.request(Net::HTTP::Get.new("/dev666/cmogstored.test"))
assert_kind_of Net::HTTPOK, resp
assert_equal "HI", resp.body
diff --git a/test/http-parser-1.c b/test/http-parser-1.c
index 9125b9c..f699611 100644
--- a/test/http-parser-1.c
+++ b/test/http-parser-1.c
@@ -41,6 +41,7 @@ int main(void)
assert(http->_p.persistent && "not persistent");
assert(state == MOG_PARSER_DONE && "parser not done");
assert_path_equal("/foo");
+ assert(!http->_p.usage_txt && "not a usage request");
}
if ("normal HTTP GET request with redundant leading slash") {
@@ -51,6 +52,7 @@ int main(void)
assert(http->_p.persistent && "not persistent");
assert(state == MOG_PARSER_DONE && "parser not done");
assert_path_equal("/foo");
+ assert(!http->_p.usage_txt && "not a usage request");
}
if ("HTTP/1.1 request with explicit close") {
@@ -64,6 +66,7 @@ int main(void)
assert(http->_p.persistent == 0 && "should not be persistent");
assert(state == MOG_PARSER_DONE && "parser not done");
assert_path_equal("/foo");
+ assert(!http->_p.usage_txt && "not a usage request");
}
if ("HTTP/1.0 request with keepalive") {
@@ -76,6 +79,7 @@ int main(void)
assert(http->_p.persistent == 1 && "should be persistent");
assert(state == MOG_PARSER_DONE && "parser not done");
assert_path_equal("/foo");
+ assert(!http->_p.usage_txt && "not a usage request");
}
if ("bogus HTTP/1.0 request") {
@@ -84,6 +88,7 @@ int main(void)
"\r\n");
state = mog_http_parse(http, buf, len);
assert(state == MOG_PARSER_ERROR && "parser not errored");
+ assert(!http->_p.usage_txt && "not a usage request");
}
if ("bogus request") {
@@ -92,6 +97,7 @@ int main(void)
"\r\n");
state = mog_http_parse(http, buf, len);
assert(state == MOG_PARSER_ERROR && "parser not errored");
+ assert(!http->_p.usage_txt && "not a usage request");
}
if ("HTTP/1.1 HEAD request") {
@@ -104,6 +110,7 @@ int main(void)
assert(http->_p.persistent == 1 && "should be persistent");
assert(state == MOG_PARSER_DONE && "parser not done");
assert_path_equal("/foo");
+ assert(!http->_p.usage_txt && "not a usage request");
}
if ("HTTP/1.1 PUT request") {
@@ -121,6 +128,7 @@ int main(void)
assert_path_equal("/foo");
assert(strcmp(buf + http->_p.buf_off, "partial body request")
== 0 && "buffer repositioned to body start");
+ assert(!http->_p.usage_txt && "not a usage request");
}
if ("HTTP/1.1 PUT chunked request header") {
@@ -139,6 +147,7 @@ int main(void)
assert_path_equal("/foo");
assert(strcmp(buf + http->_p.buf_off, "16\r\npartial...") == 0
&& "buffer repositioned to body start");
+ assert(!http->_p.usage_txt && "not a usage request");
}
if ("HTTP/1.1 PUT with Content-Range") {
@@ -160,6 +169,7 @@ int main(void)
assert_path_equal("/foo");
assert(strcmp(buf + http->_p.buf_off, "16\r\npartial...") == 0
&& "buffer repositioned to body start");
+ assert(!http->_p.usage_txt && "not a usage request");
}
if ("HTTP/1.1 PUT chunked request header w/Trailer") {
@@ -179,6 +189,7 @@ int main(void)
assert_path_equal("/foo");
assert(strcmp(buf + http->_p.buf_off, "16\r\npartial...") == 0
&& "buffer repositioned to body start");
+ assert(!http->_p.usage_txt && "not a usage request");
}
if ("HTTP/1.1 DELETE request") {
@@ -193,6 +204,7 @@ int main(void)
assert(http->_p.persistent == 1 && "should be persistent");
assert(state == MOG_PARSER_DONE && "parser not done");
assert_path_equal("/foo");
+ assert(!http->_p.usage_txt && "not a usage request");
}
if ("HTTP/1.1 MKCOL request") {
@@ -207,6 +219,7 @@ int main(void)
assert(http->_p.persistent == 1 && "should be persistent");
assert(state == MOG_PARSER_DONE && "parser not done");
assert_path_equal("/foo");
+ assert(!http->_p.usage_txt && "not a usage request");
}
if ("HTTP/1.1 Range (mid) GET request") {
@@ -223,6 +236,7 @@ int main(void)
assert(http->_p.persistent == 1 && "should be persistent");
assert(state == MOG_PARSER_DONE && "parser not done");
assert_path_equal("/foo");
+ assert(!http->_p.usage_txt && "not a usage request");
}
if ("HTTP/1.1 Range (tip) GET request") {
@@ -239,6 +253,7 @@ int main(void)
assert(http->_p.persistent == 1 && "should be persistent");
assert(state == MOG_PARSER_DONE && "parser not done");
assert_path_equal("/foo");
+ assert(!http->_p.usage_txt && "not a usage request");
}
if ("HTTP/1.1 Range (end) GET request") {
@@ -255,6 +270,7 @@ int main(void)
assert(http->_p.persistent == 1 && "should be persistent");
assert(state == MOG_PARSER_DONE && "parser not done");
assert_path_equal("/foo");
+ assert(!http->_p.usage_txt && "not a usage request");
}
if ("HTTP/1.1 devid parse") {
@@ -266,6 +282,25 @@ int main(void)
assert(http->_p.mog_devid == 666 && "dev666 set");
assert(state == MOG_PARSER_DONE && "parser not done");
assert_path_equal("/dev666/0/1.fid");
+ assert(!http->_p.usage_txt && "not a usage request");
+ }
+
+ if ("HTTP/1.0 devN/usage request") {
+ buf_set("GET /dev666/usage HTTP/1.0\r\n\r\n");
+ state = mog_http_parse(http, buf, len);
+ assert(http->_p.http_method == MOG_HTTP_METHOD_GET
+ && "http_method should be GET");
+ assert(http->_p.mog_devid == 666 && "dev666 set");
+ assert(state == MOG_PARSER_DONE && "parser not done");
+ assert(http->_p.usage_txt && "a usage request");
+
+ buf_set("GET /dev666/usager HTTP/1.0\r\n\r\n");
+ state = mog_http_parse(http, buf, len);
+ assert(!http->_p.usage_txt && "a usage request");
+
+ buf_set("GET /dev666/usag HTTP/1.0\r\n\r\n");
+ state = mog_http_parse(http, buf, len);
+ assert(!http->_p.usage_txt && "a usage request");
}
reset();
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] serve /dev*/usage requests from memory
2018-11-27 9:59 [PATCH] serve /dev*/usage requests from memory Eric Wong
@ 2018-11-28 0:19 ` Eric Wong
2018-12-07 23:56 ` [PATCH 2/1] http_parser: workaround parsing OOM in Ragel 6.10 Eric Wong
1 sibling, 0 replies; 3+ messages in thread
From: Eric Wong @ 2018-11-28 0:19 UTC (permalink / raw)
To: cmogstored-public
Needs the following to pass valgrind tests, too.
Without it, there would be a slow memory leak for rare
device replacements
diff --git a/dev.c b/dev.c
index 40ddeb7..3b52023 100644
--- a/dev.c
+++ b/dev.c
@@ -304,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);
}
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 2/1] http_parser: workaround parsing OOM in Ragel 6.10
2018-11-27 9:59 [PATCH] serve /dev*/usage requests from memory Eric Wong
2018-11-28 0:19 ` Eric Wong
@ 2018-12-07 23:56 ` Eric Wong
1 sibling, 0 replies; 3+ messages in thread
From: Eric Wong @ 2018-12-07 23:56 UTC (permalink / raw)
To: cmogstored-public
Noticed in FreeBSD 11.2 where Ragel 6.10 was OOM-ing, this
doesn't affect Ragel 6.9.
TODO: make sure this is fixed upstream in Ragel.
---
http_parser.rl | 10 +++++-----
path_parser.rl | 3 ++-
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/http_parser.rl b/http_parser.rl
index 4ecb97a..e07aea8 100644
--- a/http_parser.rl
+++ b/http_parser.rl
@@ -48,16 +48,16 @@ static char *skip_header(struct mog_http *http, char *buf, const char *pe)
DELETE = "DELETE "> { http->_p.http_method = MOG_HTTP_METHOD_DELETE; };
MKCOL = "MKCOL "> { http->_p.http_method = MOG_HTTP_METHOD_MKCOL; };
- mog_fs_path = (mog_path) > { http->_p.path_tip = to_u8(fpc - buf); }
+ mog_path_start = '/' > { http->_p.path_tip = to_u8(fpc - buf); };
# TODO: maybe folks use query string/fragments for logging...
- (" HTTP/1.") > { http->_p.path_end = to_u8(fpc - buf); };
-
- usage_path = ('/' devid "usage HTTP/1.") @ { http->_p.usage_txt = 1; };
+ mog_path_end = (" HTTP/1.") > { http->_p.path_end = to_u8(fpc - buf); };
+ usage_path = ("usage HTTP/1.") @ { http->_p.usage_txt = 1; };
# no HTTP/0.9 for now, sorry (not :P)
req_line = (HEAD|GET|PUT|DELETE|MKCOL)
("http://" [^/]+)?
- '/'*(usage_path | mog_fs_path)
+ '/'* mog_path_start devid? (usage_path |
+ (mog_path_rest mog_path_end) )
('0'|'1'> { http->_p.persistent = 1; }) '\r'LF;
content_length = "Content-Length:"i sep
diff --git a/path_parser.rl b/path_parser.rl
index 4f0b3ec..974b6c6 100644
--- a/path_parser.rl
+++ b/path_parser.rl
@@ -17,5 +17,6 @@
}
'/';
# only stuff MogileFS will use
- mog_path = '/' (devid)? [a-zA-Z0-9/\.\-]{0,36};
+ mog_path_rest = [a-zA-Z0-9/\.\-]{0,36};
+ mog_path = '/' (devid)? mog_path_rest;
}%%
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2018-12-07 23:56 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-11-27 9:59 [PATCH] serve /dev*/usage requests from memory Eric Wong
2018-11-28 0:19 ` Eric Wong
2018-12-07 23:56 ` [PATCH 2/1] http_parser: workaround parsing OOM in Ragel 6.10 Eric Wong
Code repositories for project(s) associated with this public inbox
https://yhbt.net/cmogstored.git/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).