1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
|
/*
* Copyright (c) International Business Machines Corp., 2000-2002
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <time.h>
#include <errno.h>
#include "jfs_types.h"
#include "jfs_endian.h"
#include "jfs_filsys.h"
#include "jfs_dinode.h"
#include "initmap.h"
#include "inode.h"
#include "devices.h"
#include "inodes.h"
#include "debug.h"
#include "message.h"
/* endian routines */
extern unsigned type_jfs;
/*
* NAME: init_aggr_inode_table
*
* FUNCTION: Initialize aggregate inodes to disk
*
* PARAMETERS:
* aggr_block_size - block size for aggregate
* dev_ptr - open port for device to write to
* aggr_inodes - Array of initial aggregate inodes. They have been
* initialized elsewhere.
* num_aggr_inodes - Number of aggregate inodes initialized.
* table_loc - Byte offset of table location
* inode_map_loc - Block offset of inode map
* inode_map_sz - Byte count of inode map
* inostamp - Inode stamp to be used for aggregate inodes
*
* RETURNS:
* success: 0
* failure: any other value
*/
int init_aggr_inode_table(int aggr_block_size,
FILE *dev_ptr,
struct dinode *aggr_inodes,
int num_aggr_inodes,
int64_t table_loc,
int64_t inode_map_loc,
int inode_map_sz, unsigned inostamp)
{
void *buffer;
int64_t first_block, last_block, index;
int i, rc;
struct dinode *buf_ai;
/*
* Allocate space for first inode extent, and clear
*/
buffer = calloc(INODE_EXTENT_SIZE, sizeof (char));
if (buffer == NULL) {
message_user(MSG_OSO_INSUFF_MEMORY, NULL, 0, OSO_MSG);
return (ENOMEM);
}
/*
* Initialize inodes: 0, 1, 3, and 4
* Inode 2 has already been initialized;
*/
DBG_TRACE(("size of dinode = %d\n", sizeof (struct dinode)))
aggr_inodes[AGGR_RESERVED_I].di_nlink = 1;
/*
* Initialize inode 1: "self" inode
*/
init_inode(&(aggr_inodes[AGGREGATE_I]), AGGREGATE_I, AGGREGATE_I,
inode_map_sz / aggr_block_size, inode_map_sz, inode_map_loc,
IFJOURNAL | IFREG, max_extent_data,
table_loc / aggr_block_size, aggr_block_size, inostamp);
aggr_inodes[AGGREGATE_I].di_gengen = 1;
/*
* Initialize inode 3: inline log inode
*/
init_inode(&(aggr_inodes[LOG_I]), AGGREGATE_I, LOG_I, 0, 0, 0,
IFJOURNAL | IFREG, no_data, table_loc / aggr_block_size,
aggr_block_size, inostamp);
/*
* Initialize inode 4: bad block inode
*/
init_inode(&(aggr_inodes[BADBLOCK_I]), AGGREGATE_I, BADBLOCK_I, 0, 0, 0,
IFJOURNAL | IFREG | ISPARSE, no_data,
table_loc / aggr_block_size, aggr_block_size, inostamp);
/*
* Copy initialized inodes to buffer
*/
memcpy(buffer, aggr_inodes, num_aggr_inodes * sizeof (struct dinode));
/*
* Write Inode extent to disk
*/
/* swap if on big endian machine */
/* swap gengen from aggr_inodes[AGGREGATE_I] in buffer */
buf_ai = ((struct dinode *) buffer) + AGGREGATE_I;
buf_ai->di_gengen = __le32_to_cpu(buf_ai->di_gengen);
for (i = 0; i < num_aggr_inodes; i++) {
ujfs_swap_dinode((struct dinode *) buffer, PUT, type_jfs);
buffer = (char *) buffer + sizeof (struct dinode);
}
buffer = (char *) buffer - (num_aggr_inodes * sizeof (struct dinode));
rc = ujfs_rw_diskblocks(dev_ptr, table_loc, INODE_EXTENT_SIZE, buffer,
PUT);
free(buffer);
if (rc != 0)
return rc;
/*
* Mark blocks allocated in block allocation map
*/
first_block = table_loc / aggr_block_size;
last_block = first_block + (INODE_EXTENT_SIZE / aggr_block_size);
for (index = first_block; ((index < last_block) && (rc == 0)); index++) {
rc = markit(index, ALLOC);
}
return (rc);
}
/*
* NAME: init_fileset_inode_table
*
* FUNCTION: Initialize fileset inodes and write to disk
*
* PARAMETERS:
* aggr_block_size - block size for aggregate
* dev_ptr - open port for device to write to
* inode_location - Filled in with byte offset of first extent of fileset
* inode table
* inode_size - Filled in with byte count of first extent of fileset
* inode table
* fileset_start - First block for fileset, will use this to determine
* where to put the inodes on disk
* fileset_inode_map_loc - First block of fileset inode map
* inostamp - stamp for inode
*
* RETURNS:
* success: 0
* failure: any other value
*/
int init_fileset_inode_table(int aggr_block_size,
FILE *dev_ptr,
int64_t * inode_location,
int *inode_size,
int64_t fileset_start,
int64_t fileset_inode_map_loc, unsigned inostamp)
{
void *buffer, *bp;
struct dinode inode_buffer;
int64_t first_block, last_block, index;
int i, rc;
int root_size;
dtroot_t *root_header;
/*
* Find space for the inode extent
*
* Release 1 will not support multiple filesets per aggregate, so the
* location of the inode extent can be fixed. However in future releases
* this will have to be modified to find the space for this extent using
* the block allocation map.
*/
#ifdef ONE_FILESET_PER_AGGR
/*
* The first fileset inode extent is the first thing written for the
* fileset, so its location is the start of the fileset
*/
*inode_location = fileset_start * aggr_block_size;
#else
*inode_location = get_space(*inode_size);
#endif /* ONE_FILESET_PER_AGGR */
/*
* Allocate space for first inode extent, and clear
*/
*inode_size = INODE_EXTENT_SIZE;
bp = buffer = calloc(*inode_size, sizeof (char));
if (bp == NULL) {
message_user(MSG_OSO_INSUFF_MEMORY, NULL, 0, OSO_MSG);
return (ENOMEM);
}
/*
* Inode 0 - Reserved Inode
*/
memset(&inode_buffer, 0, sizeof (inode_buffer));
init_inode(&inode_buffer, FILESYSTEM_I, FILESET_RSVD_I, 0, 0, 0,
IFJOURNAL | IFREG, no_data, fileset_start, aggr_block_size,
inostamp);
memcpy(bp, &inode_buffer, sizeof (inode_buffer));
bp = (char *) bp + sizeof (inode_buffer);
/*
* Inode 1 - 2nd half of fileset superblock information
*
* When we add support for VFS this will be a special inode with
* different information. For now we will just make it look like an
* empty inode to reserve it.
*/
memset(&inode_buffer, 0, sizeof (inode_buffer));
init_inode(&inode_buffer, FILESYSTEM_I, FILESET_EXT_I, 0, 0, 0,
IFJOURNAL | IFREG, no_data, fileset_start, aggr_block_size,
inostamp);
memcpy(bp, &inode_buffer, sizeof (inode_buffer));
bp = (char *) bp + sizeof (inode_buffer);
/*
* Inode 2 - Root directory
*/
memset(&inode_buffer, 0, sizeof (inode_buffer));
root_size =
sizeof (struct dinode) - offsetof(struct dinode, di_inlinedata);
init_inode(&inode_buffer, FILESYSTEM_I, ROOT_I, 0, root_size, 0,
IFJOURNAL | IFDIR | 0755, no_data, fileset_start,
aggr_block_size, inostamp);
/* Set number of links for root to account for '.' entry */
inode_buffer.di_nlink = 2;
/*
* Initialize the directory B+-tree header for the root inode
* Since the root directory has no entries the nextindex is 0; nextindex
* is for the stbl index not the slot index.
*/
root_header = (dtroot_t *) & (inode_buffer.di_DASD);
root_header->header.flag = DXD_INDEX | BT_ROOT | BT_LEAF;
setDASDLIMIT(&(root_header->header.DASD), 0);
setDASDUSED(&(root_header->header.DASD), 0);
root_header->header.nextindex = 0;
/*
* Determine how many slots will fit
*/
root_header->header.freecnt = DTROOTMAXSLOT - 1;
root_header->header.freelist = DTENTRYSTART;
root_header->header.idotdot = 2;
for (index = DTENTRYSTART; index < DTROOTMAXSLOT; index++) {
root_header->slot[index].cnt = 1;
root_header->slot[index].next = index + 1;
}
/*
* Last entry should end the free list.
*/
index--;
root_header->slot[index].next = -1;
memcpy(bp, &inode_buffer, sizeof (inode_buffer));
bp = (char *) bp + sizeof (inode_buffer);
/*
* Inode 3 - ACL File
*/
memset(&inode_buffer, 0, sizeof (inode_buffer));
init_inode(&inode_buffer, FILESYSTEM_I, ACL_I, 0, 0, 0,
IFJOURNAL | IFREG, no_data, fileset_start, aggr_block_size,
inostamp);
memcpy(bp, &inode_buffer, sizeof (inode_buffer));
/*
* Write Inode extent to disk
*/
/* swap if on big endian machine */
bp = buffer;
for (i = 0; i < 4; i++) {
ujfs_swap_dinode((struct dinode *) bp, PUT, type_jfs);
bp = (char *) bp + sizeof (inode_buffer);
}
rc = ujfs_rw_diskblocks(dev_ptr, *inode_location, *inode_size, buffer,
PUT);
free(buffer);
if (rc != 0)
return rc;
/*
* Mark blocks allocated in block allocation map
*/
first_block = *inode_location / aggr_block_size;
last_block = (*inode_location + *inode_size) / aggr_block_size;
for (index = first_block; ((index < last_block) && (rc == 0)); index++) {
rc = markit(index, ALLOC);
}
return (rc);
}
/*
* NAME: init_fileset_inodes
*
* FUNCTION: Initialize fileset inodes in aggregate inode table
*
* PARAMETERS:
* aggr_block_size - block size for aggregate
* dev_ptr - open port for device to write to
* inode_map_loc - byte offset for first extent of fileset's inode map
* inode_map_size - byte count for first extent of fileset's inode map
* fileset_start - First block of fileset. Will be used to determine
* location of the AG table.
* inostamp - time stamp for inodes in this fileset
*
* RETURNS:
* success: 0
* failure: any other value
*/
int init_fileset_inodes(int aggr_block_size,
FILE *dev_ptr,
int64_t inode_map_loc,
int inode_map_size,
int64_t fileset_start,
unsigned inostamp)
{
struct dinode inode_buffer;
unsigned inode_num;
int rc;
/*
* Figure out which is the next free aggregate fileset inode
*
* Release 1 only supports one fileset per aggregate, so we know this
* will always be inode FILESYSTEM_I in the aggregate inode table. In
* future releases we will need to modify this code to look in the
* aggregate inode table for the next available free inode.
*/
#ifdef ONE_FILESET_PER_AGGR
inode_num = FILESYSTEM_I;
#else
inode_num = get_next_free();
#endif /* ONE_FILESET_PER_AGGR */
/*
* Initialize Fileset Inode: Fileset Inode Allocation Map
*/
memset(&inode_buffer, 0, sizeof (inode_buffer));
init_inode(&inode_buffer, AGGREGATE_I, inode_num,
inode_map_size / aggr_block_size, inode_map_size,
inode_map_loc, IFJOURNAL | IFREG, max_extent_data,
AITBL_OFF / aggr_block_size, aggr_block_size, inostamp);
/* swap here if necessary for big endian */
inode_buffer.di_gengen = __le32_to_cpu(1);
/*
* Write fileset inode to disk
*/
rc = ujfs_rwinode(dev_ptr, &inode_buffer, inode_num, PUT,
aggr_block_size, AGGREGATE_I, type_jfs);
return (rc);
}
/*
* NAME: init_inode
*
* FUNCTION: Initialize inode fields for an inode with a single extent or inline
* data or a directory inode
*
* PARAMETERS:
* new_inode - Pointer to inode to be initialized
* fileset_num - Fileset number for inode
* inode_num - Inode number of inode
* num_blocks - Number of aggregate blocks allocated to inode
* size - Size in bytes allocated to inode
* first_block - Offset of first block of inode's extent
* mode - Mode for inode
* inode_type - Indicates the type of inode to be initialized.
* Currently supported types are inline data, extents,
* and no data. The other parameters to this function
* will provide the necessary information.
* inoext_address - Address of inode extent containing this inode
* aggr_block_size - Aggregate block size
* inostamp - Stamp used to identify inode as belonging to fileset
*
* RETURNS: None
*/
void init_inode(struct dinode *new_inode,
int fileset_num,
unsigned inode_num,
int64_t num_blocks,
int64_t size,
int64_t first_block,
mode_t mode,
ino_data_type inode_type,
int64_t inoext_address,
int aggr_block_size,
unsigned inostamp)
{
/*
* Initialize inode with where this stuff lives
*/
new_inode->di_inostamp = inostamp;
new_inode->di_fileset = fileset_num;
new_inode->di_number = inode_num;
new_inode->di_gen = 1;
PXDaddress(&(new_inode->di_ixpxd), inoext_address);
PXDlength(&(new_inode->di_ixpxd), INODE_EXTENT_SIZE / aggr_block_size);
new_inode->di_mode = mode;
new_inode->di_nblocks = num_blocks;
new_inode->di_size = size;
new_inode->di_nlink = 1;
new_inode->di_next_index = 2;
switch (inode_type) {
case inline_data:
new_inode->di_dxd.flag = DXD_INLINE;
DXDlength(&(new_inode->di_dxd),
sizeof (struct dinode) - offsetof(struct dinode,
di_inlinedata));
DXDaddress(&(new_inode->di_dxd), 0);
break;
case extent_data:
case max_extent_data:
((xtpage_t *) & (new_inode->di_DASD))->header.flag =
DXD_INDEX | BT_ROOT | BT_LEAF;
/*
* Since this is the root, we don't actually use the next and
* prev entries. Set to 0 in case we decide to use this space
* for something in the future.
*/
((xtpage_t *) & (new_inode->di_DASD))->header.next = 0;
((xtpage_t *) & (new_inode->di_DASD))->header.prev = 0;
((xtpage_t *) & (new_inode->di_DASD))->header.nextindex =
XTENTRYSTART + 1;
((xtpage_t *) & (new_inode->di_DASD))->header.maxentry =
XTROOTMAXSLOT;
((xtpage_t *) & (new_inode->di_DASD))->xad[XTENTRYSTART].flag =
0;
((xtpage_t *) & (new_inode->di_DASD))->xad[XTENTRYSTART].rsvrd =
0;
XADoffset(&((xtpage_t *) & (new_inode->di_DASD))->
xad[XTENTRYSTART], 0);
XADlength(&((xtpage_t *) & (new_inode->di_DASD))->
xad[XTENTRYSTART], num_blocks);
XADaddress(&((xtpage_t *) & (new_inode->di_DASD))->
xad[XTENTRYSTART], first_block);
break;
case no_data:
/*
* No data to be filled in here, don't do anything
*/
((xtpage_t *) & (new_inode->di_DASD))->header.flag =
DXD_INDEX | BT_ROOT | BT_LEAF;
/*
* Since this is the root, we don't actually use the next and
* prev entries. Set to 0 in case we decide to use this space
* for something in the future.
*/
((xtpage_t *) & (new_inode->di_DASD))->header.next = 0;
((xtpage_t *) & (new_inode->di_DASD))->header.prev = 0;
((xtpage_t *) & (new_inode->di_DASD))->header.nextindex =
XTENTRYSTART;
((xtpage_t *) & (new_inode->di_DASD))->header.maxentry =
XTROOTMAXSLOT;
((xtpage_t *) & (new_inode->di_DASD))->xad[XTENTRYSTART].flag =
0;
((xtpage_t *) & (new_inode->di_DASD))->xad[XTENTRYSTART].rsvrd =
0;
break;
default:
DBG_ERROR(("Internal error: %s(%d): Unrecognized inode data type %d\n",
__FILE__, __LINE__, inode_type))
break;
}
new_inode->di_atime.tv_sec = new_inode->di_ctime.tv_sec =
new_inode->di_mtime.tv_sec = new_inode->di_otime.tv_sec =
(unsigned) time(NULL);
return;
}
|