about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2013-06-20 01:51:09 +0000
committerEric Wong <normalperson@yhbt.net>2013-06-20 02:38:07 +0000
commit16e31f8dce64323fdef6151a30756ce2bc770a88 (patch)
tree9dd368a9b0e0cd80283652e5477b6fc1ab0e9722
parent91cb86eb03d828bda8a4ac9cd0c3edbac73418af (diff)
downloadcmogstored-wip-1.3.tar.gz
Simply releasing the descriptor triggering ENOSPC/ENOMEM errors from
epoll_ctl and kevent is not good enough, as those descriptors may
have other descriptors (e.g. files to be served) hanging off of them.
-rw-r--r--cmogstored.h4
-rw-r--r--http.c25
-rw-r--r--http_put.c11
-rw-r--r--mgmt.c10
-rw-r--r--queue_common.c18
-rw-r--r--queue_epoll.c2
-rw-r--r--queue_kqueue.c2
7 files changed, 60 insertions, 12 deletions
diff --git a/cmogstored.h b/cmogstored.h
index c9e1f46..9a84a57 100644
--- a/cmogstored.h
+++ b/cmogstored.h
@@ -432,6 +432,7 @@ void mog_mgmt_post_accept(int fd, struct mog_svc *,
                                 union mog_sockaddr *, socklen_t);
 enum mog_next mog_mgmt_queue_step(struct mog_fd *) MOG_CHECK;
 void mog_mgmt_quit_step(struct mog_fd *);
+void mog_mgmt_drop(struct mog_fd *);
 
 /* queue_epoll.c */
 struct mog_queue * mog_queue_new(void);
@@ -498,6 +499,8 @@ enum mog_next mog_http_queue_step(struct mog_fd *) MOG_CHECK;
 void mog_http_quit_step(struct mog_fd *);
 char *mog_http_path(struct mog_http *, char *buf);
 void mog_http_reset(struct mog_http *);
+void mog_http_unlink_ftmp(struct mog_http *);
+void mog_http_drop(struct mog_fd *);
 
 /* http_dav.c */
 void mog_http_delete(struct mog_fd *, char *buf);
@@ -529,6 +532,7 @@ int mog_mkpath_for(struct mog_svc *svc, char *path);
 /* queue_common.c */
 struct mog_queue *mog_queue_init(int queue_fd);
 void mog_queue_stop(struct mog_queue *keep);
+void mog_queue_drop(struct mog_fd *);
 
 /* fsck_queue.c */
 bool mog_fsck_queue_ready(struct mog_fd *mfd) MOG_CHECK;
diff --git a/http.c b/http.c
index 74ca982..a4c2cb8 100644
--- a/http.c
+++ b/http.c
@@ -95,6 +95,31 @@ MOG_NOINLINE static void http_close(struct mog_fd *mfd)
         mog_fd_put(mfd);
 }
 
+void mog_http_unlink_ftmp(struct mog_http *http)
+{
+        struct mog_file *file = &http->forward->as.file;
+
+        if (!file->tmppath)
+                return;
+
+        if (mog_unlink(http->svc, file->tmppath) != 0)
+                syslog(LOG_ERR, "Failed to unlink %s (in %s): %m",
+                       file->tmppath, http->svc->docroot);
+}
+
+/* called if epoll/kevent is out-of-space */
+void mog_http_drop(struct mog_fd *mfd)
+{
+        struct mog_http *http = &mfd->as.http;
+
+        assert(http->forward != MOG_IOSTAT);
+        if (http->forward) {
+                mog_http_unlink_ftmp(http);
+                mog_file_close(http->forward);
+        }
+        http_close(mfd);
+}
+
 /* returns true if we can continue queue step, false if not */
 static enum mog_next http_wbuf_in_progress(struct mog_http *http)
 {
diff --git a/http_put.c b/http_put.c
index f86113e..db9228d 100644
--- a/http_put.c
+++ b/http_put.c
@@ -14,18 +14,9 @@ static __thread struct {
 
 static void file_close_null(struct mog_http *http)
 {
-        struct mog_file *file;
-
         if (http->forward == NULL)
                 return;
-
-        file = &http->forward->as.file;
-
-        if (file->tmppath) {
-                if (mog_unlink(http->svc, file->tmppath) != 0)
-                        syslog(LOG_ERR, "Failed to unlink %s (in %s): %m",
-                               file->tmppath, http->svc->docroot);
-        }
+        mog_http_unlink_ftmp(http);
         mog_file_close(http->forward);
         http->forward = NULL;
 }
diff --git a/mgmt.c b/mgmt.c
index 9909d27..3468e24 100644
--- a/mgmt.c
+++ b/mgmt.c
@@ -82,6 +82,16 @@ MOG_NOINLINE static void mgmt_close(struct mog_fd *mfd)
         mog_fd_put(mfd);
 }
 
+/* called if epoll/kevent is out-of-space */
+void mog_mgmt_drop(struct mog_fd *mfd)
+{
+        struct mog_mgmt *mgmt = &mfd->as.mgmt;
+
+        if (mgmt->forward && mgmt->forward != MOG_IOSTAT)
+                mog_file_close(mgmt->forward);
+        mgmt_close(mfd);
+}
+
 void mog_mgmt_writev(struct mog_mgmt *mgmt, struct iovec *iov, int iovcnt)
 {
         struct mog_fd *mfd = mog_fd_of(mgmt);
diff --git a/queue_common.c b/queue_common.c
index 79a5869..b9c2f99 100644
--- a/queue_common.c
+++ b/queue_common.c
@@ -46,3 +46,21 @@ void mog_queue_stop(struct mog_queue *keep)
                 mog_fd_put(mfd);
         }
 }
+
+void mog_queue_drop(struct mog_fd *mfd)
+{
+        switch (mfd->fd_type) {
+        case MOG_FD_TYPE_HTTP:
+        case MOG_FD_TYPE_HTTPGET:
+                mog_http_drop(mfd);
+                return;
+        case MOG_FD_TYPE_MGMT:
+                mog_mgmt_drop(mfd);
+                return;
+        default:
+                syslog(LOG_ERR,
+                       "dropping fd_type=%d, functionality may be compromised",
+                       mfd->fd_type);
+                mog_fd_put(mfd);
+        }
+}
diff --git a/queue_epoll.c b/queue_epoll.c
index aaa30f6..e6d36d5 100644
--- a/queue_epoll.c
+++ b/queue_epoll.c
@@ -160,7 +160,7 @@ epoll_ctl_error(struct mog_queue *q, struct mog_fd *mfd)
         case ENOMEM:
         case ENOSPC:
                 syslog(LOG_ERR, "epoll_ctl: %m, dropping file descriptor");
-                mog_fd_put(mfd);
+                mog_queue_drop(mfd);
                 return;
         default:
                 syslog(LOG_ERR, "unhandled epoll_ctl() error: %m");
diff --git a/queue_kqueue.c b/queue_kqueue.c
index 020b339..6254984 100644
--- a/queue_kqueue.c
+++ b/queue_kqueue.c
@@ -86,7 +86,7 @@ kevent_add_error(struct mog_queue *q, struct mog_fd *mfd)
         case ENOMEM:
                 syslog(LOG_ERR,
                       "kevent(EV_ADD) out-of-space, dropping file descriptor");
-                mog_fd_put(mfd);
+                mog_queue_drop(mfd);
                 return;
         default:
                 syslog(LOG_ERR, "unhandled kevent(EV_ADD) error: %m");