#include <rx/rx.h>
-afs_int32 DErrno;
-
afs_uint32 dir_lookup_hits = 0;
afs_uint32 dir_lookup_misses = 0;
afs_uint32 dir_create_entry = 0;
* \param[in] adc pointer to directory dcache
* \param[in] page number of the desired directory page
* \param[out] entry buffer to return requested page
+ * \param[out] physerr (optional) pointer to return errno, if any
*
* \retval 0 success
- * \retval non-zero invalid directory or internal IO error
+ * \retval non-zero invalid directory or internal IO error;
+ * if physerr is supplied by caller, it will be set:
+ * 0 logical error
+ * errno physical error
*/
int
-DRead(struct dcache *adc, int page, struct DirBuffer *entry)
+DReadWithErrno(struct dcache *adc, int page, struct DirBuffer *entry, int *physerr)
{
/* Read a page from the disk. */
struct buffer *tb, *tb2;
AFS_STATCNT(DRead);
+ if (physerr != NULL)
+ *physerr = 0;
+
memset(entry, 0, sizeof(struct DirBuffer));
if (adc->f.chunk == 0 && adc->f.chunkBytes == 0) {
AFS_BUFFER_PAGESIZE);
afs_CFileClose(tfile);
if (code < AFS_BUFFER_PAGESIZE) {
+ if (code < 0 && physerr != NULL)
+ *physerr = -code;
code = EIO;
goto error;
}
return code;
}
+/*!
+ * Read and return the requested directory page.
+ *
+ * \param[in] adc pointer to directory dcache
+ * \param[in] page number of the desired directory page
+ * \param[out] entry buffer to return requested page
+ *
+ * \retval 0 success
+ * \retval non-zero invalid directory or internal IO error;
+ */
+int
+DRead(struct dcache *adc, int page, struct DirBuffer *entry)
+{
+ return DReadWithErrno(adc, page, entry, NULL);
+}
+
static void
FixupBucket(struct buffer *ap)
{
*
* extern void FidZero(DirHandle *);
* extern int FidEq(DirHandle *a, DirHandle *b);
- * extern int ReallyRead(DirHandle *a, int block, char *data);
+ * extern int ReallyRead(DirHandle *a, int block, char *data, int *physerr);
*/
extern void FidZero(dir_file_t);
extern int FidEq(dir_file_t, dir_file_t);
-extern int ReallyRead(dir_file_t, int block, char *data);
+extern int ReallyRead(dir_file_t, int block, char *data, int *physerr);
extern int ReallyWrite(dir_file_t, int block, char *data);
extern void FidZap(dir_file_t);
extern int FidVolEq(dir_file_t, afs_int32 vid);
/**
* read a page out of a directory object.
*
- * @param[in] fid directory object fid
- * @param[in] page page in hash table to be read
+ * @param[in] fid directory object fid
+ * @param[in] page page in hash table to be read
+ * @param[out] entry buffer to be filled w/ page contents
+ * @param[out] physerr (optional) pointer to return possible errno
*
- * @return pointer to requested page in directory cache
- * @retval NULL read failed
+ * @retval 0 success
+ * @retval EIO logical directory error or physical IO error;
+ * if *physerr was supplied, it will be set to 0
+ * for logical errors, or the errno for physical
+ * errors.
*/
int
-DRead(dir_file_t fid, int page, struct DirBuffer *entry)
+DReadWithErrno(dir_file_t fid, int page, struct DirBuffer *entry, int *physerr)
{
/* Read a page from the disk. */
struct buffer *tb, *tb2, **bufhead;
+ int code;
+
+ if (physerr != NULL)
+ *physerr = 0;
memset(entry, 0, sizeof(struct DirBuffer));
ObtainWriteLock(&tb->lock);
tb->lockers++;
ReleaseWriteLock(&afs_bufferLock);
- if (ReallyRead(bufferDir(tb), tb->page, tb->data)) {
+ code = ReallyRead(bufferDir(tb), tb->page, tb->data, physerr);
+ if (code != 0) {
tb->lockers--;
FidZap(bufferDir(tb)); /* disaster */
ReleaseWriteLock(&tb->lock);
- return EIO;
+ return code;
}
/* Note that findslot sets the page field in the buffer equal to
* what it is searching for.
return 0;
}
+/**
+ * read a page out of a directory object.
+ *
+ * @param[in] fid directory object fid
+ * @param[in] page page in hash table to be read
+ * @param[out] entry buffer to be filled w/ page contents
+ *
+ * @retval 0 success
+ * @retval EIO logical directory error or physical IO error
+ */
+int
+DRead(dir_file_t fid, int page, struct DirBuffer *entry)
+{
+ return DReadWithErrno(fid, page, entry, NULL);
+}
+
static int
FixupBucket(struct buffer *ap)
# include "dir.h"
#endif /* KERNEL */
-afs_int32 DErrno;
-
/* Local static prototypes */
static int FindBlobs(dir_file_t, int);
static void AddPage(dir_file_t, int);
/* Return a pointer to an entry, given its number. Also return the maximum
* size of the entry, which is determined by its position within the directory
* page.
+ *
+ * If physerr is supplied by caller, it will be set to:
+ * 0 for logical errors
+ * errno for physical errors
*/
-
static int
GetBlobWithLimit(dir_file_t dir, afs_int32 blobno,
- struct DirBuffer *buffer, afs_size_t *maxlen)
+ struct DirBuffer *buffer, afs_size_t *maxlen, int *physerr)
{
afs_size_t pos;
int code;
*maxlen = 0;
memset(buffer, 0, sizeof(struct DirBuffer));
- code = DRead(dir, blobno >> LEPP, buffer);
+ code = DReadWithErrno(dir, blobno >> LEPP, buffer, physerr);
if (code)
return code;
return 0;
}
+/*
+ * Given an entry's number, return a pointer to that entry.
+ * If physerr is supplied by caller, it will be set to:
+ * 0 for logical errors
+ * errno for physical errors
+ */
+int
+afs_dir_GetBlobWithErrno(dir_file_t dir, afs_int32 blobno, struct DirBuffer *buffer,
+ int *physerr)
+{
+ afs_size_t maxlen = 0;
+ return GetBlobWithLimit(dir, blobno, buffer, &maxlen, physerr);
+}
+
/* Given an entries number, return a pointer to that entry */
int
afs_dir_GetBlob(dir_file_t dir, afs_int32 blobno, struct DirBuffer *buffer)
{
afs_size_t maxlen = 0;
- return GetBlobWithLimit(dir, blobno, buffer, &maxlen);
+ return GetBlobWithLimit(dir, blobno, buffer, &maxlen, NULL);
}
/* Return an entry, having verified that the name held within the entry
int code;
char *cp;
- code = GetBlobWithLimit(file, blobno, &buffer, &maxlen);
+ code = GetBlobWithLimit(file, blobno, &buffer, &maxlen, NULL);
if (code)
return code;
extern int afs_dir_IsEmpty(dir_file_t dir);
extern int afs_dir_GetBlob(dir_file_t dir, afs_int32 blobno,
struct DirBuffer *);
+extern int afs_dir_GetBlobWithErrno(dir_file_t dir, afs_int32 blobno,
+ struct DirBuffer *, int *physerr);
extern int afs_dir_GetVerifiedBlob(dir_file_t dir, afs_int32 blobno,
struct DirBuffer *);
extern int afs_dir_DirHash(char *string);
extern void DInit(int abuffers);
extern int DRead(dir_file_t fid, int page, struct DirBuffer *);
+extern int DReadWithErrno(dir_file_t fid, int page, struct DirBuffer *, int *physerr);
extern int DFlush(void);
extern int DFlushVolume(afs_int32);
extern int DNew(dir_file_t fid, int page, struct DirBuffer *);
#define MAXENAME 256
-extern afs_int32 DErrno;
-
/* figure out how many pages in use in a directory, given ptr to its (locked)
* header */
static int
afs_int32 entcount, maxents;
unsigned short ne;
int code;
+ int physerr;
eaSize = BIGMAXPAGES * EPP / 8;
/* Read the directory header */
- code = DRead(file,0, &headerbuf);
+ code = DReadWithErrno(file, 0, &headerbuf, &physerr);
if (code) {
- /* if DErrno is 0, then we know that the read worked, but was short,
+ /* if physerr is 0, then we know that the read worked, but was short,
* and the damage is permanent. Otherwise, we got an I/O or programming
* error. Claim the dir is OK, but log something.
*/
- if (DErrno != 0) {
- printf("Could not read first page in directory (%d)\n", DErrno);
+ if (physerr != 0) {
+ printf("Could not read first page in directory (%d)\n", physerr);
Die("dirok1");
AFS_UNREACHED(return 1);
}
*/
for (i = 0; i < usedPages; i++) {
/* Read the page header */
- code = DRead(file, i, &pagebuf);
+ code = DReadWithErrno(file, i, &pagebuf, &physerr);
if (code) {
DRelease(&headerbuf, 0);
- if (DErrno != 0) {
+ if (physerr != 0) {
/* couldn't read page, but not because it wasn't there permanently */
- printf("Failed to read dir page %d (errno %d)\n", i, DErrno);
+ printf("Failed to read dir page %d (errno %d)\n", i, physerr);
Die("dirok2");
AFS_UNREACHED(return 1);
}
}
/* Read the directory entry */
- DErrno = 0;
- code = afs_dir_GetBlob(file, entry, &entrybuf);
+ code = afs_dir_GetBlobWithErrno(file, entry, &entrybuf, &physerr);
if (code) {
- if (DErrno != 0) {
+ if (physerr != 0) {
/* something went wrong reading the page, but it wasn't
* really something wrong with the dir that we can fix.
*/
printf("Could not get dir blob %d (errno %d)\n", entry,
- DErrno);
+ physerr);
DRelease(&headerbuf, 0);
Die("dirok3");
}
* Note that if this matches, alloMap has already been checked against it.
*/
for (i = 0; i < usedPages; i++) {
- code = DRead(file, i, &pagebuf);
+ code = DReadWithErrno(file, i, &pagebuf, &physerr);
if (code) {
printf
("Failed on second attempt to read dir page %d (errno %d)\n",
- i, DErrno);
+ i, physerr);
DRelease(&headerbuf, 0);
- /* if DErrno is 0, then the dir is really bad, and we return dir *not* OK.
- * otherwise, we want to return true (1), meaning the dir isn't known
- * to be bad (we can't tell, since I/Os are failing.
+ /* if physerr is 0, then the dir is really bad, and we return dir
+ * *not* OK. Otherwise, we Die instead of returning true (1),
+ * becauase the dir isn't known to be bad (we can't tell, since
+ * I/Os are failing).
*/
- if (DErrno != 0)
+ if (physerr != 0)
Die("dirok4");
else
return 0; /* dir is really shorter */
struct DirHeader *dhp;
struct DirEntry *ep;
int entry;
+ int physerr;
memset(dot, 0, sizeof(dot));
memset(dotdot, 0, sizeof(dotdot));
afs_dir_MakeDir(toFile, dot, dotdot); /* Returns no error code. */
- /* Find out how many pages are valid, using stupid heuristic since DRead
- * never returns null.
- */
- code = DRead(fromFile, 0, &headerbuf);
+ /* Find out how many pages are valid. */
+ code = DReadWithErrno(fromFile, 0, &headerbuf, &physerr);
if (code) {
printf("Failed to read first page of fromDir!\n");
- /* if DErrno != 0, then our call failed and we should let our
+ /* if physerr != 0, then our call failed and we should let our
* caller know that there's something wrong with the new dir. If not,
* then we return here anyway, with an empty, but at least good, directory.
*/
- return DErrno;
+ return physerr;
}
dhp = (struct DirHeader *)headerbuf.data;
break;
}
- DErrno = 0;
- code = afs_dir_GetBlob(fromFile, entry, &entrybuf);
+ code = afs_dir_GetBlobWithErrno(fromFile, entry, &entrybuf, &physerr);
if (code) {
- if (DErrno) {
+ if (physerr != 0) {
printf
("can't continue down hash chain (entry %d, errno %d)\n",
- entry, DErrno);
+ entry, physerr);
DRelease(&headerbuf, 0);
- return DErrno;
+ return physerr;
}
printf
("Warning: bogus hash chain encountered, switching to next.\n");
}
}
+/*
+ * Read the specified page from a directory object
+ *
+ * \parm[in] dir handle to the directory object
+ * \parm[in] block requested page from the directory object
+ * \parm[out] data buffer for the returned page
+ * \parm[out] physerr (optional) pointer to errno if physical error
+ *
+ * \retval 0 success
+ * \retval EIO physical or logical error;
+ * if physerr is supplied by caller, it will be set to:
+ * 0 for logical errors
+ * errno for physical errors
+ */
int
-ReallyRead(dirhandle *dir, int block, char *data)
+ReallyRead(dirhandle *dir, int block, char *data, int *physerr)
{
- int code;
- if (lseek(dir->fd, block * PAGESIZE, 0) == -1)
- return errno;
+ int code = 0;
+
+ if (lseek(dir->fd, block * PAGESIZE, 0) == -1) {
+ code = EIO;
+ goto done;
+ }
code = read(dir->fd, data, PAGESIZE);
- if (code < 0)
- return errno;
- if (code != PAGESIZE)
- return EIO;
- return 0;
+ if (code < 0) {
+ code = EIO;
+ goto done;
+ }
+ if (code != PAGESIZE) {
+ errno = 0; /* logical error - short read */
+ code = EIO;
+ goto done;
+ }
+
+ errno = 0;
+
+ done:
+ if (physerr != NULL)
+ *physerr = errno;
+ return code;
}
int
afs_int32 lpErrno, lpCount;
-/* returns 0 on success, errno on failure */
+/*
+ * Read the specified page from a directory object
+ *
+ * \parm[in] file handle to the directory object
+ * \parm[in] block requested page from the directory object
+ * \parm[out] data buffer for the returned page
+ * \parm[out] physerr (optional) pointer to errno if physical error
+ *
+ * \retval 0 success
+ * \retval EIO physical or logical error;
+ * if physerr is supplied by caller, it will be set to:
+ * 0 for logical errors
+ * errno for physical errors
+ */
int
-ReallyRead(DirHandle * file, int block, char *data)
+ReallyRead(DirHandle *file, int block, char *data, int *physerr)
{
- int code;
+ int saverr = 0;
+ int code = 0;
ssize_t rdlen;
FdHandle_t *fdP;
afs_ino_str_t stmp;
fdP = IH_OPEN(file->dirh_handle);
if (fdP == NULL) {
- code = errno;
+ saverr = errno;
+ code = EIO;
ViceLog(0,
("ReallyRead(): open failed device %X inode %s (volume=%" AFS_VOLID_FMT ") errno %d\n",
file->dirh_handle->ih_dev, PrintInode(stmp,
file->dirh_handle->
ih_ino),
- afs_printable_VolumeId_lu(file->dirh_handle->ih_vid), code));
- return code;
+ afs_printable_VolumeId_lu(file->dirh_handle->ih_vid), saverr));
+ goto done;
}
rdlen = FDH_PREAD(fdP, data, PAGESIZE, ((afs_foff_t)block) * PAGESIZE);
if (rdlen != PAGESIZE) {
if (rdlen < 0)
- code = errno;
+ saverr = errno;
else
- code = EIO;
+ saverr = 0; /* logical error: short read */
+ code = EIO;
ViceLog(0,
("ReallyRead(): read failed device %X inode %s (volume=%" AFS_VOLID_FMT ") errno %d\n",
file->dirh_handle->ih_dev, PrintInode(stmp,
file->dirh_handle->
ih_ino),
- afs_printable_VolumeId_lu(file->dirh_handle->ih_vid), code));
+ afs_printable_VolumeId_lu(file->dirh_handle->ih_vid), saverr));
FDH_REALLYCLOSE(fdP);
- return code;
+ goto done;
}
FDH_CLOSE(fdP);
- return 0;
+
+ done:
+ if (physerr != NULL)
+ *physerr = saverr;
+ return code;
}
#include <afs/dir.h>
#include "vol_internal.h"
-/* returns 0 on success, errno on failure */
+/*
+ * Read the specified page from a directory object
+ *
+ * \parm[in] file handle to the directory object
+ * \parm[in] block requested page from the directory object
+ * \parm[out] data buffer for the returned page
+ * \parm[out] physerr (optional) pointer to errno if physical error
+ *
+ * \retval 0 success
+ * \retval EIO physical or logical error;
+ * if physerr is supplied by caller, it will be set to:
+ * 0 for logical errors
+ * errno for physical errors
+ */
int
-ReallyRead(DirHandle * file, int block, char *data)
+ReallyRead(DirHandle *file, int block, char *data, int *physerr)
{
FdHandle_t *fdP;
- int code;
+ int code = 0;
+ int saverr = 0;
ssize_t nBytes;
+
errno = 0;
fdP = IH_OPEN(file->dirh_handle);
if (fdP == NULL) {
- code = errno;
- return code;
+ saverr = errno;
+ code = EIO;
+ goto done;
}
nBytes = FDH_PREAD(fdP, data, (afs_fsize_t) AFS_PAGESIZE,
((afs_foff_t)block) * AFS_PAGESIZE);
if (nBytes != AFS_PAGESIZE) {
if (nBytes < 0)
- code = errno;
+ saverr = errno;
else
- code = EIO;
+ saverr = 0; /* logical error: short read */
+ code = EIO;
FDH_REALLYCLOSE(fdP);
- return code;
+ goto done;
}
FDH_CLOSE(fdP);
- return 0;
+
+ done:
+ if (physerr != NULL)
+ *physerr = saverr;
+ return code;
}
/* returns 0 on success, errno on failure */
#include "vol.h"
#include "physio.h"
-/* returns 0 on success, errno on failure */
+/*
+ * Read the specified page from a directory object
+ *
+ * \parm[in] file handle to the directory object
+ * \parm[in] block requested page from the directory object
+ * \parm[out] data buffer for the returned page
+ * \parm[out] physerr (optional) pointer to errno if physical error
+ *
+ * \retval 0 success
+ * \retval EIO physical or logical error;
+ * if physerr is supplied by caller, it will be set to:
+ * 0 for logical errors
+ * errno for physical errors
+ */
int
-ReallyRead(DirHandle * file, int block, char *data)
+ReallyRead(DirHandle *file, int block, char *data, int *physerr)
{
FdHandle_t *fdP;
- int code;
+ int code = 0;
+ int saverr = 0;
ssize_t nBytes;
errno = 0;
fdP = IH_OPEN(file->dirh_handle);
if (fdP == NULL) {
- code = errno;
- return code;
+ saverr = errno;
+ code = EIO;
+ goto done;;
}
nBytes = FDH_PREAD(fdP, data, AFS_PAGESIZE, ((afs_foff_t)block) * AFS_PAGESIZE);
if (nBytes != AFS_PAGESIZE) {
if (nBytes < 0)
- code = errno;
+ saverr = errno;
else
- code = EIO;
+ saverr = 0; /* logical error: short read */
+ code = EIO;
FDH_REALLYCLOSE(fdP);
- return code;
+ goto done;
}
FDH_CLOSE(fdP);
- return 0;
+
+ done:
+ if (physerr != NULL)
+ *physerr = saverr;
+ return code;
}
/* returns 0 on success, errno on failure */