From 8265e1210cefdff2a0553dc2a0696bb3cb2396bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Fri, 2 Jun 2006 14:16:13 +0000 Subject: [PATCH] Implemented mandatory file locking, BeOS style. BNode::Lock() and BNode::Unlock() are now working as expected. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17697 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/vfs.h | 1 + src/system/kernel/fs/fd.c | 2 ++ src/system/kernel/fs/vfs.cpp | 61 +++++++++++++++++++++++++++++++----- 3 files changed, 57 insertions(+), 7 deletions(-) diff --git a/headers/private/kernel/vfs.h b/headers/private/kernel/vfs.h index 8e584d97f8..3dbbec26d0 100644 --- a/headers/private/kernel/vfs.h +++ b/headers/private/kernel/vfs.h @@ -98,6 +98,7 @@ status_t vfs_get_fs_node_from_path(mount_id mountID, const char *path, status_t vfs_stat_vnode(void *_vnode, struct stat *stat); status_t vfs_get_vnode_name(void *vnode, char *name, size_t nameSize); status_t vfs_get_cwd(mount_id *_mountID, vnode_id *_vnodeID); +void vfs_unlock_vnode_if_locked(struct file_descriptor *descriptor); status_t vfs_disconnect_vnode(mount_id mountID, vnode_id vnodeID); void vfs_free_unused_vnodes(int32 level); diff --git a/src/system/kernel/fs/fd.c b/src/system/kernel/fs/fd.c index 5fbf3ea840..bbf1c5e5d9 100644 --- a/src/system/kernel/fs/fd.c +++ b/src/system/kernel/fs/fd.c @@ -168,6 +168,8 @@ void close_fd(struct file_descriptor *descriptor) { if (atomic_add(&descriptor->open_count, -1) == 1) { + vfs_unlock_vnode_if_locked(descriptor); + if (descriptor->ops->fd_close) descriptor->ops->fd_close(descriptor); } diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index 02bc3bd359..f8bdeda54a 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -59,7 +59,8 @@ const static uint32 kMaxUnusedVnodes = 8192; // This is the maximum number of unused vnodes that the system - // will keep around. + // will keep around (weak limit, if there is enough memory left, + // they won't get flushed even when hitting that limit). // It may be chosen with respect to the available memory or enhanced // by some timestamp/frequency heurism. @@ -78,6 +79,7 @@ struct vnode { uint8 busy : 1; uint8 unpublished : 1; struct advisory_locking *advisory_locking; + struct file_descriptor *mandatory_locked_by; }; struct vnode_hash_key { @@ -2139,6 +2141,10 @@ get_new_fd(int type, struct fs_mount *mount, struct vnode *vnode, struct file_descriptor *descriptor; int fd; + // if the vnode is locked, we don't allow creating a new file descriptor for it + if (vnode && vnode->mandatory_locked_by != NULL) + return B_BUSY; + descriptor = alloc_fd(); if (!descriptor) return B_NO_MEMORY; @@ -3133,6 +3139,19 @@ vfs_get_vnode_name(void *_vnode, char *name, size_t nameSize) } +/** If the given descriptor locked its vnode, that lock will be released. + */ + +void +vfs_unlock_vnode_if_locked(struct file_descriptor *descriptor) +{ + struct vnode *vnode = fd_vnode(descriptor); + + if (vnode != NULL && vnode->mandatory_locked_by == descriptor) + vnode->mandatory_locked_by = NULL; +} + + /** Closes all file descriptors of the specified I/O context that * don't have the O_CLOEXEC flag set. */ @@ -4191,18 +4210,46 @@ common_sync(int fd, bool kernel) static status_t common_lock_node(int fd, bool kernel) { - // TODO: Implement! - //return EOPNOTSUPP; - return B_OK; + struct file_descriptor *descriptor; + struct vnode *vnode; + + descriptor = get_fd_and_vnode(fd, &vnode, kernel); + if (descriptor == NULL) + return B_FILE_ERROR; + + status_t status = B_OK; + + // We need to set the locking atomically - someone + // else might set one at the same time + if (atomic_test_and_set((vint32 *)&vnode->mandatory_locked_by, + (addr_t)descriptor, NULL) != NULL) + status = B_BUSY; + + put_fd(descriptor); + return status; } static status_t common_unlock_node(int fd, bool kernel) { - // TODO: Implement! - //return EOPNOTSUPP; - return B_OK; + struct file_descriptor *descriptor; + struct vnode *vnode; + + descriptor = get_fd_and_vnode(fd, &vnode, kernel); + if (descriptor == NULL) + return B_FILE_ERROR; + + status_t status = B_OK; + + // We need to set the locking atomically - someone + // else might set one at the same time + if (atomic_test_and_set((vint32 *)&vnode->mandatory_locked_by, + NULL, (addr_t)descriptor) != (int32)descriptor) + status = B_BAD_VALUE; + + put_fd(descriptor); + return status; }