/* * Fill out the disk parameter structure. Return SDGP_RESULT_OK if the * structure is correctly filled in, SDGP_RESULT_OFFLINE otherwise. The caller * is responsible for clearing the SDEV_MEDIA_LOADED flag if the structure * cannot be completed. */ int sd_get_parms(struct sd_softc *sc, struct disk_parms *dp, int flags) { union scsi_mode_sense_buf *buf = NULL; struct page_rigid_geometry *rigid = NULL; struct page_flex_geometry *flex = NULL; struct page_reduced_geometry *reduced = NULL; u_char *page0 = NULL; u_int32_t heads = 0, sectors = 0, cyls = 0, secsize = 0; int err = 0, big; if (sd_size(sc, flags) != 0) return (SDGP_RESULT_OFFLINE); if (ISSET(sc->flags, SDF_THIN) && sd_thin_params(sc, flags) != 0) { /* we dont know the unmap limits, so we cant use thin shizz */ CLR(sc->flags, SDF_THIN); } buf = dma_alloc(sizeof(*buf), PR_NOWAIT); if (buf == NULL) goto validate; /* * Ask for page 0 (vendor specific) mode sense data to find * READONLY info. The only thing USB devices will ask for. */ err = scsi_do_mode_sense(sc->sc_link, 0, buf, (void **)&page0, NULL, NULL, NULL, 1, flags | SCSI_SILENT, &big); if (err == 0) { if (big && buf->hdr_big.dev_spec & SMH_DSP_WRITE_PROT) SET(sc->sc_link->flags, SDEV_READONLY); else if (!big && buf->hdr.dev_spec & SMH_DSP_WRITE_PROT) SET(sc->sc_link->flags, SDEV_READONLY); else CLR(sc->sc_link->flags, SDEV_READONLY); } /* * Many UMASS devices choke when asked about their geometry. Most * don't have a meaningful geometry anyway, so just fake it if * scsi_size() worked. */ if ((sc->sc_link->flags & SDEV_UMASS) && (dp->disksize > 0)) goto validate; switch (sc->sc_link->inqdata.device & SID_TYPE) { case T_OPTICAL: /* No more information needed or available. */ break; case T_RDIRECT: /* T_RDIRECT supports only PAGE_REDUCED_GEOMETRY (6). */ err = scsi_do_mode_sense(sc->sc_link, PAGE_REDUCED_GEOMETRY, buf, (void **)&reduced, NULL, NULL, &secsize, sizeof(*reduced), flags | SCSI_SILENT, NULL); if (!err && reduced && DISK_PGCODE(reduced, PAGE_REDUCED_GEOMETRY)) { if (dp->disksize == 0) dp->disksize = _5btol(reduced->sectors); if (secsize == 0) secsize = _2btol(reduced->bytes_s); } break; default: /* * NOTE: Some devices leave off the last four bytes of * PAGE_RIGID_GEOMETRY and PAGE_FLEX_GEOMETRY mode sense pages. * The only information in those four bytes is RPM information * so accept the page. The extra bytes will be zero and RPM will * end up with the default value of 3600. */ if (((sc->sc_link->flags & SDEV_ATAPI) == 0) || ((sc->sc_link->flags & SDEV_REMOVABLE) == 0)) err = scsi_do_mode_sense(sc->sc_link, PAGE_RIGID_GEOMETRY, buf, (void **)&rigid, NULL, NULL, &secsize, sizeof(*rigid) - 4, flags | SCSI_SILENT, NULL); if (!err && rigid && DISK_PGCODE(rigid, PAGE_RIGID_GEOMETRY)) { heads = rigid->nheads; cyls = _3btol(rigid->ncyl); if (heads * cyls > 0) sectors = dp->disksize / (heads * cyls); } else { err = scsi_do_mode_sense(sc->sc_link, PAGE_FLEX_GEOMETRY, buf, (void **)&flex, NULL, NULL, &secsize, sizeof(*flex) - 4, flags | SCSI_SILENT, NULL); if (!err && flex && DISK_PGCODE(flex, PAGE_FLEX_GEOMETRY)) { sectors = flex->ph_sec_tr; heads = flex->nheads; cyls = _2btol(flex->ncyl); if (secsize == 0) secsize = _2btol(flex->bytes_s); if (dp->disksize == 0) dp->disksize = heads * cyls * sectors; } } break; } validate: if (buf) dma_free(buf, sizeof(*buf)); if (dp->disksize == 0) return (SDGP_RESULT_OFFLINE); if (dp->secsize == 0) dp->secsize = (secsize == 0) ? 512 : secsize; /* * Restrict secsize values to powers of two between 512 and 64k. */ switch (dp->secsize) { case 0x200: /* == 512, == DEV_BSIZE on all architectures. */ case 0x400: case 0x800: case 0x1000: case 0x2000: case 0x4000: case 0x8000: case 0x10000: break; default: SC_DEBUG(sc->sc_link, SDEV_DB1, ("sd_get_parms: bad secsize: %#x\n", dp->secsize)); return (SDGP_RESULT_OFFLINE); } /* * XXX THINK ABOUT THIS!! Using values such that sectors * heads * * cyls is <= disk_size can lead to wasted space. We need a more * careful calculation/validation to make everything work out * optimally. */ if (dp->disksize > 0xffffffff && (dp->heads * dp->sectors) < 0xffff) { dp->heads = 511; dp->sectors = 255; cyls = 0; } else { /* * Use standard geometry values for anything we still don't * know. */ dp->heads = (heads == 0) ? 255 : heads; dp->sectors = (sectors == 0) ? 63 : sectors; } dp->cyls = (cyls == 0) ? dp->disksize / (dp->heads * dp->sectors) : cyls; if (dp->cyls == 0) { dp->heads = dp->cyls = 1; dp->sectors = dp->disksize; } return (SDGP_RESULT_OK); }
/* preconditions: reiserfs_read_super already executed, therefore * INFO block is valid * returns: 0 if error, nonzero iff we were able to find the file successfully * postconditions: on a nonzero return, INFO->fileinfo contains the info * of the file we were trying to look up, filepos is 0 and filemax is * the size of the file. */ static int reiserfs_open_file( char *dirname ) { struct reiserfs_de_head *de_head; char *rest, ch; __u32 dir_id, objectid, parent_dir_id = 0, parent_objectid = 0; char linkbuf[PATH_MAX]; /* buffer for following symbolic links */ int link_count = 0; int mode; errnum = 0; dir_id = cpu_to_le32(REISERFS_ROOT_PARENT_OBJECTID); objectid = cpu_to_le32(REISERFS_ROOT_OBJECTID); while ( 1 ) { DEBUG_F( "dirname=%s\n", dirname ); /* Search for the stat info first. */ if ( !search_stat( dir_id, objectid ) ) return 0; DEBUG_F( "sd_mode=0%o sd_size=%Lu\n", sd_mode((struct stat_data *) INFO->current_item ), sd_size(INFO->current_ih, INFO->current_item )); mode = sd_mode((struct stat_data *)INFO->current_item); /* If we've got a symbolic link, then chase it. */ if ( S_ISLNK( mode ) ) { int len = 0; DEBUG_F("link count = %d\n", link_count); DEBUG_SLEEP; if ( ++link_count > MAX_LINK_COUNT ) { DEBUG_F("Symlink loop\n"); errnum = FILE_ERR_SYMLINK_LOOP; return 0; } /* Get the symlink size. */ INFO->file->len = sd_size(INFO->current_ih, INFO->current_item); /* Find out how long our remaining name is. */ while ( dirname[len] && !isspace( dirname[len] ) ) len++; if ( INFO->file->len + len > sizeof ( linkbuf ) - 1 ) { errnum = FILE_ERR_LENGTH; return 0; } /* Copy the remaining name to the end of the symlink data. Note * * that DIRNAME and LINKBUF may overlap! */ memmove( linkbuf + INFO->file->len, dirname, len + 1 ); INFO->fileinfo.k_dir_id = dir_id; INFO->fileinfo.k_objectid = objectid; INFO->file->pos = 0; if ( !next_key() || reiserfs_read_data( linkbuf, INFO->file->len ) != INFO->file->len ) { DEBUG_F("reiserfs_open_file - if !next_key || reiserfs_read_data\n"); DEBUG_SLEEP; errnum = FILE_IOERR; return 0; } DEBUG_F( "symlink=%s\n", linkbuf ); DEBUG_SLEEP; dirname = linkbuf; if ( *dirname == '/' ) { /* It's an absolute link, so look it up in root. */ dir_id = cpu_to_le32(REISERFS_ROOT_PARENT_OBJECTID); objectid = cpu_to_le32(REISERFS_ROOT_OBJECTID); } else { /* Relative, so look it up in our parent directory. */ dir_id = parent_dir_id; objectid = parent_objectid; } /* Now lookup the new name. */ continue; } /* if we have a real file (and we're not just printing * * possibilities), then this is where we want to exit */ if ( !*dirname || isspace( *dirname ) ) { if ( !S_ISREG( mode ) ) { errnum = FILE_ERR_BAD_TYPE; return 0; } INFO->file->pos = 0; INFO->file->len = sd_size(INFO->current_ih, INFO->current_item); INFO->fileinfo.k_dir_id = dir_id; INFO->fileinfo.k_objectid = objectid; return next_key(); } /* continue with the file/directory name interpretation */ while ( *dirname == '/' ) dirname++; if ( !S_ISDIR( mode ) ) { errnum = FILE_ERR_NOTDIR; return 0; } for ( rest = dirname; ( ch = *rest ) && !isspace( ch ) && ch != '/'; rest++ ) ; *rest = 0; while ( 1 ) { char *name_end; int num_entries; if ( !next_key() ) return 0; if ( INFO->current_ih->ih_key.k_objectid != objectid ) break; name_end = INFO->current_item + ih_item_len(INFO->current_ih); de_head = ( struct reiserfs_de_head * ) INFO->current_item; num_entries = ih_entry_count(INFO->current_ih); while ( num_entries > 0 ) { char *filename = INFO->current_item + deh_location(de_head); char tmp = *name_end; if( deh_state(de_head) & (1 << DEH_Visible)) { int cmp; /* Directory names in ReiserFS are not null * terminated. * We write a temporary 0 behind it. * NOTE: that this * may overwrite the first block in * the tree cache. * That doesn't hurt as long as we * don't call next_key * () in between. */ *name_end = 0; cmp = strcmp( dirname, filename ); *name_end = tmp; if ( cmp == 0 ) goto found; } /* The beginning of this name marks the end of the next name. */ name_end = filename; de_head++; num_entries--; } } errnum = FILE_ERR_NOTFOUND; *rest = ch; return 0; found: *rest = ch; dirname = rest; parent_dir_id = dir_id; parent_objectid = objectid; dir_id = de_head->deh_dir_id; /* LE */ objectid = de_head->deh_objectid; /* LE */ } }