diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-07-08 02:59:00 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-07-08 02:59:00 +0000 |
commit | 1fcb7623bc138d780101d7a70cfe29b11f7c67ef (patch) | |
tree | e1ec9bb6aa19db16a405fb4393e2a90c38b4c75d /fs/umsdos | |
parent | 458fe58677afb17219d864e100131728038b4f1b (diff) |
Merge with Linux 2.4.0-test3-pre5. 64-bit kernel are still not
-Werror clean.
Diffstat (limited to 'fs/umsdos')
-rw-r--r-- | fs/umsdos/dir.c | 66 | ||||
-rw-r--r-- | fs/umsdos/emd.c | 607 | ||||
-rw-r--r-- | fs/umsdos/inode.c | 73 | ||||
-rw-r--r-- | fs/umsdos/ioctl.c | 12 | ||||
-rw-r--r-- | fs/umsdos/namei.c | 12 |
5 files changed, 337 insertions, 433 deletions
diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c index a8352917a..a84b8891f 100644 --- a/fs/umsdos/dir.c +++ b/fs/umsdos/dir.c @@ -16,8 +16,7 @@ #include <linux/limits.h> #include <linux/umsdos_fs.h> #include <linux/malloc.h> - -#include <asm/uaccess.h> +#include <linux/pagemap.h> #define UMSDOS_SPECIAL_DIRFPOS 3 extern struct dentry *saved_root; @@ -102,7 +101,7 @@ static int umsdos_readdir_x (struct inode *dir, struct file *filp, struct dentry *demd; off_t start_fpos; int ret = 0; - struct file new_filp; + loff_t pos; umsdos_startlookup (dir); @@ -162,24 +161,21 @@ static int umsdos_readdir_x (struct inode *dir, struct file *filp, goto out_dput; } - /* set up our private filp ... */ - fill_new_filp(&new_filp, demd); - new_filp.f_pos = filp->f_pos; + pos = filp->f_pos; start_fpos = filp->f_pos; - if (new_filp.f_pos <= UMSDOS_SPECIAL_DIRFPOS + 1) - new_filp.f_pos = 0; -Printk (("f_pos %Ld i_size %ld\n", new_filp.f_pos, demd->d_inode->i_size)); + if (pos <= UMSDOS_SPECIAL_DIRFPOS + 1) + pos = 0; ret = 0; - while (new_filp.f_pos < demd->d_inode->i_size) { - off_t cur_f_pos = new_filp.f_pos; + while (pos < demd->d_inode->i_size) { + off_t cur_f_pos = pos; struct dentry *dret; struct inode *inode; struct umsdos_dirent entry; struct umsdos_info info; ret = -EIO; - if (umsdos_emd_dir_readentry (&new_filp, &entry) != 0) + if (umsdos_emd_dir_readentry (demd, &pos, &entry) != 0) break; if (entry.name_len == 0) continue; @@ -240,7 +236,7 @@ dret->d_parent->d_name.name, dret->d_name.name); if (inode != pseudo_root && !(entry.flags & UMSDOS_HIDDEN)) { if (filldir (dirbuf, entry.name, entry.name_len, cur_f_pos, inode->i_ino) < 0) { - new_filp.f_pos = cur_f_pos; + pos = cur_f_pos; } Printk(("umsdos_readdir_x: got %s/%s, ino=%ld\n", dret->d_parent->d_name.name, dret->d_name.name, inode->i_ino)); @@ -278,7 +274,7 @@ filp->f_dentry->d_name.name, info.entry.name); * (see comments at the beginning), we put back * the special offset. */ - filp->f_pos = new_filp.f_pos; + filp->f_pos = pos; if (filp->f_pos == 0) filp->f_pos = start_fpos; out_dput: @@ -688,28 +684,26 @@ struct dentry *umsdos_solve_hlink (struct dentry *hlink) struct dentry *dentry_dst; char *path, *pt; int len; - struct file filp; + struct address_space *mapping = hlink->d_inode->i_mapping; + struct page *page; -#ifdef UMSDOS_DEBUG_VERBOSE -printk("umsdos_solve_hlink: following %s/%s\n", -hlink->d_parent->d_name.name, hlink->d_name.name); -#endif + page=read_cache_page(mapping,0,(filler_t *)mapping->a_ops->readpage,NULL); + dentry_dst=(struct dentry *)page; + if (IS_ERR(page)) + goto out; + wait_on_page(page); + if (!Page_Uptodate(page)) + goto async_fail; - dentry_dst = ERR_PTR (-ENOMEM); + dentry_dst = ERR_PTR(-ENOMEM); path = (char *) kmalloc (PATH_MAX, GFP_KERNEL); if (path == NULL) - goto out; + goto out_release; + memcpy(path, (char*)kmap(page), hlink->d_inode->i_size); + kunmap(page); + page_cache_release(page); - fill_new_filp (&filp, hlink); - filp.f_flags = O_RDONLY; - - len = umsdos_file_read_kmem (&filp, path, hlink->d_inode->i_size); - if (len != hlink->d_inode->i_size) - goto out_noread; -#ifdef UMSDOS_DEBUG_VERBOSE -printk ("umsdos_solve_hlink: %s/%s is path %s\n", -hlink->d_parent->d_name.name, hlink->d_name.name, path); -#endif + len = hlink->d_inode->i_size; /* start at root dentry */ dentry_dst = dget(base); @@ -775,17 +769,17 @@ dentry_dst->d_parent->d_name.name, dentry_dst->d_name.name); } else printk(KERN_WARNING "umsdos_solve_hlink: err=%ld\n", PTR_ERR(dentry_dst)); - -out_free: kfree (path); out: dput(hlink); /* original hlink no longer needed */ return dentry_dst; -out_noread: - printk(KERN_WARNING "umsdos_solve_hlink: failed reading pseudolink!\n"); - goto out_free; +async_fail: + dentry_dst = ERR_PTR(-EIO); +out_release: + page_cache_release(page); + goto out; } diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c index d9b00e8c9..84e8ca99f 100644 --- a/fs/umsdos/emd.c +++ b/fs/umsdos/emd.c @@ -15,169 +15,25 @@ #include <linux/msdos_fs.h> #include <linux/umsdos_fs.h> #include <linux/dcache.h> - -#include <asm/uaccess.h> +#include <linux/pagemap.h> #include <asm/delay.h> - -/* - * Read a file into kernel space memory - * returns how many bytes read (from fat_file_read) - */ - -ssize_t umsdos_file_read_kmem ( struct file *filp, - char *buf, - size_t count) +static void copy_entry(struct umsdos_dirent *p, struct umsdos_dirent *q) { - ssize_t ret; - mm_segment_t old_fs = get_fs (); - - set_fs (KERNEL_DS); - ret = fat_file_read (filp, buf, count, &filp->f_pos); - set_fs (old_fs); - return ret; + p->name_len = q->name_len; + p->flags = q->flags; + p->nlink = le16_to_cpu (q->nlink); + /* FIXME -- 32bit UID/GID issues */ + p->uid = le16_to_cpu (q->uid); + p->gid = le16_to_cpu (q->gid); + p->atime = le32_to_cpu (q->atime); + p->mtime = le32_to_cpu (q->mtime); + p->ctime = le32_to_cpu (q->ctime); + p->rdev = le16_to_cpu (q->rdev); + p->mode = le16_to_cpu (q->mode); } - -/* - * Write to file from kernel space. - * Does the real job, assumes all structures are initialized! - */ - - -ssize_t umsdos_file_write_kmem_real (struct file * filp, - const char *buf, - size_t count) -{ - mm_segment_t old_fs = get_fs (); - ssize_t ret; - - set_fs (KERNEL_DS); - ret = fat_file_write (filp, buf, count, &filp->f_pos); - set_fs (old_fs); - if (ret < 0) { - printk(KERN_WARNING "umsdos_file_write: ret=%d\n", ret); - goto out; - } -#ifdef UMSDOS_PARANOIA -if (ret != count) -printk(KERN_WARNING "umsdos_file_write: count=%u, ret=%u\n", count, ret); -#endif -out: - return ret; -} - - -/* - * Write to a file from kernel space. - */ - -ssize_t umsdos_file_write_kmem (struct file *filp, - const char *buf, - size_t count) -{ - ssize_t ret; - - ret = umsdos_file_write_kmem_real (filp, buf, count); - return ret; -} - - - -/* - * Write a block of bytes into one EMD file. - * The block of data is NOT in user space. - * - * Return 0 if OK, a negative error code if not. - * - * Note: buffer is in kernel memory, not in user space. - */ - -ssize_t umsdos_emd_dir_write ( struct file *filp, - char *buf, - size_t count) -{ - int written; - -#ifdef __BIG_ENDIAN - struct umsdos_dirent *d = (struct umsdos_dirent *) buf; - - d->nlink = cpu_to_le16 (d->nlink); - d->uid = cpu_to_le16 (d->uid); - d->gid = cpu_to_le16 (d->gid); - d->atime = cpu_to_le32 (d->atime); - d->mtime = cpu_to_le32 (d->mtime); - d->ctime = cpu_to_le32 (d->ctime); - d->rdev = cpu_to_le16 (d->rdev); - d->mode = cpu_to_le16 (d->mode); -#endif - - filp->f_flags = 0; -Printk (("umsdos_emd_dir_write /mn/: calling write_kmem with %p, %p, %d, %Ld\n", -filp, buf, count, filp->f_pos)); - written = umsdos_file_write_kmem (filp, buf, count); - -#ifdef __BIG_ENDIAN - d->nlink = le16_to_cpu (d->nlink); - d->uid = le16_to_cpu (d->uid); - d->gid = le16_to_cpu (d->gid); - d->atime = le32_to_cpu (d->atime); - d->mtime = le32_to_cpu (d->mtime); - d->ctime = le32_to_cpu (d->ctime); - d->rdev = le16_to_cpu (d->rdev); - d->mode = le16_to_cpu (d->mode); -#endif - -#ifdef UMSDOS_PARANOIA -if (written != count) -printk(KERN_ERR "umsdos_emd_dir_write: ERROR: written (%d) != count (%d)\n", -written, count); -#endif - - return (written != count) ? -EIO : 0; -} - - - -/* - * Read a block of bytes from one EMD file. - * The block of data is NOT in user space. - * Return 0 if OK, -EIO if any error. - */ -/* buffer in kernel memory, not in user space */ - -ssize_t umsdos_emd_dir_read (struct file *filp, char *buf, size_t count) -{ - ssize_t sizeread, ret = 0; - -#ifdef __BIG_ENDIAN - struct umsdos_dirent *d = (struct umsdos_dirent *) buf; - -#endif - - filp->f_flags = 0; - sizeread = umsdos_file_read_kmem (filp, buf, count); - if (sizeread != count) { - printk (KERN_WARNING - "UMSDOS: EMD problem, pos=%Ld, count=%d, read=%d\n", - filp->f_pos, count, sizeread); - ret = -EIO; - } -#ifdef __BIG_ENDIAN - d->nlink = le16_to_cpu (d->nlink); - d->uid = le16_to_cpu (d->uid); - d->gid = le16_to_cpu (d->gid); - d->atime = le32_to_cpu (d->atime); - d->mtime = le32_to_cpu (d->mtime); - d->ctime = le32_to_cpu (d->ctime); - d->rdev = le16_to_cpu (d->rdev); - d->mode = le16_to_cpu (d->mode); -#endif - return ret; -} - - /* * Lookup the EMD dentry for a directory. * @@ -256,35 +112,60 @@ out: * does not change {d,i}_count */ -int umsdos_emd_dir_readentry (struct file *filp, struct umsdos_dirent *entry) +int umsdos_emd_dir_readentry (struct dentry *demd, loff_t *pos, struct umsdos_dirent *entry) { - int ret; - - Printk ((KERN_DEBUG "umsdos_emd_dir_readentry /mn/: entering.\n")); - - ret = umsdos_emd_dir_read (filp, (char *) entry, UMSDOS_REC_SIZE); - if (ret == 0) { /* if no error */ - /* Variable size record. Maybe, we have to read some more */ - int recsize = umsdos_evalrecsize (entry->name_len); - - if (recsize > UMSDOS_REC_SIZE) { -Printk ((KERN_DEBUG "umsdos_emd_dir_readentry /mn/: %d > %d!\n", -recsize, UMSDOS_REC_SIZE)); - ret = umsdos_emd_dir_read (filp, - ((char *) entry) + UMSDOS_REC_SIZE, - recsize - UMSDOS_REC_SIZE); + struct address_space *mapping = demd->d_inode->i_mapping; + struct page *page; + struct umsdos_dirent *p; + int offs = *pos & ~PAGE_CACHE_MASK; + int recsize; + + page = read_cache_page(mapping, *pos>>PAGE_CACHE_SHIFT, + (filler_t*)mapping->a_ops->readpage, NULL); + if (IS_ERR(page)) + goto sync_fail; + wait_on_page(page); + if (!Page_Uptodate(page)) + goto async_fail; + p = (struct umsdos_dirent*)((char*)kmap(page)+offs); + recsize = umsdos_evalrecsize(p->name_len); + if (offs + recsize > PAGE_CACHE_SIZE) { + struct page *page2; + int part = ((char*)page_address(page)+PAGE_CACHE_SIZE)-p->spare; + page2 = read_cache_page(mapping, 1+(*pos>>PAGE_CACHE_SHIFT), + (filler_t*)mapping->a_ops->readpage, NULL); + if (IS_ERR(page2)) { + kunmap(page); + page_cache_release(page); + page = page2; + goto sync_fail; } - } - Printk (("umsdos_emd_dir_readentry /mn/: ret=%d.\n", ret)); - if (entry && ret == 0) { -Printk (("umsdos_emd_dir_readentry /mn/: returning len=%d,name=%.*s\n", -(int) entry->name_len, (int) entry->name_len, entry->name)); - } - return ret; + wait_on_page(page2); + if (!Page_Uptodate(page2)) { + kunmap(page); + page_cache_release(page2); + goto async_fail; + } + memcpy(entry->spare,p->spare,part); + memcpy(entry->spare+part,(char*)kmap(page2), + recsize+offs-PAGE_CACHE_SIZE); + kunmap(page2); + page_cache_release(page2); + } else + memcpy(entry->spare,p->spare,((char*)p+recsize)-p->spare); + copy_entry(entry, p); + kunmap(page); + page_cache_release(page); + *pos += recsize; + return 0; +async_fail: + page_cache_release(page); + page = ERR_PTR(-EIO); +sync_fail: + return PTR_ERR(page); } - /* * Write an entry in the EMD file. * Return 0 if OK, -EIO if some error. @@ -298,8 +179,10 @@ static int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info, struct umsdos_dirent *entry = &info->entry; struct dentry *emd_dentry; int ret; - struct umsdos_dirent entry0; - struct file filp; + struct umsdos_dirent entry0,*p; + struct address_space *mapping; + struct page *page, *page2 = NULL; + int offs; emd_dentry = umsdos_get_emd_dentry(parent); ret = PTR_ERR(emd_dentry); @@ -335,76 +218,97 @@ static int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info, memset (entry->spare, 0, sizeof (entry->spare)); } - fill_new_filp (&filp, emd_dentry); - filp.f_pos = info->f_pos; - filp.f_reada = 0; - filp.f_flags = O_RDWR; - /* write the entry and update the parent timestamps */ - ret = umsdos_emd_dir_write (&filp, (char *) entry, info->recsize); - if (!ret) { - dir->i_ctime = dir->i_mtime = CURRENT_TIME; - mark_inode_dirty(dir); - } else - printk ("UMSDOS: problem with EMD file: can't write\n"); + mapping = emd_dentry->d_inode->i_mapping; + offs = info->f_pos & ~PAGE_CACHE_MASK; + ret = -ENOMEM; + page = grab_cache_page(mapping, info->f_pos>>PAGE_CACHE_SHIFT); + if (!page) + goto out_dput; + p = (struct umsdos_dirent*)((char*)page_address(page)+offs); + if (offs + info->recsize > PAGE_CACHE_SIZE) { + ret = mapping->a_ops->prepare_write(NULL,page,offs, + PAGE_CACHE_SIZE); + if (ret) + goto out_unlock; + page2 = grab_cache_page(mapping, + (info->f_pos>>PAGE_CACHE_SHIFT)+1); + if (!page2) + goto out_unlock2; + ret = mapping->a_ops->prepare_write(NULL,page2,0, + offs+info->recsize-PAGE_CACHE_SIZE); + if (ret) + goto out_unlock3; + p->name_len = entry->name_len; + p->flags = entry->flags; + p->nlink = cpu_to_le16(entry->nlink); + p->uid = cpu_to_le16(entry->uid); + p->gid = cpu_to_le16(entry->gid); + p->atime = cpu_to_le32(entry->atime); + p->mtime = cpu_to_le32(entry->mtime); + p->ctime = cpu_to_le32(entry->ctime); + p->rdev = cpu_to_le16(entry->rdev); + p->mode = cpu_to_le16(entry->mode); + memcpy(p->name,entry->name, + ((char*)page_address(page)+PAGE_CACHE_SIZE)-p->spare); + memcpy((char*)page_address(page2), + entry->spare+PAGE_CACHE_SIZE-offs, + offs+info->recsize-PAGE_CACHE_SIZE); + ret = mapping->a_ops->commit_write(NULL,page2,0, + offs+info->recsize-PAGE_CACHE_SIZE); + if (ret) + goto out_unlock3; + ret = mapping->a_ops->commit_write(NULL,page,offs, + PAGE_CACHE_SIZE); + UnlockPage(page2); + page_cache_release(page2); + if (ret) + goto out_unlock; + } else { + ret = mapping->a_ops->prepare_write(NULL,page,offs, + info->recsize); + if (ret) + goto out_unlock; + p->name_len = entry->name_len; + p->flags = entry->flags; + p->nlink = cpu_to_le16(entry->nlink); + p->uid = cpu_to_le16(entry->uid); + p->gid = cpu_to_le16(entry->gid); + p->atime = cpu_to_le32(entry->atime); + p->mtime = cpu_to_le32(entry->mtime); + p->ctime = cpu_to_le32(entry->ctime); + p->rdev = cpu_to_le16(entry->rdev); + p->mode = cpu_to_le16(entry->mode); + memcpy(p->spare,entry->spare,((char*)p+info->recsize)-p->spare); + ret = mapping->a_ops->commit_write(NULL,page,offs, + info->recsize); + if (ret) + goto out_unlock; + } + UnlockPage(page); + page_cache_release(page); + + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + mark_inode_dirty(dir); out_dput: dput(emd_dentry); out: Printk (("umsdos_writeentry /mn/: returning %d...\n", ret)); return ret; +out_unlock3: + UnlockPage(page2); + page_cache_release(page2); +out_unlock2: + ClearPageUptodate(page); + kunmap(page); +out_unlock: + UnlockPage(page); + page_cache_release(page); + printk ("UMSDOS: problem with EMD file: can't write\n"); + goto out_dput; } - - -#define CHUNK_SIZE (8*UMSDOS_REC_SIZE) -struct find_buffer { - char buffer[CHUNK_SIZE]; - int pos; /* read offset in buffer */ - int size; /* Current size of buffer */ - struct file filp; -}; - - - -/* - * Fill the read buffer and take care of the bytes remaining inside. - * Unread bytes are simply moved to the beginning. - * - * Return -ENOENT if EOF, 0 if OK, a negative error code if any problem. - * - * Note: the caller must hold a lock on the parent directory. - */ - -static int umsdos_fillbuf (struct find_buffer *buf) -{ - struct inode *inode = buf->filp.f_dentry->d_inode; - int mustmove = buf->size - buf->pos; - int mustread, remain; - int ret = -ENOENT; - - if (mustmove > 0) { - memcpy (buf->buffer, buf->buffer + buf->pos, mustmove); - } - buf->pos = 0; - mustread = CHUNK_SIZE - mustmove; - remain = inode->i_size - buf->filp.f_pos; - if (remain < mustread) - mustread = remain; - if (mustread > 0) { - ret = umsdos_emd_dir_read (&buf->filp, buf->buffer + mustmove, - mustread); - if (ret == 0) - buf->size = mustmove + mustread; - } else if (mustmove) { - buf->size = mustmove; - ret = 0; - } - return ret; -} - - - /* * General search, locate a name in the EMD file or an empty slot to * store it. if info->entry.name_len == 0, search the first empty @@ -432,115 +336,144 @@ static int umsdos_fillbuf (struct find_buffer *buf) * record, multiple contiguous records are allocated. */ -static int umsdos_find (struct dentry *parent, struct umsdos_info *info) +static int umsdos_find (struct dentry *demd, struct umsdos_info *info) { struct umsdos_dirent *entry = &info->entry; int recsize = info->recsize; - struct dentry *demd; struct inode *emd_dir; int ret = -ENOENT; - struct find_buffer buf; struct { off_t posok; /* Position available to store the entry */ - int found; /* A valid empty position has been found. */ off_t one; /* One empty position -> maybe <- large enough */ - int onesize; /* size of empty region starting at one */ } empty; + int found = 0; + int empty_size = 0; + struct address_space *mapping; + filler_t *readpage; + struct page *page = NULL; + int index = -1; + int offs = PAGE_CACHE_SIZE,max_offs = PAGE_CACHE_SIZE; + char *p = NULL; + loff_t pos = 0; -Printk (("umsdos_find: locating %s in %s/%s\n", -entry->name, parent->d_parent->d_name.name, parent->d_name.name)); - - /* - * Lookup the EMD file in the parent directory. - */ - demd = umsdos_get_emd_dentry(parent); - ret = PTR_ERR(demd); - if (IS_ERR(demd)) - goto out; /* make sure there's an EMD file ... */ ret = -ENOENT; emd_dir = demd->d_inode; if (!emd_dir) goto out_dput; + mapping = emd_dir->i_mapping; + readpage = (filler_t*)mapping->a_ops->readpage; -Printk(("umsdos_find: found EMD file %s/%s, ino=%p\n", -demd->d_parent->d_name.name, demd->d_name.name, emd_dir)); - - fill_new_filp (&buf.filp, demd); - - buf.pos = 0; - buf.size = 0; - - empty.found = 0; empty.posok = emd_dir->i_size; - empty.onesize = 0; while (1) { - struct umsdos_dirent *rentry = (struct umsdos_dirent *) - (buf.buffer + buf.pos); - int file_pos = buf.filp.f_pos - buf.size + buf.pos; - - if (buf.pos == buf.size) { - ret = umsdos_fillbuf (&buf); - if (ret < 0) { - /* Not found, so note where it can be added */ + struct umsdos_dirent *rentry; + int entry_size; + + if (offs >= max_offs) { + if (page) { + kunmap(page); + page_cache_release(page); + } + if (pos >= emd_dir->i_size) { info->f_pos = empty.posok; break; } - } else if (rentry->name_len == 0) { + if (++index == (emd_dir->i_size>>PAGE_CACHE_SHIFT)) + max_offs = emd_dir->i_size & ~PAGE_CACHE_MASK; + offs -= PAGE_CACHE_SIZE; + page = read_cache_page(mapping,index,readpage,NULL); + if (IS_ERR(page)) + goto sync_fail; + wait_on_page(page); + if (!Page_Uptodate(page)) + goto async_fail; + p = (char*)kmap(page); + } + + rentry = (struct umsdos_dirent *)(p+offs); + + if (rentry->name_len == 0) { /* We are looking for an empty section at least */ /* as large as recsize. */ if (entry->name_len == 0) { - info->f_pos = file_pos; + info->f_pos = pos; ret = 0; break; - } else if (!empty.found) { - if (empty.onesize == 0) { - /* This is the first empty record of a section. */ - empty.one = file_pos; - } - /* grow the empty section */ - empty.onesize += UMSDOS_REC_SIZE; - if (empty.onesize == recsize) { - /* Here is a large enough section. */ - empty.posok = empty.one; - empty.found = 1; - } } - buf.pos += UMSDOS_REC_SIZE; - } else { - int entry_size = umsdos_evalrecsize (rentry->name_len); - - if (buf.pos + entry_size > buf.size) { - ret = umsdos_fillbuf (&buf); - if (ret < 0) { - /* Not found, so note where it can be added */ - info->f_pos = empty.posok; - break; - } - } else { - empty.onesize = 0; /* Reset the free slot search. */ - if (entry->name_len == rentry->name_len - && memcmp (entry->name, rentry->name, rentry->name_len) == 0) { - info->f_pos = file_pos; - *entry = *rentry; - ret = 0; - break; - } else { - buf.pos += entry_size; - } + offs += UMSDOS_REC_SIZE; + pos += UMSDOS_REC_SIZE; + if (found) + continue; + if (!empty_size) + empty.one = pos-UMSDOS_REC_SIZE; + empty_size += UMSDOS_REC_SIZE; + if (empty_size == recsize) { + /* Here is a large enough section. */ + empty.posok = empty.one; + found = 1; } + continue; } + + entry_size = umsdos_evalrecsize(rentry->name_len); + if (entry_size > PAGE_CACHE_SIZE) + goto async_fail; + empty_size = 0; + if (entry->name_len != rentry->name_len) + goto skip_it; + + if (entry_size + offs > PAGE_CACHE_SIZE) { + /* Sucker spans the page boundary */ + int len = (p+PAGE_CACHE_SIZE)-rentry->name; + struct page *next_page; + char *q; + next_page = read_cache_page(mapping,index+1,readpage,NULL); + if (IS_ERR(next_page)) { + page_cache_release(page); + page = next_page; + goto sync_fail; + } + wait_on_page(next_page); + if (!Page_Uptodate(next_page)) { + page_cache_release(page); + page = next_page; + goto async_fail; + } + q = (char*)kmap(next_page); + if (memcmp(entry->name, rentry->name, len) || + memcmp(entry->name+len, q, entry->name_len-len)) { + kunmap(next_page); + page_cache_release(next_page); + goto skip_it; + } + kunmap(next_page); + page_cache_release(next_page); + } else if (memcmp (entry->name, rentry->name, entry->name_len)) + goto skip_it; + + info->f_pos = pos; + copy_entry(entry, rentry); + ret = 0; + break; +skip_it: + offs+=entry_size; + pos+=entry_size; + } + if (page) { + kunmap(page); + page_cache_release(page); } -Printk(("umsdos_find: ready to mangle %s, len=%d, pos=%ld\n", -entry->name, entry->name_len, (long)info->f_pos)); umsdos_manglename (info); out_dput: dput(demd); - -out: - Printk (("umsdos_find: returning %d\n", ret)); return ret; + +async_fail: + page_cache_release(page); + page = ERR_PTR(-EIO); +sync_fail: + return PTR_ERR(page); } @@ -557,12 +490,17 @@ out: int umsdos_newentry (struct dentry *parent, struct umsdos_info *info) { int err, ret = -EEXIST; + struct dentry *demd = umsdos_get_emd_dentry(parent); - err = umsdos_find (parent, info); + ret = PTR_ERR(demd); + if (IS_ERR(ret)) + goto out; + err = umsdos_find (demd, info); if (err && err == -ENOENT) { ret = umsdos_writeentry (parent, info, 0); Printk (("umsdos_writeentry EMD ret = %d\n", ret)); } +out: return ret; } @@ -580,15 +518,20 @@ int umsdos_newentry (struct dentry *parent, struct umsdos_info *info) int umsdos_newhidden (struct dentry *parent, struct umsdos_info *info) { int ret; + struct dentry *demd = umsdos_get_emd_dentry(parent); + ret = PTR_ERR(demd); + if (IS_ERR(ret)) + goto out; umsdos_parse ("..LINK", 6, info); info->entry.name_len = 0; - ret = umsdos_find (parent, info); + ret = umsdos_find (demd, info); if (ret == -ENOENT || ret == 0) { info->entry.name_len = sprintf (info->entry.name, "..LINK%ld", info->f_pos); ret = 0; } +out: return ret; } @@ -603,8 +546,12 @@ int umsdos_newhidden (struct dentry *parent, struct umsdos_info *info) int umsdos_delentry (struct dentry *parent, struct umsdos_info *info, int isdir) { int ret; + struct dentry *demd = umsdos_get_emd_dentry(parent); - ret = umsdos_find (parent, info); + ret = PTR_ERR(demd); + if (IS_ERR(ret)) + goto out; + ret = umsdos_find (demd, info); if (ret) goto out; if (info->entry.name_len == 0) @@ -637,7 +584,7 @@ int umsdos_isempty (struct dentry *dentry) { struct dentry *demd; int ret = 2; - struct file filp; + loff_t pos = 0; demd = umsdos_get_emd_dentry(dentry); if (IS_ERR(demd)) @@ -646,14 +593,11 @@ int umsdos_isempty (struct dentry *dentry) if (!demd->d_inode) goto out_dput; - fill_new_filp (&filp, demd); - filp.f_flags = O_RDONLY; - ret = 1; - while (filp.f_pos < demd->d_inode->i_size) { + while (pos < demd->d_inode->i_size) { struct umsdos_dirent entry; - if (umsdos_emd_dir_readentry (&filp, &entry) != 0) { + if (umsdos_emd_dir_readentry (demd, &pos, &entry) != 0) { ret = 0; break; } @@ -666,9 +610,6 @@ int umsdos_isempty (struct dentry *dentry) out_dput: dput(demd); out: -Printk(("umsdos_isempty: checked %s/%s, empty=%d\n", -dentry->d_parent->d_name.name, dentry->d_name.name, ret)); - return ret; } @@ -686,8 +627,12 @@ int umsdos_findentry (struct dentry *parent, struct umsdos_info *info, int expect) { int ret; + struct dentry *demd = umsdos_get_emd_dentry(parent); - ret = umsdos_find (parent, info); + ret = PTR_ERR(demd); + if (IS_ERR(ret)) + goto out; + ret = umsdos_find (demd, info); if (ret) goto out; diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c index 8c61dcaf8..bb48b6bf2 100644 --- a/fs/umsdos/inode.c +++ b/fs/umsdos/inode.c @@ -18,6 +18,7 @@ #include <linux/stat.h> #include <linux/umsdos_fs.h> #include <linux/list.h> +#include <linux/pagemap.h> extern struct dentry_operations umsdos_dentry_operations; @@ -28,23 +29,6 @@ struct inode *pseudo_root = NULL; /* Useful to simulate the pseudo DOS */ static struct dentry *check_pseudo_root(struct super_block *); -/* - * Initialize a private filp - */ -void fill_new_filp (struct file *filp, struct dentry *dentry) -{ - if (!dentry) - printk(KERN_ERR "fill_new_filp: NULL dentry!\n"); - - memset (filp, 0, sizeof (struct file)); - filp->f_reada = 1; - filp->f_flags = O_RDWR; - filp->f_dentry = dentry; - filp->f_op = dentry->d_inode->i_fop; -} - - - void UMSDOS_put_inode (struct inode *inode) { PRINTK ((KERN_DEBUG @@ -200,9 +184,11 @@ int umsdos_notify_change_locked(struct dentry *dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode; struct dentry *demd; + struct address_space *mapping; + struct page *page; int ret = 0; - struct file filp; - struct umsdos_dirent entry; + struct umsdos_dirent *entry; + int offs; Printk(("UMSDOS_notify_change: entering for %s/%s (%d)\n", dentry->d_parent->d_name.name, dentry->d_name.name, inode->u.umsdos_i.i_patched)); @@ -235,52 +221,43 @@ dentry->d_parent->d_name.name, dentry->d_name.name, inode->u.umsdos_i.i_patched) * See emd.c */ - fill_new_filp (&filp, demd); - filp.f_pos = inode->u.umsdos_i.pos; -Printk(("UMSDOS_notify_change: %s/%s reading at %d\n", -dentry->d_parent->d_name.name, dentry->d_name.name, (int) filp.f_pos)); - /* Read only the start of the entry since we don't touch the name */ - ret = umsdos_emd_dir_read (&filp, (char *) &entry, UMSDOS_REC_SIZE); - if (ret) { - printk(KERN_WARNING - "umsdos_notify_change: %s/%s EMD read error, ret=%d\n", - dentry->d_parent->d_name.name, dentry->d_name.name,ret); + mapping = demd->d_inode->i_mapping; + offs = inode->u.umsdos_i.pos & ~PAGE_CACHE_MASK; + ret = -ENOMEM; + page=grab_cache_page(mapping,inode->u.umsdos_i.pos>>PAGE_CACHE_SHIFT); + if (!page) goto out_dput; - } + ret=mapping->a_ops->prepare_write(NULL,page,offs,offs+UMSDOS_REC_SIZE); + if (ret) + goto out_unlock; + entry = (struct umsdos_dirent*)((char*)page_address(page)+offs); if (attr->ia_valid & ATTR_UID) - entry.uid = attr->ia_uid; + entry->uid = cpu_to_le16(attr->ia_uid); if (attr->ia_valid & ATTR_GID) - entry.gid = attr->ia_gid; + entry->gid = cpu_to_le16(attr->ia_gid); if (attr->ia_valid & ATTR_MODE) - entry.mode = attr->ia_mode; + entry->mode = cpu_to_le16(attr->ia_mode); if (attr->ia_valid & ATTR_ATIME) - entry.atime = attr->ia_atime; + entry->atime = cpu_to_le32(attr->ia_atime); if (attr->ia_valid & ATTR_MTIME) - entry.mtime = attr->ia_mtime; + entry->mtime = cpu_to_le32(attr->ia_mtime); if (attr->ia_valid & ATTR_CTIME) - entry.ctime = attr->ia_ctime; - - entry.nlink = inode->i_nlink; - filp.f_pos = inode->u.umsdos_i.pos; - ret = umsdos_emd_dir_write (&filp, (char *) &entry, UMSDOS_REC_SIZE); + entry->ctime = cpu_to_le32(attr->ia_ctime); + entry->nlink = cpu_to_le16(inode->i_nlink); + ret=mapping->a_ops->commit_write(NULL,page,offs,offs+UMSDOS_REC_SIZE); if (ret) printk(KERN_WARNING "umsdos_notify_change: %s/%s EMD write error, ret=%d\n", dentry->d_parent->d_name.name, dentry->d_name.name,ret); - Printk (("notify pos %lu ret %d nlink %d ", - inode->u.umsdos_i.pos, ret, entry.nlink)); /* #Specification: notify_change / msdos fs * notify_change operation are done only on the * EMD file. The msdos fs is not even called. */ -#ifdef UMSDOS_DEBUG_VERBOSE -if (entry.flags & UMSDOS_HIDDEN) -printk("umsdos_notify_change: %s/%s hidden, nlink=%d, ret=%d\n", -dentry->d_parent->d_name.name, dentry->d_name.name, entry.nlink, ret); -#endif - +out_unlock: + UnlockPage(page); + page_cache_release(page); out_dput: dput(demd); out: diff --git a/fs/umsdos/ioctl.c b/fs/umsdos/ioctl.c index a8adf6ed8..17d38c2dd 100644 --- a/fs/umsdos/ioctl.c +++ b/fs/umsdos/ioctl.c @@ -75,7 +75,6 @@ int UMSDOS_ioctl_dir(struct inode *dir, struct file *filp, unsigned int cmd, struct dentry *dentry = filp->f_dentry; struct umsdos_ioctl *idata = (struct umsdos_ioctl *) data_ptr; int ret; - struct file new_filp; struct umsdos_ioctl data; Printk(("UMSDOS_ioctl_dir: %s/%s, cmd=%d, data=%08lx\n", @@ -161,6 +160,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, cmd, data_ptr)); * Return > 0 if success. */ struct dentry *demd; + loff_t pos = filp->f_pos; /* The absence of the EMD is simply seen as an EOF */ demd = umsdos_get_emd_dentry(dentry); @@ -171,14 +171,12 @@ dentry->d_parent->d_name.name, dentry->d_name.name, cmd, data_ptr)); if (!demd->d_inode) goto read_dput; - fill_new_filp(&new_filp, demd); - new_filp.f_pos = filp->f_pos; - while (new_filp.f_pos < demd->d_inode->i_size) { - off_t f_pos = new_filp.f_pos; + while (pos < demd->d_inode->i_size) { + off_t f_pos = pos; struct umsdos_dirent entry; struct umsdos_info info; - ret = umsdos_emd_dir_readentry (&new_filp, &entry); + ret = umsdos_emd_dir_readentry (demd, &pos, &entry); if (ret) break; if (entry.name_len <= 0) @@ -199,7 +197,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, cmd, data_ptr)); break; } /* update the original f_pos */ - filp->f_pos = new_filp.f_pos; + filp->f_pos = pos; read_dput: d_drop(demd); dput(demd); diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c index c4cb0cb9f..4102ce6e0 100644 --- a/fs/umsdos/namei.c +++ b/fs/umsdos/namei.c @@ -496,10 +496,6 @@ static int umsdos_symlink_x (struct inode *dir, struct dentry *dentry, const char *symname, int mode, char flags) { int ret, len; - struct file filp; - -Printk(("umsdos_symlink: %s/%s to %s\n", -dentry->d_parent->d_name.name, dentry->d_name.name, symname)); ret = umsdos_create_any (dir, dentry, mode, 0, flags); if (ret) { @@ -508,19 +504,13 @@ dentry->d_parent->d_name.name, dentry->d_name.name, symname)); goto out; } - fill_new_filp (&filp, dentry); len = strlen (symname); - ret = umsdos_file_write_kmem_real (&filp, symname, len); + ret = block_symlink(dentry->d_inode, symname, len); if (ret < 0) goto out_unlink; - if (ret != len) - goto out_error; - ret = 0; out: return ret; -out_error: - ret = -EIO; out_unlink: printk(KERN_WARNING "umsdos_symlink: write failed, unlinking\n"); UMSDOS_unlink (dir, dentry); |