// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2003 Silicon Graphics, Inc. * All Rights Reserved. */ /* * * loggen: Generate log entries. Very much incomplete. The empty log * record is a bit of a misnomer since we need to jump through * hoops to get a log record that parses ok yet does nothing. * * - dxm 29/09/00 */ #include #include #ifdef HAVE_XFS_XFS_LOG_FORMAT_H #include #define XFS_TRANS_MAGIC XFS_TRANS_HEADER_MAGIC #else /* HAVE_XFS_XFS_LOG_FORMAT_H */ #include #include #endif /* HAVE_XFS_XFS_LOG_FORMAT_H */ #ifndef ASSIGN_ANY_LSN_DISK #define ASSIGN_ANY_LSN_DISK(lsn,cycle,block) \ { \ INT_SET(((uint *)&(lsn))[0], ARCH_CONVERT, (cycle)); \ INT_SET(((uint *)&(lsn))[1], ARCH_CONVERT, (block)); \ } #endif void usage(void) { fprintf(stderr,"Usage: loggen\n" " set up parameters before writing record(s):\n" " -f f - set format\n" " -u u - set uuid\n" " -c c - set cycle\n" " -b b - set block\n" " -C c - set tail cycle\n" " -B b - set tail block\n" " write log record(s):\n" " -z n - write n zero block(s) (1BB)\n" " -e n - write n empty record(s) (2BB)\n" " -m n - write n unmount record(s) (2BB)\n" "\n" " redirect stdout to external log partition, or pipe to\n" " dd with appropriate parameters to stuff into internal log.\n" ); exit(1); } int bufblocks = 0; void *buf = NULL; int param_cycle = 1; int param_block = 0; int param_tail_cycle = 1; int param_tail_block = 0; int param_fmt = XLOG_FMT; uuid_t param_uuid = {0}; void loggen_alloc(int blocks) { if (!(buf=realloc(buf, blocks*BBSIZE))) { fprintf(stderr,"failed to allocate %d block(s)\n", blocks); exit(1); } memset(buf, 0, blocks*BBSIZE); bufblocks=blocks; } void loggen_write(void) { if (!buf) { fprintf(stderr,"no buffer allocated\n"); exit(1); } if (fwrite(buf, BBSIZE, bufblocks, stdout) != bufblocks) { perror("fwrite"); exit(1); } } void loggen_zero(int count) { if (!count) count=1; fprintf(stderr," *** zero block (1BB) x %d\n", count); loggen_alloc(1); while (count--) loggen_write(); } void loggen_unmount(int count) { xlog_rec_header_t *head; xlog_op_header_t *op; /* the data section must be 32 bit size aligned */ struct { uint16_t magic; uint16_t pad1; uint32_t pad2; /* may as well make it 64 bits */ } magic = { XLOG_UNMOUNT_TYPE, 0, 0 }; if (!count) count=1; fprintf(stderr," *** unmount record (2BB) x %d\n", count); loggen_alloc(2); head = (xlog_rec_header_t *)buf; op = (xlog_op_header_t *)(((char*)buf)+BBSIZE); /* note that oh_tid actually contains the cycle number * and the tid is stored in h_cycle_data[0] - that's the * way things end up on disk. */ head->h_magicno = cpu_to_be32(XLOG_HEADER_MAGIC_NUM); head->h_cycle = cpu_to_be32(param_cycle); head->h_version = cpu_to_be32(1); head->h_len = cpu_to_be32(20); head->h_prev_block = cpu_to_be32(-1); head->h_num_logops = cpu_to_be32(1); head->h_cycle_data[0] = cpu_to_be32(0xb0c0d0d0); head->h_fmt = cpu_to_be32(param_fmt); head->h_tail_lsn = cpu_to_be64(xlog_assign_lsn(param_tail_cycle, param_tail_block)); memcpy(head->h_fs_uuid, param_uuid, sizeof(uuid_t)); /* now a log unmount op */ op->oh_tid = cpu_to_be32(param_cycle); op->oh_len = cpu_to_be32(sizeof(magic)); op->oh_clientid = XFS_LOG; op->oh_flags = XLOG_UNMOUNT_TRANS; op->oh_res2 = cpu_to_be16(0); /* and the data for this op */ memcpy(op+1, &magic, sizeof(magic)); while (count--) { head->h_lsn = cpu_to_be64(xlog_assign_lsn(param_cycle, param_block++)); loggen_write(); } } void loggen_empty(int count) { xlog_rec_header_t *head; xlog_op_header_t *op1, *op2, *op3, *op4, *op5; xfs_trans_header_t *trans; xfs_buf_log_format_t blfs; xfs_buf_log_format_t *blf; int *data; char *p; if (!count) count=1; fprintf(stderr," *** empty record (2BB) x %d\n", count); loggen_alloc(2); p=(char*)buf; head = (xlog_rec_header_t *)p; p+=BBSIZE; op1 = (xlog_op_header_t *)p; p+=sizeof(xlog_op_header_t); op2 = (xlog_op_header_t *)p; p+=sizeof(xlog_op_header_t); trans = (xfs_trans_header_t *)p; p+=sizeof(xfs_trans_header_t); op3 = (xlog_op_header_t *)p; p+=sizeof(xlog_op_header_t); blf = (xfs_buf_log_format_t*)p; p+=sizeof(xfs_buf_log_format_t); op4 = (xlog_op_header_t *)p; p+=sizeof(xlog_op_header_t); data = (int *)p; p+=sizeof(int); op5 = (xlog_op_header_t *)p; p+=sizeof(xlog_op_header_t); /* note that oh_tid actually contains the cycle number * and the tid is stored in h_cycle_data[0] - that's the * way things end up on disk. */ head->h_magicno = cpu_to_be32(XLOG_HEADER_MAGIC_NUM); head->h_cycle = cpu_to_be32(param_cycle); head->h_version = cpu_to_be32(1); head->h_len = cpu_to_be32(5*sizeof(xlog_op_header_t) + sizeof(xfs_trans_header_t)+ sizeof(xfs_buf_log_format_t)+ sizeof(int)); head->h_prev_block = cpu_to_be32(-1); head->h_num_logops = cpu_to_be32(5); head->h_cycle_data[0] = cpu_to_be32(0xb0c0d0d0); head->h_fmt = cpu_to_be32(param_fmt); head->h_tail_lsn = cpu_to_be64(xlog_assign_lsn(param_tail_cycle, param_tail_block)); memcpy(head->h_fs_uuid, param_uuid, sizeof(uuid_t)); /* start */ op1->oh_tid = cpu_to_be32(1); op1->oh_len = cpu_to_be32(0); op1->oh_clientid = XFS_TRANSACTION; op1->oh_flags = XLOG_START_TRANS; op1->oh_res2 = cpu_to_be16(0); /* dummy */ op2->oh_tid = cpu_to_be32(0xb0c0d0d0); op2->oh_len = cpu_to_be32(sizeof(xfs_trans_header_t)); op2->oh_clientid = XFS_TRANSACTION; op2->oh_flags = 0; op2->oh_res2 = cpu_to_be16(0); /* dummy transaction - this stuff doesn't get endian converted */ trans->th_magic = XFS_TRANS_MAGIC; trans->th_type = XFS_TRANS_DUMMY1; trans->th_tid = 0; trans->th_num_items = 1; /* buffer */ op3->oh_tid = cpu_to_be32(0xb0c0d0d0); op3->oh_len = cpu_to_be32(sizeof(xfs_buf_log_format_t)); op3->oh_clientid = XFS_TRANSACTION; op3->oh_flags = 0; op3->oh_res2 = cpu_to_be16(0); /* an empty buffer too */ blfs.blf_type = XFS_LI_BUF; blfs.blf_size = 2; #ifdef XFS_BLF_CANCEL blfs.blf_flags = XFS_BLF_CANCEL; #else blfs.blf_flags = XFS_BLI_CANCEL; #endif blfs.blf_len = 0; blfs.blf_blkno = 1; blfs.blf_map_size = 1; blfs.blf_data_map[0]= 0; memcpy(blf, &blfs, sizeof(blfs)); /* commit */ op4->oh_tid = cpu_to_be32(0xb0c0d0d0); op4->oh_len = cpu_to_be32(sizeof(int)); op4->oh_clientid = XFS_TRANSACTION; op4->oh_flags = 0; op4->oh_res2 = cpu_to_be16(0); /* and the data */ *data=*(int*)(char*)"FISH"; /* this won't get written (I hope) */ /* commit */ op5->oh_tid = cpu_to_be32(0xb0c0d0d0); op5->oh_len = cpu_to_be32(0); op5->oh_clientid = XFS_TRANSACTION; op5->oh_flags = XLOG_COMMIT_TRANS; op5->oh_res2 = cpu_to_be16(0); while (count--) { head->h_lsn = cpu_to_be64(xlog_assign_lsn(param_cycle, param_block++)); loggen_write(); } } int main(int argc, char *argv[]) { int c; fprintf(stderr,"*** loggen\n"); if (argc<2) usage(); while ((c = getopt(argc, argv, "f:u:c:b:C:B:z:e:m:")) != -1) { switch (c) { case 'f': param_fmt=atoi(optarg); break; case 'u': memset(param_uuid, atoi(optarg), sizeof(param_uuid)); break; case 'c': param_cycle=atoi(optarg); break; case 'b': param_block=atoi(optarg); break; case 'C': param_tail_cycle=atoi(optarg); break; case 'B': param_tail_block=atoi(optarg); break; case 'z': loggen_zero(atoi(optarg)); break; case 'e': loggen_empty(atoi(optarg)); break; case 'm': loggen_unmount(atoi(optarg)); break; default: fprintf(stderr, "unknown option\n"); usage(); } } return 0; }