Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

improve robustness

1. serialize all operations under prefix folder
2. monitor uses lock for preventing conflicts
3. monitor has more robust rename operation
4. lock files were moved into the root of prefix folder
  • Loading branch information...
commit 26ca3eb7c40730c7694057b888682b131a0df2ba 1 parent 9311c81
@darwin darwin authored
View
7 daemon/common.h
@@ -1,6 +1,7 @@
-#define SUSPEND_LOCK_PATH "/tmp/.asepsis.suspend.lock"
-#define DAEMON_LOCK_PATH "/tmp/asepsis.daemon.lock"
+#define SUSPEND_LOCK_PATH "/usr/local/.dscage/.asepsis.suspend.lock"
+#define DAEMON_LOCK_PATH "/usr/local/.dscage/.asepsis.daemon.lock"
+#define SERIALIZATION_LOCK_PATH "/usr/local/.dscage/.asepsis.serialization.lock"
#define DISABLED_TWEAK_PATH "/var/db/.asepsis.disabled"
-#define KEXT_PATH "/System/Library/Extensions/Asepsis.kext"
+#define KEXT_PATH "/System/Library/Extensions/Asepsis.kext"
View
59 daemon/monitor.c
@@ -32,17 +32,37 @@ extern int asepsis_stop_monitor(void);
// http://stackoverflow.com/questions/3184445/how-to-clear-directory-contents-in-c-on-linux-basically-i-want-to-do-rm-rf
static int rmdir_recursive_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
+ DLOG("remove %s", fpath);
int res = remove(fpath);
if (res) {
- ERROR("unable to remove %s (%s)", fpath, strerror(res));
+ ERROR("unable to remove %s (%s)", fpath, strerror(errno));
}
return res;
}
-
+
static int rmdir_recursive(const char *path) {
- return nftw(path, rmdir_recursive_cb, 64, FTW_DEPTH | FTW_PHYS);
+ struct stat sb;
+
+ // check full path for presence
+ if (stat(path, &sb) == 0) {
+ if (S_ISDIR (sb.st_mode)) {
+ DLOG("rmdir_recursive %s", path);
+ return nftw(path, rmdir_recursive_cb, 64, FTW_DEPTH | FTW_PHYS);
+ } else {
+ DLOG("remove %s", path);
+ int res = remove(path); // in case path is just a file path
+ if (res) {
+ ERROR("unable to remove %s (%s)", path, strerror(errno));
+ }
+ return 0;
+ }
+ }
+
+ return 0;
}
+#define REENTRY(x) 1
+#define path "asepsis_handle_delete"
static int asepsis_handle_delete(const char* path1) {
int res = 0;
@@ -54,21 +74,29 @@ static int asepsis_handle_delete(const char* path1) {
if (!makePrefixPath(path1, prefixPath1)) {
return 0; // the prefixed path would be too long
}
+
+ SUSPEND_LOCK_CHECK();
if (!isDirectory(prefixPath1)) {
// nothing to do, source dir is not present in our cache
+ SUSPEND_LOCK_RELEASE();
return 0;
}
// do mirror remove
DLOG("handle delete %s", prefixPath1);
+ SERIALIZATION_LOCK_CHECK();
res = rmdir_recursive(prefixPath1); // this is dangerous, but we know that our path has prefix at least
if (res) {
- ERROR("unable to remove directory %s (%s)", prefixPath1, strerror(res));
+ ERROR("unable to remove directory %s (%s)", prefixPath1, strerror(errno));
}
+ SERIALIZATION_LOCK_RELEASE();
+ SUSPEND_LOCK_RELEASE();
return res;
}
+#undef path
+#define path "asepsis_handle_rename"
static int asepsis_handle_rename(const char* path1, const char* path2) {
int res = 0;
@@ -86,17 +114,34 @@ static int asepsis_handle_rename(const char* path1, const char* path2) {
return 0; // the prefixed path would be too long
}
+ SUSPEND_LOCK_CHECK();
+
if (!isDirectory(prefixPath1)) {
// nothing to do, source dir is not present in our cache
+ SUSPEND_LOCK_RELEASE();
return 0;
}
// do mirror rename
DLOG("handle rename %s -> %s", prefixPath1, prefixPath2);
+
+ SERIALIZATION_LOCK_CHECK();
+
+ // here we need to be especially careful
+ // rename(2) may fail under some special circumstances
+ // 1. something gets into the way of renaming
+ // 2. parent folder is missing for new name
+ rmdir_recursive(prefixPath2); // there may be some old content (pathological case)
+ ensureDirectoryForPath(prefixPath2); // like mkdir -p $prefixPath2 (but excluding last directory)
+
+ // ok, now it should be safe to call rename
res = rename(prefixPath1, prefixPath2); // this is dangerous, but we know that our path has prefix at least
if (res) {
- ERROR("unable to rename directories %s -> %s (%s)", prefixPath1, prefixPath2, strerror(res));
+ ERROR("unable to rename directories %s -> %s (%s)", prefixPath1, prefixPath2, strerror(errno));
}
+
+ SERIALIZATION_LOCK_RELEASE();
+ SUSPEND_LOCK_RELEASE();
return res;
}
@@ -143,7 +188,7 @@ static void* asepsis_monitor_thread(void* data) {
DLOG("asepsis_monitor_thread entering loop...");
g_monitor_entered_loop = 1;
while (1) {
- if (recv(g_monitor_socket, &em, sizeof(struct EchelonMessage), 0) != sizeof(struct EchelonMessage)) {
+ if (recv(g_monitor_socket, &em, sizeof(struct EchelonMessage), MSG_WAITALL) != sizeof(struct EchelonMessage)) {
if (g_received_signal) {
INFO("asepsis_monitor_thread received signal, closing ...");
} else {
@@ -152,9 +197,11 @@ static void* asepsis_monitor_thread(void* data) {
break;
}
if (em.operation == ECHELON_OP_RENAME) {
+ // DLOG("asepsis_monitor_thread received rename op %s -> %s", em.path1, em.path2);
asepsis_handle_rename(em.path1, em.path2);
}
if (em.operation == ECHELON_OP_DELETE) {
+ // DLOG("asepsis_monitor_thread received delete op %s", em.path1);
asepsis_handle_delete(em.path1);
}
}
View
23 dylib/interposing.c
@@ -48,21 +48,6 @@ INTERPOSE(getattrlist);
INTERPOSE(setattrlist);
////////////////////////////////////////////////////////////////////////////////////////////////////
-// some external process might want to suspend our operations - imagine asepsis "migration utility"
-
-#define SUSPEND_LOCK_RELEASE() \
- close(lock);\
- unlink(SUSPEND_LOCK_PATH);
-
-#define SUSPEND_LOCK_CHECK() \
- int lock = open(SUSPEND_LOCK_PATH, O_CREAT|O_RDONLY, S_IRUSR|S_IRGRP|S_IROTH);\
- if (flock(lock, LOCK_SH|LOCK_NB) != 0) {\
- DLOG("suspended: %s", path);\
- close(lock);\
- return REENTRY(path);\
- }
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
// interposed functions
#define REENTRY(path) open(path, flags, mode)
@@ -85,9 +70,11 @@ int asepsis_open(const char * path, int flags, mode_t mode) {
}
SUSPEND_LOCK_CHECK();
underscorePatch(prefixPath);
+ SERIALIZATION_LOCK_CHECK();
DLOG("asepsis_open %s (flags=%016x mode=%016x) -> %s", path, flags, mode, prefixPath);
ensureDirectoryForPath(prefixPath);
int res = REENTRY(prefixPath);
+ SERIALIZATION_LOCK_RELEASE();
SUSPEND_LOCK_RELEASE();
return res;
}
@@ -113,9 +100,11 @@ int asepsis_openx_np(const char * path, int flags, filesec_t sec) {
}
SUSPEND_LOCK_CHECK();
underscorePatch(prefixPath);
+ SERIALIZATION_LOCK_CHECK();
DLOG("openx_np %s (flags=%016x mode=%16p) -> %s", path, flags, sec, prefixPath);
ensureDirectoryForPath(prefixPath);
int res = REENTRY(prefixPath);
+ SERIALIZATION_LOCK_RELEASE();
SUSPEND_LOCK_RELEASE();
return res;
}
@@ -141,8 +130,10 @@ int asepsis_getattrlist(const char *path, void *alist, void *attributeBuffer, si
}
SUSPEND_LOCK_CHECK();
underscorePatch(prefixPath);
+ SERIALIZATION_LOCK_CHECK();
DLOG("getattrlist %s -> %s", path, prefixPath);
int res = REENTRY(prefixPath);
+ SERIALIZATION_LOCK_RELEASE();
SUSPEND_LOCK_RELEASE();
return res;
}
@@ -168,8 +159,10 @@ int asepsis_setattrlist(const char *path, void *alist, void *attributeBuffer, si
}
SUSPEND_LOCK_CHECK();
underscorePatch(prefixPath);
+ SERIALIZATION_LOCK_CHECK();
DLOG("setattrlist %s -> %s", path, prefixPath);
int res = REENTRY(prefixPath);
+ SERIALIZATION_LOCK_RELEASE();
SUSPEND_LOCK_RELEASE();
return res;
}
View
29 dylib/shared.c
@@ -18,6 +18,35 @@ extern void asepsis_setup_logging(void);
extern int g_asepsis_disabled;
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// some external process might want to suspend our operations - imagine asepsis "migration utility"
+
+#define SUSPEND_LOCK_RELEASE() \
+ close(lock);\
+ unlink(SUSPEND_LOCK_PATH);
+
+#define SUSPEND_LOCK_CHECK() \
+ int lock = open(SUSPEND_LOCK_PATH, O_CREAT|O_RDONLY, S_IRUSR|S_IRGRP|S_IROTH);\
+ if (flock(lock, LOCK_SH|LOCK_NB) != 0) {\
+ DLOG("suspended: %s", path);\
+ close(lock);\
+ return REENTRY(path);\
+ }
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// to prevent race conditions in when calling rename(2) from monitor
+// => serialize all accesses to the prefix folder
+
+#define SERIALIZATION_LOCK_CHECK() \
+ int slock = open(SERIALIZATION_LOCK_PATH, O_CREAT|O_RDONLY, S_IRUSR|S_IRGRP|S_IROTH);\
+ flock(slock, LOCK_EX);
+
+#define SERIALIZATION_LOCK_RELEASE() \
+ close(slock);\
+ unlink(SERIALIZATION_LOCK_PATH);
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
ASEPSIS_INLINE int isDisabled() {
asepsis_setup_safe();
return g_asepsis_disabled;
View
4 kext/echelon.c
@@ -274,9 +274,7 @@ static void send_message(struct EchelonMessage* info) {
int res = ctl_enqueuedata(gConnection, gUnit, info, sizeof(struct EchelonMessage), 0);
if (res) {
// most likely out of socket buffer space
- printf("asepsis.kext: unable to send message, ctl_enqueuedata failed %d, disconnecting client\n", res);
- gConnection = 0;
- gUnit = 0;
+ printf("asepsis.kext: unable to send message, ctl_enqueuedata failed %d, message lost\n", res);
}
lck_mtx_unlock(gLock);
Please sign in to comment.
Something went wrong with that request. Please try again.