yaffs_lstat(str,&s);
- printf("%s ino %d length %d mode %X ",de->d_name,(int)s.st_ino,(int)s.st_size,s.st_mode);
+ printf("%s ino %lld length %d mode %X ",de->d_name,(int)s.st_ino,s.st_size,s.st_mode);
switch(s.st_mode & S_IFMT)
{
case S_IFREG: printf("data file"); break;
yaffs_lstat(str,&s);
- printf("%s inode %d obj %x length %d mode %X ",str,s.st_ino,de->d_dont_use,(int)s.st_size,s.st_mode);
+ printf("%s inode %d obj %x length %lld mode %X ",
+ str,s.st_ino,de->d_dont_use, s.st_size,s.st_mode);
switch(s.st_mode & S_IFMT)
{
case S_IFREG: printf("data file"); break;
printf("Second mount returns %d\n", yaffs_mount(mountpt));
}
+#define N_WRITES 2000
+#define STRIDE 2000
+
+#define BUFFER_N 1100
+unsigned xxbuffer[BUFFER_N];
+
+
+void set_buffer(int n)
+{
+ int i;
+ for(i = 0; i < BUFFER_N; i++)
+ xxbuffer[i] = i + n;
+}
+
+void write_big_sparse_file(int h)
+{
+ int i;
+ loff_t offset = 0;
+ loff_t pos;
+ int n = sizeof(xxbuffer);
+ int wrote;
+
+ for(i = 0; i < N_WRITES; i++) {
+ printf("writing at %lld\n", offset);
+ set_buffer(i);
+ pos = yaffs_lseek(h, offset, SEEK_SET);
+ if(pos != offset) {
+ printf("mismatched seek pos %lld offset %lld\n",
+ pos, offset);
+ perror("lseek64");
+ exit(1);
+ }
+ wrote = yaffs_write(h, xxbuffer, n);
+
+ if(wrote != n) {
+ printf("mismatched write wrote %d n %d\n", wrote, n);
+ exit(1);
+ }
+
+ offset += (STRIDE * sizeof(xxbuffer));
+ }
+
+ yaffs_ftruncate(h, offset);
+
+}
+
+
+
+
+void verify_big_sparse_file(int h)
+{
+ unsigned check_buffer[BUFFER_N];
+ int i;
+ loff_t offset = 0;
+ loff_t pos;
+ int n = sizeof(check_buffer);
+ int result;
+ const char * check_type;
+ int checks_failed = 0;
+ int checks_passed = 0;
+
+ for(i = 0; i < N_WRITES * STRIDE; i++) {
+ if(i % STRIDE) {
+ check_type = "zero";
+ memset(xxbuffer,0, n);
+ } else {
+ check_type = "buffer";
+ set_buffer(i/STRIDE);
+ }
+ //printf("%s checking %lld\n", check_type, offset);
+ pos = yaffs_lseek(h, offset, SEEK_SET);
+ if(pos != offset) {
+ printf("mismatched seek pos %lld offset %lld\n",
+ pos, offset);
+ perror("lseek64");
+ exit(1);
+ }
+ result = yaffs_read(h, check_buffer, n);
+
+ if(result != n) {
+ printf("mismatched read result %d n %d\n", result, n);
+ exit(1);
+ }
+
+
+
+
+ if(memcmp(xxbuffer, check_buffer, n)) {
+ int j;
+
+ printf("buffer at %lld mismatches\n", pos);
+ printf("xxbuffer ");
+ for(j = 0; j < 20; j++)
+ printf(" %d",xxbuffer[j]);
+ printf("\n");
+ printf("check_buffer ");
+ for(j = 0; j < 20; j++)
+ printf(" %d",check_buffer[j]);
+ printf("\n");
+
+ checks_failed++;
+ } else {
+ checks_passed++;
+ }
+
+ offset += sizeof(xxbuffer);
+ }
+
+ printf("%d checks passed, %d checks failed\n", checks_passed, checks_failed);
+
+}
+
+
+void large_file_test(const char *mountpt)
+{
+ int handle;
+ char fullname[100];
+
+ yaffs_trace_mask = 0;
+
+ yaffs_start_up();
+
+ yaffs_mount(mountpt);
+ printf("mounted\n");
+ dumpDir(mountpt);
+
+ sprintf(fullname, "%s/%s", mountpt, "big-test-file");
+
+ handle = yaffs_open(fullname, O_RDONLY, 0);
+
+ handle = yaffs_open(fullname, O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE);
+
+ if(handle < 0) {
+ perror("opening file");
+ exit(1);
+ }
+
+ write_big_sparse_file(handle);
+ verify_big_sparse_file(handle);
+
+ yaffs_close(handle);
+
+ printf("Job done\n");
+ yaffs_unmount(mountpt);
+
+ yaffs_mount(mountpt);
+ printf("mounted again\n");
+ dumpDir(mountpt);
+ handle = yaffs_open(fullname, O_RDONLY, 0);
+ verify_big_sparse_file(handle);
+ yaffs_unmount(mountpt);
+
+
+ yaffs_mount_common(mountpt, 0, 1);
+ printf("mounted with no checkpt\n");
+ dumpDir(mountpt);
+ handle = yaffs_open(fullname, O_RDONLY, 0);
+ verify_big_sparse_file(handle);
+ yaffs_unmount(mountpt);
+
+}
+
+
int random_seed;
int simulate_power_failure;
start_twice("/yaffs2");
+ //large_file_test("/yaffs2");
+
+ //basic_utime_test("/yaffs2");
return 0;
u8 shareWrite:1;
int inodeId:12; /* Index to corresponding yaffsfs_Inode */
int handleCount:10; /* Number of handles for this fd */
- u32 position; /* current position in file */
+ loff_t position; /* current position in file */
}yaffsfs_FileDes;
typedef struct {
-int yaffsfs_do_read(int handle, void *vbuf, unsigned int nbyte, int isPread, int offset)
+int yaffsfs_do_read(int handle, void *vbuf, unsigned int nbyte, int isPread, loff_t offset)
{
yaffsfs_FileDes *fd = NULL;
struct yaffs_obj *obj = NULL;
- int pos = 0;
- int startPos = 0;
- int endPos = 0;
+ loff_t pos = 0;
+ loff_t startPos = 0;
+ loff_t endPos = 0;
int nRead = 0;
int nToRead = 0;
int totalRead = 0;
- unsigned int maxRead;
+ loff_t maxRead;
u8 *buf = (u8 *)vbuf;
if(!vbuf){
return yaffsfs_do_read(handle, buf, nbyte, 0, 0);
}
-int yaffs_pread(int handle, void *buf, unsigned int nbyte, unsigned int offset)
+int yaffs_pread(int handle, void *buf, unsigned int nbyte, loff_t offset)
{
return yaffsfs_do_read(handle, buf, nbyte, 1, offset);
}
-int yaffsfs_do_write(int handle, const void *vbuf, unsigned int nbyte, int isPwrite, int offset)
+int yaffsfs_do_write(int handle, const void *vbuf, unsigned int nbyte, int isPwrite, loff_t offset)
{
yaffsfs_FileDes *fd = NULL;
struct yaffs_obj *obj = NULL;
- int pos = 0;
- int startPos = 0;
- int endPos;
+ loff_t pos = 0;
+ loff_t startPos = 0;
+ loff_t endPos;
int nWritten = 0;
int totalWritten = 0;
int write_trhrough = 0;
return yaffsfs_do_write(fd, buf, nbyte, 0, 0);
}
-int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, unsigned int offset)
+int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, loff_t offset)
{
return yaffsfs_do_write(fd, buf, nbyte, 1, offset);
}
-int yaffs_truncate(const YCHAR *path,off_t new_size)
+int yaffs_truncate(const YCHAR *path,loff_t new_size)
{
struct yaffs_obj *obj = NULL;
struct yaffs_obj *dir = NULL;
else if(new_size < 0 || new_size > YAFFS_MAX_FILE_SIZE)
yaffsfs_SetError(-EINVAL);
else
- result = yaffs_resize_file(obj,new_size);
+ result = yaffs_resize_file(obj, new_size);
yaffsfs_Unlock();
return (result) ? 0 : -1;
}
-int yaffs_ftruncate(int handle, off_t new_size)
+int yaffs_ftruncate(int handle, loff_t new_size)
{
yaffsfs_FileDes *fd = NULL;
struct yaffs_obj *obj = NULL;
yaffsfs_SetError(-EINVAL);
else
/* resize the file */
- result = yaffs_resize_file(obj,new_size);
+ result = yaffs_resize_file(obj, new_size);
yaffsfs_Unlock();
return (result) ? 0 : -1;
}
-off_t yaffs_lseek(int handle, off_t offset, int whence)
+loff_t yaffs_lseek(int handle, loff_t offset, int whence)
{
yaffsfs_FileDes *fd = NULL;
struct yaffs_obj *obj = NULL;
- int pos = -1;
- int fSize = -1;
+ loff_t pos = -1;
+ loff_t fSize = -1;
yaffsfs_Lock();
fd = yaffsfs_HandleToFileDes(handle);
return (void *)dev;
}
-int yaffs_mount2(const YCHAR *path,int read_only)
+int yaffs_mount_common(const YCHAR *path,int read_only, int skip_checkpt)
{
int retVal=-1;
int result=YAFFS_FAIL;
if(dev){
if(!dev->is_mounted){
dev->read_only = read_only ? 1 : 0;
- result = yaffs_guts_initialise(dev);
+ if(skip_checkpt) {
+ u8 skip = dev->param.skip_checkpt_rd;
+ dev->param.skip_checkpt_rd = 1;
+ result = yaffs_guts_initialise(dev);
+ dev->param.skip_checkpt_rd = skip;
+ } else {
+ result = yaffs_guts_initialise(dev);
+ }
+
if(result == YAFFS_FAIL)
yaffsfs_SetError(-ENOMEM);
retVal = result ? 0 : -1;
}
+int yaffs_mount2(const YCHAR *path, int readonly)
+{
+ return yaffs_mount_common(path, readonly, 0);
+}
int yaffs_mount(const YCHAR *path)
{
- return yaffs_mount2(path,0);
+ return yaffs_mount_common(path, 0, 0);
}
int yaffs_sync(const YCHAR *path)
#define NAME_MAX 256
#endif
-#define YAFFS_MAX_FILE_SIZE (0x7FFFFFFF)
+#define YAFFS_MAX_FILE_SIZE (0x800000000LL - 1)
struct yaffs_dirent{
long d_ino; /* inode number */
off_t d_off; /* offset to this dirent */
- unsigned short d_reclen; /* length of this d_name */
+ unsigned short d_reclen; /* length of this dirent */
YUCHAR d_type; /* type of this record */
YCHAR d_name [NAME_MAX+1]; /* file name (null-terminated) */
unsigned d_dont_use; /* debug pointer, not for public consumption */
struct yaffs_stat{
- int st_dev; /* device */
+ int st_dev; /* device */
int st_ino; /* inode */
unsigned st_mode; /* protection */
int st_nlink; /* number of hard links */
int st_uid; /* user ID of owner */
int st_gid; /* group ID of owner */
unsigned st_rdev; /* device type (if inode device) */
- off_t st_size; /* total size, in bytes */
+ loff_t st_size; /* total size, in bytes */
unsigned long st_blksize; /* blocksize for filesystem I/O */
unsigned long st_blocks; /* number of blocks allocated */
#ifdef CONFIG_YAFFS_WINCE
unsigned long yst_wince_mtime[2];
unsigned long yst_wince_ctime[2];
#else
- unsigned long yst_atime; /* time of last access */
+ unsigned long yst_atime; /* time of last access */
unsigned long yst_mtime; /* time of last modification */
unsigned long yst_ctime; /* time of last change */
#endif
int yaffs_read(int fd, void *buf, unsigned int nbyte) ;
int yaffs_write(int fd, const void *buf, unsigned int nbyte) ;
-int yaffs_pread(int fd, void *buf, unsigned int nbyte, unsigned int offset);
-int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, unsigned int offset);
+int yaffs_pread(int fd, void *buf, unsigned int nbyte, loff_t offset);
+int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, loff_t offset);
-off_t yaffs_lseek(int fd, off_t offset, int whence) ;
+loff_t yaffs_lseek(int fd, loff_t offset, int whence) ;
-int yaffs_truncate(const YCHAR *path, off_t new_size);
-int yaffs_ftruncate(int fd, off_t new_size);
+int yaffs_truncate(const YCHAR *path, loff_t new_size);
+int yaffs_ftruncate(int fd, loff_t new_size);
int yaffs_unlink(const YCHAR *path) ;
int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath) ;
int yaffs_mount(const YCHAR *path) ;
int yaffs_mount2(const YCHAR *path, int read_only);
+int yaffs_mount_common(const YCHAR *path, int read_only, int skip_checkpt);
+
int yaffs_unmount(const YCHAR *path) ;
int yaffs_unmount2(const YCHAR *path, int force);
int yaffs_remount(const YCHAR *path, int force, int read_only);
--- /dev/null
+CFLAGS += -Wall -D_FILE_OFFSET_BITS=64
+
+TARGETS = xattrtest writebigsparse verifybigsparse
+all: $(TARGETS)
+
+xattrtest: xattrtest.c
+ gcc $(CFLAGS) -o $@ $<
+
+writebigsparse: writebigsparse.c
+ gcc $(CFLAGS) -o $@ $<
+
+verifybigsparse: verifybigsparse.c
+ gcc $(CFLAGS) -o $@ $<
+
+
+.PHONEY: clean
+clean:
+ rm -f $(TARGETS)
--- /dev/null
+#define _LARGEFILE64_SOURCE
+#include<stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#define N_WRITES 16
+#define STRIDE 250000
+
+#define BUFFER_N 1100
+unsigned xxbuffer[BUFFER_N];
+
+
+void set_buffer(int n)
+{
+ int i;
+ for(i = 0; i < BUFFER_N; i++)
+ xxbuffer[i] = i + n;
+}
+
+
+void verify_big_sparse_file(int h)
+{
+ unsigned check_buffer[BUFFER_N];
+ int i;
+ loff_t offset = 0;
+ loff_t pos;
+ int n = sizeof(check_buffer);
+ int result;
+ const char * check_type;
+ int checks_failed = 0;
+ int checks_passed = 0;
+
+ for(i = 0; i < N_WRITES * STRIDE; i++) {
+ if(i % STRIDE) {
+ check_type = "zero";
+ memset(xxbuffer,0, n);
+ } else {
+ check_type = "buffer";
+ set_buffer(i/STRIDE);
+ }
+ //printf("%s checking %lld\n", check_type, offset);
+ pos = lseek64(h, offset, SEEK_SET);
+ if(pos != offset) {
+ printf("mismatched seek pos %lld offset %lld\n",
+ pos, offset);
+ perror("lseek64");
+ exit(1);
+ }
+ result = read(h, check_buffer, n);
+
+ if(result != n) {
+ printf("mismatched read result %d n %d\n", result, n);
+ exit(1);
+ }
+
+
+
+
+ if(memcmp(xxbuffer, check_buffer, n)) {
+ int j;
+
+ printf("buffer at %lld mismatches\n", pos);
+ printf("xxbuffer ");
+ for(j = 0; j < 20; j++)
+ printf(" %d",xxbuffer[j]);
+ printf("\n");
+ printf("check_buffer ");
+ for(j = 0; j < 20; j++)
+ printf(" %d",check_buffer[j]);
+ printf("\n");
+
+ checks_failed++;
+ } else {
+ checks_passed++;
+ }
+
+ offset += sizeof(xxbuffer);
+ }
+
+ printf("%d checks passed, %d checks failed\n", checks_passed, checks_failed);
+
+}
+
+
+int main(int argc, char *argv[])
+{
+ int handle;
+
+ if(argc < 2) {
+ printf("Gimme a file name!\n");
+ exit(1);
+ }
+
+ handle = open(argv[1], O_RDONLY);
+
+ if(handle < 0) {
+ perror("opening file");
+ exit(1);
+ }
+
+ verify_big_sparse_file(handle);
+
+ printf("Job done\n");
+ return 0;
+}
--- /dev/null
+#define _LARGEFILE64_SOURCE
+#include<stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+
+#define N_WRITES 16
+#define STRIDE 250000
+
+#define BUFFER_N 1100
+unsigned xxbuffer[BUFFER_N];
+
+
+void set_buffer(int n)
+{
+ int i;
+ for(i = 0; i < BUFFER_N; i++)
+ xxbuffer[i] = i + n;
+}
+
+void write_big_sparse_file(int h)
+{
+ int i;
+ loff_t offset = 0;
+ loff_t pos;
+ int n = sizeof(xxbuffer);
+ int wrote;
+
+ for(i = 0; i < N_WRITES; i++) {
+ printf("writing at %lld\n", offset);
+ set_buffer(i);
+ pos = lseek64(h, offset, SEEK_SET);
+ if(pos != offset) {
+ printf("mismatched seek pos %lld offset %lld\n",
+ pos, offset);
+ perror("lseek64");
+ exit(1);
+ }
+ wrote = write(h, xxbuffer, n);
+
+ if(wrote != n) {
+ printf("mismatched write wrote %d n %d\n", wrote, n);
+ exit(1);
+ }
+
+ offset += (STRIDE * sizeof(xxbuffer));
+ }
+
+ ftruncate(h, offset);
+
+}
+
+
+int main(int argc, char *argv[])
+{
+ int handle;
+
+ if(argc < 2) {
+ printf("Gimme a file name!\n");
+ exit(1);
+ }
+
+ handle = open(argv[1], O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE);
+
+ if(handle < 0) {
+ perror("opening file");
+ exit(1);
+ }
+
+ write_big_sparse_file(handle);
+
+ printf("Job done\n");
+ return 0;
+}
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
-
+#include <unistd.h>
+#include <sys/xattr.h>
static void print_xattrib_val(const char *path, const char *name)
{
int h;
int result;
int val1;
- int valread;
-
strcpy(name,mountpt);
strcat(name,"/");
int main(int argc, char *argv[])
{
basic_xattr_test("/mnt/");
+ return 0;
}
/* Function to calculate chunk and offset */
-static inline void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
- int *chunk_out, u32 *offset_out)
+void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
+ int *chunk_out, u32 *offset_out)
{
int chunk;
u32 offset;
#endif
}
+loff_t yaffs_max_file_size(struct yaffs_dev *dev)
+{
+ return ((loff_t) YAFFS_MAX_CHUNK_ID) * dev->data_bytes_per_chunk;
+}
+
/*-------------------- TNODES -------------------
* List of spare tnodes
case YAFFS_OBJECT_TYPE_FILE:
the_obj->variant.file_variant.file_size = 0;
the_obj->variant.file_variant.scanned_size = 0;
- the_obj->variant.file_variant.shrink_size = ~0; /* max */
+ the_obj->variant.file_variant.shrink_size =
+ yaffs_max_file_size(dev);
the_obj->variant.file_variant.top_level = 0;
the_obj->variant.file_variant.top = tn;
break;
/* Update file size */
if (object->variant_type == YAFFS_OBJECT_TYPE_FILE) {
- oh->file_size =
+ yaffs_oh_size_load( oh,
+ object->variant.file_variant.file_size);
+ tags.extra_file_size =
object->variant.file_variant.file_size;
- tags.extra_length = oh->file_size;
}
yaffs_verify_oh(object, oh, &tags, 1);
}
} else {
#else
+ dev = dev;
{
#endif
strncpy(name, oh_name, buff_size - 1);
}
} else {
#else
+ dev = dev;
{
#endif
strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1);
u8 *buffer = NULL;
YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1];
struct yaffs_obj_hdr *oh = NULL;
+ loff_t file_size = 0;
strcpy(old_name, _Y("silly old name"));
/* Should not happen */
break;
case YAFFS_OBJECT_TYPE_FILE:
- oh->file_size =
- (oh->parent_obj_id == YAFFS_OBJECTID_DELETED ||
- oh->parent_obj_id == YAFFS_OBJECTID_UNLINKED) ?
- 0 : in->variant.file_variant.file_size;
+ if (oh->parent_obj_id != YAFFS_OBJECTID_DELETED &&
+ oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED)
+ file_size = in->variant.file_variant.file_size;
+ yaffs_oh_size_load(oh, file_size);
break;
case YAFFS_OBJECT_TYPE_HARDLINK:
oh->equiv_id = in->variant.hardlink_variant.equiv_id;
/* Add extra info for file header */
new_tags.extra_available = 1;
new_tags.extra_parent_id = oh->parent_obj_id;
- new_tags.extra_length = oh->file_size;
+ new_tags.extra_file_size = file_size;
new_tags.extra_is_shrink = oh->is_shrink;
new_tags.extra_equiv_id = oh->equiv_id;
new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0;
}
int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
- int n_bytes, int write_trhrough)
+ int n_bytes, int write_through)
{
int chunk;
int n = n_bytes;
int n_done = 0;
int n_writeback;
- int start_write = offset;
+ loff_t start_write = offset;
int chunk_written = 0;
u32 n_bytes_read;
- u32 chunk_start;
+ loff_t chunk_start;
struct yaffs_dev *dev;
dev = in->my_dev;
while (n > 0 && chunk_written >= 0) {
yaffs_addr_to_chunk(dev, offset, &chunk, &start);
- if (chunk * dev->data_bytes_per_chunk + start != offset ||
+ if (((loff_t)chunk) * dev->data_bytes_per_chunk + start != offset ||
start >= dev->data_bytes_per_chunk) {
yaffs_trace(YAFFS_TRACE_ERROR,
- "AddrToChunk of offset %d gives chunk %d start %d",
- (int)offset, chunk, start);
+ "AddrToChunk of offset %lld gives chunk %d start %d",
+ offset, chunk, start);
}
chunk++; /* File pos to chunk in file offset */
* before.
*/
- chunk_start = ((chunk - 1) * dev->data_bytes_per_chunk);
+ chunk_start = (((loff_t)(chunk - 1)) * dev->data_bytes_per_chunk);
if (chunk_start > in->variant.file_variant.file_size)
n_bytes_read = 0; /* Past end of file */
cache->locked = 0;
cache->n_bytes = n_writeback;
- if (write_trhrough) {
+ if (write_through) {
chunk_written =
yaffs_wr_data_obj
(cache->object,
}
int yaffs_wr_file(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
- int n_bytes, int write_trhrough)
+ int n_bytes, int write_through)
{
yaffs2_handle_hole(in, offset);
- return yaffs_do_file_wr(in, buffer, offset, n_bytes, write_trhrough);
+ return yaffs_do_file_wr(in, buffer, offset, n_bytes, write_through);
}
/* ---------------------- File resizing stuff ------------------ */
int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size)
{
struct yaffs_dev *dev = in->my_dev;
- int old_size = in->variant.file_variant.file_size;
+ loff_t old_size = in->variant.file_variant.file_size;
yaffs_flush_file_cache(in);
yaffs_invalidate_whole_cache(in);
return strnlen(name, YAFFS_MAX_NAME_LENGTH);
}
-int yaffs_get_obj_length(struct yaffs_obj *obj)
+loff_t yaffs_get_obj_length(struct yaffs_obj *obj)
{
/* Dereference any hard linking */
obj = yaffs_get_equivalent_obj(obj);
return n_free;
}
+
+/*\
+ * Marshalling functions to get loff_t file sizes into aand out of
+ * object headers.
+ */
+void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize)
+{
+ oh->file_size_low = (fsize & 0xFFFFFFFF);
+ oh->file_size_high = ((fsize >> 32) & 0xFFFFFFFF);
+}
+
+loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh)
+{
+ loff_t retval;
+
+ if(~(oh->file_size_high))
+ retval = (((loff_t) oh->file_size_high) << 32) |
+ (((loff_t) oh->file_size_low) & 0xFFFFFFFF);
+ else
+ retval = (loff_t) oh->file_size_low;
+
+ return retval;
+}
*/
#define YAFFS_MAGIC 0x5941ff53
+/*
+ * Tnodes form a tree with the tnodes in "levels"
+ * Levels greater than 0 hold 8 slots which point to other tnodes.
+ * Those at level 0 hold 16 slots which point to chunks in NAND.
+ *
+ * A maximum level of 8 thust supports files of size up to:
+ *
+ * 2^(3*MAX_LEVEL+4)
+ *
+ * Thus a max level of 8 supports files with up to 2^^28 chunks which gives
+ * a maximum file size of arounf 51Gbytees with 2k chunks.
+ */
#define YAFFS_NTNODES_LEVEL0 16
#define YAFFS_TNODES_LEVEL0_BITS 4
#define YAFFS_TNODES_LEVEL0_MASK 0xf
#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2)
#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1)
#define YAFFS_TNODES_INTERNAL_MASK 0x7
-#define YAFFS_TNODES_MAX_LEVEL 6
-
+#define YAFFS_TNODES_MAX_LEVEL 8
+#define YAFFS_TNODES_MAX_BITS (YAFFS_TNODES_LEVEL0_BITS + \
+ YAFFS_TNODES_INTERNAL_BITS * \
+ YAFFS_TNODES_MAX_LEVEL)
+#define YAFFS_MAX_CHUNK_ID ((1 << YAFFS_TNODES_MAX_BITS) - 1)
/* Constants for YAFFS1 mode */
#define YAFFS_BYTES_PER_SPARE 16
#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024
#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32
-#define YAFFS_MAX_CHUNK_ID 0x000fffff
+
#define YAFFS_ALLOCATION_NOBJECTS 100
#define YAFFS_ALLOCATION_NTNODES 100
#define YAFFS_OBJECT_SPACE 0x40000
#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE - 1)
-#define YAFFS_CHECKPOINT_VERSION 4
+#define YAFFS_CHECKPOINT_VERSION 5
#ifdef CONFIG_YAFFS_UNICODE
#define YAFFS_MAX_NAME_LENGTH 127
enum yaffs_obj_type extra_obj_type; /* What object type? */
- unsigned extra_length; /* Length if it is a file */
+ loff_t extra_file_size; /* Length if it is a file */
unsigned extra_equiv_id; /* Equivalent object for a hard link */
};
u32 yst_ctime;
/* File size applies to files only */
- int file_size;
+ u32 file_size_low;
/* Equivalent object id applies to hard links only. */
int equiv_id;
u32 inband_shadowed_obj_id;
u32 inband_is_shrink;
- u32 reserved[2];
+ u32 file_size_high;
+ u32 reserved[1];
int shadows_obj; /* This object header shadows the
specified object if > 0 */
*/
struct yaffs_file_var {
- u32 file_size;
- u32 scanned_size;
- u32 shrink_size;
+ loff_t file_size;
+ loff_t scanned_size;
+ loff_t shrink_size;
int top_level;
struct yaffs_tnode *top;
};
u8 unlink_allowed:1;
u8 serial;
int n_data_chunks;
- u32 size_or_equiv_obj;
+ loff_t size_or_equiv_obj;
};
/*--------------------- Temporary buffers ----------------
int yaffs_del_obj(struct yaffs_obj *obj);
int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size);
-int yaffs_get_obj_length(struct yaffs_obj *obj);
+loff_t yaffs_get_obj_length(struct yaffs_obj *obj);
int yaffs_get_obj_inode(struct yaffs_obj *obj);
unsigned yaffs_get_obj_type(struct yaffs_obj *obj);
int yaffs_get_obj_link_count(struct yaffs_obj *obj);
unsigned pos);
int yaffs_is_non_empty_dir(struct yaffs_obj *obj);
+
+void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
+ int *chunk_out, u32 *offset_out);
+/*
+ * Marshalling functions to get loff_t file sizes into aand out of
+ * object headers.
+ */
+void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize);
+loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh);
+loff_t yaffs_max_file_size(struct yaffs_dev *dev);
+
+
#endif
}
+static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t)
+{
+ if(t->chunk_id != 0 || !t->extra_available)
+ return 0;
+
+ /* Check if the file size is too long to store */
+ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE &&
+ (t->extra_file_size>> 31) != 0)
+ return 0;
+ return 1;
+}
+
void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt,
const struct yaffs_ext_tags *t)
{
ptt->n_bytes = t->n_bytes;
ptt->obj_id = t->obj_id;
- if (t->chunk_id == 0 && t->extra_available) {
+ /* Only store extra tags for object headers.
+ * If it is a file then only store if the file size is short\
+ * enough to fit.
+ */
+ if (yaffs_check_tags_extra_packable(t)) {
/* Store the extra header info instead */
/* We save the parent object in the chunk_id */
ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id;
if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
ptt->n_bytes = t->extra_equiv_id;
else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
- ptt->n_bytes = t->extra_length;
+ ptt->n_bytes = (unsigned) t->extra_file_size;
else
ptt->n_bytes = 0;
}
if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
t->extra_equiv_id = ptt->n_bytes;
else
- t->extra_length = ptt->n_bytes;
+ t->extra_file_size = ptt->n_bytes;
}
yaffs_dump_packed_tags2_tags_only(ptt);
yaffs_dump_tags2(t);
void yaffs_verify_file(struct yaffs_obj *obj)
{
+ u32 x;
int required_depth;
int actual_depth;
- u32 last_chunk;
+ int last_chunk;
+ u32 offset_in_chunk;
u32 the_chunk;
- u32 x;
+
u32 i;
struct yaffs_dev *dev;
struct yaffs_ext_tags tags;
dev = obj->my_dev;
obj_id = obj->obj_id;
+
/* Check file size is consistent with tnode depth */
- last_chunk =
- obj->variant.file_variant.file_size / dev->data_bytes_per_chunk + 1;
+ yaffs_addr_to_chunk(dev, obj->variant.file_variant.file_size,
+ &last_chunk, &offset_in_chunk);
+ last_chunk++;
x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS;
required_depth = 0;
while (x > 0) {
struct yaffs_obj *obj;
unsigned char *pg_buf;
int ret;
+ loff_t pos = ((loff_t) pg->index) << PAGE_CACHE_SHIFT;
struct yaffs_dev *dev;
yaffs_trace(YAFFS_TRACE_OS,
- "yaffs_readpage_nolock at %08x, size %08x",
- (unsigned)(pg->index << PAGE_CACHE_SHIFT),
- (unsigned)PAGE_CACHE_SIZE);
+ "yaffs_readpage_nolock at %lld, size %08x",
+ (long long)pos,
+ (unsigned)PAGE_CACHE_SIZE);
obj = yaffs_dentry_to_obj(f->f_dentry);
yaffs_gross_lock(dev);
- ret = yaffs_file_rd(obj, pg_buf,
- pg->index << PAGE_CACHE_SHIFT, PAGE_CACHE_SIZE);
+ ret = yaffs_file_rd(obj, pg_buf, pos, PAGE_CACHE_SIZE);
yaffs_gross_unlock(dev);
if (page->index > end_index || !n_bytes) {
yaffs_trace(YAFFS_TRACE_OS,
- "yaffs_writepage at %08x, inode size = %08x!!",
- (unsigned)(page->index << PAGE_CACHE_SHIFT),
- (unsigned)inode->i_size);
+ "yaffs_writepage at %lld, inode size = %lld!!",
+ ((loff_t)page->index) << PAGE_CACHE_SHIFT,
+ inode->i_size);
yaffs_trace(YAFFS_TRACE_OS,
" -> don't care!!");
yaffs_gross_lock(dev);
yaffs_trace(YAFFS_TRACE_OS,
- "yaffs_writepage at %08x, size %08x",
- (unsigned)(page->index << PAGE_CACHE_SHIFT), n_bytes);
+ "yaffs_writepage at %lld, size %08x",
+ ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes);
yaffs_trace(YAFFS_TRACE_OS,
- "writepag0: obj = %05x, ino = %05x",
- (int)obj->variant.file_variant.file_size, (int)inode->i_size);
+ "writepag0: obj = %lld, ino = %lld",
+ obj->variant.file_variant.file_size, inode->i_size);
n_written = yaffs_wr_file(obj, buffer,
- page->index << PAGE_CACHE_SHIFT, n_bytes, 0);
+ ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes, 0);
yaffs_touch_super(dev);
yaffs_trace(YAFFS_TRACE_OS,
- "writepag1: obj = %05x, ino = %05x",
- (int)obj->variant.file_variant.file_size, (int)inode->i_size);
+ "writepag1: obj = %lld, ino = %lld",
+ obj->variant.file_variant.file_size, inode->i_size);
yaffs_gross_unlock(dev);
addr = kva + offset_into_page;
yaffs_trace(YAFFS_TRACE_OS,
- "yaffs_write_end addr %p pos %x n_bytes %d",
- addr, (unsigned)pos, copied);
+ "yaffs_write_end addr %p pos %lld n_bytes %d",
+ addr, pos, copied);
ret = yaffs_file_write(filp, addr, copied, &pos);
int n_bytes = to - offset;
int n_written;
- unsigned spos = pos;
- unsigned saddr;
-
kva = kmap(pg);
addr = kva + offset;
- saddr = (unsigned)addr;
-
yaffs_trace(YAFFS_TRACE_OS,
- "yaffs_commit_write addr %x pos %x n_bytes %d",
- saddr, spos, n_bytes);
+ "yaffs_commit_write addr %p pos %lld n_bytes %d",
+ addr, pos, n_bytes);
n_written = yaffs_file_write(f, addr, n_bytes, &pos);
set_nlink(inode, yaffs_get_obj_link_count(obj));
yaffs_trace(YAFFS_TRACE_OS,
- "yaffs_fill_inode mode %x uid %d gid %d size %d count %d",
+ "yaffs_fill_inode mode %x uid %d gid %d size %lld count %d",
inode->i_mode, inode->i_uid, inode->i_gid,
- (int)inode->i_size, atomic_read(&inode->i_count));
+ inode->i_size, atomic_read(&inode->i_count));
switch (obj->yst_mode & S_IFMT) {
default: /* fifo, device or socket */
loff_t * pos)
{
struct yaffs_obj *obj;
- int n_written, ipos;
+ int n_written;
+ loff_t ipos;
struct inode *inode;
struct yaffs_dev *dev;
ipos = *pos;
yaffs_trace(YAFFS_TRACE_OS,
- "yaffs_file_write about to write writing %u(%x) bytes to object %d at %d(%x)",
- (unsigned)n, (unsigned)n, obj->obj_id, ipos, ipos);
+ "yaffs_file_write about to write writing %u(%x) bytes to object %d at %lld",
+ (unsigned)n, (unsigned)n, obj->obj_id, ipos);
n_written = yaffs_wr_file(obj, buf, ipos, n, 0);
inode->i_blocks = (ipos + 511) >> 9;
yaffs_trace(YAFFS_TRACE_OS,
- "yaffs_file_write size updated to %d bytes, %d blocks",
+ "yaffs_file_write size updated to %lld bytes, %d blocks",
ipos, (int)(inode->i_blocks));
}
yaffs_trace(YAFFS_TRACE_OS,
"yaffs_setattr of object %d",
yaffs_inode_to_obj(inode)->obj_id);
-
+#if 0
/* Fail if a requested resize >= 2GB */
if (attr->ia_valid & ATTR_SIZE && (attr->ia_size >> 31))
error = -EINVAL;
+#endif
if (error == 0)
error = inode_change_ok(inode, attr);
sb->u.generic_sbp = dev;
#endif
+
dev->driver_context = mtd;
param->name = mtd->name;
if (!context->bg_thread)
param->defered_dir_update = 0;
+ sb->s_maxbytes = yaffs_max_file_size(dev);
+
/* Release lock before yaffs_get_inode() */
yaffs_gross_unlock(dev);
static char *yaffs_dump_dev_part1(char *buf, struct yaffs_dev *dev)
{
+ buf += sprintf(buf, "max file size....... %lld\n",
+ (long long) yaffs_max_file_size(dev));
buf += sprintf(buf, "data_bytes_per_chunk. %d\n",
dev->data_bytes_per_chunk);
buf += sprintf(buf, "chunk_grp_bits....... %d\n", dev->chunk_grp_bits);
case YAFFS_OBJECT_TYPE_FILE:
if (dev->param.
use_header_file_size)
-
- in->variant.
- file_variant.file_size
- = oh->file_size;
-
+ in->variant.
+ file_variant.file_size
+ = yaffs_oh_to_size(oh);
break;
case YAFFS_OBJECT_TYPE_HARDLINK:
in->variant.
* of hole marker.
*/
loff_t old_file_size;
- int increase;
+ loff_t increase;
int small_hole;
int result = YAFFS_OK;
struct yaffs_dev *dev = NULL;
if (local_buffer) {
/* fill hole with zero bytes */
- int pos = old_file_size;
+ loff_t pos = old_file_size;
int this_write;
int written;
memset(local_buffer, 0, dev->data_bytes_per_chunk);
struct yaffs_obj *in;
struct yaffs_obj *parent;
int equiv_id;
- int file_size;
+ loff_t file_size;
int is_shrink;
int is_unlinked;
struct yaffs_ext_tags tags;
dev->n_free_chunks++;
} else if (tags.chunk_id > 0) {
/* chunk_id > 0 so it is a data chunk... */
- unsigned int endpos;
- u32 chunk_base = (tags.chunk_id - 1) *
+ loff_t endpos;
+ loff_t chunk_base = (tags.chunk_id - 1) *
dev->data_bytes_per_chunk;
*found_chunks = 1;
(tags.extra_available &&
tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
)) {
- u32 this_size = (oh) ?
- oh->file_size :
- tags.extra_length;
+ loff_t this_size = (oh) ?
+ yaffs_oh_to_size(oh) :
+ tags.extra_file_size;
u32 parent_obj_id = (oh) ?
oh->parent_obj_id :
tags.extra_parent_id;
parent = yaffs_find_or_create_by_number(dev,
oh->parent_obj_id,
YAFFS_OBJECT_TYPE_DIRECTORY);
- file_size = oh->file_size;
+ file_size = yaffs_oh_to_size(oh);
is_shrink = oh->is_shrink;
equiv_id = oh->equiv_id;
} else {
parent = yaffs_find_or_create_by_number(dev,
tags.extra_parent_id,
YAFFS_OBJECT_TYPE_DIRECTORY);
- file_size = tags.extra_length;
+ file_size = tags.extra_file_size;
is_shrink = tags.extra_is_shrink;
equiv_id = tags.extra_equiv_id;
in->lazy_loaded = 1;