From 419b074b159983b0efc8f39eb68afc71c9812d5d Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 29 Sep 2014 15:48:52 -0600 Subject: [PATCH] Completes the re-implementation of mq_unlink() --- fs/mqueue/mq_close.c | 98 +++++++++++++++++------------ fs/mqueue/mq_open.c | 7 +-- fs/mqueue/mq_unlink.c | 128 +++++++++++++++++++++++--------------- fs/mqueue/mqueue.h | 23 +++++++ fs/semaphore/sem_unlink.c | 2 +- 5 files changed, 161 insertions(+), 97 deletions(-) diff --git a/fs/mqueue/mq_close.c b/fs/mqueue/mq_close.c index 4526f0771c..a83772ee27 100644 --- a/fs/mqueue/mq_close.c +++ b/fs/mqueue/mq_close.c @@ -1,7 +1,7 @@ /**************************************************************************** - * sched/mqueue/mq_close.c + * fs/mqueue/mq_close.c * - * Copyright (C) 2007, 2009, 2013 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2009, 2013-2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -107,7 +107,7 @@ int mq_close(mqd_t mqdes) FAR struct tcb_s *rtcb = sched_self(); FAR struct task_group_s *group = rtcb->group; FAR struct mqueue_inode_s *msgq; - struct inode *inode ; + FAR struct inode *inode; DEBUGASSERT(group); @@ -128,11 +128,6 @@ int mq_close(mqd_t mqdes) msgq = mqdes->msgq; DEBUGASSERT(msgq && msgq->inode); - /* Get the inode from the message queue structure */ - - inode = msgq->inode; - DEBUGASSERT(inode->u.i_mqueue == msgq); - /* Check if the calling task has a notification attached to * the message queue via this mqdes. */ @@ -147,40 +142,65 @@ int mq_close(mqd_t mqdes) } #endif + /* Get the inode from the message queue structure */ + + inode = msgq->inode; + DEBUGASSERT(inode->u.i_mqueue == msgq); + /* 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) - { - /* Free the message queue (and any messages left in it) */ - - mq_msgqfree(msgq); - - /* Release and free the inode container */ - - inode_semgive(); - inode_free(inode->i_child); - kmm_free(inode); - return OK; - } - - /* Deallocate the message descriptor */ - - mq_desfree(mqdes); - - sched_unlock(); - inode_semgive(); + mq_release(inode); } return OK; } + +/**************************************************************************** + * Name: mq_close + * + * Description: + * Release a reference count on a message queue inode. + * + * Parameters: + * inode - The message queue inode + * + * Return Value: + * None + * + ****************************************************************************/ + +void mq_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(); +} diff --git a/fs/mqueue/mq_open.c b/fs/mqueue/mq_open.c index 4731e3a332..15cae3f4ff 100644 --- a/fs/mqueue/mq_open.c +++ b/fs/mqueue/mq_open.c @@ -1,5 +1,5 @@ /**************************************************************************** - * sched/mqueue/mq_open.c + * fs/mqueue/mq_open.c * * Copyright (C) 2007-2009, 2011, 2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt @@ -64,11 +64,6 @@ /**************************************************************************** * Pre-procesor Definitions ****************************************************************************/ -/* Configuration ************************************************************/ - -#ifndef CONFIG_FS_MQUEUE_MPATH -# define CONFIG_FS_MQUEUE_MPATH "/var/mqueue" -#endif /**************************************************************************** * Private Type Declarations diff --git a/fs/mqueue/mq_unlink.c b/fs/mqueue/mq_unlink.c index 3ee6840f70..1e7ae5db35 100644 --- a/fs/mqueue/mq_unlink.c +++ b/fs/mqueue/mq_unlink.c @@ -1,7 +1,7 @@ /************************************************************************ - * sched/mqueue/mq_unlink.c + * fs/mqueue/mq_unlink.c * - * Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2009, 2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -39,10 +39,14 @@ #include -#include +#include #include -#include +#include +#include +#include + +#include "inode/inode.h" #include "mqueue/mqueue.h" /************************************************************************ @@ -88,58 +92,80 @@ * ************************************************************************/ -int mq_unlink(const char *mq_name) +int mq_unlink(FAR const char *mq_name) { - FAR struct mqueue_inode_s *msgq; - irqstate_t saved_state; - int ret = ERROR; + FAR struct inode *inode; + FAR const char *relpath = NULL; + char fullpath[MAX_MQUEUE_PATH]; + int errcode; + int ret; - /* Verify the input values */ + /* Get the full path to the message queue */ - if (mq_name) + snprintf(fullpath, MAX_MQUEUE_PATH, CONFIG_FS_MQUEUE_MPATH "/%s", mq_name); + + /* Get the inode for this message queue. */ + + sched_lock(); + inode = inode_find(fullpath, &relpath); + if (!inode) { - sched_lock(); + /* There is no inode that includes in this path */ - /* Find the named message queue */ - - msgq = mq_findnamed(mq_name); - if (msgq) - { - /* If it is no longer connected, then we can just - * discard the message queue now. - */ - - if (!msgq->nconnect) - { - /* Remove the message queue from the list of all - * message queues - */ - - saved_state = irqsave(); - (void)sq_rem((FAR sq_entry_t*)msgq, &g_msgqueues); - irqrestore(saved_state); - - /* Then deallocate it (and any messages left in it) */ - - mq_msgqfree(msgq); - } - - /* If the message queue is still connected to a message descriptor, - * then mark it for deletion when the last message descriptor is - * closed - */ - - else - { - msgq->unlinked = true; - } - - ret = OK; - } - - sched_unlock(); + errcode = ENOENT; + goto errout; } - return ret; -} + /* Verify that what we found is, indeed, a message queue */ + if (!INODE_IS_MQUEUE(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 message queue + * if that reference count decrements to zero. Since we hold one reference, + * that can only occur if the message queue is not in-use. + */ + + inode_semgive(); + mq_release(inode); + return OK; + +errout_with_semaphore: + inode_semgive(); +errout_with_inode: + inode_release(inode); +errout: + set_errno(errcode); + return ERROR; +} diff --git a/fs/mqueue/mqueue.h b/fs/mqueue/mqueue.h index e183021886..89d5ab700e 100644 --- a/fs/mqueue/mqueue.h +++ b/fs/mqueue/mqueue.h @@ -45,6 +45,13 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ +/* Configuration ************************************************************/ + +#ifndef CONFIG_FS_MQUEUE_MPATH +# define CONFIG_FS_MQUEUE_MPATH "/var/mqueue" +#endif + +/* Sizes of things */ #define MAX_MQUEUE_PATH 64 @@ -68,6 +75,22 @@ extern "C" * Public Function Prototypes ****************************************************************************/ +/**************************************************************************** + * Name: mq_close + * + * Description: + * Release a reference count on a message queue inode. + * + * Parameters: + * inode - The message queue inode + * + * Return Value: + * None + * + ****************************************************************************/ + +void mq_release(FAR struct inode *inode); + #undef EXTERN #ifdef __cplusplus } diff --git a/fs/semaphore/sem_unlink.c b/fs/semaphore/sem_unlink.c index 399614273f..6b10b1a6b9 100644 --- a/fs/semaphore/sem_unlink.c +++ b/fs/semaphore/sem_unlink.c @@ -99,7 +99,7 @@ int sem_unlink(FAR const char *name) { FAR struct inode *inode; - FAR const char *relpath = NULL; + FAR const char *relpath = NULL; char fullpath[MAX_SEMPATH]; int errcode; int ret;