Fix permission management for IPC and also for EXT2.
This commit is contained in:
+18
-13
@@ -17,14 +17,15 @@
|
||||
/// @brief List of commands for semctl function.
|
||||
/// @{
|
||||
|
||||
#define GETPID 11 ///< Get sempid.
|
||||
#define GETVAL 12 ///< Get semval.
|
||||
#define GETALL 13 ///< Get all semval's.
|
||||
#define GETNCNT 14 ///< Get semncnt.
|
||||
#define GETZCNT 15 ///< Get semzcnt.
|
||||
#define SETVAL 16 ///< Set semval.
|
||||
#define SETALL 17 ///< Set all semval's.
|
||||
#define GETNSEMS 19 ///< Get sem_nsems
|
||||
#define GETPID 11 ///< Get sempid.
|
||||
#define GETVAL 12 ///< Get semval.
|
||||
#define GETALL 13 ///< Get all semval's.
|
||||
#define GETNCNT 14 ///< Get semncnt.
|
||||
#define GETZCNT 15 ///< Get semzcnt.
|
||||
#define SETVAL 16 ///< Set semval.
|
||||
#define SETALL 17 ///< Set all semval's.
|
||||
#define SEM_STAT 18 ///< Return a semid_ds structure.
|
||||
#define SEM_INFO 19 ///< Return a seminfo structure.
|
||||
|
||||
/// }@
|
||||
|
||||
@@ -44,12 +45,12 @@ union semun {
|
||||
|
||||
/// @brief Single Semaphore.
|
||||
struct sem {
|
||||
/// @brief Semaphore Value.
|
||||
unsigned short sem_val;
|
||||
/// @brief Process ID of the last operation.
|
||||
pid_t sem_pid;
|
||||
/// @brief Number of processes waiting of semaphore.
|
||||
//unsigned short semncnt;
|
||||
/// @brief Semaphore Value.
|
||||
unsigned short sem_val;
|
||||
/// @brief Number of processes waiting for the semaphore.
|
||||
unsigned short sem_ncnt;
|
||||
/// @brief Number of processes waiting for the value to become 0
|
||||
unsigned short sem_zcnt;
|
||||
};
|
||||
@@ -63,7 +64,7 @@ struct semid_ds {
|
||||
/// @brief Last change time.
|
||||
time_t sem_ctime;
|
||||
/// @brief Number of semaphores in set.
|
||||
unsigned long sem_nsems;
|
||||
unsigned short sem_nsems;
|
||||
};
|
||||
|
||||
/// @brief Buffer to use with the semaphore IPC.
|
||||
@@ -78,6 +79,10 @@ struct sembuf {
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/// @brief Initializes the semaphore system.
|
||||
/// @return int
|
||||
int sem_init();
|
||||
|
||||
/// @brief Get a System V semaphore set identifier.
|
||||
/// @param key can be used either to obtain the identifier of a previously
|
||||
/// created semaphore set, or to create a new set.
|
||||
|
||||
+69
-59
@@ -4,10 +4,10 @@
|
||||
/// See LICENSE.md for details.
|
||||
|
||||
// Setup the logging for this file (do this before any other include).
|
||||
#include "sys/kernel_levels.h" // Include kernel log levels.
|
||||
#define __DEBUG_HEADER__ "[EXT2 ]" ///< Change header.
|
||||
#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level.
|
||||
#include "io/debug.h" // Include debugging functions.
|
||||
#include "sys/kernel_levels.h" // Include kernel log levels.
|
||||
#define __DEBUG_HEADER__ "[EXT2 ]" ///< Change header.
|
||||
#define __DEBUG_LEVEL__ LOGLEVEL_DEBUG ///< Set log level.
|
||||
#include "io/debug.h" // Include debugging functions.
|
||||
|
||||
#include "fs/ext2.h"
|
||||
#include "process/scheduler.h"
|
||||
@@ -478,46 +478,52 @@ static const char *time_to_string(uint32_t time)
|
||||
return s;
|
||||
}
|
||||
|
||||
static inline int __ext2_valid_permissions(
|
||||
const task_struct *task,
|
||||
const mode_t mask,
|
||||
const uid_t uid,
|
||||
const gid_t gid,
|
||||
const int usr,
|
||||
const int grp,
|
||||
const int oth)
|
||||
{
|
||||
// The task is the owner.
|
||||
if ((mask & usr) && (task->uid == uid))
|
||||
return 1;
|
||||
// The task belongs to the correct group.
|
||||
if ((mask & grp) && (task->gid == gid))
|
||||
return 1;
|
||||
// The task is not the owner and does not belong to the correct group.
|
||||
if ((mask & oth) && (task->uid != uid) && (task->gid != gid))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief Checks if the requests in flags are valid.
|
||||
/// @param flags the flags to check.
|
||||
/// @param mask the mask to check against.
|
||||
/// @param uid the uid of the owner.
|
||||
/// @param gid the gid of the owner.
|
||||
/// @return true on success, false otherwise.
|
||||
static bool_t ext2_valid_permissions(int flags, mode_t mask, uid_t uid, gid_t gid)
|
||||
/// @return 1 on success, 0 otherwise.
|
||||
static int ext2_valid_permissions(int flags, mode_t mask, uid_t uid, gid_t gid)
|
||||
{
|
||||
// Check the permissions.
|
||||
task_struct *task = scheduler_get_current_process();
|
||||
if (task == NULL) {
|
||||
pr_warning("Failed to get the current running process, assuming we are booting.\n");
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
// The current task is the owner.
|
||||
if (task->uid == uid) {
|
||||
if (!bitmask_check(mask, S_IRUSR))
|
||||
return false;
|
||||
if (bitmask_check(flags, O_WRONLY) && !bitmask_check(mask, S_IWUSR))
|
||||
return false;
|
||||
if (bitmask_check(flags, O_RDWR) && (!bitmask_check(mask, S_IRUSR) || !bitmask_check(mask, S_IWUSR)))
|
||||
return false;
|
||||
}
|
||||
if (task->gid == gid) {
|
||||
if (!bitmask_check(mask, S_IRGRP))
|
||||
return false;
|
||||
if (bitmask_check(flags, O_WRONLY) && !bitmask_check(mask, S_IWGRP))
|
||||
return false;
|
||||
if (bitmask_check(flags, O_RDWR) && (!bitmask_check(mask, S_IRGRP) || !bitmask_check(mask, S_IWGRP)))
|
||||
return false;
|
||||
}
|
||||
if ((task->uid != uid) && (task->gid != gid)) {
|
||||
if (!bitmask_check(mask, S_IROTH))
|
||||
return false;
|
||||
if (bitmask_check(flags, O_WRONLY) && !bitmask_check(mask, S_IWOTH))
|
||||
return false;
|
||||
if (bitmask_check(flags, O_RDWR) && (!bitmask_check(mask, S_IROTH) || !bitmask_check(mask, S_IWOTH)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
// Init, and all root processes have full permissions.
|
||||
if ((task->pid == 0) || (task->uid == 0) || (task->gid == 0))
|
||||
return 1;
|
||||
|
||||
if (((flags & O_RDONLY) == O_RDONLY) && __ext2_valid_permissions(task, mask, uid, gid, S_IRUSR, S_IRGRP, S_IROTH))
|
||||
return 1;
|
||||
if (((flags & O_WRONLY) == O_WRONLY) && __ext2_valid_permissions(task, mask, uid, gid, S_IWUSR, S_IWGRP, S_IWOTH))
|
||||
return 1;
|
||||
if (((flags & O_RDWR) == O_RDWR) && __ext2_valid_permissions(task, mask, uid, gid, S_IRUSR | S_IWUSR, S_IRGRP | S_IWGRP, S_IROTH | S_IWOTH))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief Dumps on debugging output the superblock.
|
||||
@@ -756,12 +762,12 @@ static void ext2_set_bitmap_bit(uint8_t *buffer, uint32_t linear_index, ext2_blo
|
||||
/// @param fs the ext2 filesystem structure.
|
||||
/// @param cache the cache from which we read the bgdt data.
|
||||
/// @param linear_index the output variable where we store the linear indes to the free inode.
|
||||
/// @return true if we found a free inode, false otherwise.
|
||||
static inline bool_t ext2_find_free_inode_in_group(
|
||||
/// @return 1 if we found a free inode, 0 otherwise.
|
||||
static inline int ext2_find_free_inode_in_group(
|
||||
ext2_filesystem_t *fs,
|
||||
uint8_t *cache,
|
||||
uint32_t *linear_index,
|
||||
bool_t skip_reserved)
|
||||
int skip_reserved)
|
||||
{
|
||||
for ((*linear_index) = 0; (*linear_index) < fs->superblock.inodes_per_group; ++(*linear_index)) {
|
||||
// If we need to skip the reserved inodes, we skip the round if the
|
||||
@@ -770,9 +776,9 @@ static inline bool_t ext2_find_free_inode_in_group(
|
||||
continue;
|
||||
// Check if the entry is free.
|
||||
if (!ext2_check_bitmap_bit(cache, *linear_index))
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief Searches for a free inode inside the Block Group Descriptor Table (BGDT).
|
||||
@@ -780,8 +786,8 @@ static inline bool_t ext2_find_free_inode_in_group(
|
||||
/// @param cache the cache from which we read the bgdt data.
|
||||
/// @param group_index the output variable where we store the group index.
|
||||
/// @param linear_index the output variable where we store the linear indes to the free inode.
|
||||
/// @return true if we found a free inode, false otherwise.
|
||||
static inline bool_t ext2_find_free_inode(
|
||||
/// @return 1 if we found a free inode, 0 otherwise.
|
||||
static inline int ext2_find_free_inode(
|
||||
ext2_filesystem_t *fs,
|
||||
uint8_t *cache,
|
||||
uint32_t *group_index,
|
||||
@@ -795,7 +801,7 @@ static inline bool_t ext2_find_free_inode(
|
||||
// Find the first free inode. We need to ask to skip reserved inodes,
|
||||
// only if we are in group 0.
|
||||
if (ext2_find_free_inode_in_group(fs, cache, linear_index, (*group_index) == 0))
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
// Get the group and bit index of the first free block.
|
||||
for ((*group_index) = 0; (*group_index) < fs->block_groups_count; ++(*group_index)) {
|
||||
@@ -804,15 +810,15 @@ static inline bool_t ext2_find_free_inode(
|
||||
// Read the block bitmap.
|
||||
if (ext2_read_block(fs, fs->block_groups[(*group_index)].inode_bitmap, cache) < 0) {
|
||||
pr_err("Failed to read the inode bitmap for group `%d`.\n", (*group_index));
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
// Find the first free inode. We need to ask to skip reserved
|
||||
// inodes, only if we are in group 0.
|
||||
if (ext2_find_free_inode_in_group(fs, cache, linear_index, (*group_index) == 0))
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief Searches for a free block inside the group data loaded inside the cache.
|
||||
@@ -820,23 +826,23 @@ static inline bool_t ext2_find_free_inode(
|
||||
/// @param cache the cache from which we read the bgdt data.
|
||||
/// @param group_index the output variable where we store the group index.
|
||||
/// @param linear_index the output variable where we store the linear indes to the free block.
|
||||
/// @return true if we found a free block, false otherwise.
|
||||
static inline bool_t ext2_find_free_block_in_group(ext2_filesystem_t *fs, uint8_t *cache, uint32_t *linear_index)
|
||||
/// @return 1 if we found a free block, 0 otherwise.
|
||||
static inline int ext2_find_free_block_in_group(ext2_filesystem_t *fs, uint8_t *cache, uint32_t *linear_index)
|
||||
{
|
||||
for ((*linear_index) = 0; (*linear_index) < fs->superblock.blocks_per_group; ++(*linear_index)) {
|
||||
// Check if the entry is free.
|
||||
if (!ext2_check_bitmap_bit(cache, *linear_index))
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief Searches for a free block.
|
||||
/// @param fs the ext2 filesystem structure.
|
||||
/// @param cache the cache from which we read the bgdt data.
|
||||
/// @param linear_index the output variable where we store the linear indes to the free block.
|
||||
/// @return true if we found a free block, false otherwise.
|
||||
static inline bool_t ext2_find_free_block(
|
||||
/// @return 1 if we found a free block, 0 otherwise.
|
||||
static inline int ext2_find_free_block(
|
||||
ext2_filesystem_t *fs,
|
||||
uint8_t *cache,
|
||||
uint32_t *group_index,
|
||||
@@ -849,14 +855,14 @@ static inline bool_t ext2_find_free_block(
|
||||
// Read the block bitmap.
|
||||
if (ext2_read_block(fs, fs->block_groups[(*group_index)].block_bitmap, cache) < 0) {
|
||||
pr_err("Failed to read the block bitmap for group `%d`.\n", (*group_index));
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
// Find the first free block.
|
||||
if (ext2_find_free_block_in_group(fs, cache, linear_index))
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief Reads the superblock from the block device associated with this filesystem.
|
||||
@@ -1614,8 +1620,8 @@ ext2_dirent_t *ext2_direntry_iterator_get(ext2_direntry_iterator_t *iterator)
|
||||
|
||||
/// @brief Check if the iterator is valid.
|
||||
/// @param iterator the iterator to check.
|
||||
/// @return true if valid, false otherwise.
|
||||
bool_t ext2_direntry_iterator_valid(ext2_direntry_iterator_t *iterator)
|
||||
/// @return 1 if valid, 0 otherwise.
|
||||
int ext2_direntry_iterator_valid(ext2_direntry_iterator_t *iterator)
|
||||
{
|
||||
return iterator->direntry != NULL;
|
||||
}
|
||||
@@ -1679,14 +1685,14 @@ void ext2_direntry_iterator_next(ext2_direntry_iterator_t *iterator)
|
||||
iterator->direntry = ext2_direntry_iterator_get(iterator);
|
||||
}
|
||||
|
||||
static inline bool_t ext2_directory_is_empty(ext2_filesystem_t *fs, uint8_t *cache, ext2_inode_t *inode)
|
||||
static inline int ext2_directory_is_empty(ext2_filesystem_t *fs, uint8_t *cache, ext2_inode_t *inode)
|
||||
{
|
||||
ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, inode);
|
||||
for (; ext2_direntry_iterator_valid(&it); ext2_direntry_iterator_next(&it)) {
|
||||
if (it.direntry->inode != 0)
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@@ -2344,6 +2350,7 @@ static vfs_file_t *ext2_open(const char *path, int flags, mode_t mode)
|
||||
pr_err("A file or directory already exists at `%s` (O_CREAT | O_EXCL).\n", absolute_path);
|
||||
return NULL;
|
||||
} else if (bitmask_check(flags, O_DIRECTORY) && (direntry.file_type != ext2_file_type_directory)) {
|
||||
pr_err("That is not a directory.");
|
||||
errno = ENOTDIR;
|
||||
return NULL;
|
||||
}
|
||||
@@ -2366,7 +2373,10 @@ static vfs_file_t *ext2_open(const char *path, int flags, mode_t mode)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ext2_dump_inode(&inode);
|
||||
|
||||
if (!ext2_valid_permissions(flags, inode.mode, inode.uid, inode.gid)) {
|
||||
pr_err("Task does not have access permission.\n");
|
||||
errno = EACCES;
|
||||
return NULL;
|
||||
}
|
||||
@@ -2664,7 +2674,7 @@ static ssize_t ext2_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_
|
||||
return -ENOENT;
|
||||
}
|
||||
uint32_t current = 0;
|
||||
ssize_t written = 0;
|
||||
ssize_t written = 0;
|
||||
// Allocate the cache.
|
||||
uint8_t *cache = kmem_cache_alloc(fs->ext2_buffer_cache, GFP_KERNEL);
|
||||
// Clean the cache.
|
||||
|
||||
+4
-4
@@ -4,10 +4,10 @@
|
||||
/// See LICENSE.md for details.
|
||||
|
||||
// Setup the logging for this file (do this before any other include).
|
||||
#include "sys/kernel_levels.h" // Include kernel log levels.
|
||||
#define __DEBUG_HEADER__ "[VFS ]" ///< Change header.
|
||||
#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level.
|
||||
#include "io/debug.h" // Include debugging functions.
|
||||
#include "sys/kernel_levels.h" // Include kernel log levels.
|
||||
#define __DEBUG_HEADER__ "[VFS ]" ///< Change header.
|
||||
#define __DEBUG_LEVEL__ LOGLEVEL_DEBUG ///< Set log level.
|
||||
#include "io/debug.h" // Include debugging functions.
|
||||
|
||||
#include "fs/vfs.h"
|
||||
#include "process/scheduler.h"
|
||||
|
||||
+18
-16
@@ -11,35 +11,31 @@
|
||||
#include "fcntl.h"
|
||||
|
||||
int ipc_check_perm(
|
||||
task_struct *task,
|
||||
struct ipc_perm *perm,
|
||||
int usr,
|
||||
int grp,
|
||||
int oth)
|
||||
{
|
||||
// Get the calling task.
|
||||
task_struct *task = scheduler_get_current_process();
|
||||
assert(task && "Failed to get the current running process.");
|
||||
assert(perm && "Received a NULL ipc_perm.");
|
||||
// Init process has unlimited power.
|
||||
if (task->pid == 0)
|
||||
return 1;
|
||||
assert(task && "Received a NULL task.");
|
||||
assert(perm && "Received a NULL perm.");
|
||||
int check_parent = (perm->key < 0) && task->parent && (task->parent->pid != 0);
|
||||
if ((perm->mode & usr)) {
|
||||
if (perm->mode & usr) {
|
||||
if ((perm->uid == task->uid) || (perm->cuid == task->uid))
|
||||
return 1;
|
||||
if (check_parent && ((perm->uid == task->parent->uid) || (perm->cuid == task->parent->uid)))
|
||||
return 1;
|
||||
}
|
||||
if ((perm->mode & grp)) {
|
||||
if (perm->mode & grp) {
|
||||
if ((perm->gid == task->gid) || (perm->cgid == task->gid))
|
||||
return 1;
|
||||
if (check_parent && ((perm->gid == task->parent->gid) || (perm->cgid == task->parent->gid)))
|
||||
return 1;
|
||||
}
|
||||
if ((perm->mode & oth)) {
|
||||
if (check_parent && ((perm->uid == task->parent->uid) || (perm->cuid == task->parent->uid)))
|
||||
if (perm->mode & oth) {
|
||||
if (check_parent && ((perm->uid != task->parent->uid) || (perm->cuid != task->parent->uid)))
|
||||
return 1;
|
||||
if (check_parent && ((perm->gid == task->parent->gid) || (perm->cgid == task->parent->gid)))
|
||||
if (check_parent && ((perm->gid != task->parent->gid) || (perm->cgid != task->parent->gid)))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -47,12 +43,18 @@ int ipc_check_perm(
|
||||
|
||||
int ipc_valid_permissions(int flags, struct ipc_perm *perm)
|
||||
{
|
||||
// If the key is negative, it means it was a private key.
|
||||
if ((flags & O_RDONLY) && ipc_check_perm(perm, S_IRUSR, S_IRGRP, S_IROTH))
|
||||
// Get the calling task.
|
||||
task_struct *task = scheduler_get_current_process();
|
||||
assert(task && "Failed to get the current running process.");
|
||||
// Init, and all root processes have full permissions.
|
||||
if ((task->pid == 0) || (task->uid == 0) || (task->gid == 0))
|
||||
return 1;
|
||||
if ((flags & O_WRONLY) && ipc_check_perm(perm, S_IWUSR, S_IWGRP, S_IWOTH))
|
||||
// Check permissions.
|
||||
if (((flags & O_RDONLY) == O_RDONLY) && ipc_check_perm(task, perm, S_IRUSR, S_IRGRP, S_IROTH))
|
||||
return 1;
|
||||
if ((flags & O_RDWR) && ipc_check_perm(perm, S_IRUSR | S_IWUSR, S_IRGRP | S_IWGRP, S_IROTH | S_IWOTH))
|
||||
if (((flags & O_WRONLY) == O_WRONLY) && ipc_check_perm(task, perm, S_IWUSR, S_IWGRP, S_IWOTH))
|
||||
return 1;
|
||||
if (((flags & O_RDWR) == O_RDWR) && ipc_check_perm(task, perm, S_IRUSR | S_IWUSR, S_IRGRP | S_IWGRP, S_IROTH | S_IWOTH))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
+242
-251
@@ -52,8 +52,9 @@
|
||||
#include "fcntl.h"
|
||||
|
||||
///@brief A value to compute the semid value.
|
||||
int semid_assign = 0;
|
||||
int __sem_id = 0;
|
||||
|
||||
/// @brief Semaphore management structure.
|
||||
typedef struct {
|
||||
/// @brief Semaphore ID associated to the semaphore set.
|
||||
int id;
|
||||
@@ -61,14 +62,12 @@ typedef struct {
|
||||
struct semid_ds semid;
|
||||
/// @brief List of all the semaphores.
|
||||
struct sem *sems;
|
||||
/// Reference inside the list of semaphore management structures.
|
||||
list_head list;
|
||||
} sem_info_t;
|
||||
|
||||
/// @brief List of all current active semaphores.
|
||||
list_t semaphores_list = {
|
||||
.head = NULL,
|
||||
.tail = NULL,
|
||||
.size = 0
|
||||
};
|
||||
list_head semaphores_list;
|
||||
|
||||
// ============================================================================
|
||||
// KEY GENERATION (Private)
|
||||
@@ -93,83 +92,50 @@ static inline int ipc_sem_rand()
|
||||
// MEMORY MANAGEMENT (Private)
|
||||
// ============================================================================
|
||||
|
||||
/// @brief Allocates the memory for an array of semaphores.
|
||||
/// @param nsems number of semaphores in the array.
|
||||
/// @return a pointer to the allocated array of semaphores.
|
||||
static inline struct sem *__sem_set_alloc(int nsems)
|
||||
/// @brief Allocates the memory for semaphore management structure.
|
||||
/// @param key IPC_KEY associated with the set of semaphores.
|
||||
/// @param nsems number of semaphores to initialize.
|
||||
/// @param semflg flags used to create the set of semaphores.
|
||||
/// @return a pointer to the allocated semaphore management structure.
|
||||
static inline sem_info_t *__sem_info_alloc(key_t key, int nsems, int semflg)
|
||||
{
|
||||
// Allocate the memory.
|
||||
struct sem *ptr = (struct sem *)kmalloc(sizeof(struct sem) * nsems);
|
||||
sem_info_t *sem_info = (sem_info_t *)kmalloc(sizeof(sem_info_t));
|
||||
// Check the allocated memory.
|
||||
assert(ptr && "Failed to allocate memory for the array of semaphores.");
|
||||
assert(sem_info && "Failed to allocate memory for a semaphore management structure.");
|
||||
// Clean the memory.
|
||||
memset(ptr, 0, sizeof(struct sem));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/// @brief Frees the memory of an array of semaphores.
|
||||
/// @param ptr the pointer to the array of semaphores.
|
||||
static inline void __sem_set_dealloc(struct sem *ptr)
|
||||
{
|
||||
assert(ptr && "Received a NULL pointer.");
|
||||
kfree(ptr);
|
||||
}
|
||||
|
||||
/// @brief Initializes a single semaphore.
|
||||
/// @param ptr the pointer to the single semaphore.
|
||||
static inline void __sem_init(struct sem *ptr)
|
||||
{
|
||||
ptr->sem_val = 0;
|
||||
ptr->sem_pid = sys_getpid();
|
||||
ptr->sem_zcnt = 0;
|
||||
}
|
||||
|
||||
/// @brief Allocates the memory for a semid structure.
|
||||
/// @return a pointer to the allocated semid structure.
|
||||
static inline struct sem_info_t *__sem_info_alloc(int nsems)
|
||||
{
|
||||
// Allocate the memory.
|
||||
sem_info_t *ptr = (sem_info_t *)kmalloc(sizeof(sem_info_t));
|
||||
// Check the allocated memory.
|
||||
assert(ptr && "Failed to allocate memory for a semid structure.");
|
||||
// Clean the memory.
|
||||
memset(ptr, 0, sizeof(sem_info_t));
|
||||
memset(sem_info, 0, sizeof(sem_info_t));
|
||||
// Allocate the memory for semaphores.
|
||||
ptr->sems = (struct sem *)kmalloc(sizeof(struct sem) * nsems);
|
||||
sem_info->sems = (struct sem *)kmalloc(sizeof(struct sem) * nsems);
|
||||
// Check the allocated memory.
|
||||
assert(ptr && "Failed to allocate memory for a semid structure.");
|
||||
assert(sem_info->sems && "Failed to allocate memory for a set of semaphores.");
|
||||
// Clean the memory.
|
||||
memset(ptr, 0, sizeof(sem_info_t));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/// @brief Frees the memory of a semid structure.
|
||||
/// @param ptr pointer to the semid structure.
|
||||
static inline void __sem_info_dealloc(struct semid_ds *ptr)
|
||||
{
|
||||
assert(ptr && "Received a NULL pointer.");
|
||||
// Deallocate the array of semaphores.
|
||||
__sem_set_dealloc(ptr->sems);
|
||||
// Deallocate the semid memory.
|
||||
kfree(ptr);
|
||||
}
|
||||
|
||||
/// @brief Initializes a semid struct.
|
||||
/// @param ptr the pointer to the semid struct.
|
||||
/// @param key IPC_KEY associated with the set of semaphores
|
||||
/// @param nsems number of semaphores to initialize
|
||||
/// @todo The way we compute the semid is a temporary solution.
|
||||
static inline void __sem_info_init(struct semid_ds *ptr, key_t key, int nsems, int semflg)
|
||||
{
|
||||
assert(ptr && "Received a NULL pointer.");
|
||||
ptr->sem_perm = register_ipc(key, semflg & 0x1FF);
|
||||
ptr->sem_otime = 0;
|
||||
ptr->sem_ctime = 0;
|
||||
ptr->sem_nsems = nsems;
|
||||
ptr->sems = __sem_set_alloc(nsems);
|
||||
memset(sem_info->sems, 0, sizeof(struct sem) * nsems);
|
||||
// Initialize its values.
|
||||
sem_info->id = ++__sem_id;
|
||||
sem_info->semid.sem_perm = register_ipc(key, semflg & 0x1FF);
|
||||
sem_info->semid.sem_otime = 0;
|
||||
sem_info->semid.sem_ctime = 0;
|
||||
sem_info->semid.sem_nsems = nsems;
|
||||
for (int i = 0; i < nsems; i++) {
|
||||
__sem_init(&ptr->sems[i]);
|
||||
sem_info->sems[i].sem_pid = sys_getpid();
|
||||
sem_info->sems[i].sem_val = 0;
|
||||
sem_info->sems[i].sem_ncnt = 0;
|
||||
sem_info->sems[i].sem_zcnt = 0;
|
||||
}
|
||||
// Return the semaphore management structure.
|
||||
return sem_info;
|
||||
}
|
||||
|
||||
/// @brief Frees the memory of a semaphore management structure.
|
||||
/// @param sem_info pointer to the semaphore management structure.
|
||||
static inline void __sem_info_dealloc(sem_info_t *sem_info)
|
||||
{
|
||||
assert(sem_info && "Received a NULL pointer.");
|
||||
// Deallocate the array of semaphores.
|
||||
kfree(sem_info->sems);
|
||||
// Deallocate the semid memory.
|
||||
kfree(sem_info);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@@ -179,17 +145,17 @@ static inline void __sem_info_init(struct semid_ds *ptr, key_t key, int nsems, i
|
||||
/// @brief Searches for the semaphore with the given id.
|
||||
/// @param semid the id we are searching.
|
||||
/// @return the semaphore with the given id.
|
||||
static inline struct semid_ds *__find_semaphore_by_id(int semid)
|
||||
static inline sem_info_t *__list_find_sem_info_by_id(int semid)
|
||||
{
|
||||
struct semid_ds *sem_set;
|
||||
sem_info_t *sem_info;
|
||||
// Iterate through the list of semaphore set.
|
||||
listnode_foreach(listnode, &semaphores_list)
|
||||
list_for_each_decl(it, &semaphores_list)
|
||||
{
|
||||
// Get the current list of semaphore set.
|
||||
sem_set = (struct semid_ds *)listnode->value;
|
||||
// Get the current entry.
|
||||
sem_info = list_entry(it, sem_info_t, list);
|
||||
// If semaphore set is valid, check the id.
|
||||
if (sem_set && (sem_set->semid == semid))
|
||||
return sem_set;
|
||||
if (sem_info && (sem_info->id == semid))
|
||||
return sem_info;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -197,101 +163,110 @@ static inline struct semid_ds *__find_semaphore_by_id(int semid)
|
||||
/// @brief Searches for the semaphore with the given key.
|
||||
/// @param key the key we are searching.
|
||||
/// @return the semaphore with the given key.
|
||||
static inline struct semid_ds *__find_semaphore_by_key(key_t key)
|
||||
static inline sem_info_t *__list_find_sem_info_by_key(key_t key)
|
||||
{
|
||||
struct semid_ds *sem_set;
|
||||
sem_info_t *sem_info;
|
||||
// Iterate through the list of semaphore set.
|
||||
listnode_foreach(listnode, &semaphores_list)
|
||||
list_for_each_decl(it, &semaphores_list)
|
||||
{
|
||||
// Get the current list of semaphore set.
|
||||
sem_set = (struct semid_ds *)listnode->value;
|
||||
// Get the current entry.
|
||||
sem_info = list_entry(it, sem_info_t, list);
|
||||
// If semaphore set is valid, check the id.
|
||||
if (sem_set && (sem_set->sem_perm.key == key))
|
||||
return sem_set;
|
||||
if (sem_info && (sem_info->semid.sem_perm.key == key))
|
||||
return sem_info;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void __list_add_sem_info(sem_info_t *sem_info)
|
||||
{
|
||||
assert(sem_info && "Received a NULL pointer.");
|
||||
// Add the new sem_info at the end.
|
||||
list_head_insert_before(&sem_info->list, &semaphores_list);
|
||||
}
|
||||
|
||||
static inline void __list_remove_sem_info(sem_info_t *sem_info)
|
||||
{
|
||||
assert(sem_info && "Received a NULL pointer.");
|
||||
// Delete the sem_info from the list.
|
||||
list_head_remove(&sem_info->list);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// SYSTEM FUNCTIONS
|
||||
// ============================================================================
|
||||
|
||||
int sem_init()
|
||||
{
|
||||
list_head_init(&semaphores_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
long sys_semget(key_t key, int nsems, int semflg)
|
||||
{
|
||||
struct semid_ds *sem_set = NULL;
|
||||
sem_info_t *sem_info = NULL;
|
||||
// Check if nsems is less than 0 or greater than the maximum number of
|
||||
// semaphores per semaphore set.
|
||||
if ((nsems < 0) || (nsems > SEM_SET_MAX)) {
|
||||
pr_err("Wrong number of semaphores for semaphore set.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// Need to find a unique key.
|
||||
if (key == IPC_PRIVATE) {
|
||||
// Exit when i find a unique key.
|
||||
do {
|
||||
key = -ipc_sem_rand();
|
||||
} while (__find_semaphore_by_key(key));
|
||||
} while (__list_find_sem_info_by_key(key));
|
||||
// We have a unique key, create the semaphore set.
|
||||
sem_set = __semid_alloc();
|
||||
// Initialize the semaphore set.
|
||||
__semid_init(sem_set, key, nsems, semflg);
|
||||
sem_info = __sem_info_alloc(key, nsems, semflg);
|
||||
// Add the semaphore set to the list.
|
||||
list_insert_front(&semaphores_list, sem_set);
|
||||
// Return the id of the semaphore set.
|
||||
return sem_set->semid;
|
||||
}
|
||||
__list_add_sem_info(sem_info);
|
||||
} else {
|
||||
// Get the semaphore set if it exists.
|
||||
sem_info = __list_find_sem_info_by_key(key);
|
||||
|
||||
// Get the semaphore set if it exists.
|
||||
sem_set = __find_semaphore_by_key(key);
|
||||
// Check if a semaphore set with the given key already exists, but nsems is
|
||||
// larger than the number of semaphores in that set.
|
||||
if (sem_info && (nsems > sem_info->semid.sem_nsems)) {
|
||||
pr_err("Wrong number of semaphores for and existing semaphore set.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// Check if a semaphore set with the given key already exists, but nsems is
|
||||
// larger than the number of semaphores in that set.
|
||||
if (sem_set && (nsems > sem_set->sem_nsems)) {
|
||||
pr_err("Wrong number of semaphores for and existing semaphore set.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
// Check if no semaphore set exists for the given key and semflg did not
|
||||
// specify IPC_CREAT.
|
||||
if (!sem_info && !(semflg & IPC_CREAT)) {
|
||||
pr_err("No semaphore set exists for the given key and semflg did not specify IPC_CREAT.\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
// Check if no semaphore set exists for the given key and semflg did not
|
||||
// specify IPC_CREAT.
|
||||
if (!sem_set && !(semflg & IPC_CREAT)) {
|
||||
pr_err("No semaphore set exists for the given key and semflg did not specify IPC_CREAT.\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
// Check if IPC_CREAT and IPC_EXCL were specified in semflg, but a semaphore
|
||||
// set already exists for key.
|
||||
if (sem_info && (semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
|
||||
pr_err("IPC_CREAT and IPC_EXCL were specified in semflg, but a semaphore set already exists for key.\n");
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
// Check if IPC_CREAT and IPC_EXCL were specified in semflg, but a semaphore
|
||||
// set already exists for key.
|
||||
if (sem_set && (semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
|
||||
pr_err("IPC_CREAT and IPC_EXCL were specified in semflg, but a semaphore set already exists for key.\n");
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
// Check if the semaphore set exists for the given key, but the calling
|
||||
// process does not have permission to access the set.
|
||||
if (sem_set && !ipc_valid_permissions(semflg, &sem_set->sem_perm)) {
|
||||
pr_err("The semaphore set exists for the given key, but the calling process does not have permission to access the set.\n");
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
// If the semaphore set does not exist we need to create a new one.
|
||||
if (sem_set == NULL) {
|
||||
// Create the semaphore set.
|
||||
sem_set = __semid_alloc();
|
||||
// Initialize the semaphore set.
|
||||
__semid_init(sem_set, key, nsems, semflg);
|
||||
// Add the semaphore set to the list.
|
||||
list_insert_front(&semaphores_list, sem_set);
|
||||
// Check if the semaphore set exists for the given key, but the calling
|
||||
// process does not have permission to access the set.
|
||||
if (sem_info && !ipc_valid_permissions(semflg, &sem_info->semid.sem_perm)) {
|
||||
pr_err("The semaphore set exists for the given key, but the calling process does not have permission to access the set.\n");
|
||||
return -EACCES;
|
||||
}
|
||||
// If the semaphore set does not exist we need to create a new one.
|
||||
if (sem_info == NULL) {
|
||||
// Create the semaphore set.
|
||||
sem_info = __sem_info_alloc(key, nsems, semflg);
|
||||
// Add the semaphore set to the list.
|
||||
__list_add_sem_info(sem_info);
|
||||
}
|
||||
}
|
||||
// Return the id of the semaphore set.
|
||||
return sem_set->semid;
|
||||
return sem_info->id;
|
||||
}
|
||||
|
||||
long sys_semop(int semid, struct sembuf *sops, unsigned nsops)
|
||||
{
|
||||
struct semid_ds *sem_set;
|
||||
unsigned short sem_num;
|
||||
struct sem *semaphore;
|
||||
|
||||
sem_info_t *sem_info = NULL;
|
||||
// The semid is less than zero.
|
||||
if (semid < 0) {
|
||||
pr_err("The semid is less than zero.\n");
|
||||
@@ -307,58 +282,49 @@ long sys_semop(int semid, struct sembuf *sops, unsigned nsops)
|
||||
pr_err("The value of nsops is negative.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// Search for the semaphore.
|
||||
sem_set = __find_semaphore_by_id(semid);
|
||||
sem_info = __list_find_sem_info_by_id(semid);
|
||||
// The semaphore set doesn't exist.
|
||||
if (!sem_set) {
|
||||
if (!sem_info) {
|
||||
pr_err("The semaphore set doesn't exist.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// Get the semaphore number.
|
||||
sem_num = sops->sem_num;
|
||||
// The value of sem_num is less than 0 or greater than or equal to the number of semaphores in the set.
|
||||
if ((sem_num < 0) || (sem_num >= sem_set->sem_nsems)) {
|
||||
if ((sops->sem_num < 0) || (sops->sem_num >= sem_info->semid.sem_nsems)) {
|
||||
pr_err("The value of sem_num is less than 0 or greater than or equal to the number of semaphores in the set.\n");
|
||||
return -EFBIG;
|
||||
}
|
||||
// Check if the semaphore set exists for the given key, but the calling
|
||||
// process does not have permission to access the set.
|
||||
if (sem_set && !ipc_valid_permissions(O_RDWR, &sem_set->sem_perm)) {
|
||||
if (sem_info && !ipc_valid_permissions(O_RDWR, &sem_info->semid.sem_perm)) {
|
||||
pr_err("The semaphore set exists for the given key, but the calling process does not have permission to access the set.\n");
|
||||
return -EACCES;
|
||||
}
|
||||
// Update semop time.
|
||||
sem_set->sem_otime = sys_time(NULL);
|
||||
// Get the specific semaphore.
|
||||
semaphore = &sem_set->sems[sem_num];
|
||||
|
||||
sem_info->semid.sem_otime = sys_time(NULL);
|
||||
// If the operation is negative then we need to check for possible blocking
|
||||
// operation. If the value of the sem were to become negative then we return
|
||||
// a special value.
|
||||
if (((int)semaphore->sem_val + (int)sops->sem_op) < 0) {
|
||||
if (((int)sem_info->sems[sops->sem_num].sem_val + (int)sops->sem_op) < 0) {
|
||||
// The value would become negative, we cannot perform the operation.
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
// Update the semaphore value.
|
||||
semaphore->sem_val += sops->sem_op;
|
||||
sem_info->sems[sops->sem_num].sem_val += sops->sem_op;
|
||||
// Update the pid of the process that did last op.
|
||||
semaphore->sem_pid = sys_getpid();
|
||||
sem_info->sems[sops->sem_num].sem_pid = sys_getpid();
|
||||
// Update the time.
|
||||
sem_set->sem_ctime = sys_time(NULL);
|
||||
sem_info->semid.sem_ctime = sys_time(NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
long sys_semctl(int semid, int semnum, int cmd, union semun *arg)
|
||||
{
|
||||
struct semid_ds *sem_set;
|
||||
|
||||
sem_info_t *sem_info = NULL;
|
||||
// Search for the semaphore.
|
||||
sem_set = __find_semaphore_by_id(semid);
|
||||
sem_info = __list_find_sem_info_by_id(semid);
|
||||
// The semaphore set doesn't exist.
|
||||
if (!sem_set) {
|
||||
if (!sem_info) {
|
||||
pr_err("The semaphore set doesn't exist.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -371,50 +337,43 @@ long sys_semctl(int semid, int semnum, int cmd, union semun *arg)
|
||||
// Remove the semaphore set; any processes blocked is awakened (errno set to
|
||||
// EIDRM); no argument required.
|
||||
case IPC_RMID:
|
||||
if ((sem_set->sem_perm.uid != task->uid) && (sem_set->sem_perm.cuid != task->uid)) {
|
||||
if ((sem_info->semid.sem_perm.uid != task->uid) && (sem_info->semid.sem_perm.cuid != task->uid)) {
|
||||
pr_err("The calling process is not the creator or the owner of the semaphore set.\n");
|
||||
return -EPERM;
|
||||
}
|
||||
// Remove the set from the list.
|
||||
list_remove_node(&semaphores_list, list_find(&semaphores_list, sem_set));
|
||||
__list_remove_sem_info(sem_info);
|
||||
// Delete the set.
|
||||
__semid_dealloc(sem_set);
|
||||
__sem_info_dealloc(sem_info);
|
||||
break;
|
||||
|
||||
// Place a copy of the semid_ds data structure in the buffer pointed to by
|
||||
// arg.buf.
|
||||
case IPC_STAT:
|
||||
// The value of the semnum-th semaphore in the set is initialized to the
|
||||
// value specified in arg.val.
|
||||
case SETVAL:
|
||||
// Check if the index is valid.
|
||||
if ((semnum < 0) || (semnum >= (sem_info->semid.sem_nsems))) {
|
||||
pr_err("Semaphore number out of bound (%d not in [%d, %d])\n", semnum, 0, sem_info->semid.sem_nsems);
|
||||
return -EINVAL;
|
||||
}
|
||||
// Check if the argument is a null pointer.
|
||||
if (!arg) {
|
||||
pr_err("The argument is NULL.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
// Check if the buffer is a null pointer.
|
||||
if (!arg->buf) {
|
||||
pr_err("The buffer is NULL.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
// Check if the array of semaphores inside the buffer is a null pointer.
|
||||
if (!arg->buf->sems) {
|
||||
pr_err("The array of semaphores inside the buffer is NULL.\n");
|
||||
// Checking if the value is valid.
|
||||
if (arg->val < 0) {
|
||||
pr_err("The value to set is not valid %d.\n", arg->val);
|
||||
return -EINVAL;
|
||||
}
|
||||
// Check permissions.
|
||||
if (!ipc_valid_permissions(O_RDONLY, sem_set->sem_perm)) {
|
||||
if (!ipc_valid_permissions(O_WRONLY, &sem_info->semid.sem_perm)) {
|
||||
pr_err("The calling process does not have read permission to access the set.\n");
|
||||
return -EACCES;
|
||||
}
|
||||
// Copying all the data.
|
||||
arg->buf->sem_perm = sem_set->sem_perm;
|
||||
arg->buf->semid = sem_set->semid;
|
||||
arg->buf->sem_otime = sem_set->sem_otime;
|
||||
arg->buf->sem_ctime = sem_set->sem_ctime;
|
||||
arg->buf->sem_nsems = sem_set->sem_nsems;
|
||||
for (int i = 0; i < sem_set->sem_nsems; i++) {
|
||||
arg->buf->sems[i].sem_val = sem_set->sems[i].sem_val;
|
||||
arg->buf->sems[i].sem_pid = sem_set->sems[i].sem_pid;
|
||||
arg->buf->sems[i].sem_zcnt = sem_set->sems[i].sem_zcnt;
|
||||
}
|
||||
// Setting the value.
|
||||
sem_info->sems[semnum].sem_val = arg->val;
|
||||
// Update the last change time.
|
||||
sem_info->semid.sem_ctime = sys_time(NULL);
|
||||
return 0;
|
||||
|
||||
// Initialize all semaphore in the set referred to by semid, using the
|
||||
@@ -430,12 +389,39 @@ long sys_semctl(int semid, int semnum, int cmd, union semun *arg)
|
||||
pr_err("The array is NULL.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
// Check permissions.
|
||||
if (!ipc_valid_permissions(O_WRONLY, &sem_info->semid.sem_perm)) {
|
||||
pr_err("The calling process does not have read permission to access the set.\n");
|
||||
return -EACCES;
|
||||
}
|
||||
// Setting the values.
|
||||
for (unsigned i = 0; i < sem_set->sem_nsems; ++i) {
|
||||
sem_set->sems[i].sem_val = arg->array[i];
|
||||
for (unsigned i = 0; i < sem_info->semid.sem_nsems; ++i) {
|
||||
sem_info->sems[i].sem_val = arg->array[i];
|
||||
}
|
||||
// Update the last change time.
|
||||
sem_set->sem_ctime = sys_time(NULL);
|
||||
sem_info->semid.sem_ctime = sys_time(NULL);
|
||||
return 0;
|
||||
|
||||
// Place a copy of the semid_ds data structure in the buffer pointed to by
|
||||
// arg.buf.
|
||||
case IPC_STAT:
|
||||
// Check if the argument is a null pointer.
|
||||
if (!arg) {
|
||||
pr_err("The argument is NULL.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
// Check if the buffer is a null pointer.
|
||||
if (!arg->buf) {
|
||||
pr_err("The buffer is NULL.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
// Check permissions.
|
||||
if (!ipc_valid_permissions(O_RDONLY, &sem_info->semid.sem_perm)) {
|
||||
pr_err("The calling process does not have read permission to access the set.\n");
|
||||
return -EACCES;
|
||||
}
|
||||
// Copying all the data.
|
||||
memcpy(arg->buf, &sem_info->semid, sizeof(struct semid_ds));
|
||||
return 0;
|
||||
|
||||
// Retrieve the values of all of the semaphores in the set referred to by
|
||||
@@ -451,70 +437,76 @@ long sys_semctl(int semid, int semnum, int cmd, union semun *arg)
|
||||
pr_err("The array is NULL.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
for (unsigned i = 0; i < sem_set->sem_nsems; ++i) {
|
||||
arg->array[i] = sem_set->sems[i].sem_val;
|
||||
for (unsigned i = 0; i < sem_info->semid.sem_nsems; ++i) {
|
||||
arg->array[i] = sem_info->sems[i].sem_val;
|
||||
}
|
||||
return 0;
|
||||
|
||||
// The value of the semnum-th semaphore in the set is initialized to the
|
||||
// value specified in arg.val.
|
||||
case SETVAL:
|
||||
// Check if the index is valid.
|
||||
if ((semnum < 0) || (semnum >= (sem_set->sem_nsems))) {
|
||||
pr_err("Semaphore number out of bound (%d not in [%d, %d])\n", semnum, 0, sem_set->sem_nsems);
|
||||
return -EINVAL;
|
||||
}
|
||||
// Check if the argument is a null pointer.
|
||||
if (!arg) {
|
||||
pr_err("The argument is NULL.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
// Checking if the value is valid.
|
||||
if (arg->val < 0) {
|
||||
pr_err("The value to set is not valid %d.\n", arg->val);
|
||||
return -EINVAL;
|
||||
}
|
||||
// Setting the value.
|
||||
sem_set->sems[semnum].sem_val = arg->val;
|
||||
// Update the last change time.
|
||||
sem_set->sem_ctime = sys_time(NULL);
|
||||
return 0;
|
||||
|
||||
// Returns the value of the semnum-th semaphore in the set specified by
|
||||
// semid; no argument required.
|
||||
case GETVAL:
|
||||
// Check if the index is valid.
|
||||
if ((semnum < 0) || (semnum >= (sem_set->sem_nsems))) {
|
||||
pr_err("Semaphore number out of bound (%d not in [%d, %d])\n", semnum, 0, sem_set->sem_nsems);
|
||||
if ((semnum < 0) || (semnum >= (sem_info->semid.sem_nsems))) {
|
||||
pr_err("Semaphore number out of bound (%d not in [%d, %d])\n", semnum, 0, sem_info->semid.sem_nsems);
|
||||
return -EINVAL;
|
||||
}
|
||||
return sem_set->sems[semnum].sem_val;
|
||||
|
||||
// Check permissions.
|
||||
if (!ipc_valid_permissions(O_RDONLY, &sem_info->semid.sem_perm)) {
|
||||
pr_err("The calling process does not have read permission to access the set.\n");
|
||||
return -EACCES;
|
||||
}
|
||||
return sem_info->sems[semnum].sem_val;
|
||||
// Return the process ID of the last process to perform a semop on the
|
||||
// semnum-th semaphore.
|
||||
case GETPID:
|
||||
// Check if the index is valid.
|
||||
if ((semnum < 0) || (semnum >= (sem_set->sem_nsems))) {
|
||||
pr_err("Semaphore number out of bound (%d not in [%d, %d])\n", semnum, 0, sem_set->sem_nsems);
|
||||
if ((semnum < 0) || (semnum >= (sem_info->semid.sem_nsems))) {
|
||||
pr_err("Semaphore number out of bound (%d not in [%d, %d])\n", semnum, 0, sem_info->semid.sem_nsems);
|
||||
return -EINVAL;
|
||||
}
|
||||
return sem_set->sems[semnum].sem_pid;
|
||||
|
||||
// Check permissions.
|
||||
if (!ipc_valid_permissions(O_RDONLY, &sem_info->semid.sem_perm)) {
|
||||
pr_err("The calling process does not have read permission to access the set.\n");
|
||||
return -EACCES;
|
||||
}
|
||||
return sem_info->sems[semnum].sem_pid;
|
||||
// Return the number of processes currently waiting for the resources to
|
||||
// become available.
|
||||
case GETNCNT:
|
||||
// Check if the index is valid.
|
||||
if ((semnum < 0) || (semnum >= (sem_info->semid.sem_nsems))) {
|
||||
pr_err("Semaphore number out of bound (%d not in [%d, %d])\n", semnum, 0, sem_info->semid.sem_nsems);
|
||||
return -EINVAL;
|
||||
}
|
||||
// Check permissions.
|
||||
if (!ipc_valid_permissions(O_RDONLY, &sem_info->semid.sem_perm)) {
|
||||
pr_err("The calling process does not have read permission to access the set.\n");
|
||||
return -EACCES;
|
||||
}
|
||||
return sem_info->sems[semnum].sem_ncnt;
|
||||
// Return the number of processes currently waiting for the value of the
|
||||
// semnum-th semaphore to become 0.
|
||||
case GETZCNT:
|
||||
// Check if the index is valid.
|
||||
if ((semnum < 0) || (semnum >= (sem_set->sem_nsems))) {
|
||||
pr_err("Semaphore number out of bound (%d not in [%d, %d])\n", semnum, 0, sem_set->sem_nsems);
|
||||
if ((semnum < 0) || (semnum >= (sem_info->semid.sem_nsems))) {
|
||||
pr_err("Semaphore number out of bound (%d not in [%d, %d])\n", semnum, 0, sem_info->semid.sem_nsems);
|
||||
return -EINVAL;
|
||||
}
|
||||
return sem_set->sems[semnum].sem_zcnt;
|
||||
// Check permissions.
|
||||
if (!ipc_valid_permissions(O_RDONLY, &sem_info->semid.sem_perm)) {
|
||||
pr_err("The calling process does not have read permission to access the set.\n");
|
||||
return -EACCES;
|
||||
}
|
||||
return sem_info->sems[semnum].sem_zcnt;
|
||||
|
||||
// Return the number of semaphores in the set.
|
||||
case GETNSEMS:
|
||||
return sem_set->sem_nsems;
|
||||
case SEM_STAT:
|
||||
pr_err("Not implemented.\n");
|
||||
return -ENOSYS;
|
||||
|
||||
//not a valid argument.
|
||||
case SEM_INFO:
|
||||
pr_err("Not implemented.\n");
|
||||
return -ENOSYS;
|
||||
|
||||
// Not a valid argument.
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -533,7 +525,7 @@ ssize_t procipc_sem_read(vfs_file_t *file, char *buf, off_t offset, size_t nbyte
|
||||
return -ENOENT;
|
||||
}
|
||||
size_t buffer_len = 0, read_pos = 0, write_count = 0, ret = 0;
|
||||
struct semid_ds *entry = NULL;
|
||||
sem_info_t *sem_info = NULL;
|
||||
char buffer[BUFSIZ];
|
||||
|
||||
// Prepare a buffer.
|
||||
@@ -541,25 +533,24 @@ ssize_t procipc_sem_read(vfs_file_t *file, char *buf, off_t offset, size_t nbyte
|
||||
// Prepare the header.
|
||||
ret = sprintf(buffer, "key semid perms nsems uid gid cuid cgid otime ctime\n");
|
||||
|
||||
// Iterate through the list.
|
||||
if (semaphores_list.size > 0) {
|
||||
listnode_foreach(listnode, &semaphores_list)
|
||||
{
|
||||
// Get the entry.
|
||||
entry = ((struct semid_ds *)listnode->value);
|
||||
ret += sprintf(
|
||||
buffer + ret, "%8d %5d %10d %7d %5d %4d %5d %9d %10d %d\n",
|
||||
abs(entry->sem_perm.key),
|
||||
entry->semid,
|
||||
entry->sem_perm.mode,
|
||||
entry->sem_nsems,
|
||||
entry->sem_perm.uid,
|
||||
entry->sem_perm.gid,
|
||||
entry->sem_perm.cuid,
|
||||
entry->sem_perm.cgid,
|
||||
entry->sem_otime,
|
||||
entry->sem_ctime);
|
||||
}
|
||||
// Iterate through the list of semaphore set.
|
||||
list_for_each_decl(it, &semaphores_list)
|
||||
{
|
||||
// Get the current entry.
|
||||
sem_info = list_entry(it, sem_info_t, list);
|
||||
// Add the line.
|
||||
ret += sprintf(
|
||||
buffer + ret, "%8d %5d %10d %7d %5d %4d %5d %9d %10d %d\n",
|
||||
abs(sem_info->semid.sem_perm.key),
|
||||
sem_info->id,
|
||||
sem_info->semid.sem_perm.mode,
|
||||
sem_info->semid.sem_nsems,
|
||||
sem_info->semid.sem_perm.uid,
|
||||
sem_info->semid.sem_perm.gid,
|
||||
sem_info->semid.sem_perm.cuid,
|
||||
sem_info->semid.sem_perm.cgid,
|
||||
sem_info->semid.sem_otime,
|
||||
sem_info->semid.sem_ctime);
|
||||
}
|
||||
sprintf(buffer + ret, "\n");
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "devices/fpu.h"
|
||||
#include "system/printk.h"
|
||||
#include "sys/module.h"
|
||||
#include "sys/sem.h"
|
||||
#include "drivers/rtc.h"
|
||||
#include "stdio.h"
|
||||
#include "assert.h"
|
||||
@@ -307,6 +308,17 @@ int kmain(boot_info_t *boot_informations)
|
||||
return 1;
|
||||
}
|
||||
print_ok();
|
||||
|
||||
|
||||
//==========================================================================
|
||||
pr_notice("Initialize IPC/SEM system...\n");
|
||||
printf("Initialize IPC/SEM system...");
|
||||
if (sem_init()) {
|
||||
print_fail();
|
||||
pr_emerg("Failed to initialize the IPC/SEM system!\n");
|
||||
return 1;
|
||||
}
|
||||
print_ok();
|
||||
|
||||
//==========================================================================
|
||||
pr_notice("Setting up PS/2 driver...\n");
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
/// See LICENSE.md for details.
|
||||
|
||||
// Setup the logging for this file (do this before any other include).
|
||||
#include "sys/kernel_levels.h" // Include kernel log levels.
|
||||
#define __DEBUG_HEADER__ "[PROC ]" ///< Change header.
|
||||
#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level.
|
||||
#include "io/debug.h" // Include debugging functions.
|
||||
#include "sys/kernel_levels.h" // Include kernel log levels.
|
||||
#define __DEBUG_HEADER__ "[PROC ]" ///< Change header.
|
||||
#define __DEBUG_LEVEL__ LOGLEVEL_DEBUG ///< Set log level.
|
||||
#include "io/debug.h" // Include debugging functions.
|
||||
|
||||
#include "process/process.h"
|
||||
#include "process/scheduler.h"
|
||||
|
||||
+5
-2
@@ -64,17 +64,20 @@ int main(int argc, char **argv)
|
||||
if (!strcmp(argv[3], "-s")) {
|
||||
struct semid_ds sem;
|
||||
union semun temp;
|
||||
int semid;
|
||||
long ret;
|
||||
// Prepare the data structure.
|
||||
temp.buf = &sem;
|
||||
// Initialize the semid.
|
||||
semid = atoi(argv[2]);
|
||||
// Retrive the statistics.
|
||||
ret = semctl(atoi(argv[2]), 0, IPC_STAT, &temp);
|
||||
ret = semctl(semid, 0, IPC_STAT, &temp);
|
||||
// Check if we succeded.
|
||||
if (!ret) {
|
||||
//ret = semctl(atoi(argv[2]), 0, GETNSEMS, NULL);
|
||||
//temp.buf->sems = (struct sem *)malloc(sizeof(struct sem) * ret);
|
||||
printf("key semid owner perms nsems\n");
|
||||
printf("%10d %10d %10d %10d %d\n", sem.sem_perm.key, sem.semid, sem.sem_perm.uid, sem.sem_perm.mode, sem.sem_nsems);
|
||||
printf("%10d %10d %10d %10d %d\n", sem.sem_perm.key, semid, sem.sem_perm.uid, sem.sem_perm.mode, sem.sem_nsems);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
||||
@@ -87,8 +87,8 @@ set(TESTS
|
||||
t_gid.c
|
||||
# Test semaphores.
|
||||
t_semget.c
|
||||
t_sem1.c
|
||||
t_semflg.c
|
||||
t_semop.c
|
||||
# Test scheduling feedback tests.
|
||||
t_schedfb.c
|
||||
)
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
//test
|
||||
/// @file t_semflg.c
|
||||
/// @brief Tests some of the IPC flags.
|
||||
/// @copyright (c) 2014-2023 This file is distributed under the MIT License.
|
||||
/// See LICENSE.md for details.
|
||||
|
||||
#include "sys/unistd.h"
|
||||
#include "sys/errno.h"
|
||||
#include "sys/sem.h"
|
||||
@@ -7,20 +11,7 @@
|
||||
#include "fcntl.h"
|
||||
#include "stdio.h"
|
||||
|
||||
/*
|
||||
Testing IPC_NOWAIT flag.
|
||||
*/
|
||||
|
||||
void semid_print(struct semid_ds *temp)
|
||||
{
|
||||
printf("pid, IPC_KEY, Semid, semop, change: %d, %d, %d, %d, %d\n", temp->sem_perm.uid, temp->sem_perm.key, temp->semid, temp->sem_otime, temp->sem_ctime);
|
||||
for (int i = 0; i < (temp->sem_nsems); i++) {
|
||||
printf("%d semaphore:\n", i + 1);
|
||||
printf("value: %d, pid %d, process waiting %d\n", temp->sems[i].sem_val, temp->sems[i].sem_pid, temp->sems[i].sem_zcnt);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct sembuf op[2];
|
||||
union semun arg;
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
//test
|
||||
/// @file t_semget.c
|
||||
/// @brief This program creates a son and then performs a blocking operation on
|
||||
/// a semaphore. The son sleeps for five seconds and then it wakes up his
|
||||
/// father and then it deletes the semaphore.
|
||||
/// @copyright (c) 2014-2023 This file is distributed under the MIT License.
|
||||
/// See LICENSE.md for details.
|
||||
|
||||
#include "sys/unistd.h"
|
||||
#include "sys/errno.h"
|
||||
#include "sys/sem.h"
|
||||
@@ -7,23 +13,7 @@
|
||||
#include "fcntl.h"
|
||||
#include "stdio.h"
|
||||
|
||||
/*
|
||||
Testing Semaphores.
|
||||
This program creates a son and then performs a blocking operation on a semaphore. The son sleeps for
|
||||
five seconds and then it wakes up his father and then it deletes the semaphore.
|
||||
|
||||
*/
|
||||
|
||||
void semid_print(struct semid_ds *temp)
|
||||
{
|
||||
printf("pid, IPC_KEY, Semid, semop, change: %d, %d, %d, %d, %d\n", temp->sem_perm.uid, temp->sem_perm.key, temp->semid, temp->sem_otime, temp->sem_ctime);
|
||||
for (int i = 0; i < (temp->sem_nsems); i++) {
|
||||
printf("%d semaphore:\n", i + 1);
|
||||
printf("value: %d, pid %d, process waiting %d\n", temp->sems[i].sem_val, temp->sems[i].sem_pid, temp->sems[i].sem_zcnt);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct sembuf op_child;
|
||||
struct sembuf op_father[3];
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
//test
|
||||
/// @file t_semop.c
|
||||
/// @brief Tests semop between processes.
|
||||
/// @copyright (c) 2014-2023 This file is distributed under the MIT License.
|
||||
/// See LICENSE.md for details.
|
||||
|
||||
#include "sys/sem.h"
|
||||
#include "stdio.h"
|
||||
#include "sys/ipc.h"
|
||||
@@ -8,21 +12,7 @@
|
||||
#include "sys/unistd.h"
|
||||
#include "fcntl.h"
|
||||
|
||||
/*
|
||||
First test of System V Semaphores.
|
||||
Correct output should be: Corso di Sistemi Operativi.
|
||||
*/
|
||||
|
||||
void semid_print(struct semid_ds *temp)
|
||||
{
|
||||
printf("pid, IPC_KEY, Semid, semop, change: %d, %d, %d, %d, %d\n", temp->sem_perm.uid, temp->sem_perm.key, temp->semid, temp->sem_otime, temp->sem_ctime);
|
||||
for (int i = 0; i < (temp->sem_nsems); i++) {
|
||||
printf("%d semaphore:\n", i + 1);
|
||||
printf("value: %d, pid %d, process waiting %d\n", temp->sems[i].sem_val, temp->sems[i].sem_pid, temp->sems[i].sem_zcnt);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct sembuf sops[6];
|
||||
sops[0].sem_num = 0;
|
||||
@@ -52,7 +42,7 @@ int main()
|
||||
int status;
|
||||
|
||||
//create a semaphore set
|
||||
int semid = semget(IPC_PRIVATE, 4, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||
int semid = semget(17, 4, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||
|
||||
//set the values of the semaphores
|
||||
unsigned short values[] = { 0, 0, 0, 1 };
|
||||
Reference in New Issue
Block a user