Skip to content

Commit

Permalink
inotify: watch the directory not just file
Browse files Browse the repository at this point in the history
Editors (such as vim, nano ..) follow different approaches to save conf file.
The two commonly followed techniques are to overwrite the existing file, or to
write to a new file (.swp, .tmp ..) and move it to actual file name later. In
the later case, the inotify fails, because the file it's been intended to watch
no longer exists, as the new file is a different file with just a same name.

To handle both the file save approaches mentioned above, it is better we watch
the directory and filter for MODIFY events.

Signed-off-by: Xiubo Li <[email protected]>
  • Loading branch information
lxbsz committed Apr 3, 2019
1 parent e17cf63 commit 8ee872d
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 18 deletions.
53 changes: 36 additions & 17 deletions utils/dyn-config.c
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,10 @@ glusterBlockDynConfigStart(void *arg)
gbConfig *cfg = arg;
int monitor, wd, len;
char buf[GB_BUF_LEN];
char cfgDir[PATH_MAX];
struct inotify_event *event;
struct timespec mtim = {0, }; /* Time of last modification. */
struct stat statbuf;
char *p;


Expand All @@ -537,16 +540,32 @@ glusterBlockDynConfigStart(void *arg)
return NULL;
}

wd = inotify_add_watch(monitor, cfg->configPath, IN_ALL_EVENTS);
snprintf(cfgDir, PATH_MAX, cfg->configPath);
p = strrchr(cfgDir, '/');
if (p) {
*(p + 1) = '\0';
} else {
snprintf(cfgDir, PATH_MAX, GB_DEF_CONFIGDIR);
}

/* Editors (vim, nano ..) follow different approaches to save conf file.
* The two commonly followed techniques are to overwrite the existing
* file, or to write to a new file (.swp, .tmp ..) and move it to actual
* file name later. In the later case, the inotify fails, because the
* file it's been intended to watch no longer exists, as the new file
* is a different file with just a same name.
* To handle both the file save approaches mentioned above, it is better
* we watch the directory and filter for MODIFY events.
*/
wd = inotify_add_watch(monitor, cfgDir, IN_MODIFY);
if (wd == -1) {
LOG("mgmt", GB_LOG_ERROR,
"Failed to add \"%s\" to inotify (%d)\n", cfg->configPath, monitor);
"Failed to add \"%s\" to inotify (%d)\n", cfgDir, monitor);
return NULL;
}

LOG("mgmt", GB_LOG_INFO,
"Inotify is watching \"%s\", wd: %d, mask: IN_ALL_EVENTS\n",
cfg->configPath, wd);
"Inotify is watching \"%s\", wd: %d, mask: IN_MODIFY\n", cfgDir, wd);

while (1) {
len = read(monitor, buf, GB_BUF_LEN);
Expand All @@ -555,7 +574,7 @@ glusterBlockDynConfigStart(void *arg)
continue;
}

for (p = buf; p < buf + len;) {
for (p = buf; p < buf + len; p += sizeof(*event) + event->len) {
event = (struct inotify_event *)p;

LOG("mgmt", GB_LOG_INFO, "event->mask: 0x%x\n", event->mask);
Expand All @@ -564,25 +583,25 @@ glusterBlockDynConfigStart(void *arg)
continue;
}

/*
* If force to write to the unwritable or crashed
* config file, the vi/vim will try to move and
* delete the config file and then recreate it again
* via the *.swp
*/
if ((event->mask & IN_IGNORED) && !access(cfg->configPath, F_OK)) {
wd = inotify_add_watch(monitor, cfg->configPath, IN_ALL_EVENTS);
/* If stat fails we will skip the modify time check */
if (!stat(cfg->configPath, &statbuf)) {
if (statbuf.st_mtim.tv_sec == mtim.tv_sec &&
statbuf.st_mtim.tv_nsec == mtim.tv_nsec) {
continue;
}
}

mtim.tv_sec = statbuf.st_mtim.tv_sec;
mtim.tv_nsec = statbuf.st_mtim.tv_nsec;

/* Try to reload the config file */
if (event->mask & IN_MODIFY || event->mask & IN_IGNORED) {
glusterBlockLoadConfig(cfg, false);
if (event->mask & IN_MODIFY) {
glusterBlockLoadConfig(cfg, false);
}

p += sizeof(struct inotify_event) + event->len;
}
}

inotify_rm_watch(monitor, wd);
return NULL;
}

Expand Down
3 changes: 2 additions & 1 deletion utils/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@

# define GB_METASTORE_RESERVE 10485760 /* 10 MiB reserve for block-meta */

# define GB_DEF_CONFIGPATH "/etc/sysconfig/gluster-blockd" /* the default config file */
# define GB_DEF_CONFIGDIR "/etc/sysconfig" /* the default config file directory */
# define GB_DEF_CONFIGPATH GB_DEF_CONFIGDIR"/gluster-blockd" /* the default config file */

# define GB_TIME_STRING_BUFLEN \
(4 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 6 + 1 + 5)
Expand Down

0 comments on commit 8ee872d

Please sign in to comment.