fsal_status_t fsal_internal_fd2handle( fsal_op_context_t *p_context, int fd, fsal_handle_t *p_handle) { int rc = 0; int errsv; int mnt_id = 0; memset(p_handle, 0, sizeof(vfsfsal_handle_t)); ((vfsfsal_handle_t *)p_handle)->data.vfs_handle.handle_bytes = VFS_HANDLE_LEN ; if( ( rc = vfs_fd_to_handle( fd, &((vfsfsal_handle_t *)p_handle)->data.vfs_handle, &mnt_id ) ) ) { errsv = errno; ReturnCode(posix2fsal_error(errsv), errsv); } #if 0 { char str[1024] ; sprint_mem( str, p_handle->data.vfs_handle.handle, p_handle->data.vfs_handle.handle_bytes ) ; printf( "=====> fsal_internal_fd2handle: type=%u bytes=%u|%s\n", p_handle->data.vfs_handle.handle_type, p_handle->data.vfs_handle.handle_bytes, str ) ; } #endif ReturnCode(ERR_FSAL_NO_ERROR, 0); } /* fsal_internal_fd2handle */
int vfs_name_to_handle(int fd, struct fsal_filesystem *fs, const char *name, vfs_file_handle_t *fh) { int retval; struct stat stat; if (fstatat(fd, name, &stat, AT_SYMLINK_NOFOLLOW) < 0) return -1; if (S_ISDIR(stat.st_mode) || S_ISREG(stat.st_mode)) { int e; int tmpfd = openat(fd, name, O_RDONLY | O_NOFOLLOW, 0600); if (tmpfd < 0) return -1; retval = vfs_fd_to_handle(tmpfd, fs, fh); e = errno; close(tmpfd); errno = e; } else { retval = xfs_fsal_inode2handle(fd, stat.st_ino, fh); } LogXFSHandle(fh); return retval; }
int vfs_get_root_handle(struct vfs_filesystem *vfs_fs, struct vfs_fsal_export *exp) { enum fsid_type fsid_type; struct fsal_fsid__ fsid; int fd; int retval; void *data; size_t sz; vfs_file_handle_t *fh; vfs_alloc_handle(fh); if (path_to_fshandle(vfs_fs->fs->path, &data, &sz) < 0) { retval = errno; LogMajor(COMPONENT_FSAL, "Export root %s could not be established for XFS error %s", vfs_fs->fs->path, strerror(retval)); return retval; } fd = open(vfs_fs->fs->path, O_RDONLY | O_DIRECTORY); if (fd < 0) { retval = errno; LogMajor(COMPONENT_FSAL, "Could not open XFS mount point %s: rc = %s (%d)", vfs_fs->fs->path, strerror(retval), retval); return retval; } retval = vfs_fd_to_handle(fd, vfs_fs->fs, fh); if (retval != 0) { retval = errno; LogMajor(COMPONENT_FSAL, "Get root handle for %s failed with %s (%d)", vfs_fs->fs->path, strerror(retval), retval); goto errout; } (void) vfs_extract_fsid(fh, &fsid_type, &fsid); retval = re_index_fs_fsid(vfs_fs->fs, fsid_type, fsid.major, fsid.minor); if (retval < 0) { LogCrit(COMPONENT_FSAL, "Could not re-index XFS file system fsid for %s", vfs_fs->fs->path); retval = -retval; } errout: close(fd); return retval; }
/** * build the export entry */ fsal_status_t VFSFSAL_BuildExportContext(fsal_export_context_t * context, /* OUT */ fsal_path_t * p_export_path, /* IN */ char *fs_specific_options /* IN */ ) { /* Get the mount point for this lustre FS, * so it can be used for building .lustre/fid paths. */ vfsfsal_export_context_t * p_export_context = (vfsfsal_export_context_t *) context; FILE *fp; struct mntent *p_mnt; char rpath[MAXPATHLEN]; char mntdir[MAXPATHLEN]; char fs_spec[MAXPATHLEN]; char *first_vfs_dir = NULL; char type[MAXNAMLEN+1]; size_t pathlen, outlen; int rc; int mnt_id = 0 ; /* sanity check */ if(p_export_context == NULL) { LogCrit(COMPONENT_FSAL, "NULL mandatory argument passed to %s()", __FUNCTION__); Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_BuildExportContext); } outlen = 0; if(p_export_path != NULL) strncpy(rpath, p_export_path->path, MAXPATHLEN); /* open mnt file */ fp = setmntent(MOUNTED, "r"); if(fp == NULL) { rc = errno; LogCrit(COMPONENT_FSAL, "Error %d in setmntent(%s): %s", rc, MOUNTED, strerror(rc)); Return(posix2fsal_error(rc), rc, INDEX_FSAL_BuildExportContext); } while((p_mnt = getmntent(fp)) != NULL) { /* get the longer path vfs related export that matches export path */ if(p_mnt->mnt_dir != NULL) { pathlen = strlen(p_mnt->mnt_dir); if(first_vfs_dir == NULL) first_vfs_dir = p_mnt->mnt_dir; if((pathlen > outlen) && !strcmp(p_mnt->mnt_dir, "/")) { LogDebug(COMPONENT_FSAL, "Root mountpoint is allowed for matching %s, type=%s, fs=%s", rpath, p_mnt->mnt_type, p_mnt->mnt_fsname); outlen = pathlen; strncpy(mntdir, p_mnt->mnt_dir, MAXPATHLEN); strncpy(type, p_mnt->mnt_type, MAXNAMLEN); strncpy(fs_spec, p_mnt->mnt_fsname, MAXPATHLEN); } /* in other cases, the filesystem must be <mountpoint>/<smthg> or <mountpoint>\0 */ else if((pathlen > outlen) && !strncmp(rpath, p_mnt->mnt_dir, pathlen) && ((rpath[pathlen] == '/') || (rpath[pathlen] == '\0'))) { LogFullDebug(COMPONENT_FSAL, "%s is under mountpoint %s, type=%s, fs=%s", rpath, p_mnt->mnt_dir, p_mnt->mnt_type, p_mnt->mnt_fsname); outlen = pathlen; strncpy(mntdir, p_mnt->mnt_dir, MAXPATHLEN); strncpy(type, p_mnt->mnt_type, MAXNAMLEN); strncpy(fs_spec, p_mnt->mnt_fsname, MAXPATHLEN); } } } if(outlen <= 0) { if(p_export_path == NULL) strncpy(mntdir, first_vfs_dir, MAXPATHLEN); else { LogCrit(COMPONENT_FSAL, "No mount entry matches '%s' in %s", rpath, MOUNTED); endmntent(fp); Return(ERR_FSAL_NOENT, 0, INDEX_FSAL_BuildExportContext); } } /* Save pointer to fsal_staticfsinfo_t in export context */ p_export_context->fe_static_fs_info = &global_fs_info; /* save file descriptor to root of VFS export */ if( ( p_export_context->mount_root_fd = open(mntdir, O_RDONLY | O_DIRECTORY) ) < 0 ) { LogMajor(COMPONENT_FSAL, "FSAL BUILD EXPORT CONTEXT: ERROR: Could not open VFS mount point %s: rc = %d", mntdir, errno); ReturnCode(ERR_FSAL_INVAL, 0); } /* Keep fstype in export_context */ strncpy( p_export_context->fstype, type, MAXNAMLEN ) ; if( !strncmp( type, "xfs", MAXNAMLEN ) ) { LogMajor( COMPONENT_FSAL, "Trying to export XFS filesystem via FSAL_VFS for mount point %s. Use FSAL_XFS instead", mntdir ) ; ReturnCode(ERR_FSAL_INVAL, 0); } p_export_context->root_handle.handle_bytes = VFS_HANDLE_LEN ; if( vfs_fd_to_handle( p_export_context->mount_root_fd, &p_export_context->root_handle, &mnt_id ) ) { LogMajor(COMPONENT_FSAL, "vfs_fd_to_handle: root_path: %s, root_fd=%d, errno=(%d) %s", mntdir, p_export_context->mount_root_fd, errno, strerror(errno)); Return(posix2fsal_error(errno), errno, INDEX_FSAL_BuildExportContext) ; } #ifdef TODO if(isFullDebug(COMPONENT_FSAL)) { char str[1024] ; sprint_mem( str, p_export_context->root_handle.handle ,p_export_context->root_handle.handle_bytes ) ; LogFullDebug(COMPONENT_FSAL, "=====> root Handle: type=%u bytes=%u|%s\n", p_export_context->root_handle.handle_type, p_export_context->root_handle.handle_bytes, str ) ; } #endif Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_BuildExportContext); }
static struct vfs_fsal_obj_handle *alloc_handle(int dirfd, vfs_file_handle_t *fh, struct fsal_filesystem *fs, struct stat *stat, vfs_file_handle_t *dir_fh, const char *path, struct fsal_export *exp_hdl) { struct vfs_fsal_export *myself = container_of(exp_hdl, struct vfs_fsal_export, export); struct vfs_fsal_obj_handle *hdl; fsal_status_t st; hdl = gsh_calloc(1, (sizeof(struct vfs_fsal_obj_handle) + sizeof(vfs_file_handle_t))); if (hdl == NULL) return NULL; hdl->handle = (vfs_file_handle_t *) &hdl[1]; memcpy(hdl->handle, fh, sizeof(vfs_file_handle_t)); hdl->obj_handle.type = posix2fsal_type(stat->st_mode); hdl->dev = posix2fsal_devt(stat->st_dev); hdl->up_ops = exp_hdl->up_ops; hdl->obj_handle.fs = fs; if (hdl->obj_handle.type == REGULAR_FILE) { hdl->u.file.fd = -1; /* no open on this yet */ hdl->u.file.openflags = FSAL_O_CLOSED; } else if (hdl->obj_handle.type == SYMBOLIC_LINK) { ssize_t retlink; size_t len = stat->st_size + 1; char *link_content = gsh_malloc(len); if (link_content == NULL) goto spcerr; retlink = vfs_readlink_by_handle(fh, dirfd, path, link_content, len); if (retlink < 0 || retlink == len) goto spcerr; link_content[retlink] = '\0'; hdl->u.symlink.link_content = link_content; hdl->u.symlink.link_size = len; } else if (vfs_unopenable_type(hdl->obj_handle.type)) { /* AF_UNIX sockets, character special, and block special files require craziness */ if (dir_fh == NULL) { int retval; vfs_alloc_handle(dir_fh); retval = vfs_fd_to_handle(dirfd, hdl->obj_handle.fs, fh); if (retval < 0) goto spcerr; } hdl->u.unopenable.dir = gsh_malloc(sizeof(vfs_file_handle_t)); if (hdl->u.unopenable.dir == NULL) goto spcerr; memcpy(hdl->u.unopenable.dir, dir_fh, sizeof(vfs_file_handle_t)); hdl->u.unopenable.name = gsh_strdup(path); if (hdl->u.unopenable.name == NULL) goto spcerr; } hdl->obj_handle.attributes.mask = exp_hdl->exp_ops.fs_supported_attrs(exp_hdl); st = posix2fsal_attributes(stat, &hdl->obj_handle.attributes); if (FSAL_IS_ERROR(st)) goto spcerr; hdl->obj_handle.attributes.fsid = fs->fsid; fsal_obj_handle_init(&hdl->obj_handle, exp_hdl, posix2fsal_type(stat->st_mode)); vfs_handle_ops_init(&hdl->obj_handle.obj_ops); vfs_sub_init_handle_ops(myself, &hdl->obj_handle.obj_ops); return hdl; spcerr: if (hdl->obj_handle.type == SYMBOLIC_LINK) { if (hdl->u.symlink.link_content != NULL) gsh_free(hdl->u.symlink.link_content); } else if (vfs_unopenable_type(hdl->obj_handle.type)) { if (hdl->u.unopenable.name != NULL) gsh_free(hdl->u.unopenable.name); if (hdl->u.unopenable.dir != NULL) gsh_free(hdl->u.unopenable.dir); } gsh_free(hdl); /* elvis has left the building */ return NULL; }
static struct closefd vfs_fsal_open_and_stat(struct fsal_export *exp, struct vfs_fsal_obj_handle *myself, struct stat *stat, int open_flags, fsal_errors_t *fsal_error) { struct fsal_obj_handle *obj_hdl = &myself->obj_handle; struct closefd cfd = { .fd = -1, .close_fd = false }; int retval = 0; vfs_file_handle_t *fh = NULL; vfs_alloc_handle(fh); const char *func = "unknown"; struct vfs_filesystem *vfs_fs = myself->obj_handle.fs->private; switch (obj_hdl->type) { case SOCKET_FILE: case CHARACTER_FILE: case BLOCK_FILE: cfd.fd = vfs_open_by_handle(vfs_fs, myself->u.unopenable.dir, O_PATH | O_NOACCESS, fsal_error); if (cfd.fd < 0) { LogDebug(COMPONENT_FSAL, "Failed with %s open_flags 0x%08x", strerror(-cfd.fd), O_PATH | O_NOACCESS); return cfd; } cfd.close_fd = true; retval = fstatat(cfd.fd, myself->u.unopenable.name, stat, AT_SYMLINK_NOFOLLOW); func = "fstatat"; break; case REGULAR_FILE: if (myself->u.file.openflags == FSAL_O_CLOSED) { /* no file open at the moment */ cfd.fd = vfs_fsal_open(myself, open_flags, fsal_error); if (cfd.fd < 0) { LogDebug(COMPONENT_FSAL, "Failed with %s open_flags 0x%08x", strerror(-cfd.fd), open_flags); return cfd; } cfd.close_fd = true; } else { cfd.fd = myself->u.file.fd; } retval = fstat(cfd.fd, stat); func = "fstat"; break; case SYMBOLIC_LINK: open_flags |= (O_PATH | O_RDWR | O_NOFOLLOW); goto vfos_open; case FIFO_FILE: open_flags |= O_NONBLOCK; /* fall through */ case DIRECTORY: default: vfos_open: cfd.fd = vfs_fsal_open(myself, open_flags, fsal_error); if (cfd.fd < 0) { LogDebug(COMPONENT_FSAL, "Failed with %s open_flags 0x%08x", strerror(-cfd.fd), open_flags); return cfd; } cfd.close_fd = true; retval = vfs_stat_by_handle(cfd.fd, myself->handle, stat, open_flags); func = "vfs_stat_by_handle"; break; } if (retval < 0) { retval = errno; if (cfd.close_fd) { int rc; rc = close(cfd.fd); if (rc < 0) { rc = errno; LogDebug(COMPONENT_FSAL, "close failed with %s", strerror(rc)); } } if (retval == ENOENT) retval = ESTALE; *fsal_error = posix2fsal_error(retval); LogDebug(COMPONENT_FSAL, "%s failed with %s", func, strerror(retval)); cfd.fd = -retval; cfd.close_fd = false; return cfd; } return cfd; } static fsal_status_t getattrs(struct fsal_obj_handle *obj_hdl) { struct vfs_fsal_obj_handle *myself; struct closefd cfd = { .fd = -1, .close_fd = false }; struct stat stat; fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; fsal_status_t st; int retval = 0; myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle); if (obj_hdl->fsal != obj_hdl->fs->fsal) { LogDebug(COMPONENT_FSAL, "FSAL %s getattr for handle belonging to FSAL %s, ignoring", obj_hdl->fsal->name, obj_hdl->fs->fsal != NULL ? obj_hdl->fs->fsal->name : "(none)"); goto out; } cfd = vfs_fsal_open_and_stat(op_ctx->fsal_export, myself, &stat, O_RDONLY, &fsal_error); if (cfd.fd >= 0) { st = posix2fsal_attributes(&stat, &obj_hdl->attributes); if (cfd.close_fd) close(cfd.fd); if (FSAL_IS_ERROR(st)) { FSAL_CLEAR_MASK(obj_hdl->attributes.mask); FSAL_SET_MASK(obj_hdl->attributes.mask, ATTR_RDATTR_ERR); fsal_error = st.major; retval = st.minor; } else { obj_hdl->attributes.fsid = obj_hdl->fs->fsid; } } else { LogDebug(COMPONENT_FSAL, "Failed with %s, fsal_error %s", strerror(-cfd.fd), fsal_error == ERR_FSAL_STALE ? "ERR_FSAL_STALE" : "other"); if (obj_hdl->type == SYMBOLIC_LINK && cfd.fd == -EPERM) { /* You cannot open_by_handle (XFS on linux) a symlink * and it throws an EPERM error for it. * open_by_handle_at does not throw that error for * symlinks so we play a game here. Since there is * not much we can do with symlinks anyway, * say that we did it but don't actually * do anything. In this case, return the stat we got * at lookup time. If you *really* want to tweek things * like owners, get a modern linux kernel... */ fsal_error = ERR_FSAL_NO_ERROR; goto out; } retval = -cfd.fd; } out: return fsalstat(fsal_error, retval); } /* * NOTE: this is done under protection of the attributes rwlock * in the cache entry. */ static fsal_status_t setattrs(struct fsal_obj_handle *obj_hdl, struct attrlist *attrs) { struct vfs_fsal_obj_handle *myself; struct closefd cfd = { .fd = -1, .close_fd = false }; struct stat stat; fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; int retval = 0; int open_flags = O_RDONLY; /* apply umask, if mode attribute is to be changed */ if (FSAL_TEST_MASK(attrs->mask, ATTR_MODE)) attrs->mode &= ~op_ctx->fsal_export->exp_ops. fs_umask(op_ctx->fsal_export); myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle); if (obj_hdl->fsal != obj_hdl->fs->fsal) { LogDebug(COMPONENT_FSAL, "FSAL %s operation for handle belonging to FSAL %s, return EXDEV", obj_hdl->fsal->name, obj_hdl->fs->fsal != NULL ? obj_hdl->fs->fsal->name : "(none)"); retval = EXDEV; fsal_error = posix2fsal_error(retval); goto hdlerr; } /* This is yet another "you can't get there from here". If this object * is a socket (AF_UNIX), an fd on the socket s useless _period_. * If it is for a symlink, without O_PATH, you will get an ELOOP error * and (f)chmod doesn't work for a symlink anyway - not that it matters * because access checking is not done on the symlink but the final * target. * AF_UNIX sockets are also ozone material. If the socket is already * active listeners et al, you can manipulate the mode etc. If it is * just sitting there as in you made it with a mknod. * (one of those leaky abstractions...) * or the listener forgot to unlink it, it is lame duck. */ if (FSAL_TEST_MASK(attrs->mask, ATTR_SIZE)) open_flags = O_RDWR; cfd = vfs_fsal_open_and_stat(op_ctx->fsal_export, myself, &stat, open_flags, &fsal_error); if (cfd.fd < 0) { if (obj_hdl->type == SYMBOLIC_LINK && cfd.fd == -EPERM) { /* You cannot open_by_handle (XFS) a symlink and it * throws an EPERM error for it. open_by_handle_at * does not throw that error for symlinks so we play a * game here. Since there is not much we can do with * symlinks anyway, say that we did it * but don't actually do anything. * If you *really* want to tweek things * like owners, get a modern linux kernel... */ fsal_error = ERR_FSAL_NO_ERROR; goto out; } return fsalstat(fsal_error, cfd.fd); } /** TRUNCATE **/ if (FSAL_TEST_MASK(attrs->mask, ATTR_SIZE)) { if (obj_hdl->type != REGULAR_FILE) { fsal_error = ERR_FSAL_INVAL; goto fileerr; } retval = ftruncate(cfd.fd, attrs->filesize); if (retval != 0) { /* XXX ESXi volume creation pattern reliably * reaches this point and reliably can successfully * ftruncate on reopen. I don't know yet if fd if * we failed to handle a previous error, or what. * I don't see a prior failed op in wireshark. */ if (retval == -1 /* bad fd */) { vfs_close(obj_hdl); if (cfd.close_fd) close(cfd.fd); cfd = vfs_fsal_open_and_stat( op_ctx->fsal_export, myself, &stat, open_flags, &fsal_error); retval = ftruncate(cfd.fd, attrs->filesize); if (retval != 0) goto fileerr; } else goto fileerr; } } /** CHMOD **/ if (FSAL_TEST_MASK(attrs->mask, ATTR_MODE)) { /* The POSIX chmod call doesn't affect the symlink object, but * the entry it points to. So we must ignore it. */ if (!S_ISLNK(stat.st_mode)) { if (vfs_unopenable_type(obj_hdl->type)) retval = fchmodat(cfd.fd, myself->u.unopenable.name, fsal2unix_mode(attrs->mode), 0); else retval = fchmod(cfd.fd, fsal2unix_mode(attrs->mode)); if (retval != 0) goto fileerr; } } /** CHOWN **/ if (FSAL_TEST_MASK(attrs->mask, ATTR_OWNER | ATTR_GROUP)) { uid_t user = FSAL_TEST_MASK(attrs->mask, ATTR_OWNER) ? (int)attrs->owner : -1; gid_t group = FSAL_TEST_MASK(attrs->mask, ATTR_GROUP) ? (int)attrs->group : -1; if (vfs_unopenable_type(obj_hdl->type)) retval = fchownat(cfd.fd, myself->u.unopenable.name, user, group, AT_SYMLINK_NOFOLLOW); else if (obj_hdl->type == SYMBOLIC_LINK) retval = fchownat(cfd.fd, "", user, group, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH); else retval = fchown(cfd.fd, user, group); if (retval) goto fileerr; } /** UTIME **/ if (FSAL_TEST_MASK (attrs->mask, ATTR_ATIME | ATTR_MTIME | ATTR_ATIME_SERVER | ATTR_MTIME_SERVER)) { struct timespec timebuf[2]; if (obj_hdl->type == SYMBOLIC_LINK) goto out; /* Setting time on symlinks is illegal */ /* Atime */ if (FSAL_TEST_MASK(attrs->mask, ATTR_ATIME_SERVER)) { timebuf[0].tv_sec = 0; timebuf[0].tv_nsec = UTIME_NOW; } else if (FSAL_TEST_MASK(attrs->mask, ATTR_ATIME)) { timebuf[0] = attrs->atime; } else { timebuf[0].tv_sec = 0; timebuf[0].tv_nsec = UTIME_OMIT; } /* Mtime */ if (FSAL_TEST_MASK(attrs->mask, ATTR_MTIME_SERVER)) { timebuf[1].tv_sec = 0; timebuf[1].tv_nsec = UTIME_NOW; } else if (FSAL_TEST_MASK(attrs->mask, ATTR_MTIME)) { timebuf[1] = attrs->mtime; } else { timebuf[1].tv_sec = 0; timebuf[1].tv_nsec = UTIME_OMIT; } if (vfs_unopenable_type(obj_hdl->type)) retval = vfs_utimesat(cfd.fd, myself->u.unopenable.name, timebuf, AT_SYMLINK_NOFOLLOW); else retval = vfs_utimes(cfd.fd, timebuf); if (retval != 0) goto fileerr; } goto out; fileerr: retval = errno; fsal_error = posix2fsal_error(retval); out: if (cfd.close_fd) close(cfd.fd); hdlerr: return fsalstat(fsal_error, retval); } /* file_unlink * unlink the named file in the directory */ static fsal_status_t file_unlink(struct fsal_obj_handle *dir_hdl, const char *name) { struct vfs_fsal_obj_handle *myself; fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; struct stat stat; int fd; int retval = 0; myself = container_of(dir_hdl, struct vfs_fsal_obj_handle, obj_handle); if (dir_hdl->fsal != dir_hdl->fs->fsal) { LogDebug(COMPONENT_FSAL, "FSAL %s operation for handle belonging to FSAL %s, return EXDEV", dir_hdl->fsal->name, dir_hdl->fs->fsal != NULL ? dir_hdl->fs->fsal->name : "(none)"); retval = EXDEV; fsal_error = posix2fsal_error(retval); goto out; } fd = vfs_fsal_open(myself, O_PATH | O_NOACCESS, &fsal_error); if (fd < 0) { retval = -fd; goto out; } retval = fstatat(fd, name, &stat, AT_SYMLINK_NOFOLLOW); if (retval < 0) { retval = errno; LogDebug(COMPONENT_FSAL, "fstatat %s failed %s", name, strerror(retval)); if (retval == ENOENT) fsal_error = ERR_FSAL_STALE; else fsal_error = posix2fsal_error(retval); goto errout; } fsal_set_credentials(op_ctx->creds); retval = unlinkat(fd, name, (S_ISDIR(stat.st_mode)) ? AT_REMOVEDIR : 0); if (retval < 0) { retval = errno; if (retval == ENOENT) fsal_error = ERR_FSAL_STALE; else fsal_error = posix2fsal_error(retval); } fsal_restore_ganesha_credentials(); errout: close(fd); out: return fsalstat(fsal_error, retval); } /* handle_digest * fill in the opaque f/s file handle part. * we zero the buffer to length first. This MAY already be done above * at which point, remove memset here because the caller is zeroing * the whole struct. */ static fsal_status_t handle_digest(const struct fsal_obj_handle *obj_hdl, fsal_digesttype_t output_type, struct gsh_buffdesc *fh_desc) { const struct vfs_fsal_obj_handle *myself; myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle); if (obj_hdl->fsal != obj_hdl->fs->fsal) { /* Log, but allow digest */ LogDebug(COMPONENT_FSAL, "FSAL %s operation for handle belonging to FSAL %s", obj_hdl->fsal->name, obj_hdl->fs->fsal != NULL ? obj_hdl->fs->fsal->name : "(none)"); } switch (output_type) { case FSAL_DIGEST_NFSV3: case FSAL_DIGEST_NFSV4: if (fh_desc->len < myself->handle->handle_len) { LogMajor(COMPONENT_FSAL, "Space too small for handle. need %d, have %lu", (int) myself->handle->handle_len, fh_desc->len); return fsalstat(ERR_FSAL_TOOSMALL, 0); } memcpy(fh_desc->addr, myself->handle->handle_data, myself->handle->handle_len); break; default: return fsalstat(ERR_FSAL_SERVERFAULT, 0); } fh_desc->len = myself->handle->handle_len; return fsalstat(ERR_FSAL_NO_ERROR, 0); } /** * handle_to_key * return a handle descriptor into the handle in this object handle * @TODO reminder. make sure things like hash keys don't point here * after the handle is released. */ static void handle_to_key(struct fsal_obj_handle *obj_hdl, struct gsh_buffdesc *fh_desc) { struct vfs_fsal_obj_handle *myself; myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle); fh_desc->addr = myself->handle->handle_data; fh_desc->len = myself->handle->handle_len; } /* * release * release our export first so they know we are gone */ static void release(struct fsal_obj_handle *obj_hdl) { struct vfs_fsal_obj_handle *myself; object_file_type_t type = obj_hdl->type; myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle); if (type == REGULAR_FILE) { fsal_status_t st = vfs_close(obj_hdl); if (FSAL_IS_ERROR(st)) { LogCrit(COMPONENT_FSAL, "Could not close hdl 0x%p, error %s(%d)", obj_hdl, strerror(st.minor), st.minor); } } fsal_obj_handle_fini(obj_hdl); if (type == SYMBOLIC_LINK) { if (myself->u.symlink.link_content != NULL) gsh_free(myself->u.symlink.link_content); } else if (vfs_unopenable_type(type)) { if (myself->u.unopenable.name != NULL) gsh_free(myself->u.unopenable.name); if (myself->u.unopenable.dir != NULL) gsh_free(myself->u.unopenable.dir); } gsh_free(myself); } void vfs_handle_ops_init(struct fsal_obj_ops *ops) { ops->release = release; ops->lookup = lookup; ops->readdir = read_dirents; ops->create = create; ops->mkdir = makedir; ops->mknode = makenode; ops->symlink = makesymlink; ops->readlink = readsymlink; ops->test_access = fsal_test_access; ops->getattrs = getattrs; ops->setattrs = setattrs; ops->link = linkfile; ops->rename = renamefile; ops->unlink = file_unlink; ops->open = vfs_open; ops->status = vfs_status; ops->read = vfs_read; ops->write = vfs_write; ops->commit = vfs_commit; ops->lock_op = vfs_lock_op; ops->close = vfs_close; ops->lru_cleanup = vfs_lru_cleanup; ops->handle_digest = handle_digest; ops->handle_to_key = handle_to_key; /* xattr related functions */ ops->list_ext_attrs = vfs_list_ext_attrs; ops->getextattr_id_by_name = vfs_getextattr_id_by_name; ops->getextattr_value_by_name = vfs_getextattr_value_by_name; ops->getextattr_value_by_id = vfs_getextattr_value_by_id; ops->setextattr_value = vfs_setextattr_value; ops->setextattr_value_by_id = vfs_setextattr_value_by_id; ops->getextattr_attrs = vfs_getextattr_attrs; ops->remove_extattr_by_id = vfs_remove_extattr_by_id; ops->remove_extattr_by_name = vfs_remove_extattr_by_name; } /* export methods that create object handles */ /* lookup_path * modeled on old api except we don't stuff attributes. * KISS */ fsal_status_t vfs_lookup_path(struct fsal_export *exp_hdl, const char *path, struct fsal_obj_handle **handle) { int dir_fd = -1; struct stat stat; struct vfs_fsal_obj_handle *hdl; fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; int retval = 0; struct fsal_filesystem *fs; struct fsal_dev__ dev; vfs_file_handle_t *fh = NULL; vfs_alloc_handle(fh); *handle = NULL; /* poison it */ dir_fd = open_dir_by_path_walk(-1, path, &stat); if (dir_fd < 0) { LogCrit(COMPONENT_FSAL, "Could not open directory for path %s", path); retval = -dir_fd; goto errout; } dev = posix2fsal_devt(stat.st_dev); fs = lookup_dev(&dev); if (fs == NULL) { LogInfo(COMPONENT_FSAL, "Could not find file system for path %s", path); retval = ENOENT; goto errout; } if (fs->fsal != exp_hdl->fsal) { LogInfo(COMPONENT_FSAL, "File system for path %s did not belong to FSAL %s", path, exp_hdl->fsal->name); retval = EACCES; goto errout; } LogDebug(COMPONENT_FSAL, "filesystem %s for path %s", fs->path, path); retval = vfs_fd_to_handle(dir_fd, fs, fh); if (retval < 0) { retval = errno; LogCrit(COMPONENT_FSAL, "Could not get handle for path %s, error %s", path, strerror(retval)); goto errout; } /* allocate an obj_handle and fill it up */ hdl = alloc_handle(-1, fh, fs, &stat, NULL, "", exp_hdl); if (hdl == NULL) { retval = ENOMEM; LogCrit(COMPONENT_FSAL, "Could not allocate handle for path %s", path); goto errout; } close(dir_fd); *handle = &hdl->obj_handle; return fsalstat(ERR_FSAL_NO_ERROR, 0); errout: if (dir_fd >= 0) close(dir_fd); fsal_error = posix2fsal_error(retval); return fsalstat(fsal_error, retval); } fsal_status_t vfs_check_handle(struct fsal_export *exp_hdl, struct gsh_buffdesc *hdl_desc, struct fsal_filesystem **fs, vfs_file_handle_t *fh, bool *dummy) { fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; int retval = 0; struct fsal_fsid__ fsid; enum fsid_type fsid_type; *fs = NULL; if (!vfs_valid_handle(hdl_desc)) return fsalstat(ERR_FSAL_BADHANDLE, 0); memcpy(fh->handle_data, hdl_desc->addr, hdl_desc->len); fh->handle_len = hdl_desc->len; *dummy = vfs_is_dummy_handle(fh); retval = vfs_extract_fsid(fh, &fsid_type, &fsid); if (retval == 0) { *fs = lookup_fsid(&fsid, fsid_type); if (*fs == NULL) { LogInfo(COMPONENT_FSAL, "Could not map " "fsid=0x%016"PRIx64".0x%016"PRIx64 " to filesytem", fsid.major, fsid.minor); retval = ESTALE; fsal_error = posix2fsal_error(retval); goto errout; } if (((*fs)->fsal != exp_hdl->fsal) && !(*dummy)) { LogInfo(COMPONENT_FSAL, "fsid=0x%016"PRIx64".0x%016"PRIx64 " in handle not a %s filesystem", fsid.major, fsid.minor, exp_hdl->fsal->name); retval = ESTALE; fsal_error = posix2fsal_error(retval); goto errout; } LogDebug(COMPONENT_FSAL, "Found filesystem %s for handle for FSAL %s", (*fs)->path, (*fs)->fsal != NULL ? (*fs)->fsal->name : "(none)"); } else { LogDebug(COMPONENT_FSAL, "Could not map handle to fsid"); fsal_error = ERR_FSAL_BADHANDLE; goto errout; } errout: return fsalstat(fsal_error, retval); }