Changes in uspace/srv/vfs/vfs_file.c [553492be:4fe94c66] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/vfs/vfs_file.c
r553492be r4fe94c66 38 38 #include <errno.h> 39 39 #include <stdlib.h> 40 #include <str ing.h>40 #include <str.h> 41 41 #include <assert.h> 42 42 #include <bool.h> 43 43 #include <fibril.h> 44 #include <fibril_sync .h>44 #include <fibril_synch.h> 45 45 #include "vfs.h" 46 46 47 /** 48 * This is a per-connection table of open files. 49 * Our assumption is that each client opens only one connection and therefore 50 * there is one table of open files per task. However, this may not be the case 51 * and the client can open more connections to VFS. In that case, there will be 52 * several tables and several file handle name spaces per task. Besides of this, 53 * the functionality will stay unchanged. So unless the client knows what it is 54 * doing, it should open one connection to VFS only. 55 * 56 * Allocation of the open files table is deferred until the client makes the 57 * first VFS_OPEN operation. 58 * 59 * This resource being per-connection and, in the first place, per-fibril, we 60 * don't need to protect it by a mutex. 61 */ 62 fibril_local vfs_file_t **files = NULL; 47 #define VFS_DATA ((vfs_client_data_t *) async_client_data_get()) 48 #define FILES (VFS_DATA->files) 49 50 typedef struct { 51 fibril_mutex_t lock; 52 vfs_file_t **files; 53 } vfs_client_data_t; 63 54 64 55 /** Initialize the table of open files. */ 65 bool vfs_files_init(void) 66 { 67 if (!files) { 68 files = malloc(MAX_OPEN_FILES * sizeof(vfs_file_t *)); 69 if (!files) 56 static bool vfs_files_init(void) 57 { 58 fibril_mutex_lock(&VFS_DATA->lock); 59 if (!FILES) { 60 FILES = malloc(MAX_OPEN_FILES * sizeof(vfs_file_t *)); 61 if (!FILES) { 62 fibril_mutex_unlock(&VFS_DATA->lock); 70 63 return false; 71 memset(files, 0, MAX_OPEN_FILES * sizeof(vfs_file_t *)); 72 } 64 } 65 memset(FILES, 0, MAX_OPEN_FILES * sizeof(vfs_file_t *)); 66 } 67 fibril_mutex_unlock(&VFS_DATA->lock); 73 68 return true; 74 69 } 75 70 76 /** Allocate a file descriptor. 77 * 78 * @return First available file descriptor or a negative error 79 * code. 80 */ 81 int vfs_fd_alloc(void) 82 { 83 if (!vfs_files_init()) 84 return ENOMEM; 85 86 unsigned int i; 71 /** Cleanup the table of open files. */ 72 static void vfs_files_done(void) 73 { 74 int i; 75 76 if (!FILES) 77 return; 78 87 79 for (i = 0; i < MAX_OPEN_FILES; i++) { 88 if (!files[i]) { 89 files[i] = (vfs_file_t *) malloc(sizeof(vfs_file_t)); 90 if (!files[i]) 91 return ENOMEM; 92 93 memset(files[i], 0, sizeof(vfs_file_t)); 94 fibril_mutex_initialize(&files[i]->lock); 95 vfs_file_addref(files[i]); 96 return (int) i; 97 } 98 } 99 100 return EMFILE; 101 } 102 103 /** Release file descriptor. 104 * 105 * @param fd File descriptor being released. 106 * 107 * @return EOK on success or EBADF if fd is an invalid file 108 * descriptor. 109 */ 110 int vfs_fd_free(int fd) 111 { 112 if (!vfs_files_init()) 113 return ENOMEM; 114 115 if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (files[fd] == NULL)) 116 return EBADF; 117 118 vfs_file_delref(files[fd]); 119 files[fd] = NULL; 120 121 return EOK; 80 if (FILES[i]) { 81 (void) vfs_close_internal(FILES[i]); 82 (void) vfs_fd_free(i); 83 } 84 } 85 86 free(FILES); 87 } 88 89 void *vfs_client_data_create(void) 90 { 91 vfs_client_data_t *vfs_data; 92 93 vfs_data = malloc(sizeof(vfs_client_data_t)); 94 if (vfs_data) { 95 fibril_mutex_initialize(&vfs_data->lock); 96 vfs_data->files = NULL; 97 } 98 99 return vfs_data; 100 } 101 102 void vfs_client_data_destroy(void *data) 103 { 104 vfs_client_data_t *vfs_data = (vfs_client_data_t *) data; 105 106 vfs_files_done(); 107 free(vfs_data); 122 108 } 123 109 … … 127 113 * incremented. 128 114 */ 129 void vfs_file_addref(vfs_file_t *file) 130 { 131 /* 132 * File structures are per-connection, so no-one, except the current 133 * fibril, should have a reference to them. This is the reason we don't 134 * do any synchronization here. 135 */ 115 static void vfs_file_addref(vfs_file_t *file) 116 { 117 assert(fibril_mutex_is_locked(&VFS_DATA->lock)); 118 136 119 file->refcnt++; 137 120 } … … 142 125 * decremented. 143 126 */ 144 void vfs_file_delref(vfs_file_t *file) 145 { 127 static void vfs_file_delref(vfs_file_t *file) 128 { 129 assert(fibril_mutex_is_locked(&VFS_DATA->lock)); 130 146 131 if (file->refcnt-- == 1) { 147 132 /* … … 154 139 } 155 140 141 142 /** Allocate a file descriptor. 143 * 144 * @param desc If true, look for an available file descriptor 145 * in a descending order. 146 * 147 * @return First available file descriptor or a negative error 148 * code. 149 */ 150 int vfs_fd_alloc(bool desc) 151 { 152 if (!vfs_files_init()) 153 return ENOMEM; 154 155 unsigned int i; 156 if (desc) 157 i = MAX_OPEN_FILES - 1; 158 else 159 i = 0; 160 161 fibril_mutex_lock(&VFS_DATA->lock); 162 while (true) { 163 if (!FILES[i]) { 164 FILES[i] = (vfs_file_t *) malloc(sizeof(vfs_file_t)); 165 if (!FILES[i]) { 166 fibril_mutex_unlock(&VFS_DATA->lock); 167 return ENOMEM; 168 } 169 170 memset(FILES[i], 0, sizeof(vfs_file_t)); 171 fibril_mutex_initialize(&FILES[i]->lock); 172 vfs_file_addref(FILES[i]); 173 fibril_mutex_unlock(&VFS_DATA->lock); 174 return (int) i; 175 } 176 177 if (desc) { 178 if (i == 0) 179 break; 180 181 i--; 182 } else { 183 if (i == MAX_OPEN_FILES - 1) 184 break; 185 186 i++; 187 } 188 } 189 fibril_mutex_unlock(&VFS_DATA->lock); 190 191 return EMFILE; 192 } 193 194 /** Release file descriptor. 195 * 196 * @param fd File descriptor being released. 197 * 198 * @return EOK on success or EBADF if fd is an invalid file 199 * descriptor. 200 */ 201 int vfs_fd_free(int fd) 202 { 203 if (!vfs_files_init()) 204 return ENOMEM; 205 206 fibril_mutex_lock(&VFS_DATA->lock); 207 if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (FILES[fd] == NULL)) { 208 fibril_mutex_unlock(&VFS_DATA->lock); 209 return EBADF; 210 } 211 212 vfs_file_delref(FILES[fd]); 213 FILES[fd] = NULL; 214 fibril_mutex_unlock(&VFS_DATA->lock); 215 216 return EOK; 217 } 218 219 /** Assign a file to a file descriptor. 220 * 221 * @param file File to assign. 222 * @param fd File descriptor to assign to. 223 * 224 * @return EOK on success or EINVAL if fd is an invalid or already 225 * used file descriptor. 226 * 227 */ 228 int vfs_fd_assign(vfs_file_t *file, int fd) 229 { 230 if (!vfs_files_init()) 231 return ENOMEM; 232 233 fibril_mutex_lock(&VFS_DATA->lock); 234 if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (FILES[fd] != NULL)) { 235 fibril_mutex_unlock(&VFS_DATA->lock); 236 return EINVAL; 237 } 238 239 FILES[fd] = file; 240 vfs_file_addref(FILES[fd]); 241 fibril_mutex_unlock(&VFS_DATA->lock); 242 243 return EOK; 244 } 245 156 246 /** Find VFS file structure for a given file descriptor. 157 247 * … … 165 255 return NULL; 166 256 167 if ((fd >= 0) && (fd < MAX_OPEN_FILES)) 168 return files[fd]; 257 fibril_mutex_lock(&VFS_DATA->lock); 258 if ((fd >= 0) && (fd < MAX_OPEN_FILES)) { 259 vfs_file_t *file = FILES[fd]; 260 vfs_file_addref(file); 261 fibril_mutex_unlock(&VFS_DATA->lock); 262 return file; 263 } 264 fibril_mutex_unlock(&VFS_DATA->lock); 169 265 170 266 return NULL; 267 } 268 269 /** Stop using a file structure. 270 * 271 * @param file VFS file structure. 272 */ 273 void vfs_file_put(vfs_file_t *file) 274 { 275 fibril_mutex_lock(&VFS_DATA->lock); 276 vfs_file_delref(file); 277 fibril_mutex_unlock(&VFS_DATA->lock); 171 278 } 172 279
Note:
See TracChangeset
for help on using the changeset viewer.