infra: new timestamp ordering

This commit is contained in:
Thomas Schoebel-Theuer 2018-03-12 13:06:31 +01:00
parent db486fb6cd
commit dedaa5b55f
2 changed files with 91 additions and 0 deletions

View File

@ -192,6 +192,11 @@ extern int mars_chmod(const char *path, mode_t mode);
extern int mars_lchown(const char *path, uid_t uid);
extern void mars_remaining_space(const char *fspath, loff_t *total, loff_t *remaining);
/* Timestamp Ordering */
extern int ordered_unlink(const char *path, const struct timespec *stamp, int serial, int mode);
extern int ordered_symlink(const char *oldpath, const char *newpath, const struct timespec *stamp, uid_t uid);
/////////////////////////////////////////////////////////////////////////
extern struct mars_global *mars_global;

View File

@ -851,6 +851,92 @@ err: ;
}
EXPORT_SYMBOL_GPL(mars_remaining_space);
/*************************************************************/
/* Timestamp Ordering */
/* Timestamp ordering (e.g. via Lamport Clock) is easy when
* the object exists.
* When unlink() comes into play, it becomes more complex:
* where to store the timestamp of the object when it is
* currently deleted?
* This is necessary to allow permutations between _all_ operations
* on the object, including unlink().
* Idea: use a substitute object ".deleted-$object".
*/
static DEFINE_MUTEX(ordered_lock);
int ordered_unlink(const char *path, const struct timespec *stamp, int serial, int mode)
{
struct kstat stat;
char serial_str[32];
struct timespec now;
const char *marker_path;
int marker_status;
int status = 0;
snprintf(serial_str, sizeof(serial_str), "%d,%d", serial, mode);
if (!stamp) {
get_lamport(&now);
stamp = &now;
}
mutex_lock(&ordered_lock);
marker_path = backskip_replace(path, '/', true, "/.deleted-");
marker_status = mars_stat(marker_path, &stat, true);
if (marker_status < 0 ||
timespec_compare(stamp, &stat.mtime) >= 0) {
MARS_DBG("creating / updating marker '%s' mtime=%lu.%09lu\n",
marker_path,
stamp->tv_sec, stamp->tv_nsec);
status = mars_symlink(serial_str, marker_path, stamp, 0);
}
if (marker_status < 0 ||
timespec_compare(stamp, &stat.mtime) >= 0) {
status = mars_unlink(path);
}
mutex_unlock(&ordered_lock);
brick_string_free(marker_path);
return status;
}
int ordered_symlink(const char *oldpath, const char *newpath, const struct timespec *stamp, uid_t uid)
{
struct kstat stat;
struct timespec now;
const char *marker_path;
int status = 0;
if (!stamp) {
get_lamport(&now);
stamp = &now;
}
mutex_lock(&ordered_lock);
marker_path = backskip_replace(newpath, '/', true, "/.deleted-");
if (mars_stat(marker_path, &stat, true) >= 0 &&
timespec_compare(&stat.mtime, stamp) > 0) {
goto done;
}
if (mars_stat(newpath, &stat, true) >= 0 &&
timespec_compare(&stat.mtime, stamp) > 0) {
goto done;
}
(void)mars_unlink(marker_path);
status = mars_symlink(oldpath, newpath, stamp, uid);
done:
mutex_unlock(&ordered_lock);
brick_string_free(marker_path);
return status;
}
//////////////////////////////////////////////////////////////
// thread binding