resolving full path when creating a new file on freebsd 4.x (and more)
"Patrick Bihan-Faou" <[email protected]>
| Newsgroups | gmane.linux.dazuko.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi, Testing dazuko 2.0.3-pre4 on freebsd I noticed that I was never getting the OPEN/CLOSE events for files that were non-existant previously. After some investigation, I found that when the file does not exist, the namei() call in freebsd_get_full_fileinfo() (called from xp_file_struct_check()) returns ENOENT leading in the name not being resolved. Here is a patch for freebsd_get_full_fileinfo() that tries to resolve the first parent directory of a file if the file itself does not exist (ENOENT). The provided patch has been slightly tested on a FreeBSD 4.9 system with good success so far. Also, while there, I have replaced the vrele calls that were following NDINIT/namei calls with more adequate NDFREE() calls that also free the memory that could have been allocated during the namei() call. Now I have another question regarding the closed/modified event: To support the closed-modified event, dazuko monitors the write system call. However in FreeBSD there are at least 4 calls that can modify a file: - write() (already handled) - writev() (handles scattered buffers for a single write operation) - pwrite() (write at a specific offset) - aio_write (asynchronous IO call) Only the first syscall is handled and none of the last 3. Wouldn't that invalidate the usefulleness of the closed-modified event ? If indeed the other syscalls should be handled as well, I am willing to provide patches for that. I have more questions and suggestions, but they will come later. Patrick. _______________________________________________ Dazuko-devel mailing list [email protected] http://lists.nongnu.org/mailman/listinfo/dazuko-devel
dazuko_freebsd.c.patch
(application/octet-stream, 4.6 KB)
--- dazuko_freebsd.c.orig Fri Aug 27 14:19:20 2004
+++ dazuko_freebsd.c Fri Aug 27 15:30:32 2004
@@ -53,6 +53,7 @@
#include <sys/namei.h>
#include <sys/param.h>
#include <sys/vnode.h>
+#include <sys/fcntl.h>
#include "dazuko_freebsd.h"
#include "dazuko_xp.h"
@@ -342,12 +343,13 @@ inline int xp_compare_file(struct xp_fil
/* file structure */
-static void freebsd_get_full_fileinfo(struct proc *p, const char *path, char **fullpath, char **freefullpath, struct file_properties *file_p)
+static void freebsd_get_full_fileinfo(struct proc *p, const char *path, char **fullpath, char **freefullpath, struct file_properties *file_p, int follow_symlinks)
{
struct proc localp;
struct nameidata nd;
struct filedesc localfd;
struct vattr vattr;
+ int err;
if (p == NULL || path == NULL || fullpath == NULL || freefullpath == NULL || file_p == NULL)
return;
@@ -357,13 +359,102 @@ static void freebsd_get_full_fileinfo(st
dazuko_bzero(&localfd, sizeof(localfd));
dazuko_bzero(file_p, sizeof(struct file_properties));
- NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, path, p);
+ NDINIT(&nd, LOOKUP, follow_symlinks ? FOLLOW: NOFOLLOW, UIO_USERSPACE, path, p);
- if (namei(&nd) != 0)
+ if ((err=namei(&nd)) != 0)
{
/*
we need to understand why this fails sometimes
*/
+
+ if ( (err == ENOENT)
+ && (path[0] != '/') )
+ {
+ /* let's try to resolve the parent dir (if possible) */
+ char * kpath = xp_malloc(MAXPATHLEN+1);
+ char * fname = kpath;
+ char * lookuppath = ".";
+ char * pfullpath = NULL;
+ char * pfreefullpath = NULL;
+ size_t len;
+ int i;
+ struct nameidata ndparent;
+
+ if (!kpath)
+ {
+ xp_print("failed to allocate memory for path resolution\n");
+ NDFREE(&nd, 0);
+ return;
+ }
+
+ dazuko_bzero(kpath, MAXPATHLEN+1);
+ copyinstr(path, kpath, MAXPATHLEN+1, &len);
+
+ /* find the last / */
+ for (i = strlen(kpath); i >= 0; i--)
+ {
+ if (kpath[i] == '/')
+ {
+ kpath[i] = 0;
+ fname = kpath + i + 1;
+ lookuppath = kpath;
+ break;
+ }
+ }
+
+ /* at this point we habe:
+ * lookuppath = the name of the parent directory to lookup
+ * fname = the file name that was not found by the previous namei
+ */
+
+ dazuko_bzero(&ndparent, sizeof(ndparent));
+ NDINIT(&ndparent, LOOKUP, follow_symlinks ? FOLLOW : NOFOLLOW, UIO_SYSSPACE, lookuppath, p);
+
+ if ( (err = namei(&ndparent)) != 0 )
+ {
+ NDFREE(&nd, 0);
+ NDFREE(&ndparent, 0);
+ xp_free(kpath);
+ return;
+ }
+
+ if (!ndparent.ni_vp || (ndparent.ni_vp->v_type != VDIR))
+ {
+ /* we did not find a vnode or the vnode is not a directory... */
+ NDFREE(&nd, 0);
+ NDFREE(&ndparent, 0);
+ xp_free(kpath);
+ return;
+ }
+
+ localp.p_textvp = ndparent.ni_vp;
+ localp.p_fd = &localfd;
+ if (orig_rootmnt)
+ localfd.fd_rdir = orig_rootmnt;
+ else
+ localfd.fd_rdir = nd.ni_rootdir;
+
+ textvp_fullpath(&localp, &pfullpath, &pfreefullpath);
+
+ if (pfreefullpath)
+ {
+ int flen = strlen(pfullpath) + strlen(fname) + 2;
+ *fullpath = malloc(flen, M_TEMP, M_WAITOK);
+ if (*fullpath)
+ {
+ strcpy(*fullpath, pfullpath);
+ strcat(*fullpath, "/");
+ strcat(*fullpath, fname);
+ }
+ *freefullpath = *fullpath;
+ free(pfreefullpath, M_TEMP);
+ }
+
+ NDFREE(&nd,0);
+ NDFREE(&ndparent,0);
+ xp_free(kpath);
+ return;
+ }
}
else
{
@@ -393,7 +484,7 @@ static void freebsd_get_full_fileinfo(st
}
/* deref looked up vnode */
- vrele(nd.ni_vp);
+ NDFREE(&nd, 0);
}
}
}
@@ -404,7 +495,7 @@ inline int xp_file_struct_check(struct d
char *freefullpath = NULL;
int length;
- freebsd_get_full_fileinfo(dfs->extra_data->p, dfs->extra_data->user_filename, &fullpath, &freefullpath, &(dfs->file_p));
+ freebsd_get_full_fileinfo(dfs->extra_data->p, dfs->extra_data->user_filename, &fullpath, &freefullpath, &(dfs->file_p), 1);
if (freefullpath)
{
@@ -1188,6 +1279,8 @@ int freebsd_dazuko_device_close(dev_t de
/* init/exit */
+
+
static int dazuko_loader(struct module *m, int what, void *arg)
{
int err = 0;
@@ -1205,17 +1298,24 @@ static int dazuko_loader(struct module *
if (namei(&nd))
xp_print("dazuko: warning: failed to get root mount\n");
else
+ {
orig_rootmnt = nd.ni_rootdir;
+ vref(orig_rootmnt);
+ }
/* deref looked up vnode */
- if (nd.ni_vp)
- vrele(nd.ni_vp);
+ NDFREE(&nd, 0);
}
break;
case MOD_UNLOAD:
if (dazuko_exit() != 0)
err = EPERM;
+ if (orig_rootmnt)
+ {
+ vrele(orig_rootmnt);
+ orig_rootmnt = NULL;
+ }
break;
default: