lkml.org 
[lkml]   [1999]   [Dec]   [8]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: 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);
\
 
 \ /
  Last update: 2005-03-22 13:55    [from the cache]
©2003-2011 Jasper Spaans