Bug Summary

File:obj-scan-build/tmpfs/../../tmpfs/node.c
Location:line 254, column 7
Description:Assigned value is garbage or undefined

Annotated Source Code

1/* Node state and file contents for tmpfs.
2 Copyright (C) 2000,01,02 Free Software Foundation, Inc.
3
4This file is part of the GNU Hurd.
5
6The GNU Hurd is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11The GNU Hurd is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with the GNU Hurd; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include "tmpfs.h"
21#include <stddef.h>
22#include <stdlib.h>
23#include <fcntl.h>
24#include <hurd/hurd_types.h>
25#include <hurd/store.h>
26#include "default_pager_U.h"
27#include "libdiskfs/fs_S.h"
28
29unsigned int num_files;
30static unsigned int gen;
31
32struct node *all_nodes;
33static size_t all_nodes_nr_items;
34
35error_t
36diskfs_alloc_node (struct node *dp, mode_t mode, struct node **npp)
37{
38 struct disknode *dn;
39
40 dn = calloc (1, sizeof *dn);
41 if (dn == 0)
42 return ENOSPC((0x10 << 26) | ((28) & 0x3fff));
43 pthread_spin_lock (&diskfs_node_refcnt_lock);
44 if (round_page (tmpfs_space_used + sizeof *dn)((((vm_offset_t) (tmpfs_space_used + sizeof *dn) + __vm_page_size
- 1) / __vm_page_size) * __vm_page_size)
/ vm_page_size
45 > tmpfs_page_limit)
46 {
47 pthread_spin_unlock (&diskfs_node_refcnt_lock);
48 free (dn);
49 return ENOSPC((0x10 << 26) | ((28) & 0x3fff));
50 }
51 dn->gen = gen++;
52 ++num_files;
53 tmpfs_space_used += sizeof *dn;
54 pthread_spin_unlock (&diskfs_node_refcnt_lock);
55
56 dn->type = IFTODT (mode & S_IFMT)(((mode & 0170000) & 0170000) >> 12);
57 return diskfs_cached_lookup ((ino_t) (uintptr_t) dn, npp);
58}
59
60void
61diskfs_free_node (struct node *np, mode_t mode)
62{
63 switch (np->dn->type)
64 {
65 case DT_REGDT_REG:
66 if (np->dn->u.reg.memobj != MACH_PORT_NULL((mach_port_t) 0)) {
67 vm_deallocate (mach_task_self ()((__mach_task_self_ + 0)), np->dn->u.reg.memref, 4096);
68 mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), np->dn->u.reg.memobj);
69 }
70 break;
71 case DT_DIRDT_DIR:
72 assert (np->dn->u.dir.entries == 0)((np->dn->u.dir.entries == 0) ? (void) (0) : __assert_fail
("np->dn->u.dir.entries == 0", "../../tmpfs/node.c", 72
, __PRETTY_FUNCTION__))
;
73 break;
74 case DT_LNKDT_LNK:
75 free (np->dn->u.lnk);
76 break;
77 }
78 *np->dn->hprevp = np->dn->hnext;
79 if (np->dn->hnext != 0)
80 np->dn->hnext->dn->hprevp = np->dn->hprevp;
81 all_nodes_nr_items -= 1;
82 free (np->dn);
83 np->dn = 0;
84
85 --num_files;
86 tmpfs_space_used -= sizeof *np->dn;
87}
88
89void
90diskfs_node_norefs (struct node *np)
91{
92 if (np->dn != 0)
93 {
94 /* We don't bother to do this in diskfs_write_disknode, since it only
95 ever matters here. The node state goes back into the `struct
96 disknode' while it has no associated diskfs node. */
97
98 np->dn->size = np->dn_stat.st_size;
99 np->dn->mode = np->dn_stat.st_mode;
100 np->dn->nlink = np->dn_stat.st_nlink;
101 np->dn->uid = np->dn_stat.st_uid;
102 np->dn->author = np->dn_stat.st_author;
103 np->dn->gid = np->dn_stat.st_gid;
104 np->dn->atime = np->dn_stat.st_atim;
105 np->dn->mtime = np->dn_stat.st_mtim;
106 np->dn->ctime = np->dn_stat.st_ctim;
107 np->dn->flags = np->dn_stat.st_flags;
108
109 switch (np->dn->type)
110 {
111 case DT_REGDT_REG:
112 assert (np->allocsize % vm_page_size == 0)((np->allocsize % vm_page_size == 0) ? (void) (0) : __assert_fail
("np->allocsize % vm_page_size == 0", "../../tmpfs/node.c"
, 112, __PRETTY_FUNCTION__))
;
113 np->dn->u.reg.allocpages = np->allocsize / vm_page_size;
114 break;
115 case DT_CHRDT_CHR:
116 case DT_BLKDT_BLK:
117 np->dn->u.chr = np->dn_stat.st_rdev;
118 break;
119 }
120
121 /* Remove this node from the cache list rooted at `all_nodes'. */
122 *np->dn->hprevp = np->dn->hnext;
123 if (np->dn->hnext != 0)
124 np->dn->hnext->dn->hprevp = np->dn->hprevp;
125 all_nodes_nr_items -= 1;
126 np->dn->hnext = 0;
127 np->dn->hprevp = 0;
128 }
129
130 free (np);
131}
132
133static void
134recompute_blocks (struct node *np)
135{
136 struct disknode *const dn = np->dn;
137 struct stat *const st = &np->dn_stat;
138
139 st->st_blocks = sizeof *dn + dn->translen;
140 switch (dn->type)
141 {
142 case DT_REGDT_REG:
143 np->allocsize = dn->u.reg.allocpages * vm_page_size;
144 st->st_blocks += np->allocsize;
145 break;
146 case DT_LNKDT_LNK:
147 st->st_blocks += st->st_size + 1;
148 break;
149 case DT_CHRDT_CHR:
150 case DT_BLKDT_BLK:
151 st->st_rdev = dn->u.chr;
152 break;
153 case DT_DIRDT_DIR:
154 st->st_blocks += dn->size;
155 break;
156 }
157 st->st_blocks = (st->st_blocks + 511) / 512;
158}
159
160/* Fetch inode INUM, set *NPP to the node structure;
161 gain one user reference and lock the node. */
162error_t
163diskfs_cached_lookup (ino_t inum, struct node **npp)
164{
165 struct disknode *dn = (void *) (uintptr_t) inum;
166 struct node *np;
167
168 assert (npp)((npp) ? (void) (0) : __assert_fail ("npp", "../../tmpfs/node.c"
, 168, __PRETTY_FUNCTION__))
;
169
170 if (dn->hprevp != 0) /* There is already a node. */
171 {
172 np = *dn->hprevp;
173 assert (np->dn == dn)((np->dn == dn) ? (void) (0) : __assert_fail ("np->dn == dn"
, "../../tmpfs/node.c", 173, __PRETTY_FUNCTION__))
;
174 assert (*dn->hprevp == np)((*dn->hprevp == np) ? (void) (0) : __assert_fail ("*dn->hprevp == np"
, "../../tmpfs/node.c", 174, __PRETTY_FUNCTION__))
;
175
176 diskfs_nref (np);
177 }
178 else
179 /* Create the new node. */
180 {
181 struct stat *st;
182
183 np = diskfs_make_node (dn);
184 np->cache_id = (ino_t) (uintptr_t) dn;
185
186 pthread_spin_lock (&diskfs_node_refcnt_lock);
187 dn->hnext = all_nodes;
188 if (dn->hnext)
189 dn->hnext->dn->hprevp = &dn->hnext;
190 dn->hprevp = &all_nodes;
191 all_nodes = np;
192 all_nodes_nr_items += 1;
193 pthread_spin_unlock (&diskfs_node_refcnt_lock);
194
195 st = &np->dn_stat;
196 memset (st, 0, sizeof *st);
197 st->st_fstype = FSTYPE_MEMFS0x00000019;
198 st->st_fsid = getpid ();
199 st->st_blksize = vm_page_size;
200
201 st->st_ino = (ino_t) (uintptr_t) dn;
202 st->st_gen = dn->gen;
203
204 st->st_size = dn->size;
205 st->st_mode = dn->mode;
206 st->st_nlink = dn->nlink;
207 st->st_uid = dn->uid;
208 st->st_author = dn->author;
209 st->st_gid = dn->gid;
210 st->st_atim = dn->atime;
211 st->st_mtim = dn->mtime;
212 st->st_ctim = dn->ctime;
213 st->st_flags = dn->flags;
214
215 st->st_rdev = 0;
216 np->allocsize = 0;
217 recompute_blocks (np);
218 }
219
220 pthread_mutex_lock (&np->lock);
221 *npp = np;
222 return 0;
223}
224
225error_t
226diskfs_node_iterate (error_t (*fun) (struct node *))
227{
228 error_t err = 0;
229 size_t num_nodes;
230 struct node *node, **node_list, **p;
231
232 pthread_spin_lock (&diskfs_node_refcnt_lock);
233
234 /* We must copy everything from the hash table into another data structure
235 to avoid running into any problems with the hash-table being modified
236 during processing (normally we delegate access to hash-table with
237 diskfs_node_refcnt_lock, but we can't hold this while locking the
238 individual node locks). */
239
240 num_nodes = all_nodes_nr_items;
241
242 p = node_list = alloca (num_nodes * sizeof (struct node *))__builtin_alloca (num_nodes * sizeof (struct node *));
243 for (node = all_nodes; node != 0; node = node->dn->hnext)
1
Assuming 'node' is equal to null
2
Loop condition is false. Execution continues on line 249
244 {
245 *p++ = node;
246 node->references++;
247 }
248
249 pthread_spin_unlock (&diskfs_node_refcnt_lock);
250
251 p = node_list;
252 while (num_nodes-- > 0)
3
Loop condition is true. Entering loop body
253 {
254 node = *p++;
4
Assigned value is garbage or undefined
255 if (!err)
256 {
257 pthread_mutex_lock (&node->lock);
258 err = (*fun) (node);
259 pthread_mutex_unlock (&node->lock);
260 }
261 diskfs_nrele (node);
262 }
263
264 return err;
265}
266
267/* The user must define this function. Node NP has some light
268 references, but has just lost its last hard references. Take steps
269 so that if any light references can be freed, they are. NP is locked
270 as is the pager refcount lock. This function will be called after
271 diskfs_lost_hardrefs. */
272void
273diskfs_try_dropping_softrefs (struct node *np)
274{
275}
276
277/* The user must define this funcction. Node NP has some light
278 references but has just lost its last hard reference. NP is locked. */
279void
280diskfs_lost_hardrefs (struct node *np)
281{
282}
283
284/* The user must define this function. Node NP has just acquired
285 a hard reference where it had none previously. It is thus now
286 OK again to have light references without real users. NP is
287 locked. */
288void
289diskfs_new_hardrefs (struct node *np)
290{
291}
292
293
294
295error_t
296diskfs_get_translator (struct node *np, char **namep, u_int *namelen)
297{
298 *namelen = np->dn->translen;
299 if (*namelen == 0)
300 return 0;
301 *namep = malloc (*namelen);
302 if (*namep == 0)
303 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
304 memcpy (*namep, np->dn->trans, *namelen);
305 return 0;
306}
307
308error_t
309diskfs_set_translator (struct node *np,
310 const char *name, u_int namelen,
311 struct protid *cred)
312{
313 char *new;
314 if (namelen == 0)
315 {
316 free (np->dn->trans);
317 new = 0;
318 np->dn_stat.st_mode &= ~S_IPTRANS000010000000;
319 }
320 else
321 {
322 new = realloc (np->dn->trans, namelen);
323 if (new == 0)
324 return ENOSPC((0x10 << 26) | ((28) & 0x3fff));
325 memcpy (new, name, namelen);
326 np->dn_stat.st_mode |= S_IPTRANS000010000000;
327 }
328 adjust_used (namelen - np->dn->translen);
329 np->dn->trans = new;
330 np->dn->translen = namelen;
331 recompute_blocks (np);
332 return 0;
333}
334
335static error_t
336create_symlink_hook (struct node *np, const char *target)
337{
338 assert (np->dn->u.lnk == 0)((np->dn->u.lnk == 0) ? (void) (0) : __assert_fail ("np->dn->u.lnk == 0"
, "../../tmpfs/node.c", 338, __PRETTY_FUNCTION__))
;
339 np->dn_stat.st_size = strlen (target);
340 if (np->dn_stat.st_size > 0)
341 {
342 const size_t size = np->dn_stat.st_size + 1;
343 np->dn->u.lnk = malloc (size);
344 if (np->dn->u.lnk == 0)
345 return ENOSPC((0x10 << 26) | ((28) & 0x3fff));
346 memcpy (np->dn->u.lnk, target, size);
347 np->dn->type = DT_LNKDT_LNK;
348 adjust_used (size);
349 recompute_blocks (np);
350 }
351 return 0;
352}
353error_t (*diskfs_create_symlink_hook)(struct node *np, const char *target)
354 = create_symlink_hook;
355
356static error_t
357read_symlink_hook (struct node *np, char *target)
358{
359 memcpy (target, np->dn->u.lnk, np->dn_stat.st_size + 1);
360 return 0;
361}
362error_t (*diskfs_read_symlink_hook)(struct node *np, char *target)
363 = read_symlink_hook;
364
365void
366diskfs_write_disknode (struct node *np, int wait)
367{
368}
369
370void
371diskfs_file_update (struct node *np, int wait)
372{
373 diskfs_node_update (np, wait);
374}
375
376error_t
377diskfs_node_reload (struct node *node)
378{
379 return 0;
380}
381
382
383/* The user must define this function. Truncate locked node NP to be SIZE
384 bytes long. (If NP is already less than or equal to SIZE bytes
385 long, do nothing.) If this is a symlink (and diskfs_shortcut_symlink
386 is set) then this should clear the symlink, even if
387 diskfs_create_symlink_hook stores the link target elsewhere. */
388error_t
389diskfs_truncate (struct node *np, off_t size)
390{
391 if (np->dn->type == DT_LNKDT_LNK)
392 {
393 free (np->dn->u.lnk);
394 adjust_used (size - np->dn_stat.st_size);
395 np->dn->u.lnk = 0;
396 np->dn_stat.st_size = size;
397 return 0;
398 }
399
400 if (np->allocsize <= size)
401 return 0;
402
403 assert (np->dn->type == DT_REG)((np->dn->type == DT_REG) ? (void) (0) : __assert_fail (
"np->dn->type == DT_REG", "../../tmpfs/node.c", 403, __PRETTY_FUNCTION__
))
;
404
405 if (default_pager == MACH_PORT_NULL((mach_port_t) 0))
406 return EIO((0x10 << 26) | ((5) & 0x3fff));
407
408 np->dn_stat.st_size = size;
409
410 off_t set_size = size;
411 size = round_page (size)((((vm_offset_t) (size) + __vm_page_size - 1) / __vm_page_size
) * __vm_page_size)
;
412
413 if (np->dn->u.reg.memobj != MACH_PORT_NULL((mach_port_t) 0))
414 {
415 error_t err = default_pager_object_set_size (np->dn->u.reg.memobj, set_size);
416 if (err == MIG_BAD_ID-303)
417 /* This is an old default pager. We have no way to truncate the
418 memory object. Note that the behavior here will be wrong in
419 two ways: user accesses past the end won't fault; and, more
420 importantly, later growing the file won't zero the contents
421 past the size we just supposedly truncated to. For proper
422 behavior, use a new default pager. */
423 return 0;
424 if (err)
425 return err;
426 }
427 /* Otherwise it never had any real contents. */
428
429 adjust_used (size - np->allocsize);
430 np->dn_stat.st_blocks += (size - np->allocsize) / 512;
431 np->allocsize = size;
432
433 return 0;
434}
435
436/* The user must define this function. Grow the disk allocated to locked node
437 NP to be at least SIZE bytes, and set NP->allocsize to the actual
438 allocated size. (If the allocated size is already SIZE bytes, do
439 nothing.) CRED identifies the user responsible for the call. */
440error_t
441diskfs_grow (struct node *np, off_t size, struct protid *cred)
442{
443 assert (np->dn->type == DT_REG)((np->dn->type == DT_REG) ? (void) (0) : __assert_fail (
"np->dn->type == DT_REG", "../../tmpfs/node.c", 443, __PRETTY_FUNCTION__
))
;
444
445 if (np->allocsize >= size)
446 return 0;
447
448 off_t set_size = size;
449 size = round_page (size)((((vm_offset_t) (size) + __vm_page_size - 1) / __vm_page_size
) * __vm_page_size)
;
450 if (round_page (tmpfs_space_used + size - np->allocsize)((((vm_offset_t) (tmpfs_space_used + size - np->allocsize)
+ __vm_page_size - 1) / __vm_page_size) * __vm_page_size)
451 / vm_page_size > tmpfs_page_limit)
452 return ENOSPC((0x10 << 26) | ((28) & 0x3fff));
453
454 if (default_pager == MACH_PORT_NULL((mach_port_t) 0))
455 return EIO((0x10 << 26) | ((5) & 0x3fff));
456
457 if (np->dn->u.reg.memobj != MACH_PORT_NULL((mach_port_t) 0))
458 {
459 /* Increase the limit the memory object will allow to be accessed. */
460 error_t err = default_pager_object_set_size (np->dn->u.reg.memobj, set_size);
461 if (err == MIG_BAD_ID-303) /* Old default pager, never limited it. */
462 err = 0;
463 if (err)
464 return err;
465 }
466
467 adjust_used (size - np->allocsize);
468 np->dn_stat.st_blocks += (size - np->allocsize) / 512;
469 np->allocsize = size;
470 return 0;
471}
472
473mach_port_t
474diskfs_get_filemap (struct node *np, vm_prot_t prot)
475{
476 error_t err;
477
478 if (np->dn->type != DT_REGDT_REG)
479 {
480 errno(*__errno_location ()) = EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); /* ? */
481 return MACH_PORT_NULL((mach_port_t) 0);
482 }
483
484 if (default_pager == MACH_PORT_NULL((mach_port_t) 0))
485 {
486 errno(*__errno_location ()) = EIO((0x10 << 26) | ((5) & 0x3fff));
487 return MACH_PORT_NULL((mach_port_t) 0);
488 }
489
490 /* We don't bother to create the memory object until the first time we
491 need it (i.e. first mapping or i/o). This way we might have a clue
492 what size it's going to be beforehand, so we can tell the default
493 pager how big to make its bitmaps. This is just an optimization for
494 the default pager; the memory object can be expanded at any time just
495 by accessing more of it. (It also optimizes the case of empty files
496 so we might never make a memory object at all.) */
497 if (np->dn->u.reg.memobj == MACH_PORT_NULL((mach_port_t) 0))
498 {
499 error_t err = default_pager_object_create (default_pager,
500 &np->dn->u.reg.memobj,
501 np->allocsize);
502 if (err)
503 {
504 errno(*__errno_location ()) = err;
505 return MACH_PORT_NULL((mach_port_t) 0);
506 }
507 assert (np->dn->u.reg.memobj != MACH_PORT_NULL)((np->dn->u.reg.memobj != ((mach_port_t) 0)) ? (void) (
0) : __assert_fail ("np->dn->u.reg.memobj != ((mach_port_t) 0)"
, "../../tmpfs/node.c", 507, __PRETTY_FUNCTION__))
;
508
509 /* XXX we need to keep a reference to the object, or GNU Mach
510 will terminate it when we release the map. */
511 vm_map (mach_task_self ()((__mach_task_self_ + 0)), &np->dn->u.reg.memref, 4096, 0, 1,
512 np->dn->u.reg.memobj, 0, 0, VM_PROT_NONE((vm_prot_t) 0x00), VM_PROT_NONE((vm_prot_t) 0x00),
513 VM_INHERIT_NONE((vm_inherit_t) 2));
514 assert_perror (err)(!(err) ? (void) (0) : __assert_perror_fail ((err), "../../tmpfs/node.c"
, 514, __PRETTY_FUNCTION__))
;
515 }
516
517 /* XXX always writable */
518
519 /* Add a reference for each call, the caller will deallocate it. */
520 err = mach_port_mod_refs (mach_task_self ()((__mach_task_self_ + 0)), np->dn->u.reg.memobj,
521 MACH_PORT_RIGHT_SEND((mach_port_right_t) 0), +1);
522 assert_perror (err)(!(err) ? (void) (0) : __assert_perror_fail ((err), "../../tmpfs/node.c"
, 522, __PRETTY_FUNCTION__))
;
523
524 return np->dn->u.reg.memobj;
525}
526
527/* The user must define this function. Return a `struct pager *' suitable
528 for use as an argument to diskfs_register_memory_fault_area that
529 refers to the pager returned by diskfs_get_filemap for node NP.
530 NP is locked. */
531struct pager *
532diskfs_get_filemap_pager_struct (struct node *np)
533{
534 return 0;
535}
536
537/* We have no pager of our own, so there is no need to worry about
538 users of it, or to shut it down. */
539int
540diskfs_pager_users ()
541{
542 return 0;
543}
544void
545diskfs_shutdown_pager ()
546{
547}
548
549/* The purpose of this is to decide that it's ok to make the fs read-only.
550 Turning a temporary filesystem read-only seem pretty useless. */
551vm_prot_t
552diskfs_max_user_pager_prot ()
553{
554 return VM_PROT_READ((vm_prot_t) 0x01); /* Probable lie that lets us go read-only. */
555}
556
557error_t
558diskfs_S_file_get_storage_info (struct protid *cred,
559 mach_port_t **ports,
560 mach_msg_type_name_t *ports_type,
561 mach_msg_type_number_t *num_ports,
562 int **ints, mach_msg_type_number_t *num_ints,
563 off_t **offsets,
564 mach_msg_type_number_t *num_offsets,
565 char **data, mach_msg_type_number_t *data_len)
566{
567 mach_port_t memobj = diskfs_get_filemap (cred->po->np, VM_PROT_ALL(((vm_prot_t) 0x01)|((vm_prot_t) 0x02)|((vm_prot_t) 0x04)));
568 if (memobj == MACH_PORT_NULL((mach_port_t) 0))
569 return errno(*__errno_location ());
570
571 assert (*num_ports >= 1)((*num_ports >= 1) ? (void) (0) : __assert_fail ("*num_ports >= 1"
, "../../tmpfs/node.c", 571, __PRETTY_FUNCTION__))
; /* mig always gives us some */
572 *num_ports = 1;
573 *ports_type = MACH_MSG_TYPE_MOVE_SEND17;
574 (*ports)[0]
575 = (cred->po->openstat & O_RDWR(0x0001|0x0002)) == O_RDWR(0x0001|0x0002) ? memobj : MACH_PORT_NULL((mach_port_t) 0);
576
577 assert (*num_offsets >= 2)((*num_offsets >= 2) ? (void) (0) : __assert_fail ("*num_offsets >= 2"
, "../../tmpfs/node.c", 577, __PRETTY_FUNCTION__))
; /* mig always gives us some */
578 *num_offsets = 2;
579 (*offsets)[0] = 0;
580 (*offsets)[1] = cred->po->np->dn_stat.st_size;
581
582 assert (*num_ints >= 6)((*num_ints >= 6) ? (void) (0) : __assert_fail ("*num_ints >= 6"
, "../../tmpfs/node.c", 582, __PRETTY_FUNCTION__))
; /* mig always gives us some */
583 *num_ints = 6;
584 (*ints)[0] = STORAGE_MEMORY;
585 (*ints)[1] = (cred->po->openstat & O_WRITE0x0002) ? 0 : STORE_READONLY0x0100;
586 (*ints)[2] = 1; /* block size */
587 (*ints)[3] = 1; /* 1 run in offsets list */
588 (*ints)[4] = 0; /* name len */
589 (*ints)[5] = 0; /* misc len */
590
591 *data_len = 0;
592
593 return 0;
594}