a issue about getting a devfs node's fullpath

Zhichao1.Li at dell.com Zhichao1.Li at dell.com
Thu Oct 10 05:50:09 UTC 2019


Dear freebsd developers
I know you're swamped, so I'll be brief.
I am trying to get a node's full under /dev by calling the function 'vn_fullpath', when dealing with things like '/dev/null' or '/dev/usb/1.0.1', it works well.
However when dealing a node under more than 2 sub directories (e.g. /dev/bus/usb/001/002)  which I made by calling 'make_dev_s' , it goes a little bit different, I got a string "/dev/bus/usb/bus/usb/001/002"
And I found the function 'devfs_vptocnp' gets the string wrongly when dealing multi slashes path string, I have remark the code as followed and put some comments
would you please take a look, and tell me what the purpose this func pass the string that way?
static int
devfs_vptocnp(struct vop_vptocnp_args *ap)
{
        struct vnode *vp = ap->a_vp;
        struct vnode **dvp = ap->a_vpp;
        struct devfs_mount *dmp;
        char *buf = ap->a_buf;
        int *buflen = ap->a_buflen;
        struct devfs_dirent *dd, *de;
        int i, error;

        dmp = VFSTODEVFS(vp->v_mount);

        error = devfs_populate_vp(vp);
        if (error != 0)
                return (error);

        i = *buflen;
        dd = vp->v_data;

        if (vp->v_type == VCHR) {
                i -= strlen(dd->de_cdp->cdp_c.si_name);
                if (i < 0) {
                        error = ENOMEM;
                        goto finished;
                }
                bcopy(dd->de_cdp->cdp_c.si_name, buf + i,
                    strlen(dd->de_cdp->cdp_c.si_name));
               /*
* when dealing with VCHR
                * the element 'si_name' already
                * holds the full path string
                * except rootdir, why not just go
                * to the rootdir?
                */
                de = dd->de_dir;
        } else if (vp->v_type == VDIR) {
                if (dd == dmp->dm_rootdir) {
                        *dvp = vp;
                        vref(*dvp);
                        goto finished;
                }
                i -= dd->de_dirent->d_namlen;
                if (i < 0) {
error = ENOMEM;
                             goto finished;
                }
                bcopy(dd->de_cdp->cdp_c.si_name, buf + i,
                    strlen(dd->de_cdp->cdp_c.si_name));
                de = dd->de_dir;
        } else if (vp->v_type == VDIR) {
                if (dd == dmp->dm_rootdir) {
                        *dvp = vp;
                        vref(*dvp);
                        goto finished;
                }
                i -= dd->de_dirent->d_namlen;
                if (i < 0) {
                        error = ENOMEM;
                        goto finished;
                }
                bcopy(dd->de_dirent->d_name, buf + i,
                    dd->de_dirent->d_namlen);
                de = dd;
        } else {
                error = ENOENT;
                goto finished;
        }
        *buflen = i;
        de = devfs_parent_dirent(de);
        if (de == NULL) {
                error = ENOENT;
                goto finished;
        }
        mtx_lock(&devfs_de_interlock);
        *dvp = de->de_vnode;
        if (*dvp != NULL) {
                VI_LOCK(*dvp);
                mtx_unlock(&devfs_de_interlock);
                vholdl(*dvp);
                VI_UNLOCK(*dvp);
                vref(*dvp);
                vdrop(*dvp);
        } else {
               mtx_unlock(&devfs_de_interlock);
error = ENOENT;
        }
finished:
        sx_xunlock(&dmp->dm_lock);
        return (error);
}


More information about the freebsd-fs mailing list