void mq_inode_release(FAR struct inode *inode) { /* Decrement the reference count on the inode */ inode_semtake(); if (inode->i_crefs > 0) { inode->i_crefs--; } /* If the message queue was previously unlinked and the reference count * has decremented to zero, then release the message queue and delete * the inode now. */ if (inode->i_crefs <= 0 && (inode->i_flags & FSNODEFLAG_DELETED) != 0) { FAR struct mqueue_inode_s *msgq = inode->u.i_mqueue; DEBUGASSERT(msgq); /* Free the message queue (and any messages left in it) */ mq_msgqfree(msgq); inode->u.i_mqueue = NULL; /* Release and free the inode container */ inode_semgive(); inode_free(inode->i_child); kmm_free(inode); return; } inode_semgive(); }
void inode_release(FAR struct inode *node) { if (node) { /* Decrement the references of the inode */ inode_semtake(); if (node->i_crefs) { node->i_crefs--; } /* If the subtree was previously deleted and the reference * count has decrement to zero, then delete the inode * now. */ if (node->i_crefs <= 0 && (node->i_flags & FSNODEFLAG_DELETED) != 0) { /* If the inode has been properly unlinked, then the peer pointer * should be NULL. */ inode_semgive(); DEBUGASSERT(node->i_peer == NULL); inode_free(node); } else { inode_semgive(); } } }
void inode_release(FAR struct inode *node) { if (node) { /* Decrement the references of the inode */ inode_semtake(); if (node->i_crefs) { node->i_crefs--; } /* If the subtree was previously deleted and the reference * count has decrement to zero, then delete the inode * now. */ if (node->i_crefs <= 0 && (node->i_flags & FSNODEFLAG_DELETED) != 0) { inode_semgive(); inode_free(node->i_child); kfree(node); } else { inode_semgive(); } } }
int foreach_inode(foreach_inode_t handler, FAR void *arg) { #ifdef ENUM_INODE_ALLOC FAR struct inode_path_s *info; int ret; /* Allocate the mountpoint info structure */ info = (FAR struct inode_path_s *)kmm_malloc(sizeof(struct inode_path_s)); if (!info) { return -ENOMEM; } /* Initialize the info structure */ info->handler = handler; info->arg = arg; info->path[0] = '\0'; /* Start the recursion at the root inode */ inode_semtake(); ret = foreach_inodelevel(root_inode, info); inode_semgive(); /* Free the info structure and return the result */ kmm_free(info); return ret; #else struct inode_path_s info; int ret; /* Initialize the info structure */ info.handler = handler; info.arg = arg; info.path[0] = '\0'; /* Start the recursion at the root inode */ inode_semtake(); ret = foreach_inodelevel(root_inode, &info); inode_semgive(); return ret; #endif }
int register_blockdriver(FAR const char *path, FAR const struct block_operations *bops, mode_t mode, FAR void *priv) { FAR struct inode *node; int ret; /* Insert an inode for the device driver -- we need to hold the inode * semaphore to prevent access to the tree while we this. This is because * we will have a momentarily bad true until we populate the inode with * valid data. */ inode_semtake(); ret = inode_reserve(path, &node); if (ret >= 0) { /* We have it, now populate it with block driver specific information. * NOTE that the initial reference count on the new inode is zero. */ INODE_SET_BLOCK(node); node->u.i_bops = bops; #ifdef CONFIG_FILE_MODE node->i_mode = mode; #endif node->i_private = priv; ret = OK; } inode_semgive(); return ret; }
int register_driver(FAR const char *path, FAR const struct file_operations *fops, mode_t mode, FAR void *priv) { FAR struct inode *node; int ret; /* Insert a dummy node -- we need to hold the inode semaphore because we * will have a momentarily bad structure. */ inode_semtake(); ret = inode_reserve(path, &node); if (ret >= 0) { /* We have it, now populate it with driver specific information. */ INODE_SET_DRIVER(node); node->u.i_ops = fops; #ifdef CONFIG_FILE_MODE node->i_mode = mode; #endif node->i_private = priv; ret = OK; } inode_semgive(); return ret; }
static inline void rewindpseudodir(struct fs_dirent_s *idir) { struct inode *prev; inode_semtake(); /* Reset the position to the beginning */ prev = idir->u.pseudo.fd_next; /* (Save to delete later) */ idir->u.pseudo.fd_next = idir->fd_root; /* The next node to visit */ idir->fd_position = 0; /* Reset position */ /* Increment the reference count on the root=next node. We * should now have two references on the inode. */ idir->fd_root->i_crefs++; inode_semgive(); /* Then release the reference to the old next inode */ if (prev) { inode_release(prev); } }
int register_blockdriver(const char *path, const struct block_operations *bops, mode_t mode, void *priv) { struct inode *node; int ret = -ENOMEM; /* Insert an inode for the device driver -- we need to hold the inode semaphore * to prevent access to the tree while we this. This is because we will have a * momentarily bad true until we populate the inode with valid data. */ inode_semtake(); node = inode_reserve(path); if (node != NULL) { /* We have it, now populate it with block driver specific * information. */ INODE_SET_BLOCK(node); node->u.i_bops = bops; #ifdef CONFIG_FILE_MODE node->i_mode = mode; #endif node->i_private = priv; ret = OK; } inode_semgive(); return ret; }
void inode_addref(FAR struct inode *inode) { if (inode) { inode_semtake(); inode->i_crefs++; inode_semgive(); } }
int unregister_blockdriver(FAR const char *path) { int ret; inode_semtake(); ret = inode_remove(path); inode_semgive(); return ret; }
static inline void seekpseudodir(struct fs_dirent_s *idir, off_t offset) { struct inode *curr; struct inode *prev; off_t pos; /* Determine a starting point for the seek. If the seek * is "forward" from the current position, then we will * start at the current poisition. Otherwise, we will * "rewind" to the root dir. */ if ( offset < idir->fd_position ) { pos = 0; curr = idir->fd_root; } else { pos = idir->fd_position; curr = idir->u.pseudo.fd_next; } /* Traverse the peer list starting at the 'root' of the * the list until we find the node at 'offset". If devices * are being registered and unregistered, then this can * be a very unpredictable operation. */ inode_semtake(); for (; curr && pos != offset; pos++, curr = curr->i_peer); /* Now get the inode to vist next time that readdir() is called */ prev = idir->u.pseudo.fd_next; idir->u.pseudo.fd_next = curr; /* The next node to visit (might be null) */ idir->fd_position = pos; /* Might be beyond the last dirent */ if (curr) { /* Increment the reference count on this next node */ curr->i_crefs++; } inode_semgive(); if (prev) { inode_release(prev); } }
FAR struct inode *inode_find(FAR const char *path, FAR const char **relpath) { FAR struct inode *node; if (!*path || path[0] != '/') { return NULL; } /* Find the node matching the path. If found, * increment the count of references on the node. */ inode_semtake(); node = inode_search(&path, (FAR struct inode**)NULL, (FAR struct inode**)NULL, relpath); if (node) { node->i_crefs++; } inode_semgive(); return node; }
int sem_unlink(FAR const char *name) { FAR struct inode *inode; FAR const char *relpath = NULL; char fullpath[MAX_SEMPATH]; int errcode; int ret; /* Get the full path to the semaphore */ snprintf(fullpath, MAX_SEMPATH, CONFIG_FS_NAMED_SEMPATH "/%s", name); /* Get the inode for this semaphore. */ sched_lock(); inode = inode_find(fullpath, &relpath); if (!inode) { /* There is no inode that includes in this path */ errcode = ENOENT; goto errout; } /* Verify that what we found is, indeed, a semaphore */ if (!INODE_IS_NAMEDSEM(inode)) { errcode = ENXIO; goto errout_with_inode; } /* Refuse to unlink the inode if it has children. I.e., if it is * functioning as a directory and the directory is not empty. */ inode_semtake(); if (inode->i_child != NULL) { errcode = ENOTEMPTY; goto errout_with_semaphore; } /* Remove the old inode from the tree. Because we hold a reference count * on the inode, it will not be deleted now. This will set the * FSNODEFLAG_DELETED bit in the inode flags. */ ret = inode_remove(fullpath); /* inode_remove() should always fail with -EBUSY because we hae a reference * on the inode. -EBUSY means taht the inode was, indeed, unlinked but * thatis could not be freed because there are refrences. */ DEBUGASSERT(ret >= 0 || ret == -EBUSY); UNUSED(ret); /* Now we do not release the reference count in the normal way (by calling * inode release. Rather, we call sem_close(). sem_close will decrement * the reference count on the inode. But it will also free the semaphore * if that reference count decrements to zero. Since we hold one reference, * that can only occur if the semaphore is not in-use. */ inode_semgive(); ret = sem_close((FAR sem_t *)inode->u.i_nsem); sched_unlock(); return ret; errout_with_semaphore: inode_semgive(); errout_with_inode: inode_release(inode); errout: set_errno(errcode); sched_unlock(); return ERROR; }
int mkdir(const char *pathname, mode_t mode) { FAR struct inode *inode; const char *relpath = NULL; int errcode; int ret; /* Find the inode that includes this path */ inode = inode_find(pathname, &relpath); if (inode) { /* An inode was found that includes this path and possibly refers to a * mountpoint. */ #ifndef CONFIG_DISABLE_MOUNTPOINT /* Check if the inode is a valid mountpoint. */ if (!INODE_IS_MOUNTPT(inode) || !inode->u.i_mops) { /* The inode is not a mountpoint */ errcode = ENXIO; goto errout_with_inode; } /* Perform the mkdir operation using the relative path * at the mountpoint. */ if (inode->u.i_mops->mkdir) { ret = inode->u.i_mops->mkdir(inode, relpath, mode); if (ret < 0) { errcode = -ret; goto errout_with_inode; } } else { errcode = ENOSYS; goto errout_with_inode; } /* Release our reference on the inode */ inode_release(inode); #else /* But mountpoints are not supported in this configuration */ errcode = EEXIST; goto errout_with_inode; #endif } #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS /* No inode exists that contains this path. Create a new inode in the * pseudo-filesystem at this location. */ else { /* Create an inode in the pseudo-filesystem at this path */ inode_semtake(); ret = inode_reserve(pathname, &inode); inode_semgive(); if (ret < 0) { errcode = -ret; goto errout; } } #else else {
int mount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data) { #if defined(BDFS_SUPPORT) || defined(NONBDFS_SUPPORT) #ifdef BDFS_SUPPORT FAR struct inode *blkdrvr_inode = NULL; #endif FAR struct inode *mountpt_inode; FAR const struct mountpt_operations *mops; void *fshandle; int errcode; int status; /* Verify required pointer arguments */ DEBUGASSERT(target && filesystemtype); /* Find the specified filesystem. Try the block driver file systems first */ #ifdef BDFS_SUPPORT if ((mops = mount_findfs(g_bdfsmap, filesystemtype)) != NULL) { /* Make sure that a block driver argument was provided */ DEBUGASSERT(source); /* Find the block driver */ status = find_blockdriver(source, mountflags, &blkdrvr_inode); if (status < 0) { fdbg("Failed to find block driver %s\n", source); errcode = -status; goto errout; } } else #endif /* BDFS_SUPPORT */ #ifdef NONBDFS_SUPPORT if ((mops = mount_findfs(g_nonbdfsmap, filesystemtype)) != NULL) { } else #endif /* NONBDFS_SUPPORT */ { fdbg("Failed to find file system %s\n", filesystemtype); errcode = ENODEV; goto errout; } /* Insert a dummy node -- we need to hold the inode semaphore * to do this because we will have a momentarily bad structure. */ inode_semtake(); mountpt_inode = inode_reserve(target); if (!mountpt_inode) { /* inode_reserve can fail for a couple of reasons, but the most likely * one is that the inode already exists. */ fdbg("Failed to reserve inode\n"); errcode = EBUSY; goto errout_with_semaphore; } /* Bind the block driver to an instance of the file system. The file * system returns a reference to some opaque, fs-dependent structure * that encapsulates this binding. */ if (!mops->bind) { /* The filesystem does not support the bind operation ??? */ fdbg("Filesystem does not support bind\n"); errcode = EINVAL; goto errout_with_mountpt; } /* Increment reference count for the reference we pass to the file system */ #ifdef BDFS_SUPPORT #ifdef NONBDFS_SUPPORT if (blkdrvr_inode) #endif { blkdrvr_inode->i_crefs++; } #endif /* On failure, the bind method returns -errorcode */ #ifdef BDFS_SUPPORT status = mops->bind(blkdrvr_inode, data, &fshandle); #else status = mops->bind(NULL, data, &fshandle); #endif if (status != 0) { /* The inode is unhappy with the blkdrvr for some reason. Back out * the count for the reference we failed to pass and exit with an * error. */ fdbg("Bind method failed: %d\n", status); #ifdef BDFS_SUPPORT #ifdef NONBDFS_SUPPORT if (blkdrvr_inode) #endif { blkdrvr_inode->i_crefs--; } #endif errcode = -status; goto errout_with_mountpt; } /* We have it, now populate it with driver specific information. */ INODE_SET_MOUNTPT(mountpt_inode); mountpt_inode->u.i_mops = mops; #ifdef CONFIG_FILE_MODE mountpt_inode->i_mode = mode; #endif mountpt_inode->i_private = fshandle; inode_semgive(); /* We can release our reference to the blkdrver_inode, if the filesystem * wants to retain the blockdriver inode (which it should), then it must * have called inode_addref(). There is one reference on mountpt_inode * that will persist until umount() is called. */ #ifdef BDFS_SUPPORT #ifdef NONBDFS_SUPPORT if (blkdrvr_inode) #endif { inode_release(blkdrvr_inode); } #endif return OK; /* A lot of goto's! But they make the error handling much simpler */ errout_with_mountpt: mountpt_inode->i_crefs = 0; inode_remove(target); inode_semgive(); #ifdef BDFS_SUPPORT #ifdef NONBDFS_SUPPORT if (blkdrvr_inode) #endif { inode_release(blkdrvr_inode); } #endif inode_release(mountpt_inode); goto errout; errout_with_semaphore: inode_semgive(); #ifdef BDFS_SUPPORT #ifdef NONBDFS_SUPPORT if (blkdrvr_inode) #endif { inode_release(blkdrvr_inode); } #endif errout: errno = errcode; return ERROR; #else fdbg("No filesystems enabled\n"); ernno = ENOSYS; return error; #endif /* BDFS_SUPPORT || NONBDFS_SUPPORT */ }
static inline int readpsuedodir(struct fs_dirent_s *idir) { FAR struct inode *prev; /* Check if we are at the end of the list */ if (!idir->u.psuedo.fd_next) { /* End of file and error conditions are not distinguishable * with readdir. Here we return -ENOENT to signal the end * of the directory. */ return -ENOENT; } /* Copy the inode name into the dirent structure */ strncpy(idir->fd_dir.d_name, idir->u.psuedo.fd_next->i_name, NAME_MAX+1); /* If the node has file operations, we will say that it is * a file. */ idir->fd_dir.d_type = 0; if (idir->u.psuedo.fd_next->u.i_ops) { #ifndef CONFIG_DISABLE_MOUNTPOINT if (INODE_IS_BLOCK(idir->u.psuedo.fd_next)) { idir->fd_dir.d_type |= DTYPE_BLK; } if (INODE_IS_MOUNTPT(idir->u.psuedo.fd_next)) { idir->fd_dir.d_type |= DTYPE_DIRECTORY; } else #endif { idir->fd_dir.d_type |= DTYPE_CHR; } } /* If the node has child node(s), then we will say that it * is a directory. NOTE: that the node can be both! */ if (idir->u.psuedo.fd_next->i_child || !idir->u.psuedo.fd_next->u.i_ops) { idir->fd_dir.d_type |= DTYPE_DIRECTORY; } /* Now get the inode to vist next time that readdir() is called */ inode_semtake(); prev = idir->u.psuedo.fd_next; idir->u.psuedo.fd_next = prev->i_peer; /* The next node to visit */ if (idir->u.psuedo.fd_next) { /* Increment the reference count on this next node */ idir->u.psuedo.fd_next->i_crefs++; } inode_semgive(); if (prev) { inode_release(prev); } return OK; }
FAR DIR *opendir(FAR const char *path) { FAR struct inode *inode = NULL; FAR struct fs_dirent_s *dir; FAR const char *relpath; bool isroot = false; int ret; /* If we are given 'nothing' then we will interpret this as * request for the root inode. */ inode_semtake(); if (!path || *path == 0 || strcmp(path, "/") == 0) { inode = root_inode; isroot = true; relpath = NULL; } else { /* We don't know what to do with relative pathes */ if (*path != '/') { ret = -ENOTDIR; goto errout_with_semaphore; } /* Find the node matching the path. */ inode = inode_search(&path, (FAR struct inode**)NULL, (FAR struct inode**)NULL, &relpath); } /* Did we get an inode? */ if (!inode) { /* 'path' is not a does not exist.*/ ret = ENOTDIR; goto errout_with_semaphore; } /* Allocate a type DIR -- which is little more than an inode * container. */ dir = (FAR struct fs_dirent_s *)kuzalloc(sizeof(struct fs_dirent_s)); if (!dir) { /* Insufficient memory to complete the operation.*/ ret = ENOMEM; goto errout_with_semaphore; } /* Populate the DIR structure and return it to the caller. The way that * we do this depends on whenever this is a "normal" pseudo-file-system * inode or a file system mountpoint. */ dir->fd_position = 0; /* This is the position in the read stream */ /* First, handle the special case of the root inode. This must be * special-cased here because the root inode might ALSO be a mountpoint. */ if (isroot) { /* Whatever payload the root inode carries, the root inode is always * a directory inode in the pseudo-file system */ open_pseudodir(inode, dir); } /* Is this a node in the pseudo filesystem? Or a mountpoint? If the node * is the root (isroot == TRUE), then this is a special case. */ #ifndef CONFIG_DISABLE_MOUNTPOINT else if (INODE_IS_MOUNTPT(inode)) { /* Yes, the node is a file system mountpoint */ dir->fd_root = inode; /* Save the inode where we start */ /* Open the directory at the relative path */ ret = open_mountpoint(inode, relpath, dir); if (ret != OK) { goto errout_with_direntry; } } #endif else { /* The node is part of the root pseudo file system. Does the inode * have a child? If so that the child would be the 'root' of a list * of nodes under the directory. */ FAR struct inode *child = inode->i_child; if (child) { /* It looks we have a valid pseudo-filesystem directory node. */ open_pseudodir(child, dir); } else if (!inode->u.i_ops) { /* This is a dangling node with no children and no operations. Set * up to enumerate an empty directory. */ open_emptydir(dir); } else { ret = ENOTDIR; goto errout_with_direntry; } } inode_semgive(); return ((DIR*)dir); /* Nasty goto's make error handling simpler */ errout_with_direntry: kufree(dir); errout_with_semaphore: inode_semgive(); set_errno(ret); return NULL; }
int rmdir(FAR const char *pathname) { FAR struct inode *inode; const char *relpath = NULL; int errcode; /* Get an inode for this file. inode_find() automatically increments the * reference count on the inode if one is found. */ inode = inode_find(pathname, &relpath); if (!inode) { /* There is no inode that includes in this path */ errcode = ENOENT; goto errout; } #ifndef CONFIG_DISABLE_MOUNTPOINT /* Check if the inode is a valid mountpoint. */ if (INODE_IS_MOUNTPT(inode) && inode->u.i_mops) { /* Perform the rmdir operation using the relative path * from the mountpoint. */ if (inode->u.i_mops->rmdir) { int ret = inode->u.i_mops->rmdir(inode, relpath); if (ret < 0) { errcode = -ret; goto errout_with_inode; } } else { errcode = ENOSYS; goto errout_with_inode; } } else #endif #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS /* If this is a "dangling" pseudo-directory node (i.e., it has no operations) * then rmdir should remove the node. */ if (!inode->u.i_ops) { int ret; /* If the directory inode has children, however, then it cannot be * removed. */ if (inode->i_child) { errcode = ENOTEMPTY; goto errout_with_inode; } /* Remove the inode. NOTE: Because we hold a reference count on the * inode, it will not be deleted now. But probably when inode_release() * is called below. inode_remove should return -EBUSY to indicate that * the inode was not deleted now. */ inode_semtake(); ret = inode_remove(pathname); inode_semgive(); if (ret < 0 && ret != -EBUSY) { errcode = -ret; goto errout_with_inode; } } else { errcode = ENOTDIR; goto errout_with_inode; } #else { errcode = ENXIO; goto errout_with_inode; } #endif /* Successfully removed the directory */ inode_release(inode); return OK; errout_with_inode: inode_release(inode); errout: set_errno(errcode); return ERROR; }
mqd_t mq_open(FAR const char *mq_name, int oflags, ...) { FAR struct inode *inode; FAR const char *relpath = NULL; FAR struct mqueue_inode_s *msgq; char fullpath[MAX_MQUEUE_PATH]; va_list ap; struct mq_attr *attr; mqd_t mqdes; mode_t mode; int errcode; int ret; /* Make sure that a non-NULL name is supplied */ if (!mq_name) { errcode = EINVAL; goto errout; } /* Get the full path to the message queue */ snprintf(fullpath, MAX_MQUEUE_PATH, CONFIG_FS_MQUEUE_MPATH "/%s", mq_name); /* Make sure that the check for the existence of the message queue * and the creation of the message queue are atomic with respect to * other processes executing mq_open(). A simple sched_lock() should * be sufficient. */ sched_lock(); /* Get the inode for this mqueue. This should succeed if the message * queue has already been created. */ inode = inode_find(fullpath, &relpath); if (inode) { /* It exists. Verify that the inode is a message queue */ if (!INODE_IS_MQUEUE(inode)) { errcode = ENXIO; goto errout_with_inode; } /* It exists and is a message queue. Check if the caller wanted to * create a new mqueue with this name. */ if ((oflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) { errcode = EEXIST; goto errout_with_inode; } /* Create a message queue descriptor for the current thread */ msgq = inode->u.i_mqueue; mqdes = mq_descreate(NULL, msgq, oflags); if (!mqdes) { errcode = ENOMEM; goto errout_with_inode; } } else { /* The mqueue does not exists. Were we asked to create it? */ if ((oflags & O_CREAT) == 0) { /* The mqueue does not exist and O_CREAT is not set */ errcode = ENOENT; goto errout_with_lock; } /* Create the mqueue. First we have to extract the additional * parameters from the variable argument list. */ va_start(ap, oflags); mode = va_arg(ap, mode_t); attr = va_arg(ap, FAR struct mq_attr*); va_end(ap); /* Create an inode in the pseudo-filesystem at this path */ inode_semtake(); ret = inode_reserve(fullpath, &inode); inode_semgive(); if (ret < 0) { errcode = -ret; goto errout_with_lock; } /* Allocate memory for the new message queue. */ msgq = (FAR struct mqueue_inode_s*)mq_msgqalloc(mode, attr); if (!msgq) { errcode = ENOSPC; goto errout_with_inode; } /* Create a message queue descriptor for the TCB */ mqdes = mq_descreate(NULL, msgq, oflags); if (!mqdes) { errcode = ENOMEM; goto errout_with_msgq; } /* Bind the message queue and the inode structure */ INODE_SET_MQUEUE(inode); inode->u.i_mqueue = msgq; msgq->inode = inode; } sched_unlock(); return mqdes; errout_with_msgq: mq_msgqfree(msgq); inode->u.i_mqueue = NULL; errout_with_inode: inode_release(inode); errout_with_lock: sched_unlock(); errout: set_errno(errcode); return (mqd_t)ERROR; }
int umount(const char *target) { FAR struct inode *mountpt_inode; FAR struct inode *blkdrvr_inode = NULL; int errcode = OK; int status; /* Verify required pointer arguments */ if (!target) { errcode = EFAULT; goto errout; } /* Find the mountpt */ mountpt_inode = inode_find(target, NULL); if (!mountpt_inode) { errcode = ENOENT; goto errout; } /* Verify that the inode is a mountpoint */ if (!INODE_IS_MOUNTPT(mountpt_inode)) { errcode = EINVAL; goto errout_with_mountpt; } /* Unbind the block driver from the file system (destroying any fs * private data. */ if (!mountpt_inode->u.i_mops->unbind) { /* The filesystem does not support the unbind operation ??? */ errcode = EINVAL; goto errout_with_mountpt; } /* The unbind method returns the number of references to the * filesystem (i.e., open files), zero if the unbind was * performed, or a negated error code on a failure. */ inode_semtake(); /* Hold the semaphore through the unbind logic */ status = mountpt_inode->u.i_mops->unbind( mountpt_inode->i_private, &blkdrvr_inode); if (status < 0) { /* The inode is unhappy with the blkdrvr for some reason */ errcode = -status; goto errout_with_semaphore; } else if (status > 0) { errcode = EBUSY; goto errout_with_semaphore; } /* Successfully unbound */ mountpt_inode->i_private = NULL; /* Successfully unbound, remove the mountpoint inode from * the inode tree. The inode will not be deleted yet because * there is still at least reference on it (from the mount) */ status = inode_remove(target); inode_semgive(); /* The return value of -EBUSY is normal (in fact, it should * not be OK) */ if (status != OK && status != -EBUSY) { errcode = -status; goto errout_with_mountpt; } /* Release the mountpoint inode and any block driver inode * returned by the file system unbind above. This should cause * the inode to be deleted (unless there are other references) */ inode_release(mountpt_inode); /* Did the unbind method return a contained block driver */ if (blkdrvr_inode) { inode_release(blkdrvr_inode); } return OK; /* A lot of goto's! But they make the error handling much simpler */ errout_with_semaphore: inode_semgive(); errout_with_mountpt: inode_release(mountpt_inode); if (blkdrvr_inode) { inode_release(blkdrvr_inode); } errout: set_errno(errcode); return ERROR; }
int umount2(FAR const char *target, unsigned int flags) { FAR struct inode *mountpt_inode; FAR struct inode *blkdrvr_inode = NULL; struct inode_search_s desc; int errcode = OK; int ret; /* Verify required pointer arguments */ if (!target) { errcode = EFAULT; goto errout; } /* Find the mountpt */ SETUP_SEARCH(&desc, target, false); ret = inode_find(&desc); if (ret < 0) { errcode = ENOENT; goto errout_with_search; } /* Get the search results */ mountpt_inode = desc.node; DEBUGASSERT(mountpt_inode != NULL); /* Verify that the inode is a mountpoint */ if (!INODE_IS_MOUNTPT(mountpt_inode)) { errcode = EINVAL; goto errout_with_mountpt; } /* Unbind the block driver from the file system (destroying any fs * private data. */ if (!mountpt_inode->u.i_mops->unbind) { /* The filesystem does not support the unbind operation ??? */ errcode = EINVAL; goto errout_with_mountpt; } /* The unbind method returns the number of references to the * filesystem (i.e., open files), zero if the unbind was * performed, or a negated error code on a failure. */ inode_semtake(); /* Hold the semaphore through the unbind logic */ ret = mountpt_inode->u.i_mops->unbind(mountpt_inode->i_private, &blkdrvr_inode, flags); if (ret < 0) { /* The inode is unhappy with the blkdrvr for some reason */ errcode = -ret; goto errout_with_semaphore; } else if (ret > 0) { errcode = EBUSY; goto errout_with_semaphore; } /* Successfully unbound. Convert the mountpoint inode to regular * pseudo-file inode. */ mountpt_inode->i_flags &= ~FSNODEFLAG_TYPE_MASK; mountpt_inode->i_private = NULL; mountpt_inode->u.i_mops = NULL; #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS /* If the node has children, then do not delete it. */ if (mountpt_inode->i_child != NULL) { /* Just decrement the reference count (without deleting it) */ DEBUGASSERT(mountpt_inode->i_crefs > 0); mountpt_inode->i_crefs--; } else #endif { /* Remove the mountpoint inode from the inode tree. The inode will * not be deleted yet because there is still at least reference on * it (from the mount) */ ret = inode_remove(target); inode_semgive(); /* The return value of -EBUSY is normal (in fact, it should * not be OK) */ if (ret != OK && ret != -EBUSY) { errcode = -ret; goto errout_with_mountpt; } /* Release the mountpoint inode and any block driver inode * returned by the file system unbind above. This should cause * the inode to be deleted (unless there are other references) */ inode_release(mountpt_inode); } /* Did the unbind method return a contained block driver */ if (blkdrvr_inode) { inode_release(blkdrvr_inode); } RELEASE_SEARCH(&desc); return OK; /* A lot of goto's! But they make the error handling much simpler */ errout_with_semaphore: inode_semgive(); errout_with_mountpt: inode_release(mountpt_inode); if (blkdrvr_inode) { inode_release(blkdrvr_inode); } errout_with_search: RELEASE_SEARCH(&desc); errout: set_errno(errcode); return ERROR; }
int unlink(FAR const char *pathname) { FAR struct inode *inode; const char *relpath = NULL; int errcode; int ret; /* Get an inode for this file */ inode = inode_find(pathname, &relpath); if (!inode) { /* There is no inode that includes in this path */ errcode = ENOENT; goto errout; } #ifndef CONFIG_DISABLE_MOUNTPOINT /* Check if the inode is a valid mountpoint. */ if (INODE_IS_MOUNTPT(inode) && inode->u.i_mops) { /* Perform the unlink operation using the relative path at the * mountpoint. */ if (inode->u.i_mops->unlink) { ret = inode->u.i_mops->unlink(inode, relpath); if (ret < 0) { errcode = -ret; goto errout_with_inode; } } else { errcode = ENOSYS; goto errout_with_inode; } } else #endif #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS /* If this is a "dangling" pseudo-file node (i.e., it has operations) then rm * should remove the node. */ if (!INODE_IS_SPECIAL(inode) && inode->u.i_ops) { /* If this is a pseudo-file node (i.e., it has no operations) * then rmdir should remove the node. */ if (inode->u.i_ops) { inode_semtake(); /* Refuse to unlink the inode if it has children. I.e., if it is * functioning as a directory and the directory is not empty. */ if (inode->i_child != NULL) { errcode = ENOTEMPTY; inode_semgive(); goto errout_with_inode; } /* Remove the old inode. Because we hold a reference count on the * inode, it will not be deleted now. It will be deleted when all * of the references to to the inode have been released (perhaps * when inode_release() is called below). inode_remove() will * return -EBUSY to indicate that the inode was not deleted now. */ ret = inode_remove(pathname); inode_semgive(); if (ret < 0 && ret != -EBUSY) { errcode = -ret; goto errout_with_inode; } } else { errcode = EISDIR; goto errout_with_inode; } } else #endif { errcode = ENXIO; goto errout_with_inode; } /* Successfully unlinked */ inode_release(inode); return OK; errout_with_inode: inode_release(inode); errout: set_errno(errcode); return ERROR; }
int rename(FAR const char *oldpath, FAR const char *newpath) { FAR struct inode *oldinode; FAR struct inode *newinode; const char *oldrelpath = NULL; #ifndef CONFIG_DISABLE_MOUNTPOINT const char *newrelpath = NULL; #endif int errcode; int ret; /* Ignore paths that are interpreted as the root directory which has no name * and cannot be moved */ if (!oldpath || *oldpath == '\0' || oldpath[0] != '/' || !newpath || *newpath == '\0' || newpath[0] != '/') { return -EINVAL; } /* Get an inode that includes the oldpath */ oldinode = inode_find(oldpath, &oldrelpath); if (!oldinode) { /* There is no inode that includes in this path */ errcode = ENOENT; goto errout; } #ifndef CONFIG_DISABLE_MOUNTPOINT /* Verify that the old inode is a valid mountpoint. */ if (INODE_IS_MOUNTPT(oldinode) && oldinode->u.i_mops) { /* Get an inode for the new relpath -- it should like on the same * mountpoint */ newinode = inode_find(newpath, &newrelpath); if (!newinode) { /* There is no mountpoint that includes in this path */ errcode = ENOENT; goto errout_with_oldinode; } /* Verify that the two paths lie on the same mountpoint inode */ if (oldinode != newinode) { errcode = EXDEV; goto errout_with_newinode; } /* Perform the rename operation using the relative paths * at the common mountpoint. */ if (oldinode->u.i_mops->rename) { ret = oldinode->u.i_mops->rename(oldinode, oldrelpath, newrelpath); if (ret < 0) { errcode = -ret; goto errout_with_newinode; } } else { errcode = ENOSYS; goto errout_with_newinode; } /* Successfully renamed */ inode_release(newinode); } else #endif #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS { /* Create a new, empty inode at the destination location. * NOTE that the new inode will be created with a reference count * of zero. */ inode_semtake(); ret = inode_reserve(newpath, &newinode); if (ret < 0) { /* It is an error if a node at newpath already exists in the tree * OR if we fail to allocate memory for the new inode (and possibly * any new intermediate path segments). */ inode_semgive(); errcode = EEXIST; goto errout_with_oldinode; } /* Copy the inode state from the old inode to the newly allocated inode */ newinode->i_child = oldinode->i_child; /* Link to lower level inode */ newinode->i_flags = oldinode->i_flags; /* Flags for inode */ newinode->u.i_ops = oldinode->u.i_ops; /* Inode operations */ #ifdef CONFIG_FILE_MODE newinode->i_mode = oldinode->i_mode; /* Access mode flags */ #endif newinode->i_private = oldinode->i_private; /* Per inode driver private data */ /* We now have two copies of the inode. One with a reference count of * zero (the new one), and one that may have multiple references * including one by this logic (the old one) * * Remove the old inode. Because we hold a reference count on the * inode, it will not be deleted now. It will be deleted when all of * the references to to the inode have been released (perhaps when * inode_release() is called below). inode_remove() should return * -EBUSY to indicate that the inode was not deleted now. */ ret = inode_remove(oldpath); if (ret < 0 && ret != -EBUSY) { /* Remove the new node we just recreated */ (void)inode_remove(newpath); inode_semgive(); errcode = -ret; goto errout_with_oldinode; } /* Remove all of the children from the unlinked inode */ oldinode->i_child = NULL; inode_semgive(); } #else { errcode = ENXIO; goto errout; } #endif /* Successfully renamed */ inode_release(oldinode); return OK; #ifndef CONFIG_DISABLE_MOUNTPOINT errout_with_newinode: inode_release(newinode); #endif errout_with_oldinode: inode_release(oldinode); errout: set_errno(errcode); return ERROR; }