Messages in this thread Patch in this message | | | Date | Wed, 8 Dec 1999 20:35:26 -0500 (EST) | From | Alexander Viro <> | Subject | Re: mmap on a device returns ENODEV |
| |
On Wed, 8 Dec 1999, Alexander Viro wrote:
[snip]
> Geez... Thanks. Actually I'ld rather finish this story with the > symlinks-in-pagecache patch first. Could you comment on the variant I've > sent to you yesterday? It applies to 2.3.31 and seems to work here. I can > rediff it if you want but that would differ only in one-line offset at > fs/ext2/inode.c
Argh. OK, version of the patch against -pre2 attached. Al diff -urN linux-2.3.32-pre2/fs/autofs/symlink.c linux-bird.symlink/fs/autofs/symlink.c --- linux-2.3.32-pre2/fs/autofs/symlink.c Mon Dec 6 22:06:00 1999 +++ linux-bird.symlink/fs/autofs/symlink.c Wed Dec 8 20:19:26 1999 @@ -10,49 +10,21 @@ * * ------------------------------------------------------------------------- */ -#include <linux/string.h> -#include <linux/sched.h> #include "autofs_i.h" static int autofs_readlink(struct dentry *dentry, char *buffer, int buflen) { - struct autofs_symlink *sl; - int len; - - sl = (struct autofs_symlink *)dentry->d_inode->u.generic_ip; - len = sl->len; - if (len > buflen) len = buflen; - copy_to_user(buffer, sl->data, len); - return len; + char *s=((struct autofs_symlink *)dentry->d_inode->u.generic_ip)->data; + return vfs_readlink(dentry, buffer, buflen, s); } -static struct dentry * autofs_follow_link(struct dentry *dentry, - struct dentry *base, - unsigned int follow) +static struct dentry *autofs_follow_link(struct dentry *dentry, struct dentry *base, unsigned flags) { - struct autofs_symlink *sl; - - sl = (struct autofs_symlink *)dentry->d_inode->u.generic_ip; - return lookup_dentry(sl->data, base, follow); + char *s=((struct autofs_symlink *)dentry->d_inode->u.generic_ip)->data; + return vfs_follow_link(dentry, base, flags, s); } struct inode_operations autofs_symlink_inode_operations = { - NULL, /* file operations */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - autofs_readlink, /* readlink */ - autofs_follow_link, /* follow_link */ - NULL, /* get_block */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* truncate */ - NULL, /* permission */ - NULL /* revalidate */ + readlink: autofs_readlink, + follow_link: autofs_follow_link }; diff -urN linux-2.3.32-pre2/fs/buffer.c linux-bird.symlink/fs/buffer.c --- linux-2.3.32-pre2/fs/buffer.c Mon Dec 6 22:06:01 1999 +++ linux-bird.symlink/fs/buffer.c Wed Dec 8 20:19:26 1999 @@ -1378,11 +1378,10 @@ return err; } -int block_write_range(struct dentry *dentry, struct page *page, +int block_write_zero_range(struct inode *inode, struct page *page, unsigned zerofrom, unsigned from, unsigned to, const char * buf) { - struct inode *inode = dentry->d_inode; unsigned zeroto = 0, block_start, block_end; unsigned long block; int err = 0, partial = 0, need_balance_dirty = 0; @@ -1504,7 +1503,7 @@ int block_write_partial_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf) { - struct dentry *dentry = file->f_dentry; + struct inode *inode = file->f_dentry->d_inode; int err; if (!PageLocked(page)) @@ -1514,7 +1513,7 @@ if (bytes+offset < 0 || bytes+offset > PAGE_SIZE) BUG(); - err = block_write_range(dentry, page, offset,offset,offset+bytes, buf); + err = block_write_range(inode, page, offset, bytes, buf); return err ? err : bytes; } @@ -1525,8 +1524,7 @@ int block_write_cont_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf) { - struct dentry *dentry = file->f_dentry; - struct inode *inode = dentry->d_inode; + struct inode *inode = file->f_dentry->d_inode; int err; unsigned zerofrom = offset; @@ -1535,7 +1533,8 @@ else if (page->index == (inode->i_size >> PAGE_CACHE_SHIFT) && offset > (inode->i_size & ~PAGE_CACHE_MASK)) zerofrom = inode->i_size & ~PAGE_CACHE_MASK; - err = block_write_range(dentry, page, zerofrom,offset,offset+bytes,buf); + err = block_write_zero_range(inode, page, zerofrom,offset,offset+bytes, + buf); return err ? err : bytes; } @@ -1829,9 +1828,8 @@ * mark_buffer_uptodate() functions propagate buffer state into the * page struct once IO has completed. */ -int block_read_full_page(struct dentry * dentry, struct page * page) +static inline int __block_read_full_page(struct inode *inode, struct page *page) { - struct inode *inode = dentry->d_inode; unsigned long iblock; struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE]; unsigned int blocksize, blocks; @@ -1888,6 +1886,47 @@ if (kaddr) kunmap(page); return 0; +} + +int block_read_full_page(struct dentry *dentry, struct page *page) +{ + return __block_read_full_page(dentry->d_inode, page); +} + +int block_symlink(struct inode *inode, const char *symname, int len) +{ + struct page *page = grab_cache_page(&inode->i_data, 0); + mm_segment_t fs; + int err = -ENOMEM; + + if (!page) + goto fail; + fs = get_fs(); + set_fs(KERNEL_DS); + err = block_write_range(inode, page, 0, len-1, symname); + set_fs(fs); + inode->i_size = len-1; + if (err) + goto fail_write; + /* + * Notice that we are _not_ going to block here - end of page is + * unmapped, so this will only try to map the rest of page, see + * that it is unmapped (typically even will not look into inode - + * ->i_size will be enough for everything) and zero it out. + * OTOH it's obviously correct and should make the page up-to-date. + */ + err = __block_read_full_page(inode, page); + wait_on_page(page); + page_cache_release(page); + if (err < 0) + goto fail; + mark_inode_dirty(inode); + return 0; +fail_write: + UnlockPage(page); + page_cache_release(page); +fail: + return err; } /* diff -urN linux-2.3.32-pre2/fs/coda/symlink.c linux-bird.symlink/fs/coda/symlink.c --- linux-2.3.32-pre2/fs/coda/symlink.c Mon Dec 6 22:06:01 1999 +++ linux-bird.symlink/fs/coda/symlink.c Wed Dec 8 20:19:26 1999 @@ -14,9 +14,6 @@ #include <linux/stat.h> #include <linux/errno.h> #include <linux/locks.h> -#include <asm/segment.h> -#include <asm/uaccess.h> -#include <linux/string.h> #include <linux/coda.h> #include <linux/coda_linux.h> @@ -25,97 +22,34 @@ #include <linux/coda_cache.h> #include <linux/coda_proc.h> -static int coda_readlink(struct dentry *de, char *buffer, int length); -static struct dentry *coda_follow_link(struct dentry *, struct dentry *, - unsigned int); - -struct inode_operations coda_symlink_inode_operations = { - NULL, /* no file-operations */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - coda_readlink, /* readlink */ - coda_follow_link, /* follow_link */ - NULL, /* get_block */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* truncate */ - NULL, /* permission */ - NULL /* revalidate */ -}; - -static int coda_readlink(struct dentry *de, char *buffer, int length) +static int coda_symlink_filler(struct dentry *dentry, struct page *page) { - struct inode *inode = de->d_inode; - int len; - int error; - char *buf; - struct coda_inode_info *cp; - ENTRY; - - cp = ITOC(inode); - coda_vfs_stat.readlink++; - - /* the maximum length we receive is len */ - if ( length > CODA_MAXPATHLEN ) - len = CODA_MAXPATHLEN; - else - len = length; - CODA_ALLOC(buf, char *, len); - if ( !buf ) - return -ENOMEM; - - error = venus_readlink(inode->i_sb, &(cp->c_fid), buf, &len); - - CDEBUG(D_INODE, "result %s\n", buf); - if (! error) { - copy_to_user(buffer, buf, len); - put_user('\0', buffer + len); - error = len; - } - if ( buf ) - CODA_FREE(buf, len); - return error; -} - -static struct dentry *coda_follow_link(struct dentry *de, struct dentry *base, - unsigned int follow) -{ - struct inode *inode = de->d_inode; + struct inode *inode = dentry->d_inode; int error; struct coda_inode_info *cnp; - unsigned int len; - char mem[CODA_MAXPATHLEN]; - char *path; - ENTRY; - CDEBUG(D_INODE, "(%x/%ld)\n", inode->i_dev, inode->i_ino); - + unsigned int len = PAGE_SIZE; + char *p = (char*)kmap(page); + cnp = ITOC(inode); coda_vfs_stat.follow_link++; - len = CODA_MAXPATHLEN; - error = venus_readlink(inode->i_sb, &(cnp->c_fid), mem, &len); - - if (error) { - dput(base); - return ERR_PTR(error); - } - len = strlen(mem); - path = kmalloc(len + 1, GFP_KERNEL); - if (!path) { - dput(base); - return ERR_PTR(-ENOMEM); - } - memcpy(path, mem, len); - path[len] = 0; - - base = lookup_dentry(path, base, follow); - kfree(path); - return base; + error = venus_readlink(inode->i_sb, &(cnp->c_fid), p, &len); + if (error) + goto fail; + SetPageUptodate(page); + kunmap(page); + UnlockPage(page); + return 0; + +fail: + SetPageError(page); + kunmap(page); + UnlockPage(page); + return error; } + +struct inode_operations coda_symlink_inode_operations = { + readlink: page_readlink, + follow_link: page_follow_link, + readpage: coda_symlink_filler +}; diff -urN linux-2.3.32-pre2/fs/ext2/inode.c linux-bird.symlink/fs/ext2/inode.c --- linux-2.3.32-pre2/fs/ext2/inode.c Wed Dec 8 16:59:02 1999 +++ linux-bird.symlink/fs/ext2/inode.c Wed Dec 8 20:19:26 1999 @@ -713,7 +713,9 @@ else if (S_ISDIR(inode->i_mode)) inode->i_op = &ext2_dir_inode_operations; else if (S_ISLNK(inode->i_mode)) - inode->i_op = &ext2_symlink_inode_operations; + inode->i_op = inode->i_blocks + ?&ext2_symlink_inode_operations + :&ext2_fast_symlink_inode_operations; else init_special_inode(inode, inode->i_mode, le32_to_cpu(raw_inode->i_block[0])); diff -urN linux-2.3.32-pre2/fs/ext2/namei.c linux-bird.symlink/fs/ext2/namei.c --- linux-2.3.32-pre2/fs/ext2/namei.c Mon Dec 6 22:06:02 1999 +++ linux-bird.symlink/fs/ext2/namei.c Wed Dec 8 20:19:26 1999 @@ -677,48 +677,32 @@ int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * symname) { - struct ext2_dir_entry_2 * de; struct inode * inode; - struct buffer_head * bh = NULL, * name_block = NULL; - char * link; - int i, l, err = -EIO; - char c; + struct ext2_dir_entry_2 * de; + struct buffer_head * bh = NULL; + int l, err; - if (!(inode = ext2_new_inode (dir, S_IFLNK, &err))) { - return err; - } - inode->i_mode = S_IFLNK | S_IRWXUGO; - inode->i_op = &ext2_symlink_inode_operations; - for (l = 0; l < inode->i_sb->s_blocksize - 1 && - symname [l]; l++) - ; - if (l >= sizeof (inode->u.ext2_i.i_data)) { + err = -ENAMETOOLONG; + l = strlen(symname)+1; + if (l > dir->i_sb->s_blocksize) + goto out; - ext2_debug ("l=%d, normal symlink\n", l); + err = -EIO; + if (!(inode = ext2_new_inode (dir, S_IFLNK, &err))) + goto out; - name_block = ext2_bread (inode, 0, 1, &err); - if (!name_block) { - inode->i_nlink--; - mark_inode_dirty(inode); - iput (inode); - return err; - } - link = name_block->b_data; - } else { - link = (char *) inode->u.ext2_i.i_data; - - ext2_debug ("l=%d, fast symlink\n", l); + inode->i_mode = S_IFLNK | S_IRWXUGO; + if (l > sizeof (inode->u.ext2_i.i_data)) { + inode->i_op = &ext2_symlink_inode_operations; + err = block_symlink(inode, symname, l); + if (err) + goto out_no_entry; + } else { + inode->i_op = &ext2_fast_symlink_inode_operations; + memcpy((char*)&inode->u.ext2_i.i_data,symname,l); + inode->i_size = l-1; } - i = 0; - while (i < inode->i_sb->s_blocksize - 1 && (c = *(symname++))) - link[i++] = c; - link[i] = 0; - if (name_block) { - mark_buffer_dirty(name_block, 1); - brelse (name_block); - } - inode->i_size = i; mark_inode_dirty(inode); bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err); diff -urN linux-2.3.32-pre2/fs/ext2/symlink.c linux-bird.symlink/fs/ext2/symlink.c --- linux-2.3.32-pre2/fs/ext2/symlink.c Mon Dec 6 22:06:02 1999 +++ linux-bird.symlink/fs/ext2/symlink.c Wed Dec 8 20:19:26 1999 @@ -16,89 +16,28 @@ */ #include <linux/fs.h> -#include <asm/uaccess.h> +#include <linux/ext2_fs.h> - - -static int ext2_readlink (struct dentry *, char *, int); -static struct dentry *ext2_follow_link(struct dentry *, struct dentry *, unsigned int); - -/* - * symlinks can't do much... - */ -struct inode_operations ext2_symlink_inode_operations = { - NULL, /* no file-operations */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - ext2_readlink, /* readlink */ - ext2_follow_link, /* follow_link */ - NULL, /* get_block */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* truncate */ - NULL, /* permission */ - NULL /* revalidate */ -}; - -static struct dentry * ext2_follow_link(struct dentry * dentry, - struct dentry *base, - unsigned int follow) +static int ext2_readlink(struct dentry *dentry, char *buffer, int buflen) { - struct inode *inode = dentry->d_inode; - struct buffer_head * bh = NULL; - int error; - char * link; - - link = (char *) inode->u.ext2_i.i_data; - if (inode->i_blocks) { - if (!(bh = ext2_bread (inode, 0, 0, &error))) { - dput(base); - return ERR_PTR(-EIO); - } - link = bh->b_data; - } - UPDATE_ATIME(inode); - base = lookup_dentry(link, base, follow); - if (bh) - brelse(bh); - return base; + char *s = (char *)dentry->d_inode->u.ext2_i.i_data; + return vfs_readlink(dentry, buffer, buflen, s); } -static int ext2_readlink (struct dentry * dentry, char * buffer, int buflen) +static struct dentry *ext2_follow_link(struct dentry *dentry, struct dentry *base, unsigned flags) { - struct inode *inode = dentry->d_inode; - struct buffer_head * bh = NULL; - char * link; - int i; - - if (buflen > inode->i_sb->s_blocksize - 1) - buflen = inode->i_sb->s_blocksize - 1; + char *s = (char *)dentry->d_inode->u.ext2_i.i_data; + return vfs_follow_link(dentry, base, flags, s); +} - link = (char *) inode->u.ext2_i.i_data; - if (inode->i_blocks) { - int err; - bh = ext2_bread (inode, 0, 0, &err); - if (!bh) { - if(err < 0) /* indicate type of error */ - return err; - return 0; - } - link = bh->b_data; - } +struct inode_operations ext2_fast_symlink_inode_operations = { + readlink: ext2_readlink, + follow_link: ext2_follow_link, +}; - i = 0; - while (i < buflen && link[i]) - i++; - if (copy_to_user(buffer, link, i)) - i = -EFAULT; - if (bh) - brelse (bh); - return i; -} +struct inode_operations ext2_symlink_inode_operations = { + readlink: page_readlink, + follow_link: page_follow_link, + get_block: ext2_get_block, + readpage: block_read_full_page, +}; diff -urN linux-2.3.32-pre2/fs/minix/namei.c linux-bird.symlink/fs/minix/namei.c --- linux-2.3.32-pre2/fs/minix/namei.c Sun Sep 12 20:25:20 1999 +++ linux-bird.symlink/fs/minix/namei.c Wed Dec 8 20:19:26 1999 @@ -461,46 +461,43 @@ { struct minix_dir_entry * de; struct inode * inode = NULL; - struct buffer_head * bh = NULL, * name_block = NULL; + struct buffer_head * bh = NULL; int i; - char c; + int err; - inode = minix_new_inode(dir, &i); - if (i) - return i; + err = -ENAMETOOLONG; + i = strlen(symname)+1; + if (i>1024) + goto out; + inode = minix_new_inode(dir, &err); + if (err) + goto out; + err = -ENOSPC; if (!inode) - return -ENOSPC; + goto out; inode->i_mode = S_IFLNK | 0777; inode->i_op = &minix_symlink_inode_operations; - name_block = minix_bread(inode,0,1); - if (!name_block) { - inode->i_nlink--; - mark_inode_dirty(inode); - iput(inode); - return -ENOSPC; - } - i = 0; - while (i < 1023 && (c=*(symname++))) - name_block->b_data[i++] = c; - name_block->b_data[i] = 0; - mark_buffer_dirty(name_block, 1); - brelse(name_block); - inode->i_size = i; - mark_inode_dirty(inode); - i = minix_add_entry(dir, dentry->d_name.name, + err = block_symlink(inode, symname, i); + if (err) + goto fail; + + err = minix_add_entry(dir, dentry->d_name.name, dentry->d_name.len, &bh, &de); - if (i) { - inode->i_nlink--; - mark_inode_dirty(inode); - iput(inode); - return i; - } + if (err) + goto fail; + de->inode = inode->i_ino; mark_buffer_dirty(bh, 1); brelse(bh); d_instantiate(dentry, inode); - return 0; +out: + return err; +fail: + inode->i_nlink--; + mark_inode_dirty(inode); + iput(inode); + goto out; } int minix_link(struct dentry * old_dentry, struct inode * dir, diff -urN linux-2.3.32-pre2/fs/minix/symlink.c linux-bird.symlink/fs/minix/symlink.c --- linux-2.3.32-pre2/fs/minix/symlink.c Mon Dec 6 22:06:03 1999 +++ linux-bird.symlink/fs/minix/symlink.c Wed Dec 8 20:19:26 1999 @@ -4,77 +4,19 @@ * Copyright (C) 1991, 1992 Linus Torvalds * * minix symlink handling code + * + * Code removed. 1999, AV ;-) */ -#include <linux/errno.h> -#include <linux/sched.h> #include <linux/fs.h> #include <linux/minix_fs.h> -#include <linux/stat.h> - -#include <asm/uaccess.h> - -static int minix_readlink(struct dentry *, char *, int); -static struct dentry *minix_follow_link(struct dentry *, struct dentry *, unsigned int); /* * symlinks can't do much... */ struct inode_operations minix_symlink_inode_operations = { - NULL, /* no file-operations */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - minix_readlink, /* readlink */ - minix_follow_link, /* follow_link */ - NULL, /* get_block */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* truncate */ - NULL, /* permission */ - NULL /* revalidate */ + readlink: page_readlink, + follow_link: page_follow_link, + get_block: minix_get_block, + readpage: block_read_full_page }; - -static struct dentry * minix_follow_link(struct dentry * dentry, - struct dentry * base, - unsigned int follow) -{ - struct inode *inode = dentry->d_inode; - struct buffer_head * bh; - - bh = minix_bread(inode, 0, 0); - if (!bh) { - dput(base); - return ERR_PTR(-EIO); - } - UPDATE_ATIME(inode); - base = lookup_dentry(bh->b_data, base, follow); - brelse(bh); - return base; -} - -static int minix_readlink(struct dentry * dentry, char * buffer, int buflen) -{ - struct buffer_head * bh; - int i; - char c; - - if (buflen > 1023) - buflen = 1023; - bh = minix_bread(dentry->d_inode, 0, 0); - if (!bh) - return 0; - i = 0; - while (i<buflen && (c = bh->b_data[i])) { - i++; - put_user(c,buffer++); - } - brelse(bh); - return i; -} diff -urN linux-2.3.32-pre2/fs/namei.c linux-bird.symlink/fs/namei.c --- linux-2.3.32-pre2/fs/namei.c Thu Oct 14 20:09:31 1999 +++ linux-bird.symlink/fs/namei.c Wed Dec 8 20:19:26 1999 @@ -16,6 +16,7 @@ #include <linux/proc_fs.h> #include <linux/smp_lock.h> #include <linux/quotaops.h> +#include <linux/pagemap.h> #include <asm/uaccess.h> #include <asm/unaligned.h> @@ -1418,4 +1419,86 @@ } unlock_kernel(); return error; +} + +int vfs_readlink(struct dentry *dentry, char *buffer, int buflen, char *link) +{ + u32 len; + + len = PTR_ERR(link); + if (IS_ERR(link)) + goto out; + + len = strlen(link); + if (len > buflen) + len = buflen; + copy_to_user(buffer, link, len); +out: + return len; +} + +struct dentry * +vfs_follow_link(struct dentry *dentry, struct dentry *base, +unsigned int follow, char *link) +{ + struct dentry *result; + UPDATE_ATIME(dentry->d_inode); + + if (IS_ERR(link)) + goto fail; + + result = lookup_dentry(link, base, follow); + return result; + +fail: + dput(base); + return (struct dentry *)link; +} + +/* get the link contents into pagecache */ +static char *page_getlink(struct dentry * dentry, struct page **ppage) +{ + struct page * page; + page = read_cache_page(&dentry->d_inode->i_data, 0, + (filler_t *)dentry->d_inode->i_op->readpage, + dentry); + if (IS_ERR(page)) + goto sync_fail; + wait_on_page(page); + if (!Page_Uptodate(page)) + goto async_fail; + *ppage = page; + return (char*) kmap(page); + +async_fail: + page_cache_release(page); + return ERR_PTR(-EIO); + +sync_fail: + return (char*)page; +} + +int page_readlink(struct dentry *dentry, char *buffer, int buflen) +{ + struct page *page = NULL; + char *s = page_getlink(dentry, &page); + int res = vfs_readlink(dentry,buffer,buflen,s); + if (page) { + kunmap(page); + page_cache_release(page); + } + return res; +} + +struct dentry * +page_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow) +{ + struct page *page = NULL; + char *s = page_getlink(dentry, &page); + struct dentry *res = vfs_follow_link(dentry,base,follow,s); + if (page) { + kunmap(page); + page_cache_release(page); + } + return res; } diff -urN linux-2.3.32-pre2/fs/nfs/dir.c linux-bird.symlink/fs/nfs/dir.c --- linux-2.3.32-pre2/fs/nfs/dir.c Mon Dec 6 22:06:03 1999 +++ linux-bird.symlink/fs/nfs/dir.c Wed Dec 8 20:19:26 1999 @@ -418,7 +418,7 @@ { struct dentry *dentry = filp->f_dentry; struct inode *inode = dentry->d_inode; - struct page *page, **hash; + struct page *page; long offset; int res; @@ -432,8 +432,7 @@ if ((offset = nfs_readdir_offset(inode, filp->f_pos)) < 0) goto no_dirent_page; - hash = page_hash(&inode->i_data, offset); - page = __find_get_page(&inode->i_data, offset, hash); + page = find_get_page(&inode->i_data, offset); if (!page) goto no_dirent_page; if (!Page_Uptodate(page)) diff -urN linux-2.3.32-pre2/fs/nfs/symlink.c linux-bird.symlink/fs/nfs/symlink.c --- linux-2.3.32-pre2/fs/nfs/symlink.c Mon Dec 6 22:06:03 1999 +++ linux-bird.symlink/fs/nfs/symlink.c Wed Dec 8 20:19:27 1999 @@ -22,35 +22,6 @@ #include <linux/malloc.h> #include <linux/string.h> -#include <asm/uaccess.h> - -static int nfs_readlink(struct dentry *, char *, int); -static struct dentry *nfs_follow_link(struct dentry *, struct dentry *, unsigned int); - -/* - * symlinks can't do much... - */ -struct inode_operations nfs_symlink_inode_operations = { - NULL, /* no file-operations */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - nfs_readlink, /* readlink */ - nfs_follow_link, /* follow_link */ - NULL, /* get_block */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* truncate */ - NULL, /* permission */ - NULL /* revalidate */ -}; - /* Symlink caching in the page cache is even more simplistic * and straight-forward than readdir caching. */ @@ -91,12 +62,12 @@ if (IS_ERR(page)) goto read_failed; if (!Page_Uptodate(page)) - goto followlink_read_error; + goto getlink_read_error; *ppage = page; p = (u32 *) kmap(page); return (char*)(p+1); -followlink_read_error: +getlink_read_error: page_cache_release(page); return ERR_PTR(-EIO); read_failed: @@ -106,41 +77,31 @@ static int nfs_readlink(struct dentry *dentry, char *buffer, int buflen) { struct page *page = NULL; - u32 len; - char *s = nfs_getlink(dentry, &page); - UPDATE_ATIME(dentry->d_inode); - - len = PTR_ERR(s); - if (IS_ERR(s)) - goto out; - - len = strlen(s); - if (len > buflen) - len = buflen; - copy_to_user(buffer, s, len); - kunmap(page); - page_cache_release(page); -out: - return len; + int res = vfs_readlink(dentry,buffer,buflen,nfs_getlink(dentry,&page)); + if (page) { + kunmap(page); + page_cache_release(page); + } + return res; } static struct dentry * nfs_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow) { - struct dentry *result; struct page *page = NULL; - char *s = nfs_getlink(dentry, &page); - UPDATE_ATIME(dentry->d_inode); - - if (IS_ERR(s)) - goto fail; - - result = lookup_dentry(s, base, follow); - - kunmap(page); - page_cache_release(page); - return result; - -fail: - return (struct dentry *)s; + struct dentry *res = vfs_follow_link(dentry, base, follow, + nfs_getlink(dentry, &page)); + if (page) { + kunmap(page); + page_cache_release(page); + } + return res; } + +/* + * symlinks can't do much... + */ +struct inode_operations nfs_symlink_inode_operations = { + readlink: nfs_readlink, + follow_link: nfs_follow_link, +}; diff -urN linux-2.3.32-pre2/fs/proc/generic.c linux-bird.symlink/fs/proc/generic.c --- linux-2.3.32-pre2/fs/proc/generic.c Wed Nov 24 05:56:19 1999 +++ linux-bird.symlink/fs/proc/generic.c Wed Dec 8 20:19:27 1999 @@ -199,40 +199,21 @@ return PROC_DYNAMIC_FIRST + i; } -static int proc_readlink(struct dentry * dentry, char * buffer, int buflen) +static int proc_readlink(struct dentry *dentry, char *buffer, int buflen) { - struct inode *inode = dentry->d_inode; - struct proc_dir_entry * de; - int len; - de = (struct proc_dir_entry *) inode->u.generic_ip; - len = de->size+1; - if (len > buflen) - len = buflen; - copy_to_user(buffer, de->data, len); - return len; + char *s=((struct proc_dir_entry *)dentry->d_inode->u.generic_ip)->data; + return vfs_readlink(dentry, buffer, buflen, s); } -struct dentry * proc_follow_link(struct dentry * dentry, struct dentry *base, unsigned int follow) +static struct dentry *proc_follow_link(struct dentry *dentry, struct dentry *base, unsigned flags) { - struct inode *inode = dentry->d_inode; - struct proc_dir_entry * de; - de = (struct proc_dir_entry *) inode->u.generic_ip; - return lookup_dentry(de->data, base, follow); + char *s=((struct proc_dir_entry *)dentry->d_inode->u.generic_ip)->data; + return vfs_follow_link(dentry, base, flags, s); } static struct inode_operations proc_link_inode_operations = { - NULL, /* no file-ops */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - proc_readlink, /* readlink */ - proc_follow_link, /* follow_link */ + readlink: proc_readlink, + follow_link: proc_follow_link }; /* diff -urN linux-2.3.32-pre2/fs/proc/root.c linux-bird.symlink/fs/proc/root.c --- linux-2.3.32-pre2/fs/proc/root.c Wed Nov 24 05:56:19 1999 +++ linux-bird.symlink/fs/proc/root.c Wed Dec 8 20:19:27 1999 @@ -27,14 +27,9 @@ */ static int proc_self_readlink(struct dentry *dentry, char *buffer, int buflen) { - int len; char tmp[30]; - - len = sprintf(tmp, "%d", current->pid); - if (buflen < len) - len = buflen; - copy_to_user(buffer, tmp, len); - return len; + sprintf(tmp, "%d", current->pid); + return vfs_readlink(dentry,buffer,buflen,tmp); } static struct dentry * proc_self_follow_link(struct dentry *dentry, @@ -42,24 +37,13 @@ unsigned int follow) { char tmp[30]; - sprintf(tmp, "%d", current->pid); - return lookup_dentry(tmp, base, follow); + return vfs_follow_link(dentry,base,follow,tmp); } static struct inode_operations proc_self_inode_operations = { - NULL, /* no file-ops */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - proc_self_readlink, /* readlink */ - proc_self_follow_link, /* follow_link */ + readlink: proc_self_readlink, + follow_link: proc_self_follow_link }; static struct proc_dir_entry proc_root_self = { diff -urN linux-2.3.32-pre2/fs/romfs/inode.c linux-bird.symlink/fs/romfs/inode.c --- linux-2.3.32-pre2/fs/romfs/inode.c Mon Dec 6 22:06:04 1999 +++ linux-bird.symlink/fs/romfs/inode.c Wed Dec 8 20:19:27 1999 @@ -444,63 +444,6 @@ return result; } -static int -romfs_readlink(struct dentry *dentry, char *buffer, int len) -{ - struct inode *inode = dentry->d_inode; - int mylen; - char buf[ROMFS_MAXFN]; /* XXX dynamic */ - - if (!inode || !S_ISLNK(inode->i_mode)) { - mylen = -EBADF; - goto out; - } - - mylen = min(sizeof(buf), inode->i_size); - - if (romfs_copyfrom(inode, buf, inode->u.romfs_i.i_dataoffset, mylen) <= 0) { - mylen = -EIO; - goto out; - } - copy_to_user(buffer, buf, mylen); - -out: - return mylen; -} - -static struct dentry *romfs_follow_link(struct dentry *dentry, - struct dentry *base, - unsigned int follow) -{ - struct inode *inode = dentry->d_inode; - char *link; - int len, cnt; - - len = inode->i_size; - - dentry = ERR_PTR(-EAGAIN); /* correct? */ - if (!(link = kmalloc(len+1, GFP_KERNEL))) - goto outnobuf; - - cnt = romfs_copyfrom(inode, link, inode->u.romfs_i.i_dataoffset, len); - if (len != cnt) { - dentry = ERR_PTR(-EIO); - goto out; - } else - link[len] = 0; - - dentry = lookup_dentry(link, base, follow); - kfree(link); - - if (0) { -out: - kfree(link); -outnobuf: - dput(base); - } - return dentry; -} - /* Mapping from our types to the kernel */ static struct file_operations romfs_file_operations = { @@ -584,24 +527,9 @@ }; static struct inode_operations romfs_link_inode_operations = { - NULL, /* no file operations on symlinks */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - romfs_readlink, /* readlink */ - romfs_follow_link, /* follow_link */ - NULL, /* get_block */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* truncate */ - NULL, /* permission */ - NULL /* revalidate */ + readlink: page_readlink, + follow_link: page_follow_link, + readpage: romfs_readpage }; static mode_t romfs_modemap[] = diff -urN linux-2.3.32-pre2/fs/sysv/namei.c linux-bird.symlink/fs/sysv/namei.c --- linux-2.3.32-pre2/fs/sysv/namei.c Sun Nov 7 15:23:06 1999 +++ linux-bird.symlink/fs/sysv/namei.c Wed Dec 8 20:19:27 1999 @@ -440,59 +440,41 @@ int sysv_symlink(struct inode * dir, struct dentry * dentry, const char * symname) { - struct sysv_dir_entry * de; struct inode * inode; - struct buffer_head * name_block; - char * name_block_data; - struct super_block * sb; - int i; - char c; + struct sysv_dir_entry * de; struct buffer_head * bh; + int err; + int l; + err = -ENAMETOOLONG; + l = strlen(symname)+1; + if (l > dir->i_sb->sv_block_size_1) + goto out; + err = -ENOSPC; if (!(inode = sysv_new_inode(dir))) - return -ENOSPC; + goto out; inode->i_mode = S_IFLNK | 0777; inode->i_op = &sysv_symlink_inode_operations; - name_block = sysv_file_bread(inode, 0, 1); - if (!name_block) { - inode->i_nlink--; - mark_inode_dirty(inode); - iput(inode); - return -ENOSPC; - } - sb = inode->i_sb; - name_block_data = name_block->b_data; - i = 0; - while (i < sb->sv_block_size_1 && (c = *(symname++))) - name_block_data[i++] = c; - name_block_data[i] = 0; - mark_buffer_dirty(name_block, 1); - brelse(name_block); - inode->i_size = i; + err = block_symlink(inode, symname, l); + if (err) + goto out_no_entry; mark_inode_dirty(inode); - bh = sysv_find_entry(dir, dentry->d_name.name, - dentry->d_name.len, &de); - if (bh) { - inode->i_nlink--; - mark_inode_dirty(inode); - iput(inode); - brelse(bh); - return -EEXIST; - } - i = sysv_add_entry(dir, dentry->d_name.name, + err = sysv_add_entry(dir, dentry->d_name.name, dentry->d_name.len, &bh, &de); - if (i) { - inode->i_nlink--; - mark_inode_dirty(inode); - iput(inode); - return i; - } + if (err) + goto out_no_entry; de->inode = inode->i_ino; mark_buffer_dirty(bh, 1); brelse(bh); d_instantiate(dentry, inode); - return 0; +out: + return err; +out_no_entry: + inode->i_nlink--; + mark_inode_dirty(inode); + iput(inode); + goto out; } int sysv_link(struct dentry * old_dentry, struct inode * dir, diff -urN linux-2.3.32-pre2/fs/sysv/symlink.c linux-bird.symlink/fs/sysv/symlink.c --- linux-2.3.32-pre2/fs/sysv/symlink.c Mon Dec 6 22:06:04 1999 +++ linux-bird.symlink/fs/sysv/symlink.c Wed Dec 8 20:19:27 1999 @@ -13,77 +13,14 @@ * SystemV/Coherent symlink handling code */ -#include <linux/errno.h> -#include <linux/sched.h> #include <linux/sysv_fs.h> -#include <linux/stat.h> - -#include <asm/uaccess.h> - -static int sysv_readlink(struct dentry *, char *, int); -static struct dentry *sysv_follow_link(struct dentry *, struct dentry *, unsigned int); /* * symlinks can't do much... */ struct inode_operations sysv_symlink_inode_operations = { - NULL, /* no file-operations */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - sysv_readlink, /* readlink */ - sysv_follow_link, /* follow_link */ - NULL, /* get_block */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* truncate */ - NULL, /* permission */ - NULL /* revalidate */ + readlink: page_readlink, + follow_link: page_follow_link, + get_block: sysv_get_block, + readpage: block_read_full_page }; - -static struct dentry *sysv_follow_link(struct dentry * dentry, - struct dentry * base, - unsigned int follow) -{ - struct inode *inode = dentry->d_inode; - struct buffer_head * bh; - - bh = sysv_file_bread(inode, 0, 0); - if (!bh) { - dput(base); - return ERR_PTR(-EIO); - } - UPDATE_ATIME(inode); - base = lookup_dentry(bh->b_data, base, follow); - brelse(bh); - return base; -} - -static int sysv_readlink(struct dentry * dentry, char * buffer, int buflen) -{ - struct inode *inode = dentry->d_inode; - struct buffer_head * bh; - char * bh_data; - int i; - char c; - - if (buflen > inode->i_sb->sv_block_size_1) - buflen = inode->i_sb->sv_block_size_1; - bh = sysv_file_bread(inode, 0, 0); - if (!bh) - return 0; - bh_data = bh->b_data; - i = 0; - while (i<buflen && (c = bh_data[i])) { - i++; - put_user(c,buffer++); - } - brelse(bh); - return i; -} diff -urN linux-2.3.32-pre2/fs/udf/symlink.c linux-bird.symlink/fs/udf/symlink.c --- linux-2.3.32-pre2/fs/udf/symlink.c Mon Dec 6 22:06:04 1999 +++ linux-bird.symlink/fs/udf/symlink.c Wed Dec 8 20:19:27 1999 @@ -33,155 +33,93 @@ #include <linux/mm.h> #include <linux/stat.h> #include <linux/malloc.h> +#include <linux/pagemap.h> #include "udf_i.h" -static int udf_readlink(struct dentry *, char *, int); -static struct dentry * udf_follow_link(struct dentry * dentry, - struct dentry * base, unsigned int follow); - -/* - * symlinks can't do much... - */ -struct inode_operations udf_symlink_inode_operations = { - NULL, /* no file-operations */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - udf_readlink, /* readlink */ - udf_follow_link, /* follow_link */ - NULL, /* get_block */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* truncate */ - NULL, /* permission */ - NULL /* revalidate */ -}; - -int udf_pc_to_char(char *from, int fromlen, char **to) +static void udf_pc_to_char(char *from, int fromlen, char *to) { struct PathComponent *pc; int elen = 0, len = 0; + char *p = to; - *to = (char *)kmalloc(fromlen, GFP_KERNEL); - - if (!(*to)) - return -1; - - while (elen < fromlen) - { + while (elen < fromlen) { pc = (struct PathComponent *)(from + elen); - if (pc->componentType == 1 && pc->lengthComponentIdent == 0) - { - (*to)[0] = '/'; - len = 1; - } - else if (pc->componentType == 3) - { - memcpy(&(*to)[len], "../", 3); - len += 3; - } - else if (pc->componentType == 4) - { - memcpy(&(*to)[len], "./", 2); - len += 2; - } - else if (pc->componentType == 5) - { - memcpy(&(*to)[len], pc->componentIdent, pc->lengthComponentIdent); - len += pc->lengthComponentIdent + 1; - (*to)[len-1] = '/'; + switch (pc->componentType) { + case 1: + if (pc->lengthComponentIdent == 0) { + p = to; + *p++ = '/'; + } + break; + case 3: + memcpy(p, "../", 3); + p += 3; + break; + case 4: + memcpy(p, "./", 2); + p += 2; + /* that would be . - just ignore */ + break; + case 5: + memcpy(p+len, pc->componentIdent, + pc->lengthComponentIdent); + p += pc->lengthComponentIdent; + *p++ = '/'; } elen += sizeof(struct PathComponent) + pc->lengthComponentIdent; } - if (len) - { - len --; - (*to)[len] = '\0'; + if (p>to+1) { + p[-1] = '\0'; } - return len; } -static struct dentry * udf_follow_link(struct dentry * dentry, - struct dentry * base, unsigned int follow) +static int udf_symlink_filler(struct dentry * dentry, struct page *page) { struct inode *inode = dentry->d_inode; struct buffer_head *bh = NULL; - char *symlink, *tmpbuf; - int len; - - if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB) - { - bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize); - - if (!bh) - return 0; - - symlink = bh->b_data + udf_file_entry_alloc_offset(inode); - } - else - { - bh = bread(inode->i_dev, udf_block_map(inode, 0), inode->i_sb->s_blocksize); - - if (!bh) - return 0; - - symlink = bh->b_data; - } - - if ((len = udf_pc_to_char(symlink, inode->i_size, &tmpbuf)) >= 0) - { - base = lookup_dentry(tmpbuf, base, follow); - kfree(tmpbuf); - return base; - } - else - return ERR_PTR(-ENOMEM); -} + char *symlink; + int err; -static int udf_readlink(struct dentry * dentry, char * buffer, int buflen) -{ - struct inode *inode = dentry->d_inode; - struct buffer_head *bh = NULL; - char *symlink, *tmpbuf; - int len; + char *p = (char*)kmap(page); - if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB) - { - bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize); + err = -EIO; + if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB) { + bh = udf_tread(inode->i_sb, inode->i_ino, + inode->i_sb->s_blocksize); if (!bh) - return 0; + goto out; symlink = bh->b_data + udf_file_entry_alloc_offset(inode); - } - else - { - bh = bread(inode->i_dev, udf_block_map(inode, 0), inode->i_sb->s_blocksize); + } else { + bh = bread(inode->i_dev, udf_block_map(inode, 0), + inode->i_sb->s_blocksize); if (!bh) - return 0; + goto out; symlink = bh->b_data; } - if ((len = udf_pc_to_char(symlink, inode->i_size, &tmpbuf)) >= 0) - { - if (copy_to_user(buffer, tmpbuf, len > buflen ? buflen : len)) - len = -EFAULT; - kfree(tmpbuf); - } - else - len = -ENOMEM; - - UPDATE_ATIME(inode); - if (bh) - udf_release_data(bh); - return len; + udf_pc_to_char(symlink, inode->i_size, p); + udf_release_data(bh); + SetPageUptodate(page); + kunmap(page); + UnlockPage(page); + return 0; +out: + SetPageError(page); + kunmap(page); + UnlockPage(page); + return -EIO; } + +/* + * symlinks can't do much... + */ +struct inode_operations udf_symlink_inode_operations = { + readlink: page_readlink, + follow_link: page_follow_link, + readpage: udf_symlink_filler, +}; diff -urN linux-2.3.32-pre2/fs/ufs/inode.c linux-bird.symlink/fs/ufs/inode.c --- linux-2.3.32-pre2/fs/ufs/inode.c Thu Nov 11 22:08:02 1999 +++ linux-bird.symlink/fs/ufs/inode.c Wed Dec 8 20:19:27 1999 @@ -631,7 +631,9 @@ else if (S_ISDIR(inode->i_mode)) inode->i_op = &ufs_dir_inode_operations; else if (S_ISLNK(inode->i_mode)) - inode->i_op = &ufs_symlink_inode_operations; + inode->i_op = inode->i_blocks + ?&ufs_symlink_inode_operations + :&ufs_fast_symlink_inode_operations; else init_special_inode(inode, inode->i_mode, SWAB32(ufs_inode->ui_u2.ui_addr.ui_db[0])); diff -urN linux-2.3.32-pre2/fs/ufs/namei.c linux-bird.symlink/fs/ufs/namei.c --- linux-2.3.32-pre2/fs/ufs/namei.c Sun Sep 12 14:29:24 1999 +++ linux-bird.symlink/fs/ufs/namei.c Wed Dec 8 20:19:27 1999 @@ -751,55 +751,42 @@ int ufs_symlink (struct inode * dir, struct dentry * dentry, const char * symname) { - struct super_block * sb; + struct super_block * sb = dir->i_sb; struct ufs_dir_entry * de; struct inode * inode; - struct buffer_head * bh, * name_block; - char * link; - unsigned i, l; + struct buffer_head * bh = NULL; + unsigned l; int err; - char c; - unsigned swab; + unsigned swab = sb->u.ufs_sb.s_swab; UFSD(("ENTER\n")) - sb = dir->i_sb; - swab = sb->u.ufs_sb.s_swab; - bh = name_block = NULL; + + err = -ENAMETOOLONG; + l = strlen(symname)+1; + if (l > dir->i_sb->s_blocksize) + goto out; + err = -EIO; if (!(inode = ufs_new_inode (dir, S_IFLNK, &err))) { return err; } inode->i_mode = S_IFLNK | S_IRWXUGO; - inode->i_op = &ufs_symlink_inode_operations; - for (l = 0; l < sb->s_blocksize - 1 && symname [l]; l++); - /***if (l >= sizeof (inode->u.ufs_i.i_data)) {***/ + /***if (l > sizeof (inode->u.ufs_i.i_data)) {***/ if (1) { /* slow symlink */ - name_block = ufs_bread (inode, 0, 1, &err); - if (!name_block) { - inode->i_nlink--; - mark_inode_dirty(inode); - iput (inode); - return err; - } - link = name_block->b_data; - + inode->i_op = &ufs_symlink_inode_operations; + err = block_symlink(inode, symname, l); + if (err) + goto out_no_entry; } else { /* fast symlink */ - link = (char *) inode->u.ufs_i.i_u1.i_data; + inode->i_op = &ufs_fast_symlink_inode_operations; + memcpy((char*)&inode->u.ufs_i.i_u1.i_data,symname,l); + inode->i_size = l-1; } - i = 0; - while (i < sb->s_blocksize - 1 && (c = *(symname++))) - link[i++] = c; - link[i] = 0; - if (name_block) { - mark_buffer_dirty(name_block, 1); - brelse (name_block); - } - inode->i_size = i; mark_inode_dirty(inode); bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err); @@ -828,16 +815,12 @@ int ufs_link (struct dentry * old_dentry, struct inode * dir, struct dentry *dentry) { - struct super_block * sb; struct inode *inode = old_dentry->d_inode; + struct super_block * sb = inode->i_sb; struct ufs_dir_entry * de; struct buffer_head * bh; int err; - unsigned swab; - - inode = old_dentry->d_inode; - sb = inode->i_sb; - swab = sb->u.ufs_sb.s_swab; + unsigned swab = sb->u.ufs_sb.s_swab; if (S_ISDIR(inode->i_mode)) return -EPERM; diff -urN linux-2.3.32-pre2/fs/ufs/symlink.c linux-bird.symlink/fs/ufs/symlink.c --- linux-2.3.32-pre2/fs/ufs/symlink.c Mon Dec 6 22:06:04 1999 +++ linux-bird.symlink/fs/ufs/symlink.c Wed Dec 8 20:19:27 1999 @@ -23,116 +23,29 @@ * ext2 symlink handling code */ -#include <asm/uaccess.h> - -#include <linux/errno.h> #include <linux/fs.h> #include <linux/ufs_fs.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/stat.h> - - -#undef UFS_SYMLINK_DEBUG - -#ifdef UFS_SYMLINK_DEBUG -#define UFSD(x) printk("(%s, %d), %s:", __FILE__, __LINE__, __FUNCTION__); printk x; -#else -#define UFSD(x) -#endif - -static struct dentry * ufs_follow_link(struct dentry * dentry, - struct dentry * base, unsigned int follow) +static int ufs_readlink(struct dentry *dentry, char *buffer, int buflen) { - struct inode * inode; - struct buffer_head * bh; - int error; - char * link; - - UFSD(("ENTER\n")) - - inode = dentry->d_inode; - bh = NULL; - /* slow symlink */ - if (inode->i_blocks) { - if (!(bh = ufs_bread (inode, 0, 0, &error))) { - dput(base); - return ERR_PTR(-EIO); - } - link = bh->b_data; - } - /* fast symlink */ - else { - link = (char *) inode->u.ufs_i.i_u1.i_symlink; - } - UPDATE_ATIME(inode); - base = lookup_dentry(link, base, follow); - if (bh) - brelse(bh); - UFSD(("EXIT\n")) - return base; + char *s = (char *)dentry->d_inode->u.ufs_i.i_u1.i_symlink; + return vfs_readlink(dentry, buffer, buflen, s); } -static int ufs_readlink (struct dentry * dentry, char * buffer, int buflen) +static struct dentry *ufs_follow_link(struct dentry *dentry, struct dentry *base, unsigned flags) { - struct super_block * sb; - struct inode * inode; - struct buffer_head * bh; - char * link; - int i; - - UFSD(("ENTER\n")) - - inode = dentry->d_inode; - sb = inode->i_sb; - bh = NULL; - if (buflen > sb->s_blocksize - 1) - buflen = sb->s_blocksize - 1; - /* slow symlink */ - if (inode->i_blocks) { - int err; - bh = ufs_bread (inode, 0, 0, &err); - if (!bh) { - if(err < 0) /* indicate type of error */ - return err; - return 0; - } - link = bh->b_data; - } - /* fast symlink */ - else { - link = (char *) inode->u.ufs_i.i_u1.i_symlink; - } - i = 0; - while (i < buflen && link[i]) - i++; - if (copy_to_user(buffer, link, i)) - i = -EFAULT; - UPDATE_ATIME(inode); - if (bh) - brelse (bh); - UFSD(("ENTER\n")) - return i; + char *s = (char *)dentry->d_inode->u.ufs_i.i_u1.i_symlink; + return vfs_follow_link(dentry, base, flags, s); } +struct inode_operations ufs_fast_symlink_inode_operations = { + readlink: ufs_readlink, + follow_link: ufs_follow_link, +}; + struct inode_operations ufs_symlink_inode_operations = { - NULL, /* no file-operations */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - ufs_readlink, /* readlink */ - ufs_follow_link, /* follow_link */ - NULL, /* get_block */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* truncate */ - NULL, /* permission */ - NULL /* revalidate */ + readlink: page_readlink, + follow_link: page_follow_link, + get_block: ufs_getfrag_block, + readpage: block_read_full_page }; diff -urN linux-2.3.32-pre2/fs/umsdos/namei.c linux-bird.symlink/fs/umsdos/namei.c --- linux-2.3.32-pre2/fs/umsdos/namei.c Sun Sep 12 13:55:24 1999 +++ linux-bird.symlink/fs/umsdos/namei.c Wed Dec 8 20:19:27 1999 @@ -475,8 +475,6 @@ * Let's go for simplicity... */ -extern struct inode_operations umsdos_symlink_inode_operations; - /* * AV. Should be called with dir->i_sem down. */ diff -urN linux-2.3.32-pre2/include/linux/ext2_fs.h linux-bird.symlink/include/linux/ext2_fs.h --- linux-2.3.32-pre2/include/linux/ext2_fs.h Sun Sep 12 16:55:57 1999 +++ linux-bird.symlink/include/linux/ext2_fs.h Wed Dec 8 20:19:27 1999 @@ -615,6 +615,7 @@ /* symlink.c */ extern struct inode_operations ext2_symlink_inode_operations; +extern struct inode_operations ext2_fast_symlink_inode_operations; #endif /* __KERNEL__ */ diff -urN linux-2.3.32-pre2/include/linux/fs.h linux-bird.symlink/include/linux/fs.h --- linux-2.3.32-pre2/include/linux/fs.h Mon Dec 6 22:06:05 1999 +++ linux-bird.symlink/include/linux/fs.h Wed Dec 8 20:19:27 1999 @@ -946,12 +946,24 @@ extern int block_write_full_page (struct dentry *, struct page *); extern int block_write_partial_page (struct file *, struct page *, unsigned long, unsigned long, const char *); extern int block_write_cont_page (struct file *, struct page *, unsigned long, unsigned long, const char *); +extern int block_write_zero_range(struct inode *, struct page *, unsigned, unsigned, unsigned, const char *); +extern inline int block_write_range(struct inode *inode, struct page *page, + unsigned from, unsigned len,const char *buf) +{ + return block_write_zero_range(inode, page, from, from, from+len, buf); +} extern int block_flushpage(struct page *, unsigned long); +extern int block_symlink(struct inode *, const char *, int); extern int generic_file_mmap(struct file *, struct vm_area_struct *); extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *); extern ssize_t generic_file_write(struct file *, const char *, size_t, loff_t *, writepage_t); -extern void do_generic_file_read(struct file * filp, loff_t *ppos, read_descriptor_t * desc, read_actor_t actor); +extern void do_generic_file_read(struct file *, loff_t *, read_descriptor_t *, read_actor_t); + +extern int vfs_readlink(struct dentry *, char *, int, char *); +extern struct dentry *vfs_follow_link(struct dentry *, struct dentry *, unsigned, char *); +extern int page_readlink(struct dentry *, char *, int); +extern struct dentry *page_follow_link(struct dentry *, struct dentry *, unsigned); extern struct super_block *get_super(kdev_t); struct super_block *get_empty_super(void); diff -urN linux-2.3.32-pre2/include/linux/ufs_fs.h linux-bird.symlink/include/linux/ufs_fs.h --- linux-2.3.32-pre2/include/linux/ufs_fs.h Mon Nov 22 08:50:18 1999 +++ linux-bird.symlink/include/linux/ufs_fs.h Wed Dec 8 20:19:27 1999 @@ -563,6 +563,7 @@ /* symlink.c */ extern struct inode_operations ufs_symlink_inode_operations; +extern struct inode_operations ufs_fast_symlink_inode_operations; /* truncate.c */ extern void ufs_truncate (struct inode *); diff -urN linux-2.3.32-pre2/kernel/ksyms.c linux-bird.symlink/kernel/ksyms.c --- linux-2.3.32-pre2/kernel/ksyms.c Mon Dec 6 22:06:06 1999 +++ linux-bird.symlink/kernel/ksyms.c Wed Dec 8 20:19:27 1999 @@ -188,6 +188,7 @@ EXPORT_SYMBOL(block_write_full_page); EXPORT_SYMBOL(block_write_partial_page); EXPORT_SYMBOL(block_write_cont_page); +EXPORT_SYMBOL(block_write_zero_range); EXPORT_SYMBOL(generic_file_read); EXPORT_SYMBOL(do_generic_file_read); EXPORT_SYMBOL(generic_file_write); @@ -218,6 +219,11 @@ EXPORT_SYMBOL(__find_lock_page); EXPORT_SYMBOL(grab_cache_page); EXPORT_SYMBOL(read_cache_page); +EXPORT_SYMBOL(vfs_readlink); +EXPORT_SYMBOL(vfs_follow_link); +EXPORT_SYMBOL(page_readlink); +EXPORT_SYMBOL(page_follow_link); +EXPORT_SYMBOL(block_symlink); #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE) EXPORT_SYMBOL(do_nfsservctl);
| |