diff options
Diffstat (limited to 'fs')
549 files changed, 20967 insertions, 18818 deletions
diff --git a/fs/9p/fid.c b/fs/9p/fid.c index 15e05a15b575..b364da70ff28 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c @@ -1,6 +1,7 @@ /* * V9FS FID Management * + * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net> * Copyright (C) 2005, 2006 by Eric Van Hensbergen <ericvh@gmail.com> * * This program is free software; you can redistribute it and/or modify @@ -34,9 +35,9 @@ #include "fid.h" /** - * v9fs_fid_insert - add a fid to a dentry + * v9fs_fid_add - add a fid to a dentry + * @dentry: dentry that the fid is being added to * @fid: fid to add - * @dentry: dentry that it is being added to * */ @@ -66,52 +67,144 @@ int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid) } /** - * v9fs_fid_lookup - return a locked fid from a dentry + * v9fs_fid_find - retrieve a fid that belongs to the specified uid * @dentry: dentry to look for fid in - * - * find a fid in the dentry, obtain its semaphore and return a reference to it. - * code calling lookup is responsible for releasing lock - * - * TODO: only match fids that have the same uid as current user + * @uid: return fid that belongs to the specified user + * @any: if non-zero, return any fid associated with the dentry * */ -struct p9_fid *v9fs_fid_lookup(struct dentry *dentry) +static struct p9_fid *v9fs_fid_find(struct dentry *dentry, u32 uid, int any) { struct v9fs_dentry *dent; - struct p9_fid *fid; - - P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); - dent = dentry->d_fsdata; - if (dent) - fid = list_entry(dent->fidlist.next, struct p9_fid, dlist); - else - fid = ERR_PTR(-EBADF); + struct p9_fid *fid, *ret; + + P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p) uid %d any %d\n", + dentry->d_iname, dentry, uid, any); + dent = (struct v9fs_dentry *) dentry->d_fsdata; + ret = NULL; + if (dent) { + spin_lock(&dent->lock); + list_for_each_entry(fid, &dent->fidlist, dlist) { + if (any || fid->uid == uid) { + ret = fid; + break; + } + } + spin_unlock(&dent->lock); + } - P9_DPRINTK(P9_DEBUG_VFS, " fid: %p\n", fid); - return fid; + return ret; } /** - * v9fs_fid_clone - lookup the fid for a dentry, clone a private copy and - * release it + * v9fs_fid_lookup - lookup for a fid, try to walk if not found * @dentry: dentry to look for fid in * - * find a fid in the dentry and then clone to a new private fid - * - * TODO: only match fids that have the same uid as current user - * + * Look for a fid in the specified dentry for the current user. + * If no fid is found, try to create one walking from a fid from the parent + * dentry (if it has one), or the root dentry. If the user haven't accessed + * the fs yet, attach now and walk from the root. */ -struct p9_fid *v9fs_fid_clone(struct dentry *dentry) +struct p9_fid *v9fs_fid_lookup(struct dentry *dentry) { - struct p9_fid *ofid, *fid; + int i, n, l, clone, any, access; + u32 uid; + struct p9_fid *fid; + struct dentry *d, *ds; + struct v9fs_session_info *v9ses; + char **wnames, *uname; + + v9ses = v9fs_inode2v9ses(dentry->d_inode); + access = v9ses->flags & V9FS_ACCESS_MASK; + switch (access) { + case V9FS_ACCESS_SINGLE: + case V9FS_ACCESS_USER: + uid = current->fsuid; + any = 0; + break; + + case V9FS_ACCESS_ANY: + uid = v9ses->uid; + any = 1; + break; + + default: + uid = ~0; + any = 0; + break; + } - P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); - ofid = v9fs_fid_lookup(dentry); - if (IS_ERR(ofid)) - return ofid; + fid = v9fs_fid_find(dentry, uid, any); + if (fid) + return fid; + + ds = dentry->d_parent; + fid = v9fs_fid_find(ds, uid, any); + if (!fid) { /* walk from the root */ + n = 0; + for (ds = dentry; !IS_ROOT(ds); ds = ds->d_parent) + n++; + + fid = v9fs_fid_find(ds, uid, any); + if (!fid) { /* the user is not attached to the fs yet */ + if (access == V9FS_ACCESS_SINGLE) + return ERR_PTR(-EPERM); + + if (v9fs_extended(v9ses)) + uname = NULL; + else + uname = v9ses->uname; + + fid = p9_client_attach(v9ses->clnt, NULL, uname, uid, + v9ses->aname); + + if (IS_ERR(fid)) + return fid; + + v9fs_fid_add(ds, fid); + } + } else /* walk from the parent */ + n = 1; + + if (ds == dentry) + return fid; + + wnames = kmalloc(sizeof(char *) * n, GFP_KERNEL); + if (!wnames) + return ERR_PTR(-ENOMEM); + + for (d = dentry, i = n; i >= 0; i--, d = d->d_parent) + wnames[i] = (char *) d->d_name.name; + + clone = 1; + i = 0; + while (i < n) { + l = min(n - i, P9_MAXWELEM); + fid = p9_client_walk(fid, l, &wnames[i], clone); + if (!fid) { + kfree(wnames); + return fid; + } + + i += l; + clone = 0; + } - fid = p9_client_walk(ofid, 0, NULL, 1); + kfree(wnames); + v9fs_fid_add(dentry, fid); return fid; } + +struct p9_fid *v9fs_fid_clone(struct dentry *dentry) +{ + struct p9_fid *fid, *ret; + + fid = v9fs_fid_lookup(dentry); + if (IS_ERR(fid)) + return fid; + + ret = p9_client_walk(fid, 0, NULL, 1); + return ret; +} diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 0a7068e30ecb..873802de21cd 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -38,56 +38,41 @@ /* * Option Parsing (code inspired by NFS code) - * + * NOTE: each transport will parse its own options */ enum { /* Options that take integer arguments */ - Opt_debug, Opt_port, Opt_msize, Opt_uid, Opt_gid, Opt_afid, - Opt_rfdno, Opt_wfdno, + Opt_debug, Opt_msize, Opt_dfltuid, Opt_dfltgid, Opt_afid, /* String options */ - Opt_uname, Opt_remotename, + Opt_uname, Opt_remotename, Opt_trans, /* Options that take no arguments */ - Opt_legacy, Opt_nodevmap, Opt_unix, Opt_tcp, Opt_fd, Opt_pci, + Opt_legacy, Opt_nodevmap, /* Cache options */ Opt_cache_loose, + /* Access options */ + Opt_access, /* Error token */ Opt_err }; static match_table_t tokens = { {Opt_debug, "debug=%x"}, - {Opt_port, "port=%u"}, {Opt_msize, "msize=%u"}, - {Opt_uid, "uid=%u"}, - {Opt_gid, "gid=%u"}, + {Opt_dfltuid, "dfltuid=%u"}, + {Opt_dfltgid, "dfltgid=%u"}, {Opt_afid, "afid=%u"}, - {Opt_rfdno, "rfdno=%u"}, - {Opt_wfdno, "wfdno=%u"}, {Opt_uname, "uname=%s"}, {Opt_remotename, "aname=%s"}, - {Opt_unix, "proto=unix"}, - {Opt_tcp, "proto=tcp"}, - {Opt_fd, "proto=fd"}, -#ifdef CONFIG_PCI_9P - {Opt_pci, "proto=pci"}, -#endif - {Opt_tcp, "tcp"}, - {Opt_unix, "unix"}, - {Opt_fd, "fd"}, + {Opt_trans, "trans=%s"}, {Opt_legacy, "noextend"}, {Opt_nodevmap, "nodevmap"}, {Opt_cache_loose, "cache=loose"}, {Opt_cache_loose, "loose"}, + {Opt_access, "access=%s"}, {Opt_err, NULL} }; -extern struct p9_transport *p9pci_trans_create(void); - -/* - * Parse option string. - */ - /** * v9fs_parse_options - parse mount options into session structure * @options: options string passed from mount @@ -95,23 +80,21 @@ extern struct p9_transport *p9pci_trans_create(void); * */ -static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses) +static void v9fs_parse_options(struct v9fs_session_info *v9ses) { - char *p; + char *options = v9ses->options; substring_t args[MAX_OPT_ARGS]; + char *p; int option; int ret; + char *s, *e; /* setup defaults */ - v9ses->port = V9FS_PORT; - v9ses->maxdata = 9000; - v9ses->proto = PROTO_TCP; - v9ses->extended = 1; + v9ses->maxdata = 8192; v9ses->afid = ~0; v9ses->debug = 0; - v9ses->rfdno = ~0; - v9ses->wfdno = ~0; v9ses->cache = 0; + v9ses->trans = v9fs_default_trans(); if (!options) return; @@ -135,47 +118,29 @@ static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses) p9_debug_level = option; #endif break; - case Opt_port: - v9ses->port = option; - break; case Opt_msize: v9ses->maxdata = option; break; - case Opt_uid: - v9ses->uid = option; + case Opt_dfltuid: + v9ses->dfltuid = option; break; - case Opt_gid: - v9ses->gid = option; + case Opt_dfltgid: + v9ses->dfltgid = option; break; case Opt_afid: v9ses->afid = option; break; - case Opt_rfdno: - v9ses->rfdno = option; - break; - case Opt_wfdno: - v9ses->wfdno = option; - break; - case Opt_tcp: - v9ses->proto = PROTO_TCP; - break; - case Opt_unix: - v9ses->proto = PROTO_UNIX; - break; - case Opt_pci: - v9ses->proto = PROTO_PCI; - break; - case Opt_fd: - v9ses->proto = PROTO_FD; + case Opt_trans: + v9ses->trans = v9fs_match_trans(&args[0]); break; case Opt_uname: - match_strcpy(v9ses->name, &args[0]); + match_strcpy(v9ses->uname, &args[0]); break; case Opt_remotename: - match_strcpy(v9ses->remotename, &args[0]); + match_strcpy(v9ses->aname, &args[0]); break; case Opt_legacy: - v9ses->extended = 0; + v9ses->flags &= ~V9FS_EXTENDED; break; case Opt_nodevmap: v9ses->nodev = 1; @@ -183,6 +148,22 @@ static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses) case Opt_cache_loose: v9ses->cache = CACHE_LOOSE; break; + + case Opt_access: + s = match_strdup(&args[0]); + v9ses->flags &= ~V9FS_ACCESS_MASK; + if (strcmp(s, "user") == 0) + v9ses->flags |= V9FS_ACCESS_USER; + else if (strcmp(s, "any") == 0) + v9ses->flags |= V9FS_ACCESS_ANY; + else { + v9ses->flags |= V9FS_ACCESS_SINGLE; + v9ses->uid = simple_strtol(s, &e, 10); + if (*e != '\0') + v9ses->uid = ~0; + } + break; + default: continue; } @@ -201,56 +182,46 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, const char *dev_name, char *data) { int retval = -EINVAL; - struct p9_transport *trans; + struct p9_trans *trans = NULL; struct p9_fid *fid; - v9ses->name = __getname(); - if (!v9ses->name) + v9ses->uname = __getname(); + if (!v9ses->uname) return ERR_PTR(-ENOMEM); - v9ses->remotename = __getname(); - if (!v9ses->remotename) { - __putname(v9ses->name); + v9ses->aname = __getname(); + if (!v9ses->aname) { + __putname(v9ses->uname); return ERR_PTR(-ENOMEM); } - strcpy(v9ses->name, V9FS_DEFUSER); - strcpy(v9ses->remotename, V9FS_DEFANAME); - - v9fs_parse_options(data, v9ses); - - switch (v9ses->proto) { - case PROTO_TCP: - trans = p9_trans_create_tcp(dev_name, v9ses->port); - break; - case PROTO_UNIX: - trans = p9_trans_create_unix(dev_name); - *v9ses->remotename = 0; - break; - case PROTO_FD: - trans = p9_trans_create_fd(v9ses->rfdno, v9ses->wfdno); - *v9ses->remotename = 0; - break; -#ifdef CONFIG_PCI_9P - case PROTO_PCI: - trans = p9pci_trans_create(); - *v9ses->remotename = 0; - break; -#endif - default: - printk(KERN_ERR "v9fs: Bad mount protocol %d\n", v9ses->proto); - retval = -ENOPROTOOPT; + v9ses->flags = V9FS_EXTENDED | V9FS_ACCESS_USER; + strcpy(v9ses->uname, V9FS_DEFUSER); + strcpy(v9ses->aname, V9FS_DEFANAME); + v9ses->uid = ~0; + v9ses->dfltuid = V9FS_DEFUID; + v9ses->dfltgid = V9FS_DEFGID; + v9ses->options = kstrdup(data, GFP_KERNEL); + v9fs_parse_options(v9ses); + + if (v9ses->trans == NULL) { + retval = -EPROTONOSUPPORT; + P9_DPRINTK(P9_DEBUG_ERROR, + "No transport defined or default transport\n"); goto error; - }; + } + trans = v9ses->trans->create(dev_name, v9ses->options); if (IS_ERR(trans)) { retval = PTR_ERR(trans); trans = NULL; goto error; } + if ((v9ses->maxdata+P9_IOHDRSZ) > v9ses->trans->maxsize) + v9ses->maxdata = v9ses->trans->maxsize-P9_IOHDRSZ; - v9ses->clnt = p9_client_create(trans, v9ses->maxdata + P9_IOHDRSZ, - v9ses->extended); + v9ses->clnt = p9_client_create(trans, v9ses->maxdata+P9_IOHDRSZ, + v9fs_extended(v9ses)); if (IS_ERR(v9ses->clnt)) { retval = PTR_ERR(v9ses->clnt); @@ -259,8 +230,20 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, goto error; } - fid = p9_client_attach(v9ses->clnt, NULL, v9ses->name, - v9ses->remotename); + if (!v9ses->clnt->dotu) + v9ses->flags &= ~V9FS_EXTENDED; + + /* for legacy mode, fall back to V9FS_ACCESS_ANY */ + if (!v9fs_extended(v9ses) && + ((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) { + + v9ses->flags &= ~V9FS_ACCESS_MASK; + v9ses->flags |= V9FS_ACCESS_ANY; + v9ses->uid = ~0; + } + + fid = p9_client_attach(v9ses->clnt, NULL, v9ses->uname, ~0, + v9ses->aname); if (IS_ERR(fid)) { retval = PTR_ERR(fid); fid = NULL; @@ -268,6 +251,11 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, goto error; } + if ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_SINGLE) + fid->uid = v9ses->uid; + else + fid->uid = ~0; + return fid; error: @@ -288,8 +276,9 @@ void v9fs_session_close(struct v9fs_session_info *v9ses) v9ses->clnt = NULL; } - __putname(v9ses->name); - __putname(v9ses->remotename); + __putname(v9ses->uname); + __putname(v9ses->aname); + kfree(v9ses->options); } /** @@ -311,7 +300,7 @@ extern int v9fs_error_init(void); static int __init init_v9fs(void) { printk(KERN_INFO "Installing v9fs 9p2000 file system support\n"); - + /* TODO: Setup list of registered trasnport modules */ return register_filesystem(&v9fs_fs_type); } diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h index abc4b1668ace..db4b4193f2e2 100644 --- a/fs/9p/v9fs.h +++ b/fs/9p/v9fs.h @@ -29,31 +29,30 @@ struct v9fs_session_info { /* options */ unsigned int maxdata; - unsigned char extended; /* set to 1 if we are using UNIX extensions */ + unsigned char flags; /* session flags */ unsigned char nodev; /* set to 1 if no disable device mapping */ - unsigned short port; /* port to connect to */ unsigned short debug; /* debug level */ - unsigned short proto; /* protocol to use */ unsigned int afid; /* authentication fid */ - unsigned int rfdno; /* read file descriptor number */ - unsigned int wfdno; /* write file descriptor number */ unsigned int cache; /* cache mode */ - char *name; /* user name to mount as */ - char *remotename; /* name of remote hierarchy being mounted */ - unsigned int uid; /* default uid/muid for legacy support */ - unsigned int gid; /* default gid for legacy support */ - + char *options; /* copy of mount options */ + char *uname; /* user name to mount as */ + char *aname; /* name of remote hierarchy being mounted */ + unsigned int dfltuid; /* default uid/muid for legacy support */ + unsigned int dfltgid; /* default gid for legacy support */ + u32 uid; /* if ACCESS_SINGLE, the uid that has access */ + struct p9_trans_module *trans; /* 9p transport */ struct p9_client *clnt; /* 9p client */ struct dentry *debugfs_dir; }; -/* possible values of ->proto */ +/* session flags */ enum { - PROTO_TCP, - PROTO_UNIX, - PROTO_FD, - PROTO_PCI, + V9FS_EXTENDED = 0x01, /* 9P2000.u */ + V9FS_ACCESS_MASK = 0x06, /* access mask */ + V9FS_ACCESS_SINGLE = 0x02, /* only one user can access the files */ + V9FS_ACCESS_USER = 0x04, /* attache per user */ + V9FS_ACCESS_ANY = 0x06, /* use the same attach for all users */ }; /* possible values of ->cache */ @@ -73,11 +72,18 @@ void v9fs_session_cancel(struct v9fs_session_info *v9ses); #define V9FS_MAGIC 0x01021997 /* other default globals */ -#define V9FS_PORT 564 +#define V9FS_PORT 564 #define V9FS_DEFUSER "nobody" #define V9FS_DEFANAME "" +#define V9FS_DEFUID (-2) +#define V9FS_DEFGID (-2) static inline struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode) { return (inode->i_sb->s_fs_info); } + +static inline int v9fs_extended(struct v9fs_session_info *v9ses) +{ + return v9ses->flags & V9FS_EXTENDED; +} diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 2a40c2946d0a..ba4b1caa9c43 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -105,7 +105,7 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl) P9_DPRINTK(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl); /* No mandatory locks */ - if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) + if (__mandatory_lock(inode)) return -ENOLCK; if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { @@ -162,15 +162,17 @@ v9fs_file_write(struct file *filp, const char __user * data, fid = filp->private_data; ret = p9_client_uwrite(fid, data, *offset, count); - if (ret > 0) + if (ret > 0) { + invalidate_inode_pages2_range(inode->i_mapping, *offset, + *offset+ret); *offset += ret; + } if (*offset > inode->i_size) { inode->i_size = *offset; inode->i_blocks = (inode->i_size + 512 - 1) >> 9; } - invalidate_inode_pages2(inode->i_mapping); return ret; } diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index e5c45eed58a9..175b4d9bf3f8 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -59,7 +59,7 @@ static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode) res = mode & 0777; if (S_ISDIR(mode)) res |= P9_DMDIR; - if (v9ses->extended) { + if (v9fs_extended(v9ses)) { if (S_ISLNK(mode)) res |= P9_DMSYMLINK; if (v9ses->nodev == 0) { @@ -99,21 +99,21 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) if ((mode & P9_DMDIR) == P9_DMDIR) res |= S_IFDIR; - else if ((mode & P9_DMSYMLINK) && (v9ses->extended)) + else if ((mode & P9_DMSYMLINK) && (v9fs_extended(v9ses))) res |= S_IFLNK; - else if ((mode & P9_DMSOCKET) && (v9ses->extended) + else if ((mode & P9_DMSOCKET) && (v9fs_extended(v9ses)) && (v9ses->nodev == 0)) res |= S_IFSOCK; - else if ((mode & P9_DMNAMEDPIPE) && (v9ses->extended) + else if ((mode & P9_DMNAMEDPIPE) && (v9fs_extended(v9ses)) && (v9ses->nodev == 0)) res |= S_IFIFO; - else if ((mode & P9_DMDEVICE) && (v9ses->extended) + else if ((mode & P9_DMDEVICE) && (v9fs_extended(v9ses)) && (v9ses->nodev == 0)) res |= S_IFBLK; else res |= S_IFREG; - if (v9ses->extended) { + if (v9fs_extended(v9ses)) { if ((mode & P9_DMSETUID) == P9_DMSETUID) res |= S_ISUID; @@ -214,7 +214,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode) case S_IFBLK: case S_IFCHR: case S_IFSOCK: - if(!v9ses->extended) { + if (!v9fs_extended(v9ses)) { P9_DPRINTK(P9_DEBUG_ERROR, "special files without extended mode\n"); return ERR_PTR(-EINVAL); @@ -227,7 +227,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode) inode->i_fop = &v9fs_file_operations; break; case S_IFLNK: - if(!v9ses->extended) { + if (!v9fs_extended(v9ses)) { P9_DPRINTK(P9_DEBUG_ERROR, "extended modes used w/o 9P2000.u\n"); return ERR_PTR(-EINVAL); @@ -236,7 +236,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode) break; case S_IFDIR: inc_nlink(inode); - if(v9ses->extended) + if (v9fs_extended(v9ses)) inode->i_op = &v9fs_dir_inode_operations_ext; else inode->i_op = &v9fs_dir_inode_operations; @@ -364,7 +364,7 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) file_inode = file->d_inode; v9ses = v9fs_inode2v9ses(file_inode); v9fid = v9fs_fid_clone(file); - if(IS_ERR(v9fid)) + if (IS_ERR(v9fid)) return PTR_ERR(v9fid); return p9_client_remove(v9fid); @@ -398,7 +398,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, fid = NULL; name = (char *) dentry->d_name.name; dfid = v9fs_fid_clone(dentry->d_parent); - if(IS_ERR(dfid)) { + if (IS_ERR(dfid)) { err = PTR_ERR(dfid); dfid = NULL; goto error; @@ -432,7 +432,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, goto error; } - if(v9ses->cache) + if (v9ses->cache) dentry->d_op = &v9fs_cached_dentry_operations; else dentry->d_op = &v9fs_dentry_operations; @@ -593,7 +593,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, if (result < 0) goto error; - if((fid->qid.version)&&(v9ses->cache)) + if ((fid->qid.version) && (v9ses->cache)) dentry->d_op = &v9fs_cached_dentry_operations; else dentry->d_op = &v9fs_dentry_operations; @@ -658,17 +658,17 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, old_inode = old_dentry->d_inode; v9ses = v9fs_inode2v9ses(old_inode); oldfid = v9fs_fid_lookup(old_dentry); - if(IS_ERR(oldfid)) + if (IS_ERR(oldfid)) return PTR_ERR(oldfid); olddirfid = v9fs_fid_clone(old_dentry->d_parent); - if(IS_ERR(olddirfid)) { + if (IS_ERR(olddirfid)) { retval = PTR_ERR(olddirfid); goto done; } newdirfid = v9fs_fid_clone(new_dentry->d_parent); - if(IS_ERR(newdirfid)) { + if (IS_ERR(newdirfid)) { retval = PTR_ERR(newdirfid); goto clunk_olddir; } @@ -682,7 +682,7 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, } v9fs_blank_wstat(&wstat); - wstat.muid = v9ses->name; + wstat.muid = v9ses->uname; wstat.name = (char *) new_dentry->d_name.name; retval = p9_client_wstat(oldfid, &wstat); @@ -768,7 +768,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) if (iattr->ia_valid & ATTR_SIZE) wstat.length = iattr->ia_size; - if (v9ses->extended) { + if (v9fs_extended(v9ses)) { if (iattr->ia_valid & ATTR_UID) wstat.n_uid = iattr->ia_uid; @@ -805,10 +805,10 @@ v9fs_stat2inode(struct p9_stat *stat, struct inode *inode, inode->i_mtime.tv_sec = stat->mtime; inode->i_ctime.tv_sec = stat->mtime; - inode->i_uid = v9ses->uid; - inode->i_gid = v9ses->gid; + inode->i_uid = v9ses->dfltuid; + inode->i_gid = v9ses->dfltgid; - if (v9ses->extended) { + if (v9fs_extended(v9ses)) { inode->i_uid = stat->n_uid; inode->i_gid = stat->n_gid; } @@ -887,10 +887,10 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) retval = -EPERM; v9ses = v9fs_inode2v9ses(dentry->d_inode); fid = v9fs_fid_lookup(dentry); - if(IS_ERR(fid)) + if (IS_ERR(fid)) return PTR_ERR(fid); - if (!v9ses->extended) + if (!v9fs_extended(v9ses)) return -EBADF; st = p9_client_stat(fid); @@ -1011,7 +1011,7 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, struct p9_fid *fid; v9ses = v9fs_inode2v9ses(dir); - if (!v9ses->extended) { + if (!v9fs_extended(v9ses)) { P9_DPRINTK(P9_DEBUG_ERROR, "not extended\n"); return -EPERM; } @@ -1070,7 +1070,7 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, old_dentry->d_name.name); oldfid = v9fs_fid_clone(old_dentry); - if(IS_ERR(oldfid)) + if (IS_ERR(oldfid)) return PTR_ERR(oldfid); name = __getname(); diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index ba904371218b..bb0cef9a6b8a 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -216,24 +216,7 @@ static int v9fs_show_options(struct seq_file *m, struct vfsmount *mnt) { struct v9fs_session_info *v9ses = mnt->mnt_sb->s_fs_info; - if (v9ses->debug != 0) - seq_printf(m, ",debug=%x", v9ses->debug); - if (v9ses->port != V9FS_PORT) - seq_printf(m, ",port=%u", v9ses->port); - if (v9ses->maxdata != 9000) - seq_printf(m, ",msize=%u", v9ses->maxdata); - if (v9ses->afid != ~0) - seq_printf(m, ",afid=%u", v9ses->afid); - if (v9ses->proto == PROTO_UNIX) - seq_puts(m, ",proto=unix"); - if (v9ses->extended == 0) - seq_puts(m, ",noextend"); - if (v9ses->nodev == 1) - seq_puts(m, ",nodevmap"); - seq_printf(m, ",name=%s", v9ses->name); - seq_printf(m, ",aname=%s", v9ses->remotename); - seq_printf(m, ",uid=%u", v9ses->uid); - seq_printf(m, ",gid=%u", v9ses->gid); + seq_printf(m, "%s", v9ses->options); return 0; } diff --git a/fs/Kconfig b/fs/Kconfig index f9eed6d79066..cc28a69246a7 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -140,6 +140,7 @@ config EXT4DEV_FS tristate "Ext4dev/ext4 extended fs support development (EXPERIMENTAL)" depends on EXPERIMENTAL select JBD2 + select CRC16 help Ext4dev is a predecessor filesystem of the next generation extended fs ext4, based on ext3 filesystem code. It will be @@ -219,7 +220,7 @@ config JBD config JBD_DEBUG bool "JBD (ext3) debugging support" - depends on JBD + depends on JBD && DEBUG_FS help If you are using the ext3 journaled file system (or potentially any other file system/device using JBD), this option allows you to @@ -228,10 +229,10 @@ config JBD_DEBUG debugging output will be turned off. If you select Y here, then you will be able to turn on debugging - with "echo N > /proc/sys/fs/jbd-debug", where N is a number between - 1 and 5, the higher the number, the more debugging output is - generated. To turn debugging off again, do - "echo 0 > /proc/sys/fs/jbd-debug". + with "echo N > /sys/kernel/debug/jbd/jbd-debug", where N is a + number between 1 and 5, the higher the number, the more debugging + output is generated. To turn debugging off again, do + "echo 0 > /sys/kernel/debug/jbd/jbd-debug". config JBD2 tristate @@ -534,6 +535,24 @@ config QUOTA with the quota tools. Probably the quota support is only useful for multi user systems. If unsure, say N. +config QUOTA_NETLINK_INTERFACE + bool "Report quota messages through netlink interface" + depends on QUOTA && NET + help + If you say Y here, quota warnings (about exceeding softlimit, reaching + hardlimit, etc.) will be reported through netlink interface. If unsure, + say Y. + +config PRINT_QUOTA_WARNING + bool "Print quota warnings to console (OBSOLETE)" + depends on QUOTA + default y + help + If you say Y here, quota warnings (about exceeding softlimit, reaching + hardlimit, etc.) will be printed to the process' controlling terminal. + Note that this behavior is currently deprecated and may go away in + future. Please use notification via netlink socket instead. + config QFMT_V1 tristate "Old quota format support" depends on QUOTA @@ -555,7 +574,7 @@ config QUOTACTL default y config DNOTIFY - bool "Dnotify support" if EMBEDDED + bool "Dnotify support" default y help Dnotify is a directory-based per-fd file change notification system @@ -563,7 +582,7 @@ config DNOTIFY superior alternatives, but some applications may still rely on dnotify. - Because of this, if unsure, say Y. + If unsure, say Y. config AUTOFS_FS tristate "Kernel automounter support" @@ -999,20 +1018,6 @@ config HUGETLBFS config HUGETLB_PAGE def_bool HUGETLBFS -config RAMFS - bool - default y - ---help--- - Ramfs is a file system which keeps all files in RAM. It allows - read and write access. - - It is more of an programming example than a useable file system. If - you need a file system which lives in RAM with limit checking use - tmpfs. - - To compile this as a module, choose M here: the module will be called - ramfs. - config CONFIGFS_FS tristate "Userspace-driven configuration filesystem (EXPERIMENTAL)" depends on SYSFS && EXPERIMENTAL @@ -1225,6 +1230,14 @@ config JFFS2_FS_WRITEBUFFER - NOR flash with transparent ECC - DataFlash +config JFFS2_FS_WBUF_VERIFY + bool "Verify JFFS2 write-buffer reads" + depends on JFFS2_FS_WRITEBUFFER + default n + help + This causes JFFS2 to read back every page written through the + write-buffer, and check for errors. + config JFFS2_SUMMARY bool "JFFS2 summary support (EXPERIMENTAL)" depends on JFFS2_FS && EXPERIMENTAL @@ -1295,52 +1308,71 @@ config JFFS2_ZLIB select ZLIB_DEFLATE depends on JFFS2_FS default y - help - Zlib is designed to be a free, general-purpose, legally unencumbered, - lossless data-compression library for use on virtually any computer - hardware and operating system. See <http://www.gzip.org/zlib/> for - further information. + help + Zlib is designed to be a free, general-purpose, legally unencumbered, + lossless data-compression library for use on virtually any computer + hardware and operating system. See <http://www.gzip.org/zlib/> for + further information. + + Say 'Y' if unsure. + +config JFFS2_LZO + bool "JFFS2 LZO compression support" if JFFS2_COMPRESSION_OPTIONS + select LZO_COMPRESS + select LZO_DECOMPRESS + depends on JFFS2_FS + default n + help + minilzo-based compression. Generally works better than Zlib. - Say 'Y' if unsure. + This feature was added in July, 2007. Say 'N' if you need + compatibility with older bootloaders or kernels. config JFFS2_RTIME bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS depends on JFFS2_FS default y - help - Rtime does manage to recompress already-compressed data. Say 'Y' if unsure. + help + Rtime does manage to recompress already-compressed data. Say 'Y' if unsure. config JFFS2_RUBIN bool "JFFS2 RUBIN compression support" if JFFS2_COMPRESSION_OPTIONS depends on JFFS2_FS default n - help - RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure. + help + RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure. choice - prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS - default JFFS2_CMODE_PRIORITY - depends on JFFS2_FS - help - You can set here the default compression mode of JFFS2 from - the available compression modes. Don't touch if unsure. + prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS + default JFFS2_CMODE_PRIORITY + depends on JFFS2_FS + help + You can set here the default compression mode of JFFS2 from + the available compression modes. Don't touch if unsure. config JFFS2_CMODE_NONE - bool "no compression" - help - Uses no compression. + bool "no compression" + help + Uses no compression. config JFFS2_CMODE_PRIORITY - bool "priority" - help - Tries the compressors in a predefined order and chooses the first - successful one. + bool "priority" + help + Tries the compressors in a predefined order and chooses the first + successful one. config JFFS2_CMODE_SIZE - bool "size (EXPERIMENTAL)" - help - Tries all compressors and chooses the one which has the smallest - result. + bool "size (EXPERIMENTAL)" + help + Tries all compressors and chooses the one which has the smallest + result. + +config JFFS2_CMODE_FAVOURLZO + bool "Favour LZO" + help + Tries all compressors and chooses the one which has the smallest + result but gives some preference to LZO (which has faster + decompression) at the expense of size. endchoice @@ -1516,8 +1548,20 @@ config UFS_DEBUG endmenu -menu "Network File Systems" +menuconfig NETWORK_FILESYSTEMS + bool "Network File Systems" + default y depends on NET + ---help--- + Say Y here to get to see options for network filesystems and + filesystem-related networking code, such as NFS daemon and + RPCSEC security modules. + This option alone does not add any kernel code. + + If you say N, all options in this submenu will be skipped and + disabled; if unsure, say Y here. + +if NETWORK_FILESYSTEMS config NFS_FS tristate "NFS file system support" @@ -1728,6 +1772,14 @@ config SUNRPC config SUNRPC_GSS tristate +config SUNRPC_XPRT_RDMA + tristate "RDMA transport for sunrpc (EXPERIMENTAL)" + depends on SUNRPC && INFINIBAND && EXPERIMENTAL + default m + help + Adds a client RPC transport for supporting kernel NFS over RDMA + mounts, including Infiniband and iWARP. Experimental. + config SUNRPC_BIND34 bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)" depends on SUNRPC && EXPERIMENTAL @@ -2055,7 +2107,7 @@ config 9P_FS If unsure, say N. -endmenu +endif # NETWORK_FILESYSTEMS if BLOCK menu "Partition Types" diff --git a/fs/Makefile b/fs/Makefile index 720c29d57a62..500cf15cdb4b 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -72,7 +72,7 @@ obj-$(CONFIG_JBD) += jbd/ obj-$(CONFIG_JBD2) += jbd2/ obj-$(CONFIG_EXT2_FS) += ext2/ obj-$(CONFIG_CRAMFS) += cramfs/ -obj-$(CONFIG_RAMFS) += ramfs/ +obj-y += ramfs/ obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ obj-$(CONFIG_CODA_FS) += coda/ obj-$(CONFIG_MINIX_FS) += minix/ diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c index 7e7a04be1278..e647200262a2 100644 --- a/fs/adfs/inode.c +++ b/fs/adfs/inode.c @@ -61,10 +61,14 @@ static int adfs_readpage(struct file *file, struct page *page) return block_read_full_page(page, adfs_get_block); } -static int adfs_prepare_write(struct file *file, struct page *page, unsigned int from, unsigned int to) +static int adfs_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - return cont_prepare_write(page, from, to, adfs_get_block, - &ADFS_I(page->mapping->host)->mmu_private); + *pagep = NULL; + return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + adfs_get_block, + &ADFS_I(mapping->host)->mmu_private); } static sector_t _adfs_bmap(struct address_space *mapping, sector_t block) @@ -76,8 +80,8 @@ static const struct address_space_operations adfs_aops = { .readpage = adfs_readpage, .writepage = adfs_writepage, .sync_page = block_sync_page, - .prepare_write = adfs_prepare_write, - .commit_write = generic_commit_write, + .write_begin = adfs_write_begin, + .write_end = generic_write_end, .bmap = _adfs_bmap }; diff --git a/fs/adfs/super.c b/fs/adfs/super.c index 1c9fd3029496..b36695ae5c2e 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -228,7 +228,7 @@ static void adfs_destroy_inode(struct inode *inode) kmem_cache_free(adfs_inode_cachep, ADFS_I(inode)); } -static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(struct kmem_cache *cachep, void *foo) { struct adfs_inode_info *ei = (struct adfs_inode_info *) foo; diff --git a/fs/affs/bitmap.c b/fs/affs/bitmap.c index b330009fe42d..c4a5ad09ddf2 100644 --- a/fs/affs/bitmap.c +++ b/fs/affs/bitmap.c @@ -11,7 +11,7 @@ /* This is, of course, shamelessly stolen from fs/minix */ -static int nibblemap[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 }; +static const int nibblemap[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 }; static u32 affs_count_free_bits(u32 blocksize, const void *data) diff --git a/fs/affs/file.c b/fs/affs/file.c index c314a35f0918..6e0c9399200e 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -395,25 +395,33 @@ static int affs_writepage(struct page *page, struct writeback_control *wbc) { return block_write_full_page(page, affs_get_block, wbc); } + static int affs_readpage(struct file *file, struct page *page) { return block_read_full_page(page, affs_get_block); } -static int affs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) + +static int affs_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - return cont_prepare_write(page, from, to, affs_get_block, - &AFFS_I(page->mapping->host)->mmu_private); + *pagep = NULL; + return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + affs_get_block, + &AFFS_I(mapping->host)->mmu_private); } + static sector_t _affs_bmap(struct address_space *mapping, sector_t block) { return generic_block_bmap(mapping,block,affs_get_block); } + const struct address_space_operations affs_aops = { .readpage = affs_readpage, .writepage = affs_writepage, .sync_page = block_sync_page, - .prepare_write = affs_prepare_write, - .commit_write = generic_commit_write, + .write_begin = affs_write_begin, + .write_end = generic_write_end, .bmap = _affs_bmap }; @@ -603,54 +611,65 @@ affs_readpage_ofs(struct file *file, struct page *page) return err; } -static int affs_prepare_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to) +static int affs_write_begin_ofs(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - struct inode *inode = page->mapping->host; - u32 size, offset; - u32 tmp; + struct inode *inode = mapping->host; + struct page *page; + pgoff_t index; int err = 0; - pr_debug("AFFS: prepare_write(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to); - offset = page->index << PAGE_CACHE_SHIFT; - if (offset + from > AFFS_I(inode)->mmu_private) { - err = affs_extent_file_ofs(inode, offset + from); + pr_debug("AFFS: write_begin(%u, %llu, %llu)\n", (u32)inode->i_ino, (unsigned long long)pos, (unsigned long long)pos + len); + if (pos > AFFS_I(inode)->mmu_private) { + /* XXX: this probably leaves a too-big i_size in case of + * failure. Should really be updating i_size at write_end time + */ + err = affs_extent_file_ofs(inode, pos); if (err) return err; } - size = inode->i_size; + + index = pos >> PAGE_CACHE_SHIFT; + page = __grab_cache_page(mapping, index); + if (!page) + return -ENOMEM; + *pagep = page; if (PageUptodate(page)) return 0; - if (from) { - err = affs_do_readpage_ofs(file, page, 0, from); - if (err) - return err; - } - if (to < PAGE_CACHE_SIZE) { - zero_user_page(page, to, PAGE_CACHE_SIZE - to, KM_USER0); - if (size > offset + to) { - if (size < offset + PAGE_CACHE_SIZE) - tmp = size & ~PAGE_CACHE_MASK; - else - tmp = PAGE_CACHE_SIZE; - err = affs_do_readpage_ofs(file, page, to, tmp); - } + /* XXX: inefficient but safe in the face of short writes */ + err = affs_do_readpage_ofs(file, page, 0, PAGE_CACHE_SIZE); + if (err) { + unlock_page(page); + page_cache_release(page); } return err; } -static int affs_commit_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to) +static int affs_write_end_ofs(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) { - struct inode *inode = page->mapping->host; + struct inode *inode = mapping->host; struct super_block *sb = inode->i_sb; struct buffer_head *bh, *prev_bh; char *data; u32 bidx, boff, bsize; + unsigned from, to; u32 tmp; int written; - pr_debug("AFFS: commit_write(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to); + from = pos & (PAGE_CACHE_SIZE - 1); + to = pos + len; + /* + * XXX: not sure if this can handle short copies (len < copied), but + * we don't have to, because the page should always be uptodate here, + * due to write_begin. + */ + + pr_debug("AFFS: write_begin(%u, %llu, %llu)\n", (u32)inode->i_ino, (unsigned long long)pos, (unsigned long long)pos + len); bsize = AFFS_SB(sb)->s_data_blksize; data = page_address(page); @@ -748,6 +767,9 @@ done: if (tmp > inode->i_size) inode->i_size = AFFS_I(inode)->mmu_private = tmp; + unlock_page(page); + page_cache_release(page); + return written; out: @@ -761,8 +783,8 @@ const struct address_space_operations affs_aops_ofs = { .readpage = affs_readpage_ofs, //.writepage = affs_writepage_ofs, //.sync_page = affs_sync_page_ofs, - .prepare_write = affs_prepare_write_ofs, - .commit_write = affs_commit_write_ofs + .write_begin = affs_write_begin_ofs, + .write_end = affs_write_end_ofs }; /* Free any preallocated blocks. */ @@ -805,18 +827,13 @@ affs_truncate(struct inode *inode) if (inode->i_size > AFFS_I(inode)->mmu_private) { struct address_space *mapping = inode->i_mapping; struct page *page; - u32 size = inode->i_size - 1; + void *fsdata; + u32 size = inode->i_size; int res; - page = grab_cache_page(mapping, size >> PAGE_CACHE_SHIFT); - if (!page) - return; - size = (size & (PAGE_CACHE_SIZE - 1)) + 1; - res = mapping->a_ops->prepare_write(NULL, page, size, size); + res = mapping->a_ops->write_begin(NULL, mapping, size, 0, 0, &page, &fsdata); if (!res) - res = mapping->a_ops->commit_write(NULL, page, size, size); - unlock_page(page); - page_cache_release(page); + res = mapping->a_ops->write_end(NULL, mapping, size, 0, 0, page, fsdata); mark_inode_dirty(inode); return; } else if (inode->i_size == AFFS_I(inode)->mmu_private) diff --git a/fs/affs/super.c b/fs/affs/super.c index c80191ae2059..b53e5d0ec65c 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -84,7 +84,7 @@ static void affs_destroy_inode(struct inode *inode) kmem_cache_free(affs_inode_cachep, AFFS_I(inode)); } -static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(struct kmem_cache *cachep, void *foo) { struct affs_inode_info *ei = (struct affs_inode_info *) foo; diff --git a/fs/afs/callback.c b/fs/afs/callback.c index b8243945818d..a78d5b236bb1 100644 --- a/fs/afs/callback.c +++ b/fs/afs/callback.c @@ -20,7 +20,9 @@ #include <linux/sched.h> #include "internal.h" +#if 0 unsigned afs_vnode_update_timeout = 10; +#endif /* 0 */ #define afs_breakring_space(server) \ CIRC_SPACE((server)->cb_break_head, (server)->cb_break_tail, \ diff --git a/fs/afs/cell.c b/fs/afs/cell.c index 175a567db78c..970d38f30565 100644 --- a/fs/afs/cell.c +++ b/fs/afs/cell.c @@ -33,6 +33,7 @@ static struct afs_cell *afs_cell_root; static struct afs_cell *afs_cell_alloc(const char *name, char *vllist) { struct afs_cell *cell; + struct key *key; size_t namelen; char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next; int ret; @@ -89,20 +90,14 @@ static struct afs_cell *afs_cell_alloc(const char *name, char *vllist) do { *dp++ = toupper(*cp); } while (*cp++); - cell->anonymous_key = key_alloc(&key_type_rxrpc, keyname, 0, 0, current, - KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA); - if (IS_ERR(cell->anonymous_key)) { - _debug("no key"); - ret = PTR_ERR(cell->anonymous_key); - goto error; - } - ret = key_instantiate_and_link(cell->anonymous_key, NULL, 0, - NULL, NULL); - if (ret < 0) { - _debug("instantiate failed"); + key = rxrpc_get_null_key(keyname); + if (IS_ERR(key)) { + _debug("no key"); + ret = PTR_ERR(key); goto error; } + cell->anonymous_key = key; _debug("anon key %p{%x}", cell->anonymous_key, key_serial(cell->anonymous_key)); @@ -265,6 +260,7 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz) return cell; } +#if 0 /* * try and get a cell record */ @@ -280,6 +276,7 @@ struct afs_cell *afs_get_cell_maybe(struct afs_cell *cell) write_unlock(&afs_cells_lock); return cell; } +#endif /* 0 */ /* * destroy a cell record diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c index d5b2ad6575bc..47b71c8947f9 100644 --- a/fs/afs/cmservice.c +++ b/fs/afs/cmservice.c @@ -16,7 +16,9 @@ #include "internal.h" #include "afs_cm.h" +#if 0 struct workqueue_struct *afs_cm_workqueue; +#endif /* 0 */ static int afs_deliver_cb_init_call_back_state(struct afs_call *, struct sk_buff *, bool); diff --git a/fs/afs/flock.c b/fs/afs/flock.c index af6952e39a18..210acafe4a9b 100644 --- a/fs/afs/flock.c +++ b/fs/afs/flock.c @@ -524,8 +524,7 @@ int afs_lock(struct file *file, int cmd, struct file_lock *fl) (long long) fl->fl_start, (long long) fl->fl_end); /* AFS doesn't support mandatory locks */ - if ((vnode->vfs_inode.i_mode & (S_ISGID | S_IXGRP)) == S_ISGID && - fl->fl_type != F_UNLCK) + if (__mandatory_lock(&vnode->vfs_inode) && fl->fl_type != F_UNLCK) return -ENOLCK; if (IS_GETLK(cmd)) diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 6306438f331f..5ca3625cd39e 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -570,7 +570,6 @@ extern int afs_abort_to_error(u32); */ extern const struct inode_operations afs_mntpt_inode_operations; extern const struct file_operations afs_mntpt_file_operations; -extern unsigned long afs_mntpt_expiry_timeout; extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *); extern void afs_mntpt_kill_timer(void); diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index 6f8c96fb29eb..5ce43b63c60e 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c @@ -42,7 +42,7 @@ const struct inode_operations afs_mntpt_inode_operations = { static LIST_HEAD(afs_vfsmounts); static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out); -unsigned long afs_mntpt_expiry_timeout = 10 * 60; +static unsigned long afs_mntpt_expiry_timeout = 10 * 60; /* * check a symbolic link to see whether it actually encodes a mountpoint diff --git a/fs/afs/netdevices.c b/fs/afs/netdevices.c index fc27d4b52e5f..49f189423063 100644 --- a/fs/afs/netdevices.c +++ b/fs/afs/netdevices.c @@ -8,6 +8,7 @@ #include <linux/inetdevice.h> #include <linux/netdevice.h> #include <linux/if_arp.h> +#include <net/net_namespace.h> #include "internal.h" /* @@ -23,7 +24,7 @@ int afs_get_MAC_address(u8 *mac, size_t maclen) BUG(); rtnl_lock(); - dev = __dev_getfirstbyhwtype(ARPHRD_ETHER); + dev = __dev_getfirstbyhwtype(&init_net, ARPHRD_ETHER); if (dev) { memcpy(mac, dev->dev_addr, maclen); ret = 0; @@ -47,7 +48,7 @@ int afs_get_ipv4_interfaces(struct afs_interface *bufs, size_t maxbufs, ASSERT(maxbufs > 0); rtnl_lock(); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (dev->type == ARPHRD_LOOPBACK && !wantloopback) continue; idev = __in_dev_get_rtnl(dev); diff --git a/fs/afs/proc.c b/fs/afs/proc.c index 6edb56683b9a..846c7615ac9e 100644 --- a/fs/afs/proc.c +++ b/fs/afs/proc.c @@ -513,7 +513,7 @@ static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v) up_read(&cell->vl_sem); } -const char afs_vlocation_states[][4] = { +static const char afs_vlocation_states[][4] = { [AFS_VL_NEW] = "New", [AFS_VL_CREATING] = "Crt", [AFS_VL_VALID] = "Val", diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index 8ccee9ee1d9d..bde3f19c0995 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -239,7 +239,8 @@ void afs_flat_call_destructor(struct afs_call *call) /* * attach the data from a bunch of pages on an inode to a call */ -int afs_send_pages(struct afs_call *call, struct msghdr *msg, struct kvec *iov) +static int afs_send_pages(struct afs_call *call, struct msghdr *msg, + struct kvec *iov) { struct page *pages[8]; unsigned count, n, loop, offset, to; diff --git a/fs/afs/server.c b/fs/afs/server.c index 231ae4150279..28f2451419e1 100644 --- a/fs/afs/server.c +++ b/fs/afs/server.c @@ -13,7 +13,7 @@ #include <linux/slab.h> #include "internal.h" -unsigned afs_server_timeout = 10; /* server timeout in seconds */ +static unsigned afs_server_timeout = 10; /* server timeout in seconds */ static void afs_reap_server(struct work_struct *); diff --git a/fs/afs/super.c b/fs/afs/super.c index b8808b40f82b..4b2558c42213 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -27,8 +27,7 @@ #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */ -static void afs_i_init_once(void *foo, struct kmem_cache *cachep, - unsigned long flags); +static void afs_i_init_once(struct kmem_cache *cachep, void *foo); static int afs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt); @@ -446,8 +445,7 @@ static void afs_put_super(struct super_block *sb) /* * initialise an inode cache slab element prior to any use */ -static void afs_i_init_once(void *_vnode, struct kmem_cache *cachep, - unsigned long flags) +static void afs_i_init_once(struct kmem_cache *cachep, void *_vnode) { struct afs_vnode *vnode = _vnode; diff --git a/fs/afs/vlocation.c b/fs/afs/vlocation.c index 09e3ad0fc7cc..7b4bbe48112d 100644 --- a/fs/afs/vlocation.c +++ b/fs/afs/vlocation.c @@ -15,8 +15,8 @@ #include <linux/sched.h> #include "internal.h" -unsigned afs_vlocation_timeout = 10; /* volume location timeout in seconds */ -unsigned afs_vlocation_update_timeout = 10 * 60; +static unsigned afs_vlocation_timeout = 10; /* volume location timeout in seconds */ +static unsigned afs_vlocation_update_timeout = 10 * 60; static void afs_vlocation_reaper(struct work_struct *); static void afs_vlocation_updater(struct work_struct *); @@ -335,7 +335,7 @@ static int afs_vlocation_fill_in_record(struct afs_vlocation *vl, /* * queue a vlocation record for updates */ -void afs_vlocation_queue_for_updates(struct afs_vlocation *vl) +static void afs_vlocation_queue_for_updates(struct afs_vlocation *vl) { struct afs_vlocation *xvl; diff --git a/fs/afs/write.c b/fs/afs/write.c index a03b92a0fe1d..9a849ad3c489 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c @@ -8,7 +8,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ - +#include <linux/backing-dev.h> #include <linux/slab.h> #include <linux/fs.h> #include <linux/pagemap.h> @@ -510,9 +510,9 @@ int afs_writepage(struct page *page, struct writeback_control *wbc) /* * write a region of pages back to the server */ -int afs_writepages_region(struct address_space *mapping, - struct writeback_control *wbc, - pgoff_t index, pgoff_t end, pgoff_t *_next) +static int afs_writepages_region(struct address_space *mapping, + struct writeback_control *wbc, + pgoff_t index, pgoff_t end, pgoff_t *_next) { struct backing_dev_info *bdi = mapping->backing_dev_info; struct afs_writeback *wb; @@ -303,7 +303,7 @@ static void wait_for_all_aios(struct kioctx *ctx) set_task_state(tsk, TASK_UNINTERRUPTIBLE); while (ctx->reqs_active) { spin_unlock_irq(&ctx->ctx_lock); - schedule(); + io_schedule(); set_task_state(tsk, TASK_UNINTERRUPTIBLE); spin_lock_irq(&ctx->ctx_lock); } @@ -323,7 +323,7 @@ ssize_t fastcall wait_on_sync_kiocb(struct kiocb *iocb) set_current_state(TASK_UNINTERRUPTIBLE); if (!iocb->ki_users) break; - schedule(); + io_schedule(); } __set_current_state(TASK_RUNNING); return iocb->ki_user_data; @@ -710,18 +710,9 @@ static ssize_t aio_run_iocb(struct kiocb *iocb) /* * Now we are all set to call the retry method in async - * context. By setting this thread's io_wait context - * to point to the wait queue entry inside the currently - * running iocb for the duration of the retry, we ensure - * that async notification wakeups are queued by the - * operation instead of blocking waits, and when notified, - * cause the iocb to be kicked for continuation (through - * the aio_wake_function callback). + * context. */ - BUG_ON(current->io_wait != NULL); - current->io_wait = &iocb->ki_wait; ret = retry(iocb); - current->io_wait = NULL; if (ret != -EIOCBRETRY && ret != -EIOCBQUEUED) { BUG_ON(!list_empty(&iocb->ki_wait.task_list)); @@ -1170,7 +1161,7 @@ retry: ret = 0; if (to.timed_out) /* Only check after read evt */ break; - schedule(); + io_schedule(); if (signal_pending(tsk)) { ret = -EINTR; break; @@ -1508,10 +1499,7 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb) * Simply triggers a retry of the operation via kick_iocb. * * This callback is specified in the wait queue entry in - * a kiocb (current->io_wait points to this wait queue - * entry when an aio operation executes; it is used - * instead of a synchronous wait when an i/o blocking - * condition is encountered during aio). + * a kiocb. * * Note: * This routine is executed with the wait queue lock held. diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index b4a75880f6fd..23321889d9b0 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c @@ -76,7 +76,6 @@ int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile, { struct qstr this; struct dentry *dentry; - struct inode *inode; struct file *file; int error, fd; @@ -86,15 +85,9 @@ int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile, if (!file) return -ENFILE; - inode = igrab(anon_inode_inode); - if (IS_ERR(inode)) { - error = PTR_ERR(inode); - goto err_put_filp; - } - error = get_unused_fd(); if (error < 0) - goto err_iput; + goto err_put_filp; fd = error; /* @@ -108,14 +101,22 @@ int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile, dentry = d_alloc(anon_inode_mnt->mnt_sb->s_root, &this); if (!dentry) goto err_put_unused_fd; + + /* + * We know the anon_inode inode count is always greater than zero, + * so we can avoid doing an igrab() and we can use an open-coded + * atomic_inc(). + */ + atomic_inc(&anon_inode_inode->i_count); + dentry->d_op = &anon_inodefs_dentry_operations; /* Do not publish this dentry inside the global dentry hash table */ dentry->d_flags &= ~DCACHE_UNHASHED; - d_instantiate(dentry, inode); + d_instantiate(dentry, anon_inode_inode); file->f_path.mnt = mntget(anon_inode_mnt); file->f_path.dentry = dentry; - file->f_mapping = inode->i_mapping; + file->f_mapping = anon_inode_inode->i_mapping; file->f_pos = 0; file->f_flags = O_RDWR; @@ -127,14 +128,12 @@ int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile, fd_install(fd, file); *pfd = fd; - *pinode = inode; + *pinode = anon_inode_inode; *pfile = file; return 0; err_put_unused_fd: put_unused_fd(fd); -err_iput: - iput(inode); err_put_filp: put_filp(file); return error; diff --git a/fs/attr.c b/fs/attr.c index f8dfc2269d85..966b73e25f82 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -103,12 +103,11 @@ EXPORT_SYMBOL(inode_setattr); int notify_change(struct dentry * dentry, struct iattr * attr) { struct inode *inode = dentry->d_inode; - mode_t mode; + mode_t mode = inode->i_mode; int error; struct timespec now; unsigned int ia_valid = attr->ia_valid; - mode = inode->i_mode; now = current_fs_time(inode->i_sb); attr->ia_ctime = now; @@ -116,18 +115,34 @@ int notify_change(struct dentry * dentry, struct iattr * attr) attr->ia_atime = now; if (!(ia_valid & ATTR_MTIME_SET)) attr->ia_mtime = now; + if (ia_valid & ATTR_KILL_PRIV) { + attr->ia_valid &= ~ATTR_KILL_PRIV; + ia_valid &= ~ATTR_KILL_PRIV; + error = security_inode_need_killpriv(dentry); + if (error > 0) + error = security_inode_killpriv(dentry); + if (error) + return error; + } + + /* + * We now pass ATTR_KILL_S*ID to the lower level setattr function so + * that the function has the ability to reinterpret a mode change + * that's due to these bits. This adds an implicit restriction that + * no function will ever call notify_change with both ATTR_MODE and + * ATTR_KILL_S*ID set. + */ + if ((ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) && + (ia_valid & ATTR_MODE)) + BUG(); + if (ia_valid & ATTR_KILL_SUID) { - attr->ia_valid &= ~ATTR_KILL_SUID; if (mode & S_ISUID) { - if (!(ia_valid & ATTR_MODE)) { - ia_valid = attr->ia_valid |= ATTR_MODE; - attr->ia_mode = inode->i_mode; - } - attr->ia_mode &= ~S_ISUID; + ia_valid = attr->ia_valid |= ATTR_MODE; + attr->ia_mode = (inode->i_mode & ~S_ISUID); } } if (ia_valid & ATTR_KILL_SGID) { - attr->ia_valid &= ~ ATTR_KILL_SGID; if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { if (!(ia_valid & ATTR_MODE)) { ia_valid = attr->ia_valid |= ATTR_MODE; @@ -136,7 +151,7 @@ int notify_change(struct dentry * dentry, struct iattr * attr) attr->ia_mode &= ~S_ISGID; } } - if (!attr->ia_valid) + if (!(attr->ia_valid & ~(ATTR_KILL_SUID | ATTR_KILL_SGID))) return 0; if (ia_valid & ATTR_SIZE) diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c index e7204d71acc9..45f5992a0957 100644 --- a/fs/autofs/inode.c +++ b/fs/autofs/inode.c @@ -80,7 +80,7 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, *uid = current->uid; *gid = current->gid; - *pgrp = process_group(current); + *pgrp = task_pgrp_nr(current); *minproto = *maxproto = AUTOFS_PROTO_VERSION; diff --git a/fs/autofs/root.c b/fs/autofs/root.c index c1489533277a..5efff3c0d886 100644 --- a/fs/autofs/root.c +++ b/fs/autofs/root.c @@ -214,8 +214,8 @@ static struct dentry *autofs_root_lookup(struct inode *dir, struct dentry *dentr oz_mode = autofs_oz_mode(sbi); DPRINTK(("autofs_lookup: pid = %u, pgrp = %u, catatonic = %d, " - "oz_mode = %d\n", pid_nr(task_pid(current)), - process_group(current), sbi->catatonic, + "oz_mode = %d\n", task_pid_nr(current), + task_pgrp_nr(current), sbi->catatonic, oz_mode)); /* @@ -536,7 +536,7 @@ static int autofs_root_ioctl(struct inode *inode, struct file *filp, struct autofs_sb_info *sbi = autofs_sbi(inode->i_sb); void __user *argp = (void __user *)arg; - DPRINTK(("autofs_ioctl: cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u\n",cmd,arg,sbi,process_group(current))); + DPRINTK(("autofs_ioctl: cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u\n",cmd,arg,sbi,task_pgrp_nr(current))); if (_IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) || _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT) diff --git a/fs/autofs/waitq.c b/fs/autofs/waitq.c index 19a9cafb5ddf..be46805972f0 100644 --- a/fs/autofs/waitq.c +++ b/fs/autofs/waitq.c @@ -182,7 +182,7 @@ int autofs_wait_release(struct autofs_sb_info *sbi, autofs_wqt_t wait_queue_toke { struct autofs_wait_queue *wq, **wql; - for ( wql = &sbi->queues ; (wq = *wql) != 0 ; wql = &wq->next ) { + for (wql = &sbi->queues; (wq = *wql) != NULL; wql = &wq->next) { if ( wq->wait_queue_token == wait_queue_token ) break; } diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index d85f42fa9206..2d4ae40718d9 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h @@ -131,7 +131,7 @@ static inline struct autofs_info *autofs4_dentry_ino(struct dentry *dentry) filesystem without "magic".) */ static inline int autofs4_oz_mode(struct autofs_sb_info *sbi) { - return sbi->catatonic || process_group(current) == sbi->oz_pgrp; + return sbi->catatonic || task_pgrp_nr(current) == sbi->oz_pgrp; } /* Does a dentry have some pending activity? */ diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index 692364e8ffc3..7f05d6ccdb13 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c @@ -226,7 +226,7 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, *uid = current->uid; *gid = current->gid; - *pgrp = process_group(current); + *pgrp = task_pgrp_nr(current); *minproto = AUTOFS_MIN_PROTO_VERSION; *maxproto = AUTOFS_MAX_PROTO_VERSION; @@ -312,20 +312,18 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) struct autofs_sb_info *sbi; struct autofs_info *ino; - sbi = kmalloc(sizeof(*sbi), GFP_KERNEL); + sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); if (!sbi) goto fail_unlock; DPRINTK("starting up, sbi = %p",sbi); - memset(sbi, 0, sizeof(*sbi)); - s->s_fs_info = sbi; sbi->magic = AUTOFS_SBI_MAGIC; sbi->pipefd = -1; sbi->pipe = NULL; sbi->catatonic = 1; sbi->exp_timeout = 0; - sbi->oz_pgrp = process_group(current); + sbi->oz_pgrp = task_pgrp_nr(current); sbi->sb = s; sbi->version = 0; sbi->sub_version = 0; diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 45ff3d63b758..2bbcc8151dc3 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -582,7 +582,7 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s oz_mode = autofs4_oz_mode(sbi); DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d", - current->pid, process_group(current), sbi->catatonic, oz_mode); + current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode); unhashed = autofs4_lookup_unhashed(sbi, dentry->d_parent, &dentry->d_name); if (!unhashed) { @@ -976,7 +976,7 @@ static int autofs4_root_ioctl(struct inode *inode, struct file *filp, void __user *p = (void __user *)arg; DPRINTK("cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u", - cmd,arg,sbi,process_group(current)); + cmd,arg,sbi,task_pgrp_nr(current)); if (_IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) || _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT) diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index 0d041a9cb348..1fe28e4754c2 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c @@ -376,7 +376,7 @@ int autofs4_wait_release(struct autofs_sb_info *sbi, autofs_wqt_t wait_queue_tok struct autofs_wait_queue *wq, **wql; mutex_lock(&sbi->wq_mutex); - for (wql = &sbi->queues ; (wq = *wql) != 0 ; wql = &wq->next) { + for (wql = &sbi->queues; (wq = *wql) != NULL; wql = &wq->next) { if (wq->wait_queue_token == wait_queue_token) break; } diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index a45141827681..b28a20e61b80 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -289,7 +289,7 @@ befs_destroy_inode(struct inode *inode) kmem_cache_free(befs_inode_cachep, BEFS_I(inode)); } -static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(struct kmem_cache *cachep, void *foo) { struct befs_inode_info *bi = (struct befs_inode_info *) foo; diff --git a/fs/bfs/file.c b/fs/bfs/file.c index 24310e9ee05a..911b4ccf470f 100644 --- a/fs/bfs/file.c +++ b/fs/bfs/file.c @@ -145,9 +145,13 @@ static int bfs_readpage(struct file *file, struct page *page) return block_read_full_page(page, bfs_get_block); } -static int bfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) +static int bfs_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - return block_prepare_write(page, from, to, bfs_get_block); + *pagep = NULL; + return block_write_begin(file, mapping, pos, len, flags, + pagep, fsdata, bfs_get_block); } static sector_t bfs_bmap(struct address_space *mapping, sector_t block) @@ -159,8 +163,8 @@ const struct address_space_operations bfs_aops = { .readpage = bfs_readpage, .writepage = bfs_writepage, .sync_page = block_sync_page, - .prepare_write = bfs_prepare_write, - .commit_write = generic_commit_write, + .write_begin = bfs_write_begin, + .write_end = generic_write_end, .bmap = bfs_bmap, }; diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index f346eb14e86f..7bd9c2bbe6ee 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -244,7 +244,7 @@ static void bfs_destroy_inode(struct inode *inode) kmem_cache_free(bfs_inode_cachep, BFS_I(inode)); } -static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(struct kmem_cache *cachep, void *foo) { struct bfs_inode_info *bi = foo; diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index 813a887cd2b3..e176d195e7e5 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -31,7 +31,7 @@ static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs); static int load_aout_library(struct file*); -static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file); +static int aout_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit); static struct linux_binfmt aout_format = { .module = THIS_MODULE, @@ -88,7 +88,7 @@ if (file->f_op->llseek) { \ * dumping of the process results in another error.. */ -static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file) +static int aout_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit) { mm_segment_t fs; int has_dumped = 0; @@ -123,23 +123,19 @@ static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file) /* If the size of the dump file exceeds the rlimit, then see what would happen if we wrote the stack, but not the data area. */ #ifdef __sparc__ - if ((dump.u_dsize+dump.u_ssize) > - current->signal->rlim[RLIMIT_CORE].rlim_cur) + if ((dump.u_dsize + dump.u_ssize) > limit) dump.u_dsize = 0; #else - if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE > - current->signal->rlim[RLIMIT_CORE].rlim_cur) + if ((dump.u_dsize + dump.u_ssize+1) * PAGE_SIZE > limit) dump.u_dsize = 0; #endif /* Make sure we have enough room to write the stack and data areas. */ #ifdef __sparc__ - if ((dump.u_ssize) > - current->signal->rlim[RLIMIT_CORE].rlim_cur) + if (dump.u_ssize > limit) dump.u_ssize = 0; #else - if ((dump.u_ssize+1) * PAGE_SIZE > - current->signal->rlim[RLIMIT_CORE].rlim_cur) + if ((dump.u_ssize + 1) * PAGE_SIZE > limit) dump.u_ssize = 0; #endif diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 4482a0673b15..ba8de7ca260b 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -52,7 +52,7 @@ static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, i * don't even try. */ #if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) -static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file); +static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit); #else #define elf_core_dump NULL #endif @@ -151,6 +151,14 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, struct vm_area_struct *vma; /* + * In some cases (e.g. Hyper-Threading), we want to avoid L1 + * evictions by the processes running on the same package. One + * thing we can do is to shuffle the initial stack for them. + */ + + p = arch_align_stack(p); + + /* * If this architecture has a platform capability string, copy it * to userspace. In some cases (Sparc), this info is impossible * for userspace to get any other way, in others (i386) it is @@ -160,14 +168,6 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, if (k_platform) { size_t len = strlen(k_platform) + 1; - /* - * In some cases (e.g. Hyper-Threading), we want to avoid L1 - * evictions by the processes running on the same package. One - * thing we can do is to shuffle the initial stack for them. - */ - - p = arch_align_stack(p); - u_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); if (__copy_to_user(u_platform, k_platform, len)) return -EFAULT; @@ -175,6 +175,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, /* Create the ELF interpreter info */ elf_info = (elf_addr_t *)current->mm->saved_auxv; + /* update AT_VECTOR_SIZE_BASE if the number of NEW_AUX_ENT() changes */ #define NEW_AUX_ENT(id, val) \ do { \ elf_info[ei_index++] = id; \ @@ -185,6 +186,8 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, /* * ARCH_DLINFO must come first so PPC can do its special alignment of * AUXV. + * update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT() in + * ARCH_DLINFO changes */ ARCH_DLINFO; #endif @@ -730,6 +733,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) /* Some simple consistency checks for the interpreter */ if (elf_interpreter) { + static int warn; interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; /* Now figure out which format our binary is */ @@ -741,6 +745,13 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0) interpreter_type &= ~INTERPRETER_ELF; + if (interpreter_type == INTERPRETER_AOUT && warn < 10) { + printk(KERN_WARNING "a.out ELF interpreter %s is " + "deprecated and will not be supported " + "after Linux 2.6.25\n", elf_interpreter); + warn++; + } + retval = -ELIBBAD; if (!interpreter_type) goto out_free_dentry; @@ -1193,35 +1204,68 @@ static int dump_seek(struct file *file, loff_t off) } /* - * Decide whether a segment is worth dumping; default is yes to be - * sure (missing info is worse than too much; etc). - * Personally I'd include everything, and use the coredump limit... - * - * I think we should skip something. But I am not sure how. H.J. + * Decide what to dump of a segment, part, all or none. */ -static int maydump(struct vm_area_struct *vma, unsigned long mm_flags) +static unsigned long vma_dump_size(struct vm_area_struct *vma, + unsigned long mm_flags) { /* The vma can be set up to tell us the answer directly. */ if (vma->vm_flags & VM_ALWAYSDUMP) - return 1; + goto whole; /* Do not dump I/O mapped devices or special mappings */ if (vma->vm_flags & (VM_IO | VM_RESERVED)) return 0; +#define FILTER(type) (mm_flags & (1UL << MMF_DUMP_##type)) + /* By default, dump shared memory if mapped from an anonymous file. */ if (vma->vm_flags & VM_SHARED) { - if (vma->vm_file->f_path.dentry->d_inode->i_nlink == 0) - return test_bit(MMF_DUMP_ANON_SHARED, &mm_flags); - else - return test_bit(MMF_DUMP_MAPPED_SHARED, &mm_flags); + if (vma->vm_file->f_path.dentry->d_inode->i_nlink == 0 ? + FILTER(ANON_SHARED) : FILTER(MAPPED_SHARED)) + goto whole; + return 0; } - /* By default, if it hasn't been written to, don't write it out. */ - if (!vma->anon_vma) - return test_bit(MMF_DUMP_MAPPED_PRIVATE, &mm_flags); + /* Dump segments that have been written to. */ + if (vma->anon_vma && FILTER(ANON_PRIVATE)) + goto whole; + if (vma->vm_file == NULL) + return 0; + + if (FILTER(MAPPED_PRIVATE)) + goto whole; - return test_bit(MMF_DUMP_ANON_PRIVATE, &mm_flags); + /* + * If this looks like the beginning of a DSO or executable mapping, + * check for an ELF header. If we find one, dump the first page to + * aid in determining what was mapped here. + */ + if (FILTER(ELF_HEADERS) && vma->vm_file != NULL && vma->vm_pgoff == 0) { + u32 __user *header = (u32 __user *) vma->vm_start; + u32 word; + /* + * Doing it this way gets the constant folded by GCC. + */ + union { + u32 cmp; + char elfmag[SELFMAG]; + } magic; + BUILD_BUG_ON(SELFMAG != sizeof word); + magic.elfmag[EI_MAG0] = ELFMAG0; + magic.elfmag[EI_MAG1] = ELFMAG1; + magic.elfmag[EI_MAG2] = ELFMAG2; + magic.elfmag[EI_MAG3] = ELFMAG3; + if (get_user(word, header) == 0 && word == magic.cmp) + return PAGE_SIZE; + } + +#undef FILTER + + return 0; + +whole: + return vma->vm_end - vma->vm_start; } /* An ELF note in memory */ @@ -1339,10 +1383,10 @@ static void fill_prstatus(struct elf_prstatus *prstatus, prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; prstatus->pr_sigpend = p->pending.signal.sig[0]; prstatus->pr_sighold = p->blocked.sig[0]; - prstatus->pr_pid = p->pid; - prstatus->pr_ppid = p->parent->pid; - prstatus->pr_pgrp = process_group(p); - prstatus->pr_sid = process_session(p); + prstatus->pr_pid = task_pid_vnr(p); + prstatus->pr_ppid = task_pid_vnr(p->parent); + prstatus->pr_pgrp = task_pgrp_vnr(p); + prstatus->pr_sid = task_session_vnr(p); if (thread_group_leader(p)) { /* * This is the record for the group leader. Add in the @@ -1385,10 +1429,10 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, psinfo->pr_psargs[i] = ' '; psinfo->pr_psargs[len] = 0; - psinfo->pr_pid = p->pid; - psinfo->pr_ppid = p->parent->pid; - psinfo->pr_pgrp = process_group(p); - psinfo->pr_sid = process_session(p); + psinfo->pr_pid = task_pid_vnr(p); + psinfo->pr_ppid = task_pid_vnr(p->parent); + psinfo->pr_pgrp = task_pgrp_vnr(p); + psinfo->pr_sid = task_session_vnr(p); i = p->state ? ffz(~p->state) + 1 : 0; psinfo->pr_state = i; @@ -1411,7 +1455,7 @@ struct elf_thread_status elf_fpregset_t fpu; /* NT_PRFPREG */ struct task_struct *thread; #ifdef ELF_CORE_COPY_XFPREGS - elf_fpxregset_t xfpu; /* NT_PRXFPREG */ + elf_fpxregset_t xfpu; /* ELF_CORE_XFPREG_TYPE */ #endif struct memelfnote notes[3]; int num_notes; @@ -1446,8 +1490,8 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t) #ifdef ELF_CORE_COPY_XFPREGS if (elf_core_copy_task_xfpregs(p, &t->xfpu)) { - fill_note(&t->notes[2], "LINUX", NT_PRXFPREG, sizeof(t->xfpu), - &t->xfpu); + fill_note(&t->notes[2], "LINUX", ELF_CORE_XFPREG_TYPE, + sizeof(t->xfpu), &t->xfpu); t->num_notes++; sz += notesize(&t->notes[2]); } @@ -1488,7 +1532,7 @@ static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma, * and then they are actually written out. If we run out of core limit * we just truncate. */ -static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) +static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit) { #define NUM_NOTES 6 int has_dumped = 0; @@ -1499,7 +1543,6 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) struct vm_area_struct *vma, *gate_vma; struct elfhdr *elf = NULL; loff_t offset = 0, dataoff, foffset; - unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; int numnote; struct memelfnote *notes = NULL; struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */ @@ -1514,9 +1557,6 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) int thread_status_size = 0; elf_addr_t *auxv; unsigned long mm_flags; -#ifdef ELF_CORE_WRITE_EXTRA_NOTES - int extra_notes_size; -#endif /* * We no longer stop all VM operations. @@ -1624,7 +1664,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) #ifdef ELF_CORE_COPY_XFPREGS if (elf_core_copy_task_xfpregs(current, xfpu)) fill_note(notes + numnote++, - "LINUX", NT_PRXFPREG, sizeof(*xfpu), xfpu); + "LINUX", ELF_CORE_XFPREG_TYPE, sizeof(*xfpu), xfpu); #endif fs = get_fs(); @@ -1645,10 +1685,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) sz += thread_status_size; -#ifdef ELF_CORE_WRITE_EXTRA_NOTES - extra_notes_size = ELF_CORE_EXTRA_NOTES_SIZE; - sz += extra_notes_size; -#endif + sz += elf_coredump_extra_notes_size(); fill_elf_note_phdr(&phdr, sz, offset); offset += sz; @@ -1668,16 +1705,13 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) for (vma = first_vma(current, gate_vma); vma != NULL; vma = next_vma(vma, gate_vma)) { struct elf_phdr phdr; - size_t sz; - - sz = vma->vm_end - vma->vm_start; phdr.p_type = PT_LOAD; phdr.p_offset = offset; phdr.p_vaddr = vma->vm_start; phdr.p_paddr = 0; - phdr.p_filesz = maydump(vma, mm_flags) ? sz : 0; - phdr.p_memsz = sz; + phdr.p_filesz = vma_dump_size(vma, mm_flags); + phdr.p_memsz = vma->vm_end - vma->vm_start; offset += phdr.p_filesz; phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; if (vma->vm_flags & VM_WRITE) @@ -1698,10 +1732,8 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) if (!writenote(notes + i, file, &foffset)) goto end_coredump; -#ifdef ELF_CORE_WRITE_EXTRA_NOTES - ELF_CORE_WRITE_EXTRA_NOTES; - foffset += extra_notes_size; -#endif + if (elf_coredump_extra_notes_write(file, &foffset)) + goto end_coredump; /* write out the thread status notes section */ list_for_each(t, &thread_list) { @@ -1719,13 +1751,11 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) for (vma = first_vma(current, gate_vma); vma != NULL; vma = next_vma(vma, gate_vma)) { unsigned long addr; + unsigned long end; - if (!maydump(vma, mm_flags)) - continue; + end = vma->vm_start + vma_dump_size(vma, mm_flags); - for (addr = vma->vm_start; - addr < vma->vm_end; - addr += PAGE_SIZE) { + for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) { struct page *page; struct vm_area_struct *vma; @@ -1733,7 +1763,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) &page, &vma) <= 0) { DUMP_SEEK(PAGE_SIZE); } else { - if (page == ZERO_PAGE(addr)) { + if (page == ZERO_PAGE(0)) { if (!dump_seek(file, PAGE_SIZE)) { page_cache_release(page); goto end_coredump; diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 2f5d8dbe676d..32649f2a1654 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -75,7 +75,7 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *, struct file *, struct mm_struct *); #if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) -static int elf_fdpic_core_dump(long, struct pt_regs *, struct file *); +static int elf_fdpic_core_dump(long, struct pt_regs *, struct file *, unsigned long limit); #endif static struct linux_binfmt elf_fdpic_format = { @@ -1342,10 +1342,10 @@ static void fill_prstatus(struct elf_prstatus *prstatus, prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; prstatus->pr_sigpend = p->pending.signal.sig[0]; prstatus->pr_sighold = p->blocked.sig[0]; - prstatus->pr_pid = p->pid; - prstatus->pr_ppid = p->parent->pid; - prstatus->pr_pgrp = process_group(p); - prstatus->pr_sid = process_session(p); + prstatus->pr_pid = task_pid_vnr(p); + prstatus->pr_ppid = task_pid_vnr(p->parent); + prstatus->pr_pgrp = task_pgrp_vnr(p); + prstatus->pr_sid = task_session_vnr(p); if (thread_group_leader(p)) { /* * This is the record for the group leader. Add in the @@ -1391,10 +1391,10 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, psinfo->pr_psargs[i] = ' '; psinfo->pr_psargs[len] = 0; - psinfo->pr_pid = p->pid; - psinfo->pr_ppid = p->parent->pid; - psinfo->pr_pgrp = process_group(p); - psinfo->pr_sid = process_session(p); + psinfo->pr_pid = task_pid_vnr(p); + psinfo->pr_ppid = task_pid_vnr(p->parent); + psinfo->pr_pgrp = task_pgrp_vnr(p); + psinfo->pr_sid = task_session_vnr(p); i = p->state ? ffz(~p->state) + 1 : 0; psinfo->pr_state = i; @@ -1417,7 +1417,7 @@ struct elf_thread_status elf_fpregset_t fpu; /* NT_PRFPREG */ struct task_struct *thread; #ifdef ELF_CORE_COPY_XFPREGS - elf_fpxregset_t xfpu; /* NT_PRXFPREG */ + elf_fpxregset_t xfpu; /* ELF_CORE_XFPREG_TYPE */ #endif struct memelfnote notes[3]; int num_notes; @@ -1453,8 +1453,8 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t) #ifdef ELF_CORE_COPY_XFPREGS if (elf_core_copy_task_xfpregs(p, &t->xfpu)) { - fill_note(&t->notes[2], "LINUX", NT_PRXFPREG, sizeof(t->xfpu), - &t->xfpu); + fill_note(&t->notes[2], "LINUX", ELF_CORE_XFPREG_TYPE, + sizeof(t->xfpu), &t->xfpu); t->num_notes++; sz += notesize(&t->notes[2]); } @@ -1488,7 +1488,7 @@ static int elf_fdpic_dump_segments(struct file *file, size_t *size, &page, &vma) <= 0) { DUMP_SEEK(file->f_pos + PAGE_SIZE); } - else if (page == ZERO_PAGE(addr)) { + else if (page == ZERO_PAGE(0)) { page_cache_release(page); DUMP_SEEK(file->f_pos + PAGE_SIZE); } @@ -1552,7 +1552,7 @@ static int elf_fdpic_dump_segments(struct file *file, size_t *size, * we just truncate. */ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs, - struct file *file) + struct file *file, unsigned long limit) { #define NUM_NOTES 6 int has_dumped = 0; @@ -1563,7 +1563,6 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs, struct vm_area_struct *vma; struct elfhdr *elf = NULL; loff_t offset = 0, dataoff; - unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; int numnote; struct memelfnote *notes = NULL; struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */ @@ -1690,7 +1689,7 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs, #ifdef ELF_CORE_COPY_XFPREGS if (elf_core_copy_task_xfpregs(current, xfpu)) fill_note(notes + numnote++, - "LINUX", NT_PRXFPREG, sizeof(*xfpu), xfpu); + "LINUX", ELF_CORE_XFPREG_TYPE, sizeof(*xfpu), xfpu); #endif fs = get_fs(); diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index fcb3405bb14e..33764fd6db66 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -75,7 +75,7 @@ static int load_flat_shared_library(int id, struct lib_info *p); #endif static int load_flat_binary(struct linux_binprm *, struct pt_regs * regs); -static int flat_core_dump(long signr, struct pt_regs * regs, struct file *file); +static int flat_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit); static struct linux_binfmt flat_format = { .module = THIS_MODULE, @@ -90,7 +90,7 @@ static struct linux_binfmt flat_format = { * Currently only a stub-function. */ -static int flat_core_dump(long signr, struct pt_regs * regs, struct file *file) +static int flat_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit) { printk("Process %s:%d received signr %d and should have core dumped\n", current->comm, current->pid, (int) signr); @@ -113,7 +113,7 @@ static unsigned long create_flat_tables( char * p = (char*)pp; int argc = bprm->argc; int envc = bprm->envc; - char dummy; + char uninitialized_var(dummy); sp = (unsigned long *) ((-(unsigned long)sizeof(char *))&(unsigned long) p); @@ -290,7 +290,6 @@ out_free_buf: kfree(buf); out_free: kfree(strm.workspace); -out: return retval; } @@ -459,7 +458,9 @@ static int load_flat_file(struct linux_binprm * bprm, printk("BINFMT_FLAT: Loading file: %s\n", bprm->filename); if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) { - printk("BINFMT_FLAT: bad flat file version 0x%x (supported 0x%x and 0x%x)\n", rev, FLAT_VERSION, OLD_FLAT_VERSION); + printk("BINFMT_FLAT: bad flat file version 0x%x (supported " + "0x%lx and 0x%lx)\n", + rev, FLAT_VERSION, OLD_FLAT_VERSION); ret = -ENOEXEC; goto err; } @@ -515,7 +516,8 @@ static int load_flat_file(struct linux_binprm * bprm, /* * calculate the extra space we need to map in */ - extra = max(bss_len + stack_len, relocs * sizeof(unsigned long)); + extra = max_t(unsigned long, bss_len + stack_len, + relocs * sizeof(unsigned long)); /* * there are a couple of cases here, the separate code/data @@ -546,7 +548,7 @@ static int load_flat_file(struct linux_binprm * bprm, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0); /* Remap to use all availabe slack region space */ if (realdatastart && (realdatastart < (unsigned long)-4096)) { - reallen = ksize(realdatastart); + reallen = ksize((void *)realdatastart); if (reallen > len) { realdatastart = do_mremap(realdatastart, len, reallen, MREMAP_FIXED, realdatastart); @@ -598,7 +600,7 @@ static int load_flat_file(struct linux_binprm * bprm, PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0); /* Remap to use all availabe slack region space */ if (textpos && (textpos < (unsigned long) -4096)) { - reallen = ksize(textpos); + reallen = ksize((void *)textpos); if (reallen > len) { textpos = do_mremap(textpos, len, reallen, MREMAP_FIXED, textpos); diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c index 5bcdaaf4eae0..9208c41209f9 100644 --- a/fs/binfmt_som.c +++ b/fs/binfmt_som.c @@ -44,7 +44,7 @@ static int load_som_library(struct file *); * don't even try. */ #if 0 -static int som_core_dump(long signr, struct pt_regs * regs); +static int som_core_dump(long signr, struct pt_regs *regs, unsigned long limit); #else #define som_core_dump NULL #endif @@ -109,11 +109,14 @@ static inline struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned lon void bio_free(struct bio *bio, struct bio_set *bio_set) { - const int pool_idx = BIO_POOL_IDX(bio); + if (bio->bi_io_vec) { + const int pool_idx = BIO_POOL_IDX(bio); - BIO_BUG_ON(pool_idx >= BIOVEC_NR_POOLS); + BIO_BUG_ON(pool_idx >= BIOVEC_NR_POOLS); + + mempool_free(bio->bi_io_vec, bio_set->bvec_pools[pool_idx]); + } - mempool_free(bio->bi_io_vec, bio_set->bvec_pools[pool_idx]); mempool_free(bio, bio_set->bio_pool); } @@ -127,21 +130,9 @@ static void bio_fs_destructor(struct bio *bio) void bio_init(struct bio *bio) { - bio->bi_next = NULL; - bio->bi_bdev = NULL; + memset(bio, 0, sizeof(*bio)); bio->bi_flags = 1 << BIO_UPTODATE; - bio->bi_rw = 0; - bio->bi_vcnt = 0; - bio->bi_idx = 0; - bio->bi_phys_segments = 0; - bio->bi_hw_segments = 0; - bio->bi_hw_front_size = 0; - bio->bi_hw_back_size = 0; - bio->bi_size = 0; - bio->bi_max_vecs = 0; - bio->bi_end_io = NULL; atomic_set(&bio->bi_cnt, 1); - bio->bi_private = NULL; } /** @@ -798,13 +789,9 @@ void bio_unmap_user(struct bio *bio) bio_put(bio); } -static int bio_map_kern_endio(struct bio *bio, unsigned int bytes_done, int err) +static void bio_map_kern_endio(struct bio *bio, int err) { - if (bio->bi_size) - return 1; - bio_put(bio); - return 0; } @@ -1002,34 +989,26 @@ void bio_check_pages_dirty(struct bio *bio) /** * bio_endio - end I/O on a bio * @bio: bio - * @bytes_done: number of bytes completed * @error: error, if any * * Description: - * bio_endio() will end I/O on @bytes_done number of bytes. This may be - * just a partial part of the bio, or it may be the whole bio. bio_endio() - * is the preferred way to end I/O on a bio, it takes care of decrementing - * bi_size and clearing BIO_UPTODATE on error. @error is 0 on success, and - * and one of the established -Exxxx (-EIO, for instance) error values in - * case something went wrong. Noone should call bi_end_io() directly on - * a bio unless they own it and thus know that it has an end_io function. + * bio_endio() will end I/O on the whole bio. bio_endio() is the + * preferred way to end I/O on a bio, it takes care of clearing + * BIO_UPTODATE on error. @error is 0 on success, and and one of the + * established -Exxxx (-EIO, for instance) error values in case + * something went wrong. Noone should call bi_end_io() directly on a + * bio unless they own it and thus know that it has an end_io + * function. **/ -void bio_endio(struct bio *bio, unsigned int bytes_done, int error) +void bio_endio(struct bio *bio, int error) { if (error) clear_bit(BIO_UPTODATE, &bio->bi_flags); - - if (unlikely(bytes_done > bio->bi_size)) { - printk("%s: want %u bytes done, only %u left\n", __FUNCTION__, - bytes_done, bio->bi_size); - bytes_done = bio->bi_size; - } - - bio->bi_size -= bytes_done; - bio->bi_sector += (bytes_done >> 9); + else if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) + error = -EIO; if (bio->bi_end_io) - bio->bi_end_io(bio, bytes_done, error); + bio->bi_end_io(bio, error); } void bio_pair_release(struct bio_pair *bp) @@ -1037,37 +1016,29 @@ void bio_pair_release(struct bio_pair *bp) if (atomic_dec_and_test(&bp->cnt)) { struct bio *master = bp->bio1.bi_private; - bio_endio(master, master->bi_size, bp->error); + bio_endio(master, bp->error); mempool_free(bp, bp->bio2.bi_private); } } -static int bio_pair_end_1(struct bio * bi, unsigned int done, int err) +static void bio_pair_end_1(struct bio *bi, int err) { struct bio_pair *bp = container_of(bi, struct bio_pair, bio1); if (err) bp->error = err; - if (bi->bi_size) - return 1; - bio_pair_release(bp); - return 0; } -static int bio_pair_end_2(struct bio * bi, unsigned int done, int err) +static void bio_pair_end_2(struct bio *bi, int err) { struct bio_pair *bp = container_of(bi, struct bio_pair, bio2); if (err) bp->error = err; - if (bi->bi_size) - return 1; - bio_pair_release(bp); - return 0; } /* diff --git a/fs/block_dev.c b/fs/block_dev.c index 2980eabe5779..993f78c55221 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -172,7 +172,7 @@ blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, } #if 0 -static int blk_end_aio(struct bio *bio, unsigned int bytes_done, int error) +static void blk_end_aio(struct bio *bio, int error) { struct kiocb *iocb = bio->bi_private; atomic_t *bio_count = &iocb->ki_bio_count; @@ -378,14 +378,26 @@ static int blkdev_readpage(struct file * file, struct page * page) return block_read_full_page(page, blkdev_get_block); } -static int blkdev_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) +static int blkdev_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - return block_prepare_write(page, from, to, blkdev_get_block); + *pagep = NULL; + return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + blkdev_get_block); } -static int blkdev_commit_write(struct file *file, struct page *page, unsigned from, unsigned to) +static int blkdev_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) { - return block_commit_write(page, from, to); + int ret; + ret = block_write_end(file, mapping, pos, len, copied, page, fsdata); + + unlock_page(page); + page_cache_release(page); + + return ret; } /* @@ -453,7 +465,7 @@ static void bdev_destroy_inode(struct inode *inode) kmem_cache_free(bdev_cachep, bdi); } -static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(struct kmem_cache * cachep, void *foo) { struct bdev_inode *ei = (struct bdev_inode *) foo; struct block_device *bdev = &ei->bdev; @@ -1327,8 +1339,8 @@ const struct address_space_operations def_blk_aops = { .readpage = blkdev_readpage, .writepage = blkdev_writepage, .sync_page = block_sync_page, - .prepare_write = blkdev_prepare_write, - .commit_write = blkdev_commit_write, + .write_begin = blkdev_write_begin, + .write_end = blkdev_write_end, .writepages = generic_writepages, .direct_IO = blkdev_direct_IO, }; diff --git a/fs/buffer.c b/fs/buffer.c index 0e5ec371ce72..76403b1764c5 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -110,10 +110,14 @@ static void buffer_io_error(struct buffer_head *bh) } /* - * Default synchronous end-of-IO handler.. Just mark it up-to-date and - * unlock the buffer. This is what ll_rw_block uses too. + * End-of-IO handler helper function which does not touch the bh after + * unlocking it. + * Note: unlock_buffer() sort-of does touch the bh after unlocking it, but + * a race there is benign: unlock_buffer() only use the bh's address for + * hashing after unlocking the buffer, so it doesn't actually touch the bh + * itself. */ -void end_buffer_read_sync(struct buffer_head *bh, int uptodate) +static void __end_buffer_read_notouch(struct buffer_head *bh, int uptodate) { if (uptodate) { set_buffer_uptodate(bh); @@ -122,6 +126,15 @@ void end_buffer_read_sync(struct buffer_head *bh, int uptodate) clear_buffer_uptodate(bh); } unlock_buffer(bh); +} + +/* + * Default synchronous end-of-IO handler.. Just mark it up-to-date and + * unlock the buffer. This is what ll_rw_block uses too. + */ +void end_buffer_read_sync(struct buffer_head *bh, int uptodate) +{ + __end_buffer_read_notouch(bh, uptodate); put_bh(bh); } @@ -697,6 +710,8 @@ static int __set_page_dirty(struct page *page, if (mapping_cap_account_dirty(mapping)) { __inc_zone_page_state(page, NR_FILE_DIRTY); + __inc_bdi_stat(mapping->backing_dev_info, + BDI_RECLAIMABLE); task_io_account_write(PAGE_CACHE_SIZE); } radix_tree_tag_set(&mapping->page_tree, @@ -1715,7 +1730,6 @@ done: * The page and buffer_heads can be released at any time from * here on. */ - wbc->pages_skipped++; /* We didn't write this page */ } return err; @@ -1757,6 +1771,48 @@ recover: goto done; } +/* + * If a page has any new buffers, zero them out here, and mark them uptodate + * and dirty so they'll be written out (in order to prevent uninitialised + * block data from leaking). And clear the new bit. + */ +void page_zero_new_buffers(struct page *page, unsigned from, unsigned to) +{ + unsigned int block_start, block_end; + struct buffer_head *head, *bh; + + BUG_ON(!PageLocked(page)); + if (!page_has_buffers(page)) + return; + + bh = head = page_buffers(page); + block_start = 0; + do { + block_end = block_start + bh->b_size; + + if (buffer_new(bh)) { + if (block_end > from && block_start < to) { + if (!PageUptodate(page)) { + unsigned start, size; + + start = max(from, block_start); + size = min(to, block_end) - start; + + zero_user_page(page, start, size, KM_USER0); + set_buffer_uptodate(bh); + } + + clear_buffer_new(bh); + mark_buffer_dirty(bh); + } + } + + block_start = block_end; + bh = bh->b_this_page; + } while (bh != head); +} +EXPORT_SYMBOL(page_zero_new_buffers); + static int __block_prepare_write(struct inode *inode, struct page *page, unsigned from, unsigned to, get_block_t *get_block) { @@ -1800,7 +1856,9 @@ static int __block_prepare_write(struct inode *inode, struct page *page, unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); if (PageUptodate(page)) { + clear_buffer_new(bh); set_buffer_uptodate(bh); + mark_buffer_dirty(bh); continue; } if (block_end > to || block_start < from) { @@ -1839,38 +1897,8 @@ static int __block_prepare_write(struct inode *inode, struct page *page, if (!buffer_uptodate(*wait_bh)) err = -EIO; } - if (!err) { - bh = head; - do { - if (buffer_new(bh)) - clear_buffer_new(bh); - } while ((bh = bh->b_this_page) != head); - return 0; - } - /* Error case: */ - /* - * Zero out any newly allocated blocks to avoid exposing stale - * data. If BH_New is set, we know that the block was newly - * allocated in the above loop. - */ - bh = head; - block_start = 0; - do { - block_end = block_start+blocksize; - if (block_end <= from) - goto next_bh; - if (block_start >= to) - break; - if (buffer_new(bh)) { - clear_buffer_new(bh); - zero_user_page(page, block_start, bh->b_size, KM_USER0); - set_buffer_uptodate(bh); - mark_buffer_dirty(bh); - } -next_bh: - block_start = block_end; - bh = bh->b_this_page; - } while (bh != head); + if (unlikely(err)) + page_zero_new_buffers(page, from, to); return err; } @@ -1895,6 +1923,7 @@ static int __block_commit_write(struct inode *inode, struct page *page, set_buffer_uptodate(bh); mark_buffer_dirty(bh); } + clear_buffer_new(bh); } /* @@ -1909,6 +1938,130 @@ static int __block_commit_write(struct inode *inode, struct page *page, } /* + * block_write_begin takes care of the basic task of block allocation and + * bringing partial write blocks uptodate first. + * + * If *pagep is not NULL, then block_write_begin uses the locked page + * at *pagep rather than allocating its own. In this case, the page will + * not be unlocked or deallocated on failure. + */ +int block_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata, + get_block_t *get_block) +{ + struct inode *inode = mapping->host; + int status = 0; + struct page *page; + pgoff_t index; + unsigned start, end; + int ownpage = 0; + + index = pos >> PAGE_CACHE_SHIFT; + start = pos & (PAGE_CACHE_SIZE - 1); + end = start + len; + + page = *pagep; + if (page == NULL) { + ownpage = 1; + page = __grab_cache_page(mapping, index); + if (!page) { + status = -ENOMEM; + goto out; + } + *pagep = page; + } else + BUG_ON(!PageLocked(page)); + + status = __block_prepare_write(inode, page, start, end, get_block); + if (unlikely(status)) { + ClearPageUptodate(page); + + if (ownpage) { + unlock_page(page); + page_cache_release(page); + *pagep = NULL; + + /* + * prepare_write() may have instantiated a few blocks + * outside i_size. Trim these off again. Don't need + * i_size_read because we hold i_mutex. + */ + if (pos + len > inode->i_size) + vmtruncate(inode, inode->i_size); + } + goto out; + } + +out: + return status; +} +EXPORT_SYMBOL(block_write_begin); + +int block_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) +{ + struct inode *inode = mapping->host; + unsigned start; + + start = pos & (PAGE_CACHE_SIZE - 1); + + if (unlikely(copied < len)) { + /* + * The buffers that were written will now be uptodate, so we + * don't have to worry about a readpage reading them and + * overwriting a partial write. However if we have encountered + * a short write and only partially written into a buffer, it + * will not be marked uptodate, so a readpage might come in and + * destroy our partial write. + * + * Do the simplest thing, and just treat any short write to a + * non uptodate page as a zero-length write, and force the + * caller to redo the whole thing. + */ + if (!PageUptodate(page)) + copied = 0; + + page_zero_new_buffers(page, start+copied, start+len); + } + flush_dcache_page(page); + + /* This could be a short (even 0-length) commit */ + __block_commit_write(inode, page, start, start+copied); + + return copied; +} +EXPORT_SYMBOL(block_write_end); + +int generic_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) +{ + struct inode *inode = mapping->host; + + copied = block_write_end(file, mapping, pos, len, copied, page, fsdata); + + /* + * No need to use i_size_read() here, the i_size + * cannot change under us because we hold i_mutex. + * + * But it's important to update i_size while still holding page lock: + * page writeout could otherwise come in and zero beyond i_size. + */ + if (pos+copied > inode->i_size) { + i_size_write(inode, pos+copied); + mark_inode_dirty(inode); + } + + unlock_page(page); + page_cache_release(page); + + return copied; +} +EXPORT_SYMBOL(generic_write_end); + +/* * Generic "read page" function for block devices that have the normal * get_block functionality. This is most of the block device filesystems. * Reads the page asynchronously --- the unlock_buffer() and @@ -2004,14 +2157,14 @@ int block_read_full_page(struct page *page, get_block_t *get_block) } /* utility function for filesystems that need to do work on expanding - * truncates. Uses prepare/commit_write to allow the filesystem to + * truncates. Uses filesystem pagecache writes to allow the filesystem to * deal with the hole. */ -static int __generic_cont_expand(struct inode *inode, loff_t size, - pgoff_t index, unsigned int offset) +int generic_cont_expand_simple(struct inode *inode, loff_t size) { struct address_space *mapping = inode->i_mapping; struct page *page; + void *fsdata; unsigned long limit; int err; @@ -2024,140 +2177,115 @@ static int __generic_cont_expand(struct inode *inode, loff_t size, if (size > inode->i_sb->s_maxbytes) goto out; - err = -ENOMEM; - page = grab_cache_page(mapping, index); - if (!page) - goto out; - err = mapping->a_ops->prepare_write(NULL, page, offset, offset); - if (err) { - /* - * ->prepare_write() may have instantiated a few blocks - * outside i_size. Trim these off again. - */ - unlock_page(page); - page_cache_release(page); - vmtruncate(inode, inode->i_size); + err = pagecache_write_begin(NULL, mapping, size, 0, + AOP_FLAG_UNINTERRUPTIBLE|AOP_FLAG_CONT_EXPAND, + &page, &fsdata); + if (err) goto out; - } - err = mapping->a_ops->commit_write(NULL, page, offset, offset); + err = pagecache_write_end(NULL, mapping, size, 0, 0, page, fsdata); + BUG_ON(err > 0); - unlock_page(page); - page_cache_release(page); - if (err > 0) - err = 0; out: return err; } -int generic_cont_expand(struct inode *inode, loff_t size) +int cont_expand_zero(struct file *file, struct address_space *mapping, + loff_t pos, loff_t *bytes) { - pgoff_t index; - unsigned int offset; + struct inode *inode = mapping->host; + unsigned blocksize = 1 << inode->i_blkbits; + struct page *page; + void *fsdata; + pgoff_t index, curidx; + loff_t curpos; + unsigned zerofrom, offset, len; + int err = 0; - offset = (size & (PAGE_CACHE_SIZE - 1)); /* Within page */ + index = pos >> PAGE_CACHE_SHIFT; + offset = pos & ~PAGE_CACHE_MASK; - /* ugh. in prepare/commit_write, if from==to==start of block, we - ** skip the prepare. make sure we never send an offset for the start - ** of a block - */ - if ((offset & (inode->i_sb->s_blocksize - 1)) == 0) { - /* caller must handle this extra byte. */ - offset++; - } - index = size >> PAGE_CACHE_SHIFT; + while (index > (curidx = (curpos = *bytes)>>PAGE_CACHE_SHIFT)) { + zerofrom = curpos & ~PAGE_CACHE_MASK; + if (zerofrom & (blocksize-1)) { + *bytes |= (blocksize-1); + (*bytes)++; + } + len = PAGE_CACHE_SIZE - zerofrom; - return __generic_cont_expand(inode, size, index, offset); -} + err = pagecache_write_begin(file, mapping, curpos, len, + AOP_FLAG_UNINTERRUPTIBLE, + &page, &fsdata); + if (err) + goto out; + zero_user_page(page, zerofrom, len, KM_USER0); + err = pagecache_write_end(file, mapping, curpos, len, len, + page, fsdata); + if (err < 0) + goto out; + BUG_ON(err != len); + err = 0; + } -int generic_cont_expand_simple(struct inode *inode, loff_t size) -{ - loff_t pos = size - 1; - pgoff_t index = pos >> PAGE_CACHE_SHIFT; - unsigned int offset = (pos & (PAGE_CACHE_SIZE - 1)) + 1; + /* page covers the boundary, find the boundary offset */ + if (index == curidx) { + zerofrom = curpos & ~PAGE_CACHE_MASK; + /* if we will expand the thing last block will be filled */ + if (offset <= zerofrom) { + goto out; + } + if (zerofrom & (blocksize-1)) { + *bytes |= (blocksize-1); + (*bytes)++; + } + len = offset - zerofrom; - /* prepare/commit_write can handle even if from==to==start of block. */ - return __generic_cont_expand(inode, size, index, offset); + err = pagecache_write_begin(file, mapping, curpos, len, + AOP_FLAG_UNINTERRUPTIBLE, + &page, &fsdata); + if (err) + goto out; + zero_user_page(page, zerofrom, len, KM_USER0); + err = pagecache_write_end(file, mapping, curpos, len, len, + page, fsdata); + if (err < 0) + goto out; + BUG_ON(err != len); + err = 0; + } +out: + return err; } /* * For moronic filesystems that do not allow holes in file. * We may have to extend the file. */ - -int cont_prepare_write(struct page *page, unsigned offset, - unsigned to, get_block_t *get_block, loff_t *bytes) +int cont_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata, + get_block_t *get_block, loff_t *bytes) { - struct address_space *mapping = page->mapping; struct inode *inode = mapping->host; - struct page *new_page; - pgoff_t pgpos; - long status; - unsigned zerofrom; unsigned blocksize = 1 << inode->i_blkbits; + unsigned zerofrom; + int err; - while(page->index > (pgpos = *bytes>>PAGE_CACHE_SHIFT)) { - status = -ENOMEM; - new_page = grab_cache_page(mapping, pgpos); - if (!new_page) - goto out; - /* we might sleep */ - if (*bytes>>PAGE_CACHE_SHIFT != pgpos) { - unlock_page(new_page); - page_cache_release(new_page); - continue; - } - zerofrom = *bytes & ~PAGE_CACHE_MASK; - if (zerofrom & (blocksize-1)) { - *bytes |= (blocksize-1); - (*bytes)++; - } - status = __block_prepare_write(inode, new_page, zerofrom, - PAGE_CACHE_SIZE, get_block); - if (status) - goto out_unmap; - zero_user_page(new_page, zerofrom, PAGE_CACHE_SIZE - zerofrom, - KM_USER0); - generic_commit_write(NULL, new_page, zerofrom, PAGE_CACHE_SIZE); - unlock_page(new_page); - page_cache_release(new_page); - } - - if (page->index < pgpos) { - /* completely inside the area */ - zerofrom = offset; - } else { - /* page covers the boundary, find the boundary offset */ - zerofrom = *bytes & ~PAGE_CACHE_MASK; - - /* if we will expand the thing last block will be filled */ - if (to > zerofrom && (zerofrom & (blocksize-1))) { - *bytes |= (blocksize-1); - (*bytes)++; - } + err = cont_expand_zero(file, mapping, pos, bytes); + if (err) + goto out; - /* starting below the boundary? Nothing to zero out */ - if (offset <= zerofrom) - zerofrom = offset; - } - status = __block_prepare_write(inode, page, zerofrom, to, get_block); - if (status) - goto out1; - if (zerofrom < offset) { - zero_user_page(page, zerofrom, offset - zerofrom, KM_USER0); - __block_commit_write(inode, page, zerofrom, offset); + zerofrom = *bytes & ~PAGE_CACHE_MASK; + if (pos+len > *bytes && zerofrom & (blocksize-1)) { + *bytes |= (blocksize-1); + (*bytes)++; } - return 0; -out1: - ClearPageUptodate(page); - return status; -out_unmap: - ClearPageUptodate(new_page); - unlock_page(new_page); - page_cache_release(new_page); + *pagep = NULL; + err = block_write_begin(file, mapping, pos, len, + flags, pagep, fsdata, get_block); out: - return status; + return err; } int block_prepare_write(struct page *page, unsigned from, unsigned to, @@ -2242,81 +2370,129 @@ out_unlock: } /* - * nobh_prepare_write()'s prereads are special: the buffer_heads are freed + * nobh_write_begin()'s prereads are special: the buffer_heads are freed * immediately, while under the page lock. So it needs a special end_io * handler which does not touch the bh after unlocking it. - * - * Note: unlock_buffer() sort-of does touch the bh after unlocking it, but - * a race there is benign: unlock_buffer() only use the bh's address for - * hashing after unlocking the buffer, so it doesn't actually touch the bh - * itself. */ static void end_buffer_read_nobh(struct buffer_head *bh, int uptodate) { - if (uptodate) { - set_buffer_uptodate(bh); - } else { - /* This happens, due to failed READA attempts. */ - clear_buffer_uptodate(bh); - } - unlock_buffer(bh); + __end_buffer_read_notouch(bh, uptodate); +} + +/* + * Attach the singly-linked list of buffers created by nobh_write_begin, to + * the page (converting it to circular linked list and taking care of page + * dirty races). + */ +static void attach_nobh_buffers(struct page *page, struct buffer_head *head) +{ + struct buffer_head *bh; + + BUG_ON(!PageLocked(page)); + + spin_lock(&page->mapping->private_lock); + bh = head; + do { + if (PageDirty(page)) + set_buffer_dirty(bh); + if (!bh->b_this_page) + bh->b_this_page = head; + bh = bh->b_this_page; + } while (bh != head); + attach_page_buffers(page, head); + spin_unlock(&page->mapping->private_lock); } /* * On entry, the page is fully not uptodate. * On exit the page is fully uptodate in the areas outside (from,to) */ -int nobh_prepare_write(struct page *page, unsigned from, unsigned to, +int nobh_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata, get_block_t *get_block) { - struct inode *inode = page->mapping->host; + struct inode *inode = mapping->host; const unsigned blkbits = inode->i_blkbits; const unsigned blocksize = 1 << blkbits; - struct buffer_head map_bh; - struct buffer_head *read_bh[MAX_BUF_PER_PAGE]; + struct buffer_head *head, *bh; + struct page *page; + pgoff_t index; + unsigned from, to; unsigned block_in_page; - unsigned block_start; + unsigned block_start, block_end; sector_t block_in_file; char *kaddr; int nr_reads = 0; - int i; int ret = 0; int is_mapped_to_disk = 1; + index = pos >> PAGE_CACHE_SHIFT; + from = pos & (PAGE_CACHE_SIZE - 1); + to = from + len; + + page = __grab_cache_page(mapping, index); + if (!page) + return -ENOMEM; + *pagep = page; + *fsdata = NULL; + + if (page_has_buffers(page)) { + unlock_page(page); + page_cache_release(page); + *pagep = NULL; + return block_write_begin(file, mapping, pos, len, flags, pagep, + fsdata, get_block); + } + if (PageMappedToDisk(page)) return 0; + /* + * Allocate buffers so that we can keep track of state, and potentially + * attach them to the page if an error occurs. In the common case of + * no error, they will just be freed again without ever being attached + * to the page (which is all OK, because we're under the page lock). + * + * Be careful: the buffer linked list is a NULL terminated one, rather + * than the circular one we're used to. + */ + head = alloc_page_buffers(page, blocksize, 0); + if (!head) { + ret = -ENOMEM; + goto out_release; + } + block_in_file = (sector_t)page->index << (PAGE_CACHE_SHIFT - blkbits); - map_bh.b_page = page; /* * We loop across all blocks in the page, whether or not they are * part of the affected region. This is so we can discover if the * page is fully mapped-to-disk. */ - for (block_start = 0, block_in_page = 0; + for (block_start = 0, block_in_page = 0, bh = head; block_start < PAGE_CACHE_SIZE; - block_in_page++, block_start += blocksize) { - unsigned block_end = block_start + blocksize; + block_in_page++, block_start += blocksize, bh = bh->b_this_page) { int create; - map_bh.b_state = 0; + block_end = block_start + blocksize; + bh->b_state = 0; create = 1; if (block_start >= to) create = 0; - map_bh.b_size = blocksize; ret = get_block(inode, block_in_file + block_in_page, - &map_bh, create); + bh, create); if (ret) goto failed; - if (!buffer_mapped(&map_bh)) + if (!buffer_mapped(bh)) is_mapped_to_disk = 0; - if (buffer_new(&map_bh)) - unmap_underlying_metadata(map_bh.b_bdev, - map_bh.b_blocknr); - if (PageUptodate(page)) + if (buffer_new(bh)) + unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); + if (PageUptodate(page)) { + set_buffer_uptodate(bh); continue; - if (buffer_new(&map_bh) || !buffer_mapped(&map_bh)) { + } + if (buffer_new(bh) || !buffer_mapped(bh)) { kaddr = kmap_atomic(page, KM_USER0); if (block_start < from) memset(kaddr+block_start, 0, from-block_start); @@ -2326,49 +2502,26 @@ int nobh_prepare_write(struct page *page, unsigned from, unsigned to, kunmap_atomic(kaddr, KM_USER0); continue; } - if (buffer_uptodate(&map_bh)) + if (buffer_uptodate(bh)) continue; /* reiserfs does this */ if (block_start < from || block_end > to) { - struct buffer_head *bh = alloc_buffer_head(GFP_NOFS); - - if (!bh) { - ret = -ENOMEM; - goto failed; - } - bh->b_state = map_bh.b_state; - atomic_set(&bh->b_count, 0); - bh->b_this_page = NULL; - bh->b_page = page; - bh->b_blocknr = map_bh.b_blocknr; - bh->b_size = blocksize; - bh->b_data = (char *)(long)block_start; - bh->b_bdev = map_bh.b_bdev; - bh->b_private = NULL; - read_bh[nr_reads++] = bh; + lock_buffer(bh); + bh->b_end_io = end_buffer_read_nobh; + submit_bh(READ, bh); + nr_reads++; } } if (nr_reads) { - struct buffer_head *bh; - /* * The page is locked, so these buffers are protected from * any VM or truncate activity. Hence we don't need to care * for the buffer_head refcounts. */ - for (i = 0; i < nr_reads; i++) { - bh = read_bh[i]; - lock_buffer(bh); - bh->b_end_io = end_buffer_read_nobh; - submit_bh(READ, bh); - } - for (i = 0; i < nr_reads; i++) { - bh = read_bh[i]; + for (bh = head; bh; bh = bh->b_this_page) { wait_on_buffer(bh); if (!buffer_uptodate(bh)) ret = -EIO; - free_buffer_head(bh); - read_bh[i] = NULL; } if (ret) goto failed; @@ -2377,44 +2530,70 @@ int nobh_prepare_write(struct page *page, unsigned from, unsigned to, if (is_mapped_to_disk) SetPageMappedToDisk(page); + *fsdata = head; /* to be released by nobh_write_end */ + return 0; failed: - for (i = 0; i < nr_reads; i++) { - if (read_bh[i]) - free_buffer_head(read_bh[i]); - } - + BUG_ON(!ret); /* - * Error recovery is pretty slack. Clear the page and mark it dirty - * so we'll later zero out any blocks which _were_ allocated. + * Error recovery is a bit difficult. We need to zero out blocks that + * were newly allocated, and dirty them to ensure they get written out. + * Buffers need to be attached to the page at this point, otherwise + * the handling of potential IO errors during writeout would be hard + * (could try doing synchronous writeout, but what if that fails too?) */ - zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0); - SetPageUptodate(page); - set_page_dirty(page); + attach_nobh_buffers(page, head); + page_zero_new_buffers(page, from, to); + +out_release: + unlock_page(page); + page_cache_release(page); + *pagep = NULL; + + if (pos + len > inode->i_size) + vmtruncate(inode, inode->i_size); + return ret; } -EXPORT_SYMBOL(nobh_prepare_write); +EXPORT_SYMBOL(nobh_write_begin); -/* - * Make sure any changes to nobh_commit_write() are reflected in - * nobh_truncate_page(), since it doesn't call commit_write(). - */ -int nobh_commit_write(struct file *file, struct page *page, - unsigned from, unsigned to) +int nobh_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) { struct inode *inode = page->mapping->host; - loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + struct buffer_head *head = NULL; + struct buffer_head *bh; + + if (!PageMappedToDisk(page)) { + if (unlikely(copied < len) && !page_has_buffers(page)) + attach_nobh_buffers(page, head); + if (page_has_buffers(page)) + return generic_write_end(file, mapping, pos, len, + copied, page, fsdata); + } SetPageUptodate(page); set_page_dirty(page); - if (pos > inode->i_size) { - i_size_write(inode, pos); + if (pos+copied > inode->i_size) { + i_size_write(inode, pos+copied); mark_inode_dirty(inode); } - return 0; + + unlock_page(page); + page_cache_release(page); + + head = fsdata; + while (head) { + bh = head; + head = head->b_this_page; + free_buffer_head(bh); + } + + return copied; } -EXPORT_SYMBOL(nobh_commit_write); +EXPORT_SYMBOL(nobh_write_end); /* * nobh_writepage() - based on block_full_write_page() except @@ -2467,44 +2646,79 @@ out: } EXPORT_SYMBOL(nobh_writepage); -/* - * This function assumes that ->prepare_write() uses nobh_prepare_write(). - */ -int nobh_truncate_page(struct address_space *mapping, loff_t from) +int nobh_truncate_page(struct address_space *mapping, + loff_t from, get_block_t *get_block) { - struct inode *inode = mapping->host; - unsigned blocksize = 1 << inode->i_blkbits; pgoff_t index = from >> PAGE_CACHE_SHIFT; unsigned offset = from & (PAGE_CACHE_SIZE-1); - unsigned to; + unsigned blocksize; + sector_t iblock; + unsigned length, pos; + struct inode *inode = mapping->host; struct page *page; - const struct address_space_operations *a_ops = mapping->a_ops; - int ret = 0; + struct buffer_head map_bh; + int err; - if ((offset & (blocksize - 1)) == 0) - goto out; + blocksize = 1 << inode->i_blkbits; + length = offset & (blocksize - 1); + + /* Block boundary? Nothing to do */ + if (!length) + return 0; + + length = blocksize - length; + iblock = (sector_t)index << (PAGE_CACHE_SHIFT - inode->i_blkbits); - ret = -ENOMEM; page = grab_cache_page(mapping, index); + err = -ENOMEM; if (!page) goto out; - to = (offset + blocksize) & ~(blocksize - 1); - ret = a_ops->prepare_write(NULL, page, offset, to); - if (ret == 0) { - zero_user_page(page, offset, PAGE_CACHE_SIZE - offset, - KM_USER0); - /* - * It would be more correct to call aops->commit_write() - * here, but this is more efficient. - */ - SetPageUptodate(page); - set_page_dirty(page); + if (page_has_buffers(page)) { +has_buffers: + unlock_page(page); + page_cache_release(page); + return block_truncate_page(mapping, from, get_block); + } + + /* Find the buffer that contains "offset" */ + pos = blocksize; + while (offset >= pos) { + iblock++; + pos += blocksize; } + + err = get_block(inode, iblock, &map_bh, 0); + if (err) + goto unlock; + /* unmapped? It's a hole - nothing to do */ + if (!buffer_mapped(&map_bh)) + goto unlock; + + /* Ok, it's mapped. Make sure it's up-to-date */ + if (!PageUptodate(page)) { + err = mapping->a_ops->readpage(NULL, page); + if (err) { + page_cache_release(page); + goto out; + } + lock_page(page); + if (!PageUptodate(page)) { + err = -EIO; + goto unlock; + } + if (page_has_buffers(page)) + goto has_buffers; + } + zero_user_page(page, offset, length, KM_USER0); + set_page_dirty(page); + err = 0; + +unlock: unlock_page(page); page_cache_release(page); out: - return ret; + return err; } EXPORT_SYMBOL(nobh_truncate_page); @@ -2634,13 +2848,10 @@ sector_t generic_block_bmap(struct address_space *mapping, sector_t block, return tmp.b_blocknr; } -static int end_bio_bh_io_sync(struct bio *bio, unsigned int bytes_done, int err) +static void end_bio_bh_io_sync(struct bio *bio, int err) { struct buffer_head *bh = bio->bi_private; - if (bio->bi_size) - return 1; - if (err == -EOPNOTSUPP) { set_bit(BIO_EOPNOTSUPP, &bio->bi_flags); set_bit(BH_Eopnotsupp, &bh->b_state); @@ -2648,7 +2859,6 @@ static int end_bio_bh_io_sync(struct bio *bio, unsigned int bytes_done, int err) bh->b_end_io(bh, test_bit(BIO_UPTODATE, &bio->bi_flags)); bio_put(bio); - return 0; } int submit_bh(int rw, struct buffer_head * bh) @@ -2960,7 +3170,8 @@ static void recalc_bh_state(void) struct buffer_head *alloc_buffer_head(gfp_t gfp_flags) { - struct buffer_head *ret = kmem_cache_zalloc(bh_cachep, gfp_flags); + struct buffer_head *ret = kmem_cache_zalloc(bh_cachep, + set_migrateflags(gfp_flags, __GFP_RECLAIMABLE)); if (ret) { INIT_LIST_HEAD(&ret->b_assoc_buffers); get_cpu_var(bh_accounting).nr++; @@ -3028,14 +3239,13 @@ EXPORT_SYMBOL(block_read_full_page); EXPORT_SYMBOL(block_sync_page); EXPORT_SYMBOL(block_truncate_page); EXPORT_SYMBOL(block_write_full_page); -EXPORT_SYMBOL(cont_prepare_write); +EXPORT_SYMBOL(cont_write_begin); EXPORT_SYMBOL(end_buffer_read_sync); EXPORT_SYMBOL(end_buffer_write_sync); EXPORT_SYMBOL(file_fsync); EXPORT_SYMBOL(fsync_bdev); EXPORT_SYMBOL(generic_block_bmap); EXPORT_SYMBOL(generic_commit_write); -EXPORT_SYMBOL(generic_cont_expand); EXPORT_SYMBOL(generic_cont_expand_simple); EXPORT_SYMBOL(init_buffer); EXPORT_SYMBOL(invalidate_bdev); diff --git a/fs/char_dev.c b/fs/char_dev.c index bbbf07baa145..c3bfa76765c4 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -545,6 +545,7 @@ static struct kobject *base_probe(dev_t dev, int *part, void *data) void __init chrdev_init(void) { cdev_map = kobj_map_init(base_probe, &chrdevs_lock); + bdi_init(&directly_mappable_cdev_bdi); } diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index bed6215c0794..3d419163c3d3 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,3 +1,19 @@ +Version 1.51 +------------ +Fix memory leak in statfs when mounted to very old servers (e.g. +Windows 9x). Add new feature "POSIX open" which allows servers +which support the current POSIX Extensions to provide better semantics +(e.g. delete for open files opened with posix open). Take into +account umask on posix mkdir not just older style mkdir. Add +ability to mount to IPC$ share (which allows CIFS named pipes to be +opened, read and written as if they were files). When 1st tree +connect fails (e.g. due to signing negotiation failure) fix +leak that causes cifsd not to stop and rmmod to fail to cleanup +cifs_request_buffers pool. Fix problem with POSIX Open/Mkdir on +bigendian architectures. Fix possible memory corruption when +EAGAIN returned on kern_recvmsg. Return better error if server +requires packet signing but client has disabled it. + Version 1.50 ------------ Fix NTLMv2 signing. NFS server mounted over cifs works (if cifs mount is @@ -6,7 +22,10 @@ done with "serverino" mount option). Add support for POSIX Unlink Samba supports newer POSIX CIFS Protocol Extensions). Add "nounix" mount option to allow disabling the CIFS Unix Extensions for just that mount. Fix hang on spinlock in find_writable_file (race when -reopening file after session crash). +reopening file after session crash). Byte range unlock request to +windows server could unlock more bytes (on server copy of file) +than intended if start of unlock request is well before start of +a previous byte range lock that we issued. Version 1.49 ------------ diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index 6ecd9d6ba3f3..ff6ba8d823f0 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile @@ -3,4 +3,4 @@ # obj-$(CONFIG_CIFS) += cifs.o -cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o sess.o export.o +cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o sess.o export.o cifsacl.o diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c index f50a88d58f78..2a01f3ef96a0 100644 --- a/fs/cifs/asn1.c +++ b/fs/cifs/asn1.c @@ -385,10 +385,9 @@ asn1_oid_decode(struct asn1_ctx *ctx, unsigned long *optr; size = eoc - ctx->pointer + 1; - *oid = kmalloc(size * sizeof (unsigned long), GFP_ATOMIC); - if (*oid == NULL) { + *oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC); + if (*oid == NULL) return 0; - } optr = *oid; @@ -581,9 +580,8 @@ decode_negTokenInit(unsigned char *security_blob, int length, return 0; } else if ((cls != ASN1_UNI) || (con != ASN1_CON) || (tag != ASN1_SEQ)) { - cFYI(1, - ("Exit 6 cls = %d con = %d tag = %d end = %p (%d)", - cls, con, tag, end, *end)); + cFYI(1, ("cls = %d con = %d tag = %d end = %p (%d)", + cls, con, tag, end, *end)); } if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 1bf8cf522ad6..73c4c419663c 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -209,13 +209,16 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, i++; tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); - length = - sprintf(buf, - "\n%d) %s Uses: %d Type: %s DevInfo: 0x%x " - "Attributes: 0x%x\nPathComponentMax: %d Status: %d", - i, tcon->treeName, - atomic_read(&tcon->useCount), - tcon->nativeFileSystem, + length = sprintf(buf, "\n%d) %s Uses: %d ", i, + tcon->treeName, atomic_read(&tcon->useCount)); + buf += length; + if (tcon->nativeFileSystem) { + length = sprintf(buf, "Type: %s ", + tcon->nativeFileSystem); + buf += length; + } + length = sprintf(buf, "DevInfo: 0x%x Attributes: 0x%x" + "\nPathComponentMax: %d Status: %d", le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics), le32_to_cpu(tcon->fsAttrInfo.Attributes), le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength), @@ -876,11 +879,16 @@ security_flags_write(struct file *file, const char __user *buffer, if (count < 3) { /* single char or single char followed by null */ c = flags_string[0]; - if (c == '0' || c == 'n' || c == 'N') + if (c == '0' || c == 'n' || c == 'N') { extended_security = CIFSSEC_DEF; /* default */ - else if (c == '1' || c == 'y' || c == 'Y') + return count; + } else if (c == '1' || c == 'y' || c == 'Y') { extended_security = CIFSSEC_MAX; - return count; + return count; + } else if (!isdigit(c)) { + cERROR(1, ("invalid flag %c", c)); + return -EINVAL; + } } /* else we have a number */ diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c new file mode 100644 index 000000000000..e8e56353f5a1 --- /dev/null +++ b/fs/cifs/cifsacl.c @@ -0,0 +1,333 @@ +/* + * fs/cifs/cifsacl.c + * + * Copyright (C) International Business Machines Corp., 2007 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * Contains the routines for mapping CIFS/NTFS ACLs + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/fs.h> +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsacl.h" +#include "cifsproto.h" +#include "cifs_debug.h" + + +#ifdef CONFIG_CIFS_EXPERIMENTAL + +static struct cifs_wksid wksidarr[NUM_WK_SIDS] = { + {{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"}, + {{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"}, + {{1, 1, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(11), 0, 0, 0, 0} }, "net-users"}, + {{1, 1, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(18), 0, 0, 0, 0} }, "sys"}, + {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(544), 0, 0, 0} }, "root"}, + {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(545), 0, 0, 0} }, "users"}, + {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(546), 0, 0, 0} }, "guest"} +}; + + +/* security id for everyone */ +static const struct cifs_sid sid_everyone = + {1, 1, {0, 0, 0, 0, 0, 0}, {} }; +/* group users */ +static const struct cifs_sid sid_user = + {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; + + +int match_sid(struct cifs_sid *ctsid) +{ + int i, j; + int num_subauth, num_sat, num_saw; + struct cifs_sid *cwsid; + + if (!ctsid) + return (-1); + + for (i = 0; i < NUM_WK_SIDS; ++i) { + cwsid = &(wksidarr[i].cifssid); + + /* compare the revision */ + if (ctsid->revision != cwsid->revision) + continue; + + /* compare all of the six auth values */ + for (j = 0; j < 6; ++j) { + if (ctsid->authority[j] != cwsid->authority[j]) + break; + } + if (j < 6) + continue; /* all of the auth values did not match */ + + /* compare all of the subauth values if any */ + num_sat = ctsid->num_subauth; + num_saw = cwsid->num_subauth; + num_subauth = num_sat < num_saw ? num_sat : num_saw; + if (num_subauth) { + for (j = 0; j < num_subauth; ++j) { + if (ctsid->sub_auth[j] != cwsid->sub_auth[j]) + break; + } + if (j < num_subauth) + continue; /* all sub_auth values do not match */ + } + + cFYI(1, ("matching sid: %s\n", wksidarr[i].sidname)); + return (0); /* sids compare/match */ + } + + cFYI(1, ("No matching sid")); + return (-1); +} + +/* if the two SIDs (roughly equivalent to a UUID for a user or group) are + the same returns 1, if they do not match returns 0 */ +int compare_sids(struct cifs_sid *ctsid, struct cifs_sid *cwsid) +{ + int i; + int num_subauth, num_sat, num_saw; + + if ((!ctsid) || (!cwsid)) + return (0); + + /* compare the revision */ + if (ctsid->revision != cwsid->revision) + return (0); + + /* compare all of the six auth values */ + for (i = 0; i < 6; ++i) { + if (ctsid->authority[i] != cwsid->authority[i]) + return (0); + } + + /* compare all of the subauth values if any */ + num_sat = ctsid->num_subauth; + num_saw = cwsid->num_subauth; + num_subauth = num_sat < num_saw ? num_sat : num_saw; + if (num_subauth) { + for (i = 0; i < num_subauth; ++i) { + if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) + return (0); + } + } + + return (1); /* sids compare/match */ +} + + +static void parse_ace(struct cifs_ace *pace, char *end_of_acl) +{ + int num_subauth; + + /* validate that we do not go past end of acl */ + + /* XXX this if statement can be removed + if (end_of_acl < (char *)pace + sizeof(struct cifs_ace)) { + cERROR(1, ("ACL too small to parse ACE")); + return; + } */ + + num_subauth = pace->num_subauth; + if (num_subauth) { +#ifdef CONFIG_CIFS_DEBUG2 + int i; + cFYI(1, ("ACE revision %d num_subauth %d", + pace->revision, pace->num_subauth)); + for (i = 0; i < num_subauth; ++i) { + cFYI(1, ("ACE sub_auth[%d]: 0x%x", i, + le32_to_cpu(pace->sub_auth[i]))); + } + + /* BB add length check to make sure that we do not have huge + num auths and therefore go off the end */ + + cFYI(1, ("RID %d", le32_to_cpu(pace->sub_auth[num_subauth-1]))); +#endif + } + + return; +} + +static void parse_ntace(struct cifs_ntace *pntace, char *end_of_acl) +{ + /* validate that we do not go past end of acl */ + if (end_of_acl < (char *)pntace + sizeof(struct cifs_ntace)) { + cERROR(1, ("ACL too small to parse NT ACE")); + return; + } + +#ifdef CONFIG_CIFS_DEBUG2 + cFYI(1, ("NTACE type %d flags 0x%x size %d, access Req 0x%x", + pntace->type, pntace->flags, pntace->size, + pntace->access_req)); +#endif + return; +} + + + +static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, + struct cifs_sid *pownersid, struct cifs_sid *pgrpsid) +{ + int i; + int num_aces = 0; + int acl_size; + char *acl_base; + struct cifs_ntace **ppntace; + struct cifs_ace **ppace; + + /* BB need to add parm so we can store the SID BB */ + + /* validate that we do not go past end of acl */ + if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) { + cERROR(1, ("ACL too small to parse DACL")); + return; + } + +#ifdef CONFIG_CIFS_DEBUG2 + cFYI(1, ("DACL revision %d size %d num aces %d", + le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size), + le32_to_cpu(pdacl->num_aces))); +#endif + + acl_base = (char *)pdacl; + acl_size = sizeof(struct cifs_acl); + + num_aces = le32_to_cpu(pdacl->num_aces); + if (num_aces > 0) { + ppntace = kmalloc(num_aces * sizeof(struct cifs_ntace *), + GFP_KERNEL); + ppace = kmalloc(num_aces * sizeof(struct cifs_ace *), + GFP_KERNEL); + +/* cifscred->cecount = pdacl->num_aces; + cifscred->ntaces = kmalloc(num_aces * + sizeof(struct cifs_ntace *), GFP_KERNEL); + cifscred->aces = kmalloc(num_aces * + sizeof(struct cifs_ace *), GFP_KERNEL);*/ + + for (i = 0; i < num_aces; ++i) { + ppntace[i] = (struct cifs_ntace *) + (acl_base + acl_size); + ppace[i] = (struct cifs_ace *) ((char *)ppntace[i] + + sizeof(struct cifs_ntace)); + + parse_ntace(ppntace[i], end_of_acl); + if (end_of_acl < ((char *)ppace[i] + + (le16_to_cpu(ppntace[i]->size) - + sizeof(struct cifs_ntace)))) { + cERROR(1, ("ACL too small to parse ACE")); + break; + } else + parse_ace(ppace[i], end_of_acl); + +/* memcpy((void *)(&(cifscred->ntaces[i])), + (void *)ppntace[i], + sizeof(struct cifs_ntace)); + memcpy((void *)(&(cifscred->aces[i])), + (void *)ppace[i], + sizeof(struct cifs_ace)); */ + + acl_base = (char *)ppntace[i]; + acl_size = le16_to_cpu(ppntace[i]->size); + } + + kfree(ppace); + kfree(ppntace); + } + + return; +} + + +static int parse_sid(struct cifs_sid *psid, char *end_of_acl) +{ + + /* BB need to add parm so we can store the SID BB */ + + /* validate that we do not go past end of acl */ + if (end_of_acl < (char *)psid + sizeof(struct cifs_sid)) { + cERROR(1, ("ACL too small to parse SID")); + return -EINVAL; + } + + if (psid->num_subauth) { +#ifdef CONFIG_CIFS_DEBUG2 + int i; + cFYI(1, ("SID revision %d num_auth %d First subauth 0x%x", + psid->revision, psid->num_subauth, psid->sub_auth[0])); + + for (i = 0; i < psid->num_subauth; i++) { + cFYI(1, ("SID sub_auth[%d]: 0x%x ", i, + le32_to_cpu(psid->sub_auth[i]))); + } + + /* BB add length check to make sure that we do not have huge + num auths and therefore go off the end */ + cFYI(1, ("RID 0x%x", + le32_to_cpu(psid->sub_auth[psid->num_subauth-1]))); +#endif + } + + return 0; +} + + +/* Convert CIFS ACL to POSIX form */ +int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len) +{ + int rc; + struct cifs_sid *owner_sid_ptr, *group_sid_ptr; + struct cifs_acl *dacl_ptr; /* no need for SACL ptr */ + char *end_of_acl = ((char *)pntsd) + acl_len; + + owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + + le32_to_cpu(pntsd->osidoffset)); + group_sid_ptr = (struct cifs_sid *)((char *)pntsd + + le32_to_cpu(pntsd->gsidoffset)); + dacl_ptr = (struct cifs_acl *)((char *)pntsd + + le32_to_cpu(pntsd->dacloffset)); +#ifdef CONFIG_CIFS_DEBUG2 + cFYI(1, ("revision %d type 0x%x ooffset 0x%x goffset 0x%x " + "sacloffset 0x%x dacloffset 0x%x", + pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset), + le32_to_cpu(pntsd->gsidoffset), + le32_to_cpu(pntsd->sacloffset), + le32_to_cpu(pntsd->dacloffset))); +#endif + rc = parse_sid(owner_sid_ptr, end_of_acl); + if (rc) + return rc; + + rc = parse_sid(group_sid_ptr, end_of_acl); + if (rc) + return rc; + + parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, group_sid_ptr); + +/* cifscred->uid = owner_sid_ptr->rid; + cifscred->gid = group_sid_ptr->rid; + memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr, + sizeof (struct cifs_sid)); + memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr, + sizeof (struct cifs_sid)); */ + + + return (0); +} +#endif /* CONFIG_CIFS_EXPERIMENTAL */ diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index 5eff35d6e564..420f87813647 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h @@ -1,7 +1,7 @@ /* * fs/cifs/cifsacl.h * - * Copyright (c) International Business Machines Corp., 2005 + * Copyright (c) International Business Machines Corp., 2007 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -22,17 +22,65 @@ #ifndef _CIFSACL_H #define _CIFSACL_H + +#define NUM_AUTHS 6 /* number of authority fields */ +#define NUM_SUBAUTHS 5 /* number of sub authority fields */ +#define NUM_WK_SIDS 7 /* number of well known sids */ +#define SIDNAMELENGTH 20 /* long enough for the ones we care about */ + +#define READ_BIT 0x4 +#define WRITE_BIT 0x2 +#define EXEC_BIT 0x1 + +#define UBITSHIFT 6 +#define GBITSHIFT 3 + +struct cifs_ntsd { + __le16 revision; /* revision level */ + __le16 type; + __le32 osidoffset; + __le32 gsidoffset; + __le32 sacloffset; + __le32 dacloffset; +} __attribute__((packed)); + struct cifs_sid { __u8 revision; /* revision level */ - __u8 num_subauths; + __u8 num_subauth; + __u8 authority[6]; + __le32 sub_auth[5]; /* sub_auth[num_subauth] */ /* BB FIXME endianness BB */ +} __attribute__((packed)); + +struct cifs_acl { + __le16 revision; /* revision level */ + __le16 size; + __le32 num_aces; +} __attribute__((packed)); + +struct cifs_ntace { /* first part of ACE which contains perms */ + __u8 type; + __u8 flags; + __le16 size; + __le32 access_req; +} __attribute__((packed)); + +struct cifs_ace { /* last part of ACE which includes user info */ + __u8 revision; /* revision level */ + __u8 num_subauth; __u8 authority[6]; - __u32 sub_auth[4]; - /* next sub_auth if any ... */ + __le32 sub_auth[5]; } __attribute__((packed)); -/* everyone */ -/* extern const struct cifs_sid sid_everyone;*/ -/* group users */ -/* extern const struct cifs_sid sid_user;*/ +struct cifs_wksid { + struct cifs_sid cifssid; + char sidname[SIDNAMELENGTH]; +} __attribute__((packed)); + +#ifdef CONFIG_CIFS_EXPERIMENTAL + +extern int match_sid(struct cifs_sid *); +extern int compare_sids(struct cifs_sid *, struct cifs_sid *); + +#endif /* CONFIG_CIFS_EXPERIMENTAL */ #endif /* _CIFSACL_H */ diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 36272293027d..632070b4275d 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -345,7 +345,7 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, user = kmalloc(2 + (len * 2), GFP_KERNEL); if (user == NULL) goto calc_exit_2; - len = cifs_strtoUCS(user, ses->userName, len, nls_cp); + len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp); UniStrupr(user); hmac_md5_update((char *)user, 2*len, pctxt); @@ -356,7 +356,8 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, domain = kmalloc(2 + (len * 2), GFP_KERNEL); if (domain == NULL) goto calc_exit_1; - len = cifs_strtoUCS(domain, ses->domainName, len, nls_cp); + len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len, + nls_cp); /* the following line was removed since it didn't work well with lower cased domain name that passed as an option. Maybe converting the domain name earlier makes sense */ diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index cabb6a55d7dd..a6fbea57c4b1 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -49,10 +49,6 @@ static struct quotactl_ops cifs_quotactl_ops; #endif /* QUOTA */ -#ifdef CONFIG_CIFS_EXPERIMENTAL -extern struct export_operations cifs_export_ops; -#endif /* EXPERIMENTAL */ - int cifsFYI = 0; int cifsERROR = 1; int traceSMB = 0; @@ -240,9 +236,9 @@ static int cifs_permission(struct inode *inode, int mask, struct nameidata *nd) cifs_sb = CIFS_SB(inode->i_sb); - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) { + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) return 0; - } else /* file mode might have been restricted at mount time + else /* file mode might have been restricted at mount time on the client (above and beyond ACL on servers) for servers which do not support setting and viewing mode bits, so allowing client to check permissions is useful */ @@ -312,15 +308,15 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) seq_printf(s, ",domain=%s", cifs_sb->tcon->ses->domainName); } + if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) || + !(cifs_sb->tcon->unix_ext)) + seq_printf(s, ",uid=%d", cifs_sb->mnt_uid); + if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) || + !(cifs_sb->tcon->unix_ext)) + seq_printf(s, ",gid=%d", cifs_sb->mnt_gid); } if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) seq_printf(s, ",posixpaths"); - if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) || - !(cifs_sb->tcon->unix_ext)) - seq_printf(s, ",uid=%d", cifs_sb->mnt_uid); - if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) || - !(cifs_sb->tcon->unix_ext)) - seq_printf(s, ",gid=%d", cifs_sb->mnt_gid); seq_printf(s, ",rsize=%d", cifs_sb->rsize); seq_printf(s, ",wsize=%d", cifs_sb->wsize); } @@ -346,7 +342,7 @@ int cifs_xquota_set(struct super_block *sb, int quota_type, qid_t qid, if (pTcon) { cFYI(1, ("set type: 0x%x id: %d", quota_type, qid)); } else { - return -EIO; + rc = -EIO; } FreeXid(xid); @@ -704,7 +700,7 @@ const struct file_operations cifs_dir_ops = { }; static void -cifs_init_once(void *inode, struct kmem_cache *cachep, unsigned long flags) +cifs_init_once(struct kmem_cache *cachep, void *inode) { struct cifsInodeInfo *cifsi = inode; @@ -716,7 +712,7 @@ static int cifs_init_inodecache(void) { cifs_inode_cachep = kmem_cache_create("cifs_inode_cache", - sizeof (struct cifsInodeInfo), + sizeof(struct cifsInodeInfo), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), cifs_init_once); @@ -816,8 +812,8 @@ static int cifs_init_mids(void) { cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids", - sizeof (struct mid_q_entry), 0, - SLAB_HWCACHE_ALIGN, NULL); + sizeof(struct mid_q_entry), 0, + SLAB_HWCACHE_ALIGN, NULL); if (cifs_mid_cachep == NULL) return -ENOMEM; @@ -829,8 +825,8 @@ cifs_init_mids(void) } cifs_oplock_cachep = kmem_cache_create("cifs_oplock_structs", - sizeof (struct oplock_q_entry), 0, - SLAB_HWCACHE_ALIGN, NULL); + sizeof(struct oplock_q_entry), 0, + SLAB_HWCACHE_ALIGN, NULL); if (cifs_oplock_cachep == NULL) { mempool_destroy(cifs_mid_poolp); kmem_cache_destroy(cifs_mid_cachep); @@ -882,7 +878,8 @@ static int cifs_oplock_thread(void *dummyarg) the call */ /* mutex_lock(&inode->i_mutex);*/ if (S_ISREG(inode->i_mode)) { - rc = filemap_fdatawrite(inode->i_mapping); + rc = + filemap_fdatawrite(inode->i_mapping); if (CIFS_I(inode)->clientCanCacheRead == 0) { filemap_fdatawait(inode->i_mapping); @@ -907,8 +904,7 @@ static int cifs_oplock_thread(void *dummyarg) 0 /* len */ , 0 /* offset */, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, 0 /* wait flag */); - cFYI(1, - ("Oplock release rc = %d ", rc)); + cFYI(1, ("Oplock release rc = %d", rc)); } } else spin_unlock(&GlobalMid_Lock); diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index a20de77a3856..0a3ee5a322b0 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -1,7 +1,7 @@ /* * fs/cifs/cifsfs.h * - * Copyright (c) International Business Machines Corp., 2002, 2005 + * Copyright (c) International Business Machines Corp., 2002, 2007 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -99,7 +99,12 @@ extern int cifs_setxattr(struct dentry *, const char *, const void *, size_t, int); extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); -extern int cifs_ioctl (struct inode *inode, struct file *filep, +extern int cifs_ioctl(struct inode *inode, struct file *filep, unsigned int command, unsigned long arg); -#define CIFS_VERSION "1.50" + +#ifdef CONFIG_CIFS_EXPERIMENTAL +extern struct export_operations cifs_export_ops; +#endif /* EXPERIMENTAL */ + +#define CIFS_VERSION "1.51" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index b98742fc3b5a..87f51f23276f 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -19,6 +19,7 @@ #include <linux/in.h> #include <linux/in6.h> #include "cifs_fs_sb.h" +#include "cifsacl.h" /* * The sizes of various internal tables and strings */ @@ -89,7 +90,8 @@ enum statusEnum { }; enum securityEnum { - LANMAN = 0, /* Legacy LANMAN auth */ + PLAINTXT = 0, /* Legacy with Plaintext passwords */ + LANMAN, /* Legacy LANMAN auth */ NTLM, /* Legacy NTLM012 auth with NTLM hash */ NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ RawNTLMSSP, /* NTLMSSP without SPNEGO */ @@ -115,6 +117,17 @@ struct mac_key { } data; }; +struct cifs_cred { + int uid; + int gid; + int mode; + int cecount; + struct cifs_sid osid; + struct cifs_sid gsid; + struct cifs_ntace *ntaces; + struct cifs_ace *aces; +}; + /* ***************************************************************** * Except the CIFS PDUs themselves all the @@ -279,6 +292,7 @@ struct cifsTconInfo { FILE_SYSTEM_DEVICE_INFO fsDevInfo; FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */ FILE_SYSTEM_UNIX_INFO fsUnixInfo; + unsigned ipc:1; /* set if connection to IPC$ eg for RPC/PIPES */ unsigned retry:1; unsigned nocase:1; unsigned unix_ext:1; /* if off disable Linux extensions to CIFS protocol @@ -329,6 +343,7 @@ struct cifsFileInfo { struct list_head llist; /* list of byte range locks we have. */ unsigned closePend:1; /* file is marked to close */ unsigned invalidHandle:1; /* file closed via session abend */ + unsigned messageMode:1; /* for pipes: message vs byte mode */ atomic_t wrtPending; /* handle in use - defer close */ struct semaphore fh_sem; /* prevents reopen race after dead ses*/ char *search_resume_name; /* BB removeme BB */ @@ -464,6 +479,9 @@ struct dir_notify_req { #ifdef CONFIG_CIFS_WEAK_PW_HASH #define CIFSSEC_MAY_LANMAN 0x00010 #define CIFSSEC_MAY_PLNTXT 0x00020 +#else +#define CIFSSEC_MAY_LANMAN 0 +#define CIFSSEC_MAY_PLNTXT 0 #endif /* weak passwords */ #define CIFSSEC_MAY_SEAL 0x00040 /* not supported yet */ @@ -477,14 +495,23 @@ require use of the stronger protocol */ #ifdef CONFIG_CIFS_WEAK_PW_HASH #define CIFSSEC_MUST_LANMAN 0x10010 #define CIFSSEC_MUST_PLNTXT 0x20020 +#ifdef CONFIG_CIFS_UPCALL +#define CIFSSEC_MASK 0x3F03F /* allows weak security but also krb5 */ +#else #define CIFSSEC_MASK 0x37037 /* current flags supported if weak */ +#endif /* UPCALL */ +#else /* do not allow weak pw hash */ +#ifdef CONFIG_CIFS_UPCALL +#define CIFSSEC_MASK 0x0F00F /* flags supported if no weak allowed */ #else -#define CIFSSEC_MASK 0x07007 /* flags supported if no weak config */ +#define CIFSSEC_MASK 0x07007 /* flags supported if no weak allowed */ +#endif /* UPCALL */ #endif /* WEAK_PW_HASH */ #define CIFSSEC_MUST_SEAL 0x40040 /* not supported yet */ #define CIFSSEC_DEF CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 #define CIFSSEC_MAX CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2 +#define CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_LANMAN | CIFSSEC_MAY_PLNTXT | CIFSSEC_MAY_KRB5) /* ***************************************************************** * All constants go here diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 6a2056e58ceb..c41ff74e9128 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -215,6 +215,12 @@ /* file_execute, file_read_attributes*/ /* write_dac, and delete. */ +#define FILE_READ_RIGHTS (FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES) +#define FILE_WRITE_RIGHTS (FILE_WRITE_DATA | FILE_APPEND_DATA \ + | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES) +#define FILE_EXEC_RIGHTS (FILE_EXECUTE) + + /* * Invalid readdir handle */ @@ -360,10 +366,10 @@ struct smb_hdr { __u8 WordCount; } __attribute__((packed)); /* given a pointer to an smb_hdr retrieve the value of byte count */ -#define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) -#define BCC_LE(smb_var) ( *(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) +#define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount))) +#define BCC_LE(smb_var) ( *(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount))) /* given a pointer to an smb_hdr retrieve the pointer to the byte area */ -#define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) + 2 ) +#define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount) + 2) /* * Computer Name Length (since Netbios name was length 16 with last byte 0x20) @@ -716,6 +722,14 @@ typedef struct smb_com_findclose_req { #define REQ_OPENDIRONLY 0x00000008 #define REQ_EXTENDED_INFO 0x00000010 +/* File type */ +#define DISK_TYPE 0x0000 +#define BYTE_PIPE_TYPE 0x0001 +#define MESSAGE_PIPE_TYPE 0x0002 +#define PRINTER_TYPE 0x0003 +#define COMM_DEV_TYPE 0x0004 +#define UNKNOWN_TYPE 0xFFFF + typedef struct smb_com_open_req { /* also handles create */ struct smb_hdr hdr; /* wct = 24 */ __u8 AndXCommand; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 04a69dafedba..1a883663b22d 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -50,7 +50,8 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, int * /* bytes returned */ , const int long_op); extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, struct kvec *, int /* nvec to send */, - int * /* type of buf returned */ , const int long_op); + int * /* type of buf returned */ , const int long_op, + const int logError /* whether to log status code*/ ); extern int SendReceiveBlockingLock(const unsigned int /* xid */ , struct cifsTconInfo *, struct smb_hdr * /* input */ , @@ -65,7 +66,7 @@ extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); extern int decode_negTokenInit(unsigned char *security_blob, int length, enum securityEnum *secType); extern int cifs_inet_pton(int, char *source, void *dst); -extern int map_smb_to_linux_error(struct smb_hdr *smb); +extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr); extern void header_assemble(struct smb_hdr *, char /* command */ , const struct cifsTconInfo *, int /* length of fixed section (word count) in two byte units */); @@ -304,12 +305,13 @@ extern int cifs_calculate_mac_key(struct mac_key *key, const char *rn, const char *pass); extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, const struct nls_table *); -extern void CalcNTLMv2_response(const struct cifsSesInfo *, char * ); +extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *); extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *, const struct nls_table *); #ifdef CONFIG_CIFS_WEAK_PW_HASH extern void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key); #endif /* CIFS_WEAK_PW_HASH */ +extern int parse_sec_desc(struct cifs_ntsd *, int); extern int CIFSSMBCopy(int xid, struct cifsTconInfo *source_tcon, const char *fromName, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 8eb102f940d4..f0d9a485d095 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -34,10 +34,10 @@ #include <asm/uaccess.h> #include "cifspdu.h" #include "cifsglob.h" +#include "cifsacl.h" #include "cifsproto.h" #include "cifs_unicode.h" #include "cifs_debug.h" -#include "cifsacl.h" #ifdef CONFIG_CIFS_POSIX static struct { @@ -94,9 +94,8 @@ static void mark_open_files_invalid(struct cifsTconInfo *pTcon) write_lock(&GlobalSMBSeslock); list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { open_file = list_entry(tmp, struct cifsFileInfo, tlist); - if (open_file) { + if (open_file) open_file->invalidHandle = TRUE; - } } write_unlock(&GlobalSMBSeslock); /* BB Add call to invalidate_inodes(sb) for all superblocks mounted @@ -439,8 +438,13 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) pSMB->hdr.Mid = GetNextMid(server); pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS); + if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5) pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; + else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) { + cFYI(1, ("Kerberos only mechanism, enable extended security")); + pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; + } count = 0; for (i = 0; i < CIFS_NUM_PROT; i++) { @@ -513,7 +517,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) (int)ts.tv_sec, (int)utc.tv_sec, (int)(utc.tv_sec - ts.tv_sec))); val = (int)(utc.tv_sec - ts.tv_sec); - seconds = val < 0 ? -val : val; + seconds = abs(val); result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ; remain = seconds % MIN_TZ_ADJ; if (remain >= (MIN_TZ_ADJ / 2)) @@ -574,7 +578,20 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) server->secType = NTLM; else if (secFlags & CIFSSEC_MAY_NTLMV2) server->secType = NTLMv2; - /* else krb5 ... any others ... */ + else if (secFlags & CIFSSEC_MAY_KRB5) + server->secType = Kerberos; + else if (secFlags & CIFSSEC_MAY_LANMAN) + server->secType = LANMAN; +/* #ifdef CONFIG_CIFS_EXPERIMENTAL + else if (secFlags & CIFSSEC_MAY_PLNTXT) + server->secType = ?? +#endif */ + else { + rc = -EOPNOTSUPP; + cERROR(1, ("Invalid security type")); + goto neg_err_exit; + } + /* else ... any others ...? */ /* one byte, so no need to convert this or EncryptionKeyLen from little endian */ @@ -604,22 +621,26 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && (server->capabilities & CAP_EXTENDED_SECURITY)) { count = pSMBr->ByteCount; - if (count < 16) + if (count < 16) { rc = -EIO; - else if (count == 16) { - server->secType = RawNTLMSSP; - if (server->socketUseCount.counter > 1) { - if (memcmp(server->server_GUID, - pSMBr->u.extended_response. - GUID, 16) != 0) { - cFYI(1, ("server UID changed")); - memcpy(server->server_GUID, - pSMBr->u.extended_response.GUID, - 16); - } - } else + goto neg_err_exit; + } + + if (server->socketUseCount.counter > 1) { + if (memcmp(server->server_GUID, + pSMBr->u.extended_response. + GUID, 16) != 0) { + cFYI(1, ("server UID changed")); memcpy(server->server_GUID, - pSMBr->u.extended_response.GUID, 16); + pSMBr->u.extended_response.GUID, + 16); + } + } else + memcpy(server->server_GUID, + pSMBr->u.extended_response.GUID, 16); + + if (count == 16) { + server->secType = RawNTLMSSP; } else { rc = decode_negTokenInit(pSMBr->u.extended_response. SecurityBlob, @@ -642,10 +663,12 @@ signing_check: /* MUST_SIGN already includes the MAY_SIGN FLAG so if this is zero it means that signing is disabled */ cFYI(1, ("Signing disabled")); - if (server->secMode & SECMODE_SIGN_REQUIRED) + if (server->secMode & SECMODE_SIGN_REQUIRED) { cERROR(1, ("Server requires " - "/proc/fs/cifs/PacketSigningEnabled " - "to be on")); + "packet signing to be enabled in " + "/proc/fs/cifs/SecurityFlags.")); + rc = -EOPNOTSUPP; + } server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) { @@ -1052,7 +1075,7 @@ PsxCreat: InformationLevel) - 4; offset = param_offset + params; pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset); - pdata->Level = SMB_QUERY_FILE_UNIX_BASIC; + pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); pdata->Permissions = cpu_to_le64(mode); pdata->PosixOpenFlags = cpu_to_le32(posix_flags); pdata->OpenFlags = cpu_to_le32(*pOplock); @@ -1098,8 +1121,8 @@ PsxCreat: if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction) *pOplock |= CIFS_CREATE_ACTION; /* check to make sure response data is there */ - if (psx_rsp->ReturnedLevel != SMB_QUERY_FILE_UNIX_BASIC) { - pRetData->Type = -1; /* unknown */ + if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) { + pRetData->Type = cpu_to_le32(-1); /* unknown */ #ifdef CONFIG_CIFS_DEBUG2 cFYI(1, ("unknown type")); #endif @@ -1107,12 +1130,12 @@ PsxCreat: if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP) + sizeof(FILE_UNIX_BASIC_INFO)) { cERROR(1, ("Open response data too small")); - pRetData->Type = -1; + pRetData->Type = cpu_to_le32(-1); goto psx_create_err; } memcpy((char *) pRetData, (char *)psx_rsp + sizeof(OPEN_PSX_RSP), - sizeof (FILE_UNIX_BASIC_INFO)); + sizeof(FILE_UNIX_BASIC_INFO)); } psx_create_err: @@ -1193,9 +1216,9 @@ OldOpenRetry: } if (*pOplock & REQ_OPLOCK) pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK); - else if (*pOplock & REQ_BATCHOPLOCK) { + else if (*pOplock & REQ_BATCHOPLOCK) pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK); - } + pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO); /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */ /* 0 = read @@ -1310,9 +1333,8 @@ openRetry: } if (*pOplock & REQ_OPLOCK) pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK); - else if (*pOplock & REQ_BATCHOPLOCK) { + else if (*pOplock & REQ_BATCHOPLOCK) pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK); - } pSMB->DesiredAccess = cpu_to_le32(access_flags); pSMB->AllocationSize = 0; /* set file as system file if special file such @@ -1424,9 +1446,8 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, iov[0].iov_base = (char *)pSMB; iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; - rc = SendReceive2(xid, tcon->ses, iov, - 1 /* num iovecs */, - &resp_buf_type, 0); + rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, + &resp_buf_type, 0 /* not long op */, 1 /* log err */ ); cifs_stats_inc(&tcon->num_reads); pSMBr = (READ_RSP *)iov[0].iov_base; if (rc) { @@ -1446,11 +1467,11 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, *nbytes = 0; } else { pReadData = (char *) (&pSMBr->hdr.Protocol) + - le16_to_cpu(pSMBr->DataOffset); -/* if (rc = copy_to_user(buf, pReadData, data_length)) { + le16_to_cpu(pSMBr->DataOffset); +/* if (rc = copy_to_user(buf, pReadData, data_length)) { cERROR(1,("Faulting on read rc = %d",rc)); rc = -EFAULT; - }*/ /* can not use copy_to_user when using page cache*/ + }*/ /* can not use copy_to_user when using page cache*/ if (*buf) memcpy(*buf, pReadData, data_length); } @@ -1645,7 +1666,7 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, - long_op); + long_op, 0 /* do not log STATUS code */ ); cifs_stats_inc(&tcon->num_writes); if (rc) { cFYI(1, ("Send error Write2 = %d", rc)); @@ -2538,7 +2559,7 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata, cFYI(1, ("data starts after end of smb")); return -EINVAL; } else if (data_count + *ppdata > end_of_smb) { - cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p", + cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p", *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); return -EINVAL; @@ -2615,7 +2636,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, reparse_buf->TargetNameOffset + reparse_buf->TargetNameLen) > end_of_smb) { - cFYI(1,("reparse buf goes beyond SMB")); + cFYI(1, ("reparse buf beyond SMB")); rc = -EIO; goto qreparse_out; } @@ -3042,25 +3063,12 @@ GetExtAttrOut: #endif /* CONFIG_POSIX */ - -/* security id for everyone */ -static const struct cifs_sid sid_everyone = - {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}}; -/* group users */ -static const struct cifs_sid sid_user = - {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}}; - -/* Convert CIFS ACL to POSIX form */ -static int parse_sec_desc(struct cifs_sid *psec_desc, int acl_len) -{ - return 0; -} - +#ifdef CONFIG_CIFS_EXPERIMENTAL /* Get Security Descriptor (by handle) from remote server for a file or dir */ int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, /* BB fix up return info */ char *acl_inf, const int buflen, - const int acl_type /* ACCESS/DEFAULT not sure implication */) + const int acl_type) { int rc = 0; int buf_type = 0; @@ -3085,12 +3093,13 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, iov[0].iov_base = (char *)pSMB; iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; - rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0); + rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, + 0 /* not long op */, 0 /* do not log STATUS codes */ ); cifs_stats_inc(&tcon->num_acl_get); if (rc) { cFYI(1, ("Send error in QuerySecDesc = %d", rc)); } else { /* decode response */ - struct cifs_sid *psec_desc; + struct cifs_ntsd *psec_desc; __le32 * parm; int parm_len; int data_len; @@ -3105,8 +3114,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, goto qsec_out; pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base; - cERROR(1, ("smb %p parm %p data %p", - pSMBr, parm, psec_desc)); /* BB removeme BB */ + cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, psec_desc)); if (le32_to_cpu(pSMBr->ParameterCount) != 4) { rc = -EIO; /* bad smb */ @@ -3115,7 +3123,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, /* BB check that data area is minimum length and as big as acl_len */ - acl_len = le32_to_cpu(*(__le32 *)parm); + acl_len = le32_to_cpu(*parm); /* BB check if (acl_len > bufsize) */ parse_sec_desc(psec_desc, acl_len); @@ -3128,6 +3136,7 @@ qsec_out: /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */ return rc; } +#endif /* CONFIG_CIFS_EXPERIMENTAL */ /* Legacy Query Path Information call for lookup to old servers such as Win9x/WinME */ @@ -3363,6 +3372,9 @@ UnixQPathInfoRetry: rc = validate_t2((struct smb_t2_rsp *)pSMBr); if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) { + cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n" + "Unix Extensions can be disabled on mount " + "by specifying the nosfu mount option.")); rc = -EIO; /* bad smb */ } else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); @@ -3883,12 +3895,10 @@ getDFSRetry: pSMB->hdr.Mid = GetNextMid(ses->server); pSMB->hdr.Tid = ses->ipc_tid; pSMB->hdr.Uid = ses->Suid; - if (ses->capabilities & CAP_STATUS32) { + if (ses->capabilities & CAP_STATUS32) pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS; - } - if (ses->capabilities & CAP_DFS) { + if (ses->capabilities & CAP_DFS) pSMB->hdr.Flags2 |= SMBFLG2_DFS; - } if (ses->capabilities & CAP_UNICODE) { pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; @@ -4060,10 +4070,6 @@ oldQFSInfoRetry: (void **) &pSMBr); if (rc) return rc; - rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, - (void **) &pSMBr); - if (rc) - return rc; params = 2; /* level */ pSMB->TotalDataCount = 0; @@ -4265,7 +4271,7 @@ QFSAttributeRetry: *) (((char *) &pSMBr->hdr.Protocol) + data_offset); memcpy(&tcon->fsAttrInfo, response_data, - sizeof (FILE_SYSTEM_ATTRIBUTE_INFO)); + sizeof(FILE_SYSTEM_ATTRIBUTE_INFO)); } } cifs_buf_release(pSMB); @@ -4334,7 +4340,7 @@ QFSDeviceRetry: (((char *) &pSMBr->hdr.Protocol) + data_offset); memcpy(&tcon->fsDevInfo, response_data, - sizeof (FILE_SYSTEM_DEVICE_INFO)); + sizeof(FILE_SYSTEM_DEVICE_INFO)); } } cifs_buf_release(pSMB); @@ -4402,7 +4408,7 @@ QFSUnixRetry: *) (((char *) &pSMBr->hdr.Protocol) + data_offset); memcpy(&tcon->fsUnixInfo, response_data, - sizeof (FILE_SYSTEM_UNIX_INFO)); + sizeof(FILE_SYSTEM_UNIX_INFO)); } } cifs_buf_release(pSMB); @@ -4612,7 +4618,7 @@ SetEOFRetry: strncpy(pSMB->FileName, fileName, name_len); } params = 6 + name_len; - data_count = sizeof (struct file_end_of_file_info); + data_count = sizeof(struct file_end_of_file_info); pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxDataCount = cpu_to_le16(4100); pSMB->MaxSetupCount = 0; @@ -4800,7 +4806,7 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, data_offset = (char *) (&pSMB->hdr.Protocol) + offset; - count = sizeof (FILE_BASIC_INFO); + count = sizeof(FILE_BASIC_INFO); pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ pSMB->SetupCount = 1; @@ -4871,7 +4877,7 @@ SetTimesRetry: } params = 6 + name_len; - count = sizeof (FILE_BASIC_INFO); + count = sizeof(FILE_BASIC_INFO); pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ pSMB->MaxSetupCount = 0; @@ -4900,7 +4906,7 @@ SetTimesRetry: pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); pSMB->Reserved4 = 0; pSMB->hdr.smb_buf_length += byte_count; - memcpy(data_offset, data, sizeof (FILE_BASIC_INFO)); + memcpy(data_offset, data, sizeof(FILE_BASIC_INFO)); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -5003,7 +5009,7 @@ setPermsRetry: } params = 6 + name_len; - count = sizeof (FILE_UNIX_BASIC_INFO); + count = sizeof(FILE_UNIX_BASIC_INFO); pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ pSMB->MaxSetupCount = 0; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 4af3588c1a96..19ee11f7f35a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -124,7 +124,7 @@ cifs_reconnect(struct TCP_Server_Info *server) struct mid_q_entry *mid_entry; spin_lock(&GlobalMid_Lock); - if ( kthread_should_stop() ) { + if (kthread_should_stop()) { /* the demux thread will exit normally next time through the loop */ spin_unlock(&GlobalMid_Lock); @@ -151,9 +151,8 @@ cifs_reconnect(struct TCP_Server_Info *server) } list_for_each(tmp, &GlobalTreeConnectionList) { tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); - if ((tcon) && (tcon->ses) && (tcon->ses->server == server)) { + if ((tcon) && (tcon->ses) && (tcon->ses->server == server)) tcon->tidStatus = CifsNeedReconnect; - } } read_unlock(&GlobalSMBSeslock); /* do not want to be sending data on a socket we are freeing */ @@ -187,7 +186,7 @@ cifs_reconnect(struct TCP_Server_Info *server) spin_unlock(&GlobalMid_Lock); up(&server->tcpSem); - while ( (!kthread_should_stop()) && (server->tcpStatus != CifsGood)) { + while ((!kthread_should_stop()) && (server->tcpStatus != CifsGood)) { try_to_freeze(); if (server->protocolType == IPV6) { rc = ipv6_connect(&server->addr.sockAddr6, @@ -204,7 +203,7 @@ cifs_reconnect(struct TCP_Server_Info *server) } else { atomic_inc(&tcpSesReconnectCount); spin_lock(&GlobalMid_Lock); - if ( !kthread_should_stop() ) + if (!kthread_should_stop()) server->tcpStatus = CifsGood; server->sequence_number = 0; spin_unlock(&GlobalMid_Lock); @@ -352,17 +351,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) current->flags |= PF_MEMALLOC; server->tsk = current; /* save process info to wake at shutdown */ - cFYI(1, ("Demultiplex PID: %d", current->pid)); + cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current))); write_lock(&GlobalSMBSeslock); atomic_inc(&tcpSesAllocCount); length = tcpSesAllocCount.counter; write_unlock(&GlobalSMBSeslock); complete(&cifsd_complete); - if (length > 1) { - mempool_resize(cifs_req_poolp, - length + cifs_min_rcv, - GFP_KERNEL); - } + if (length > 1) + mempool_resize(cifs_req_poolp, length + cifs_min_rcv, + GFP_KERNEL); set_freezable(); while (!kthread_should_stop()) { @@ -378,7 +375,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) } } else if (isLargeBuf) { /* we are reusing a dirty large buf, clear its start */ - memset(bigbuf, 0, sizeof (struct smb_hdr)); + memset(bigbuf, 0, sizeof(struct smb_hdr)); } if (smallbuf == NULL) { @@ -391,7 +388,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) } /* beginning of smb buffer is cleared in our buf_get */ } else /* if existing small buf clear beginning */ - memset(smallbuf, 0, sizeof (struct smb_hdr)); + memset(smallbuf, 0, sizeof(struct smb_hdr)); isLargeBuf = FALSE; isMultiRsp = FALSE; @@ -400,11 +397,13 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) iov.iov_len = 4; smb_msg.msg_control = NULL; smb_msg.msg_controllen = 0; + pdu_length = 4; /* enough to get RFC1001 header */ +incomplete_rcv: length = kernel_recvmsg(csocket, &smb_msg, - &iov, 1, 4, 0 /* BB see socket.h flags */); + &iov, 1, pdu_length, 0 /* BB other flags? */); - if ( kthread_should_stop() ) { + if (kthread_should_stop()) { break; } else if (server->tcpStatus == CifsNeedReconnect) { cFYI(1, ("Reconnect after server stopped responding")); @@ -416,7 +415,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) msleep(1); /* minimum sleep to prevent looping allowing socket to clear and app threads to set tcpStatus CifsNeedReconnect if server hung */ - continue; + if (pdu_length < 4) + goto incomplete_rcv; + else + continue; } else if (length <= 0) { if (server->tcpStatus == CifsNew) { cFYI(1, ("tcp session abend after SMBnegprot")); @@ -437,13 +439,11 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) wake_up(&server->response_q); continue; } else if (length < 4) { - cFYI(1, - ("Frame under four bytes received (%d bytes long)", + cFYI(1, ("less than four bytes received (%d bytes)", length)); - cifs_reconnect(server); - csocket = server->ssocket; - wake_up(&server->response_q); - continue; + pdu_length -= length; + msleep(1); + goto incomplete_rcv; } /* The right amount was read from socket - 4 bytes */ @@ -504,7 +504,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) /* else we have an SMB response */ if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) || - (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) { + (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) { cERROR(1, ("Invalid size SMB length %d pdu_length %d", length, pdu_length+4)); cifs_reconnect(server); @@ -528,7 +528,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) total_read += length) { length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, pdu_length - total_read, 0); - if ( kthread_should_stop() || + if (kthread_should_stop() || (length == -EINTR)) { /* then will exit */ reconnect = 2; @@ -546,6 +546,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) allowing socket to clear and app threads to set tcpStatus CifsNeedReconnect if server hung*/ + length = 0; continue; } else if (length <= 0) { cERROR(1, ("Received no data, expecting %d", @@ -631,9 +632,9 @@ multi_t2_fnd: /* Was previous buf put in mpx struct for multi-rsp? */ if (!isMultiRsp) { /* smb buffer will be freed by user thread */ - if (isLargeBuf) { + if (isLargeBuf) bigbuf = NULL; - } else + else smallbuf = NULL; } wake_up_process(task_to_wake); @@ -676,9 +677,8 @@ multi_t2_fnd: server->ssocket = NULL; } /* buffer usuallly freed in free_mid - need to free it here on exit */ - if (bigbuf != NULL) - cifs_buf_release(bigbuf); - if (smallbuf != NULL) + cifs_buf_release(bigbuf); + if (smallbuf) /* no sense logging a debug message if NULL */ cifs_small_buf_release(smallbuf); read_lock(&GlobalSMBSeslock); @@ -702,9 +702,8 @@ multi_t2_fnd: list_for_each(tmp, &GlobalSMBSessionList) { ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); - if (ses->server == server) { + if (ses->server == server) ses->status = CifsExiting; - } } spin_lock(&GlobalMid_Lock); @@ -714,9 +713,8 @@ multi_t2_fnd: cFYI(1, ("Clearing Mid 0x%x - waking up ", mid_entry->mid)); task_to_wake = mid_entry->tsk; - if (task_to_wake) { + if (task_to_wake) wake_up_process(task_to_wake); - } } } spin_unlock(&GlobalMid_Lock); @@ -749,18 +747,15 @@ multi_t2_fnd: list_for_each(tmp, &GlobalSMBSessionList) { ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); - if (ses->server == server) { + if (ses->server == server) ses->server = NULL; - } } write_unlock(&GlobalSMBSeslock); kfree(server); - if (length > 0) { - mempool_resize(cifs_req_poolp, - length + cifs_min_rcv, - GFP_KERNEL); - } + if (length > 0) + mempool_resize(cifs_req_poolp, length + cifs_min_rcv, + GFP_KERNEL); return 0; } @@ -1477,7 +1472,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, if (psin_server->sin_port) { /* user overrode default port */ rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, - sizeof (struct sockaddr_in), 0); + sizeof(struct sockaddr_in), 0); if (rc >= 0) connected = 1; } @@ -1493,7 +1488,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, - sizeof (struct sockaddr_in), 0); + sizeof(struct sockaddr_in), 0); if (rc >= 0) connected = 1; } @@ -1502,7 +1497,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, psin_server->sin_port = htons(RFC1001_PORT); rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, - sizeof (struct sockaddr_in), 0); + sizeof(struct sockaddr_in), 0); if (rc >= 0) connected = 1; } @@ -1610,7 +1605,7 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) if (psin_server->sin6_port) { /* user overrode default port */ rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, - sizeof (struct sockaddr_in6), 0); + sizeof(struct sockaddr_in6), 0); if (rc >= 0) connected = 1; } @@ -1626,7 +1621,7 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, - sizeof (struct sockaddr_in6), 0); + sizeof(struct sockaddr_in6), 0); if (rc >= 0) connected = 1; } @@ -1634,7 +1629,7 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) if (!connected) { psin_server->sin6_port = htons(RFC1001_PORT); rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) - psin_server, sizeof (struct sockaddr_in6), 0); + psin_server, sizeof(struct sockaddr_in6), 0); if (rc >= 0) connected = 1; } @@ -1750,7 +1745,16 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon, cFYI(1, ("very large write cap")); #endif /* CIFS_DEBUG2 */ if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) { - cFYI(1, ("setting capabilities failed")); + if (vol_info == NULL) { + cFYI(1, ("resetting capabilities failed")); + } else + cERROR(1, ("Negotiating Unix capabilities " + "with the server failed. Consider " + "mounting with the Unix Extensions\n" + "disabled, if problems are found, " + "by specifying the nounix mount " + "option.")); + } } } @@ -1909,8 +1913,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, return rc; } - srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL); - if (srvTcp == NULL) { + srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL); + if (!srvTcp) { rc = -ENOMEM; sock_release(csocket); kfree(volume_info.UNC); @@ -1919,9 +1923,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, FreeXid(xid); return rc; } else { - memset(srvTcp, 0, sizeof (struct TCP_Server_Info)); memcpy(&srvTcp->addr.sockAddr, &sin_server, - sizeof (struct sockaddr_in)); + sizeof(struct sockaddr_in)); atomic_set(&srvTcp->inFlight, 0); /* BB Add code for ipv6 case too */ srvTcp->ssocket = csocket; @@ -2173,8 +2176,18 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, if (tsk) kthread_stop(tsk); } - } else + } else { cFYI(1, ("No session or bad tcon")); + if ((pSesInfo->server) && + (pSesInfo->server->tsk)) { + struct task_struct *tsk; + force_sig(SIGKILL, + pSesInfo->server->tsk); + tsk = pSesInfo->server->tsk; + if (tsk) + kthread_stop(tsk); + } + } sesInfoFree(pSesInfo); /* pSesInfo = NULL; */ } @@ -2185,8 +2198,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, tcon->ses = pSesInfo; /* do not care if following two calls succeed - informational */ - CIFSSMBQFSDeviceInfo(xid, tcon); - CIFSSMBQFSAttributeInfo(xid, tcon); + if (!tcon->ipc) { + CIFSSMBQFSDeviceInfo(xid, tcon); + CIFSSMBQFSAttributeInfo(xid, tcon); + } /* tell server which Unix caps we support */ if (tcon->ses->capabilities & CAP_UNIX) @@ -2526,8 +2541,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, sesssetup_nomem: /* do not return an error on nomem for the info strings, since that could make reconnection harder, and reconnection might be needed to free memory */ - if (smb_buffer) - cifs_buf_release(smb_buffer); + cifs_buf_release(smb_buffer); return rc; } @@ -2547,7 +2561,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, int remaining_words = 0; int bytes_returned = 0; int len; - int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE); + int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE); PNEGOTIATE_MESSAGE SecurityBlob; PCHALLENGE_MESSAGE SecurityBlob2; __u32 negotiate_flags, capabilities; @@ -2865,15 +2879,14 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, rc = -EIO; } - if (smb_buffer) - cifs_buf_release(smb_buffer); + cifs_buf_release(smb_buffer); return rc; } static int CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, - char *ntlm_session_key, int ntlmv2_flag, - const struct nls_table *nls_codepage) + char *ntlm_session_key, int ntlmv2_flag, + const struct nls_table *nls_codepage) { struct smb_hdr *smb_buffer; struct smb_hdr *smb_buffer_response; @@ -2886,7 +2899,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, int remaining_words = 0; int bytes_returned = 0; int len; - int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE); + int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE); PAUTHENTICATE_MESSAGE SecurityBlob; __u32 negotiate_flags, capabilities; __u16 count; @@ -2901,8 +2914,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, return -ENOMEM; } smb_buffer_response = smb_buffer; - pSMB = (SESSION_SETUP_ANDX *) smb_buffer; - pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response; + pSMB = (SESSION_SETUP_ANDX *)smb_buffer; + pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response; /* send SMBsessionSetup here */ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, @@ -2921,7 +2934,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | - CAP_EXTENDED_SECURITY; + CAP_EXTENDED_SECURITY; if (ses->capabilities & CAP_UNICODE) { smb_buffer->Flags2 |= SMBFLG2_UNICODE; capabilities |= CAP_UNICODE; @@ -2936,15 +2949,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, } pSMB->req.Capabilities = cpu_to_le32(capabilities); - bcc_ptr = (char *) &pSMB->req.SecurityBlob; - SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr; + bcc_ptr = (char *)&pSMB->req.SecurityBlob; + SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr; strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); SecurityBlob->MessageType = NtLmAuthenticate; bcc_ptr += SecurityBlobLength; - negotiate_flags = - NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET | - NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO | - 0x80000000 | NTLMSSP_NEGOTIATE_128; + negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET | + NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO | + 0x80000000 | NTLMSSP_NEGOTIATE_128; if (sign_CIFS_PDUs) negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN; if (ntlmv2_flag) @@ -2979,36 +2991,32 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, SecurityBlob->DomainName.Length = 0; SecurityBlob->DomainName.MaximumLength = 0; } else { - __u16 len = - cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, + __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, nls_codepage); - len *= 2; + ln *= 2; SecurityBlob->DomainName.MaximumLength = - cpu_to_le16(len); + cpu_to_le16(ln); SecurityBlob->DomainName.Buffer = cpu_to_le32(SecurityBlobLength); - bcc_ptr += len; - SecurityBlobLength += len; - SecurityBlob->DomainName.Length = - cpu_to_le16(len); + bcc_ptr += ln; + SecurityBlobLength += ln; + SecurityBlob->DomainName.Length = cpu_to_le16(ln); } if (user == NULL) { SecurityBlob->UserName.Buffer = 0; SecurityBlob->UserName.Length = 0; SecurityBlob->UserName.MaximumLength = 0; } else { - __u16 len = - cifs_strtoUCS((__le16 *) bcc_ptr, user, 64, + __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64, nls_codepage); - len *= 2; + ln *= 2; SecurityBlob->UserName.MaximumLength = - cpu_to_le16(len); + cpu_to_le16(ln); SecurityBlob->UserName.Buffer = cpu_to_le32(SecurityBlobLength); - bcc_ptr += len; - SecurityBlobLength += len; - SecurityBlob->UserName.Length = - cpu_to_le16(len); + bcc_ptr += ln; + SecurityBlobLength += ln; + SecurityBlob->UserName.Length = cpu_to_le16(ln); } /* SecurityBlob->WorkstationName.Length = @@ -3052,33 +3060,32 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, SecurityBlob->DomainName.Length = 0; SecurityBlob->DomainName.MaximumLength = 0; } else { - __u16 len; + __u16 ln; negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED; strncpy(bcc_ptr, domain, 63); - len = strnlen(domain, 64); + ln = strnlen(domain, 64); SecurityBlob->DomainName.MaximumLength = - cpu_to_le16(len); + cpu_to_le16(ln); SecurityBlob->DomainName.Buffer = cpu_to_le32(SecurityBlobLength); - bcc_ptr += len; - SecurityBlobLength += len; - SecurityBlob->DomainName.Length = cpu_to_le16(len); + bcc_ptr += ln; + SecurityBlobLength += ln; + SecurityBlob->DomainName.Length = cpu_to_le16(ln); } if (user == NULL) { SecurityBlob->UserName.Buffer = 0; SecurityBlob->UserName.Length = 0; SecurityBlob->UserName.MaximumLength = 0; } else { - __u16 len; + __u16 ln; strncpy(bcc_ptr, user, 63); - len = strnlen(user, 64); - SecurityBlob->UserName.MaximumLength = - cpu_to_le16(len); + ln = strnlen(user, 64); + SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln); SecurityBlob->UserName.Buffer = - cpu_to_le32(SecurityBlobLength); - bcc_ptr += len; - SecurityBlobLength += len; - SecurityBlob->UserName.Length = cpu_to_le16(len); + cpu_to_le32(SecurityBlobLength); + bcc_ptr += ln; + SecurityBlobLength += ln; + SecurityBlob->UserName.Length = cpu_to_le16(ln); } /* BB fill in our workstation name if known BB */ @@ -3100,12 +3107,11 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &bytes_returned, 1); if (rc) { -/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ - } else if ((smb_buffer_response->WordCount == 3) - || (smb_buffer_response->WordCount == 4)) { +/* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */ + } else if ((smb_buffer_response->WordCount == 3) || + (smb_buffer_response->WordCount == 4)) { __u16 action = le16_to_cpu(pSMBr->resp.Action); - __u16 blob_len = - le16_to_cpu(pSMBr->resp.SecurityBlobLength); + __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); if (action & GUEST_LOGIN) cFYI(1, (" Guest login")); /* BB Should we set anything in SesInfo struct ? */ @@ -3145,8 +3151,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, } else { remaining_words = BCC(smb_buffer_response) / 2; } - len = - UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1); + len = UniStrnlen((wchar_t *) bcc_ptr, + remaining_words - 1); /* We look for obvious messed up bcc or strings in response so we do not go off the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ @@ -3230,7 +3236,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, <= BCC(smb_buffer_response)) { if (ses->serverOS) kfree(ses->serverOS); - ses->serverOS = kzalloc(len + 1,GFP_KERNEL); + ses->serverOS = kzalloc(len + 1, GFP_KERNEL); strncpy(ses->serverOS,bcc_ptr, len); bcc_ptr += len; @@ -3259,28 +3265,24 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr[0] = 0; bcc_ptr++; } else - cFYI(1, - ("field of length %d " + cFYI(1, ("field of length %d " "extends beyond end of smb ", len)); } } else { - cERROR(1, - (" Security Blob extends beyond end " + cERROR(1, ("Security Blob extends beyond end " "of SMB")); } } else { cERROR(1, ("No session structure passed in.")); } } else { - cERROR(1, - (" Invalid Word count %d: ", + cERROR(1, ("Invalid Word count %d: ", smb_buffer_response->WordCount)); rc = -EIO; } - if (smb_buffer) - cifs_buf_release(smb_buffer); + cifs_buf_release(smb_buffer); return rc; } @@ -3389,6 +3391,18 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr = pByteArea(smb_buffer_response); length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2); /* skip service field (NB: this field is always ASCII) */ + if (length == 3) { + if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') && + (bcc_ptr[2] == 'C')) { + cFYI(1, ("IPC connection")); + tcon->ipc = 1; + } + } else if (length == 2) { + if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) { + /* the most common case */ + cFYI(1, ("disk share connection")); + } + } bcc_ptr += length + 1; strncpy(tcon->treeName, tree, MAX_TREE_SIZE); if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { @@ -3399,9 +3413,11 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, kfree(tcon->nativeFileSystem); tcon->nativeFileSystem = kzalloc(length + 2, GFP_KERNEL); - cifs_strfromUCS_le(tcon->nativeFileSystem, - (__le16 *) bcc_ptr, - length, nls_codepage); + if (tcon->nativeFileSystem) + cifs_strfromUCS_le( + tcon->nativeFileSystem, + (__le16 *) bcc_ptr, + length, nls_codepage); bcc_ptr += 2 * length; bcc_ptr[0] = 0; /* null terminate the string */ bcc_ptr[1] = 0; @@ -3416,8 +3432,9 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, kfree(tcon->nativeFileSystem); tcon->nativeFileSystem = kzalloc(length + 1, GFP_KERNEL); - strncpy(tcon->nativeFileSystem, bcc_ptr, - length); + if (tcon->nativeFileSystem) + strncpy(tcon->nativeFileSystem, bcc_ptr, + length); } /* else do not bother copying these information fields*/ } @@ -3433,8 +3450,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, ses->ipc_tid = smb_buffer_response->Tid; } - if (smb_buffer) - cifs_buf_release(smb_buffer); + cifs_buf_release(smb_buffer); return rc; } diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 4830acc86d74..793404b10925 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -3,7 +3,7 @@ * * vfs operations that deal with dentries * - * Copyright (C) International Business Machines Corp., 2002,2005 + * Copyright (C) International Business Machines Corp., 2002,2007 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -269,7 +269,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, CIFSSMBClose(xid, pTcon, fileHandle); } else if (newinode) { pCifsFile = - kzalloc(sizeof (struct cifsFileInfo), GFP_KERNEL); + kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); if (pCifsFile == NULL) goto cifs_create_out; @@ -397,7 +397,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, /* BB Do not bother to decode buf since no local inode yet to put timestamps in, but we can reuse it safely */ - int bytes_written; + unsigned int bytes_written; struct win_dev *pdev; pdev = (struct win_dev *)buf; if (S_ISCHR(mode)) { @@ -450,8 +450,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, xid = GetXid(); - cFYI(1, - (" parent inode = 0x%p name is: %s and dentry = 0x%p", + cFYI(1, (" parent inode = 0x%p name is: %s and dentry = 0x%p", parent_dir_inode, direntry->d_name.name, direntry)); /* check whether path exists */ diff --git a/fs/cifs/export.c b/fs/cifs/export.c index 893fd0aebff8..d614b91caeca 100644 --- a/fs/cifs/export.c +++ b/fs/cifs/export.c @@ -43,6 +43,7 @@ #include <linux/exportfs.h> #include "cifsglob.h" #include "cifs_debug.h" +#include "cifsfs.h" #ifdef CONFIG_CIFS_EXPERIMENTAL static struct dentry *cifs_get_parent(struct dentry *dentry) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 894b1f7b299d..1e7e4c06d9e3 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -467,7 +467,7 @@ reopen_error_exit: int cifs_close(struct inode *inode, struct file *file) { int rc = 0; - int xid; + int xid, timeout; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; struct cifsFileInfo *pSMBFile = @@ -485,9 +485,9 @@ int cifs_close(struct inode *inode, struct file *file) /* no sense reconnecting to close a file that is already closed */ if (pTcon->tidStatus != CifsNeedReconnect) { - int timeout = 2; + timeout = 2; while ((atomic_read(&pSMBFile->wrtPending) != 0) - && (timeout < 1000) ) { + && (timeout <= 2048)) { /* Give write a better chance to get to server ahead of the close. We do not want to add a wait_q here as it would @@ -522,12 +522,30 @@ int cifs_close(struct inode *inode, struct file *file) list_del(&pSMBFile->flist); list_del(&pSMBFile->tlist); write_unlock(&GlobalSMBSeslock); + timeout = 10; + /* We waited above to give the SMBWrite a chance to issue + on the wire (so we do not get SMBWrite returning EBADF + if writepages is racing with close. Note that writepages + does not specify a file handle, so it is possible for a file + to be opened twice, and the application close the "wrong" + file handle - in these cases we delay long enough to allow + the SMBWrite to get on the wire before the SMB Close. + We allow total wait here over 45 seconds, more than + oplock break time, and more than enough to allow any write + to complete on the server, or to time out on the client */ + while ((atomic_read(&pSMBFile->wrtPending) != 0) + && (timeout <= 50000)) { + cERROR(1, ("writes pending, delay free of handle")); + msleep(timeout); + timeout *= 8; + } kfree(pSMBFile->search_resume_name); kfree(file->private_data); file->private_data = NULL; } else rc = -EBADF; + read_lock(&GlobalSMBSeslock); if (list_empty(&(CIFS_I(inode)->openFileList))) { cFYI(1, ("closing last open instance for inode %p", inode)); /* if the file is not open we do not know if we can cache info @@ -535,6 +553,7 @@ int cifs_close(struct inode *inode, struct file *file) CIFS_I(inode)->clientCanCacheRead = FALSE; CIFS_I(inode)->clientCanCacheAll = FALSE; } + read_unlock(&GlobalSMBSeslock); if ((rc == 0) && CIFS_I(inode)->write_behind_rc) rc = CIFS_I(inode)->write_behind_rc; FreeXid(xid); @@ -767,7 +786,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) mutex_lock(&fid->lock_mutex); list_for_each_entry_safe(li, tmp, &fid->llist, llist) { if (pfLock->fl_start <= li->offset && - length >= li->length) { + (pfLock->fl_start + length) >= + (li->offset + li->length)) { stored_rc = CIFSSMBLock(xid, pTcon, netfid, li->length, li->offset, @@ -1022,6 +1042,7 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) } read_lock(&GlobalSMBSeslock); +refind_writable: list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { if (open_file->closePend) continue; @@ -1029,24 +1050,49 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) ((open_file->pfile->f_flags & O_RDWR) || (open_file->pfile->f_flags & O_WRONLY))) { atomic_inc(&open_file->wrtPending); + + if (!open_file->invalidHandle) { + /* found a good writable file */ + read_unlock(&GlobalSMBSeslock); + return open_file; + } + read_unlock(&GlobalSMBSeslock); - if ((open_file->invalidHandle) && - (!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) { - rc = cifs_reopen_file(open_file->pfile, FALSE); - /* if it fails, try another handle - might be */ - /* dangerous to hold up writepages with retry */ - if (rc) { - cFYI(1, - ("failed on reopen file in wp")); + /* Had to unlock since following call can block */ + rc = cifs_reopen_file(open_file->pfile, FALSE); + if (!rc) { + if (!open_file->closePend) + return open_file; + else { /* start over in case this was deleted */ + /* since the list could be modified */ read_lock(&GlobalSMBSeslock); - /* can not use this handle, no write - pending on this one after all */ - atomic_dec - (&open_file->wrtPending); - continue; + atomic_dec(&open_file->wrtPending); + goto refind_writable; } } - return open_file; + + /* if it fails, try another handle if possible - + (we can not do this if closePending since + loop could be modified - in which case we + have to start at the beginning of the list + again. Note that it would be bad + to hold up writepages here (rather than + in caller) with continuous retries */ + cFYI(1, ("wp failed on reopen file")); + read_lock(&GlobalSMBSeslock); + /* can not use this handle, no write + pending on this one after all */ + atomic_dec(&open_file->wrtPending); + + if (open_file->closePend) /* list could have changed */ + goto refind_writable; + /* else we simply continue to the next entry. Thus + we do not loop on reopen errors. If we + can not reopen the file, for example if we + reconnected to a server with another client + racing to delete or lock the file we would not + make progress if we restarted before the beginning + of the loop here. */ } } read_unlock(&GlobalSMBSeslock); @@ -1709,7 +1755,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, struct page *page; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; - int bytes_read = 0; + unsigned int bytes_read = 0; unsigned int read_size, i; char *smb_read_data = NULL; struct smb_com_read_rsp *pSMBr; @@ -1803,7 +1849,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, i += bytes_read >> PAGE_CACHE_SHIFT; cifs_stats_bytes_read(pTcon, bytes_read); - if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { + if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) { i++; /* account for partial page */ /* server copy of file can have smaller size diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index dd4167762a8e..5e8b388be3b6 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -115,7 +115,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, inode->i_mode = le64_to_cpu(findData.Permissions); /* since we set the inode type below we need to mask off to avoid strange results if bits set above */ - inode->i_mode &= ~S_IFMT; + inode->i_mode &= ~S_IFMT; if (type == UNIX_FILE) { inode->i_mode |= S_IFREG; } else if (type == UNIX_SYMLINK) { @@ -575,19 +575,33 @@ int cifs_get_inode_info(struct inode **pinode, return rc; } +static const struct inode_operations cifs_ipc_inode_ops = { + .lookup = cifs_lookup, +}; + /* gets root inode */ void cifs_read_inode(struct inode *inode) { - int xid; + int xid, rc; struct cifs_sb_info *cifs_sb; cifs_sb = CIFS_SB(inode->i_sb); xid = GetXid(); if (cifs_sb->tcon->unix_ext) - cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid); + rc = cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid); else - cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid); + rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid); + if (rc && cifs_sb->tcon->ipc) { + cFYI(1, ("ipc connection - fake read inode")); + inode->i_mode |= S_IFDIR; + inode->i_nlink = 2; + inode->i_op = &cifs_ipc_inode_ops; + inode->i_fop = &simple_dir_operations; + inode->i_uid = cifs_sb->mnt_uid; + inode->i_gid = cifs_sb->mnt_gid; + } + /* can not call macro FreeXid here since in a void func */ _FreeXid(xid); } @@ -919,18 +933,25 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) goto mkdir_out; } + mode &= ~current->fs->umask; rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode, NULL /* netfid */, pInfo, &oplock, full_path, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); - if (rc) { + if (rc == -EOPNOTSUPP) { + kfree(pInfo); + goto mkdir_retry_old; + } else if (rc) { cFYI(1, ("posix mkdir returned 0x%x", rc)); d_drop(direntry); } else { int obj_type; - if (pInfo->Type == -1) /* no return info - go query */ + if (pInfo->Type == cpu_to_le32(-1)) { + /* no return info, go query for it */ + kfree(pInfo); goto mkdir_get_info; + } /*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need to set uid/gid */ inc_nlink(inode); @@ -940,8 +961,10 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) direntry->d_op = &cifs_dentry_ops; newinode = new_inode(inode->i_sb); - if (newinode == NULL) + if (newinode == NULL) { + kfree(pInfo); goto mkdir_get_info; + } /* Is an i_ino of zero legal? */ /* Are there sanity checks we can use to ensure that the server is really filling in that field? */ @@ -972,7 +995,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) kfree(pInfo); goto mkdir_out; } - +mkdir_retry_old: /* BB add setting the equivalent of mode via CreateX w/ACLs */ rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); @@ -1377,8 +1400,17 @@ static int cifs_vmtruncate(struct inode *inode, loff_t offset) } i_size_write(inode, offset); spin_unlock(&inode->i_lock); + /* + * unmap_mapping_range is called twice, first simply for efficiency + * so that truncate_inode_pages does fewer single-page unmaps. However + * after this first call, and before truncate_inode_pages finishes, + * it is possible for private pages to be COWed, which remain after + * truncate_inode_pages finishes, hence the second unmap_mapping_range + * call must be made for correctness. + */ unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); truncate_inode_pages(mapping, offset); + unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); goto out_truncate; do_expand: @@ -1469,7 +1501,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) atomic_dec(&open_file->wrtPending); cFYI(1, ("SetFSize for attrs rc = %d", rc)); if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { - int bytes_written; + unsigned int bytes_written; rc = CIFSSMBWrite(xid, pTcon, nfid, 0, attrs->ia_size, &bytes_written, NULL, NULL, @@ -1502,7 +1534,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc == 0) { - int bytes_written; + unsigned int bytes_written; rc = CIFSSMBWrite(xid, pTcon, netfid, 0, attrs->ia_size, @@ -1538,6 +1570,11 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) } time_buf.Attributes = 0; + + /* skip mode change if it's just for clearing setuid/setgid */ + if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) + attrs->ia_valid &= ~ATTR_MODE; + if (attrs->ia_valid & ATTR_MODE) { cFYI(1, ("Mode changed to 0x%x", attrs->ia_mode)); mode = attrs->ia_mode; diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 6a85ef7b8797..11f265726db7 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -237,7 +237,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) char *tmp_path = NULL; char *tmpbuffer; unsigned char *referrals = NULL; - int num_referrals = 0; + unsigned int num_referrals = 0; int len; __u16 fid; diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 0bcec0844bee..51ec681fe74a 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -169,7 +169,6 @@ cifs_buf_get(void) void cifs_buf_release(void *buf_to_free) { - if (buf_to_free == NULL) { /* cFYI(1, ("Null buffer passed to cifs_buf_release"));*/ return; diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 2bfed3f45d0f..f06359cb22ee 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -114,10 +114,16 @@ static const struct smb_to_posix_error mapping_table_ERRSRV[] = { {ERRusempx, -EIO}, {ERRusestd, -EIO}, {ERR_NOTIFY_ENUM_DIR, -ENOBUFS}, - {ERRaccountexpired, -EACCES}, + {ERRnoSuchUser, -EACCES}, +/* {ERRaccountexpired, -EACCES}, {ERRbadclient, -EACCES}, {ERRbadLogonTime, -EACCES}, - {ERRpasswordExpired, -EACCES}, + {ERRpasswordExpired, -EACCES},*/ + {ERRaccountexpired, -EKEYEXPIRED}, + {ERRbadclient, -EACCES}, + {ERRbadLogonTime, -EACCES}, + {ERRpasswordExpired, -EKEYEXPIRED}, + {ERRnosupport, -EINVAL}, {0, 0} }; @@ -270,7 +276,7 @@ static const struct { from NT_STATUS_NO_SUCH_USER to NT_STATUS_LOGON_FAILURE during the session setup } */ { - ERRDOS, ERRnoaccess, NT_STATUS_NO_SUCH_USER}, { + ERRDOS, ERRnoaccess, NT_STATUS_NO_SUCH_USER}, { /* could map to 2238 */ ERRHRD, ERRgeneral, NT_STATUS_GROUP_EXISTS}, { ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_GROUP}, { ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_GROUP}, { @@ -285,10 +291,10 @@ static const struct { ERRHRD, ERRgeneral, NT_STATUS_PASSWORD_RESTRICTION}, { ERRDOS, ERRnoaccess, NT_STATUS_LOGON_FAILURE}, { ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION}, { - ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS}, { - ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION}, { + ERRSRV, ERRbadLogonTime, NT_STATUS_INVALID_LOGON_HOURS}, { + ERRSRV, ERRbadclient, NT_STATUS_INVALID_WORKSTATION}, { ERRSRV, ERRpasswordExpired, NT_STATUS_PASSWORD_EXPIRED}, { - ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED}, { + ERRSRV, ERRaccountexpired, NT_STATUS_ACCOUNT_DISABLED}, { ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED}, { ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, { ERRHRD, ERRgeneral, NT_STATUS_LUIDS_EXHAUSTED}, { @@ -585,7 +591,7 @@ static const struct { ERRDOS, ERRnoaccess, NT_STATUS_TRUST_FAILURE}, { ERRHRD, ERRgeneral, NT_STATUS_MUTANT_LIMIT_EXCEEDED}, { ERRDOS, ERRnetlogonNotStarted, NT_STATUS_NETLOGON_NOT_STARTED}, { - ERRSRV, 2239, NT_STATUS_ACCOUNT_EXPIRED}, { + ERRSRV, ERRaccountexpired, NT_STATUS_ACCOUNT_EXPIRED}, { ERRHRD, ERRgeneral, NT_STATUS_POSSIBLE_DEADLOCK}, { ERRHRD, ERRgeneral, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT}, { ERRHRD, ERRgeneral, NT_STATUS_REMOTE_SESSION_LIMIT}, { @@ -754,7 +760,7 @@ ntstatus_to_dos(__u32 ntstatus, __u8 * eclass, __u16 * ecode) } int -map_smb_to_linux_error(struct smb_hdr *smb) +map_smb_to_linux_error(struct smb_hdr *smb, int logErr) { unsigned int i; int rc = -EIO; /* if transport error smb error may not be set */ @@ -771,7 +777,9 @@ map_smb_to_linux_error(struct smb_hdr *smb) /* translate the newer STATUS codes to old style SMB errors * and then to POSIX errors */ __u32 err = le32_to_cpu(smb->Status.CifsError); - if (cifsFYI & CIFS_RC) + if (logErr && (err != (NT_STATUS_MORE_PROCESSING_REQUIRED))) + cifs_print_status(err); + else if (cifsFYI & CIFS_RC) cifs_print_status(err); ntstatus_to_dos(err, &smberrclass, &smberrcode); } else { @@ -813,7 +821,7 @@ map_smb_to_linux_error(struct smb_hdr *smb) } /* else ERRHRD class errors or junk - return EIO */ - cFYI(1, (" !!Mapping smb error code %d to POSIX err %d !!", + cFYI(1, ("Mapping smb error code %d to POSIX err %d", smberrcode, rc)); /* generic corrective action e.g. reconnect SMB session on @@ -899,8 +907,11 @@ struct timespec cnvrtDosUnixTm(__u16 date, __u16 time) cERROR(1, ("illegal hours %d", st->Hours)); days = sd->Day; month = sd->Month; - if ((days > 31) || (month > 12)) + if ((days > 31) || (month > 12)) { cERROR(1, ("illegal date, month %d day: %d", month, days)); + if (month > 12) + month = 12; + } month -= 1; days += total_days_of_prev_months[month]; days += 3652; /* account for difference in days between 1980 and 1970 */ diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 916df9431336..3746580e9701 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -121,7 +121,7 @@ static void AdjustForTZ(struct cifsTconInfo *tcon, struct inode *inode) static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, - char *buf, int *pobject_type, int isNewInode) + char *buf, unsigned int *pobject_type, int isNewInode) { loff_t local_size; struct timespec local_mtime; @@ -294,7 +294,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, } static void unix_fill_in_inode(struct inode *tmp_inode, - FILE_UNIX_INFO *pfindData, int *pobject_type, int isNewInode) + FILE_UNIX_INFO *pfindData, unsigned int *pobject_type, int isNewInode) { loff_t local_size; struct timespec local_mtime; @@ -826,7 +826,7 @@ static int cifs_filldir(char *pfindEntry, struct file *file, int rc = 0; struct qstr qstring; struct cifsFileInfo *pCifsF; - unsigned obj_type; + unsigned int obj_type; ino_t inum; struct cifs_sb_info *cifs_sb; struct inode *tmp_inode; @@ -1067,7 +1067,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) for (i = 0; (i < num_to_fill) && (rc == 0); i++) { if (current_entry == NULL) { /* evaluate whether this case is an error */ - cERROR(1,("past end of SMB num to fill %d i %d", + cERROR(1, ("past SMB end, num to fill %d i %d", num_to_fill, i)); break; } diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 892be9b4d1f3..899dc6078d9a 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -67,14 +67,59 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) pSMB->req.hdr.Flags2 |= SMBFLG2_DFS; capabilities |= CAP_DFS; } - if (ses->capabilities & CAP_UNIX) { + if (ses->capabilities & CAP_UNIX) capabilities |= CAP_UNIX; - } /* BB check whether to init vcnum BB */ return capabilities; } +static void +unicode_oslm_strings(char **pbcc_area, const struct nls_table *nls_cp) +{ + char *bcc_ptr = *pbcc_area; + int bytes_ret = 0; + + /* Copy OS version */ + bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32, + nls_cp); + bcc_ptr += 2 * bytes_ret; + bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, init_utsname()->release, + 32, nls_cp); + bcc_ptr += 2 * bytes_ret; + bcc_ptr += 2; /* trailing null */ + + bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, + 32, nls_cp); + bcc_ptr += 2 * bytes_ret; + bcc_ptr += 2; /* trailing null */ + + *pbcc_area = bcc_ptr; +} + +static void unicode_domain_string(char **pbcc_area, struct cifsSesInfo *ses, + const struct nls_table *nls_cp) +{ + char *bcc_ptr = *pbcc_area; + int bytes_ret = 0; + + /* copy domain */ + if (ses->domainName == NULL) { + /* Sending null domain better than using a bogus domain name (as + we did briefly in 2.6.18) since server will use its default */ + *bcc_ptr = 0; + *(bcc_ptr+1) = 0; + bytes_ret = 0; + } else + bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName, + 256, nls_cp); + bcc_ptr += 2 * bytes_ret; + bcc_ptr += 2; /* account for null terminator */ + + *pbcc_area = bcc_ptr; +} + + static void unicode_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, const struct nls_table *nls_cp) { @@ -100,32 +145,9 @@ static void unicode_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, } bcc_ptr += 2 * bytes_ret; bcc_ptr += 2; /* account for null termination */ - /* copy domain */ - if (ses->domainName == NULL) { - /* Sending null domain better than using a bogus domain name (as - we did briefly in 2.6.18) since server will use its default */ - *bcc_ptr = 0; - *(bcc_ptr+1) = 0; - bytes_ret = 0; - } else - bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName, - 256, nls_cp); - bcc_ptr += 2 * bytes_ret; - bcc_ptr += 2; /* account for null terminator */ - - /* Copy OS version */ - bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32, - nls_cp); - bcc_ptr += 2 * bytes_ret; - bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, init_utsname()->release, - 32, nls_cp); - bcc_ptr += 2 * bytes_ret; - bcc_ptr += 2; /* trailing null */ - bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, - 32, nls_cp); - bcc_ptr += 2 * bytes_ret; - bcc_ptr += 2; /* trailing null */ + unicode_domain_string(&bcc_ptr, ses, nls_cp); + unicode_oslm_strings(&bcc_ptr, nls_cp); *pbcc_area = bcc_ptr; } @@ -203,14 +225,11 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft, if (len >= words_left) return rc; - if (ses->serverOS) - kfree(ses->serverOS); + kfree(ses->serverOS); /* UTF-8 string will not grow more than four times as big as UCS-16 */ ses->serverOS = kzalloc(4 * len, GFP_KERNEL); - if (ses->serverOS != NULL) { - cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, - nls_cp); - } + if (ses->serverOS != NULL) + cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, nls_cp); data += 2 * (len + 1); words_left -= len + 1; @@ -220,8 +239,7 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft, if (len >= words_left) return rc; - if (ses->serverNOS) - kfree(ses->serverNOS); + kfree(ses->serverNOS); ses->serverNOS = kzalloc(4 * len, GFP_KERNEL); /* BB this is wrong length FIXME BB */ if (ses->serverNOS != NULL) { cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len, @@ -240,8 +258,7 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft, if (len > words_left) return rc; - if (ses->serverDomain) - kfree(ses->serverDomain); + kfree(ses->serverDomain); ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */ if (ses->serverDomain != NULL) { cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len, @@ -271,8 +288,7 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft, if (len >= bleft) return rc; - if (ses->serverOS) - kfree(ses->serverOS); + kfree(ses->serverOS); ses->serverOS = kzalloc(len + 1, GFP_KERNEL); if (ses->serverOS) @@ -289,8 +305,7 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft, if (len >= bleft) return rc; - if (ses->serverNOS) - kfree(ses->serverNOS); + kfree(ses->serverNOS); ses->serverNOS = kzalloc(len + 1, GFP_KERNEL); if (ses->serverNOS) @@ -479,7 +494,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, if (ses->capabilities & CAP_UNICODE) { if (iov[0].iov_len % 2) { *bcc_ptr = 0; - } bcc_ptr++; + bcc_ptr++; + } unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); } else ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); @@ -497,7 +513,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, iov[1].iov_base = str_area; iov[1].iov_len = count; - rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, 0); + rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, + 0 /* not long op */, 1 /* log NT STATUS if any */ ); /* SMB request buf freed in SendReceive2 */ cFYI(1, ("ssetup rc from sendrecv2 is %d", rc)); diff --git a/fs/cifs/smberr.h b/fs/cifs/smberr.h index 2ef0be288820..7f50e8577c1c 100644 --- a/fs/cifs/smberr.h +++ b/fs/cifs/smberr.h @@ -173,9 +173,10 @@ #define ERRusestd 251 /* temporarily unable to use either raw or mpx */ #define ERR_NOTIFY_ENUM_DIR 1024 +#define ERRnoSuchUser 2238 /* user account does not exist */ #define ERRaccountexpired 2239 -#define ERRbadclient 2240 -#define ERRbadLogonTime 2241 +#define ERRbadclient 2240 /* can not logon from this client */ +#define ERRbadLogonTime 2241 /* logon hours do not allow this */ #define ERRpasswordExpired 2242 #define ERRnetlogonNotStarted 2455 #define ERRnosupport 0xFFFF diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 746bc9405db1..7ed32b3cb781 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -55,7 +55,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) if (temp == NULL) return temp; else { - memset(temp, 0, sizeof (struct mid_q_entry)); + memset(temp, 0, sizeof(struct mid_q_entry)); temp->mid = smb_buffer->Mid; /* always LE */ temp->pid = current->pid; temp->command = smb_buffer->Command; @@ -158,7 +158,7 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, iov.iov_len = len; smb_msg.msg_name = sin; - smb_msg.msg_namelen = sizeof (struct sockaddr); + smb_msg.msg_namelen = sizeof(struct sockaddr); smb_msg.msg_control = NULL; smb_msg.msg_controllen = 0; smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/ @@ -228,7 +228,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, return -ENOTSOCK; /* BB eventually add reconnect code here */ smb_msg.msg_name = sin; - smb_msg.msg_namelen = sizeof (struct sockaddr); + smb_msg.msg_namelen = sizeof(struct sockaddr); smb_msg.msg_control = NULL; smb_msg.msg_controllen = 0; smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/ @@ -363,9 +363,8 @@ static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf, } /* else ok - we are setting up session */ } *ppmidQ = AllocMidQEntry(in_buf, ses); - if (*ppmidQ == NULL) { + if (*ppmidQ == NULL) return -ENOMEM; - } return 0; } @@ -419,7 +418,7 @@ static int wait_for_response(struct cifsSesInfo *ses, int SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, struct kvec *iov, int n_vec, int *pRespBufType /* ret */, - const int long_op) + const int long_op, const int logError) { int rc = 0; unsigned int receive_len; @@ -465,7 +464,6 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, wake_up(&ses->server->request_q); return rc; } - rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); midQ->midState = MID_REQUEST_SUBMITTED; @@ -568,13 +566,11 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, } /* BB special case reconnect tid and uid here? */ - /* BB special case Errbadpassword and pwdexpired here */ - rc = map_smb_to_linux_error(midQ->resp_buf); + rc = map_smb_to_linux_error(midQ->resp_buf, logError); /* convert ByteCount if necessary */ - if (receive_len >= - sizeof (struct smb_hdr) - - 4 /* do not count RFC1001 header */ + + if (receive_len >= sizeof(struct smb_hdr) - 4 + /* do not count RFC1001 header */ + (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) BCC(midQ->resp_buf) = le16_to_cpu(BCC_LE(midQ->resp_buf)); @@ -749,12 +745,11 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, *pbytes_returned = out_buf->smb_buf_length; /* BB special case reconnect tid and uid here? */ - rc = map_smb_to_linux_error(out_buf); + rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); /* convert ByteCount if necessary */ - if (receive_len >= - sizeof (struct smb_hdr) - - 4 /* do not count RFC1001 header */ + + if (receive_len >= sizeof(struct smb_hdr) - 4 + /* do not count RFC1001 header */ + (2 * out_buf->WordCount) + 2 /* bcc */ ) BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); } else { @@ -993,12 +988,11 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, *pbytes_returned = out_buf->smb_buf_length; /* BB special case reconnect tid and uid here? */ - rc = map_smb_to_linux_error(out_buf); + rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); /* convert ByteCount if necessary */ - if (receive_len >= - sizeof (struct smb_hdr) - - 4 /* do not count RFC1001 header */ + + if (receive_len >= sizeof(struct smb_hdr) - 4 + /* do not count RFC1001 header */ + (2 * out_buf->WordCount) + 2 /* bcc */ ) BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); } else { diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index f61e433d281c..369e838bebd3 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -261,21 +261,26 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); -/* else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { +#ifdef CONFIG_CIFS_EXPERIMENTAL + else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { __u16 fid; int oplock = FALSE; - rc = CIFSSMBOpen(xid, pTcon, full_path, - FILE_OPEN, GENERIC_READ, 0, &fid, - &oplock, NULL, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); + if (experimEnabled) + rc = CIFSSMBOpen(xid, pTcon, full_path, + FILE_OPEN, GENERIC_READ, 0, &fid, + &oplock, NULL, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); + /* else rc is EOPNOTSUPP from above */ + if(rc == 0) { rc = CIFSSMBGetCIFSACL(xid, pTcon, fid, ea_value, buf_size, ACL_TYPE_ACCESS); CIFSSMBClose(xid, pTcon, fid); } - } */ /* BB enable after fixing up return data */ + } +#endif /* EXPERIMENTAL */ #else cFYI(1, ("query POSIX ACL not supported yet")); #endif /* CONFIG_CIFS_POSIX */ diff --git a/fs/coda/inode.c b/fs/coda/inode.c index 342f4e0d582e..2f58dfc70083 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -58,7 +58,7 @@ static void coda_destroy_inode(struct inode *inode) kmem_cache_free(coda_inode_cachep, ITOC(inode)); } -static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(struct kmem_cache * cachep, void *foo) { struct coda_inode_info *ei = (struct coda_inode_info *) foo; diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index cdb4c07a7870..359e531094dd 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c @@ -51,7 +51,7 @@ static void *alloc_upcall(int opcode, int size) inp->ih.opcode = opcode; inp->ih.pid = current->pid; - inp->ih.pgid = process_group(current); + inp->ih.pgid = task_pgrp_nr(current); #ifdef CONFIG_CODA_FS_OLD_API memset(&inp->ih.cred, 0, sizeof(struct coda_cred)); inp->ih.cred.cr_fsuid = current->fsuid; diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 37310b0e8107..a4284ccac1f9 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -21,7 +21,6 @@ #include <linux/if.h> #include <linux/if_bridge.h> #include <linux/slab.h> -#include <linux/hdreg.h> #include <linux/raid/md.h> #include <linux/kd.h> #include <linux/dirent.h> @@ -33,12 +32,10 @@ #include <linux/vt.h> #include <linux/fs.h> #include <linux/file.h> -#include <linux/fd.h> #include <linux/ppp_defs.h> #include <linux/if_ppp.h> #include <linux/if_pppox.h> #include <linux/mtio.h> -#include <linux/cdrom.h> #include <linux/auto_fs.h> #include <linux/auto_fs4.h> #include <linux/tty.h> @@ -48,7 +45,6 @@ #include <linux/netdevice.h> #include <linux/raw.h> #include <linux/smb_fs.h> -#include <linux/blkpg.h> #include <linux/blkdev.h> #include <linux/elevator.h> #include <linux/rtc.h> @@ -62,7 +58,6 @@ #include <linux/i2c-dev.h> #include <linux/wireless.h> #include <linux/atalk.h> -#include <linux/blktrace_api.h> #include <linux/loop.h> #include <net/bluetooth/bluetooth.h> @@ -113,7 +108,6 @@ #include <linux/dvb/dmx.h> #include <linux/dvb/frontend.h> #include <linux/dvb/video.h> -#include <linux/lp.h> #ifdef CONFIG_SPARC #include <asm/fbio.h> @@ -324,22 +318,21 @@ struct ifconf32 { static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg) { - struct net_device *dev; - struct ifreq32 ifr32; + struct ifreq __user *uifr; int err; - if (copy_from_user(&ifr32, compat_ptr(arg), sizeof(ifr32))) + uifr = compat_alloc_user_space(sizeof(struct ifreq)); + if (copy_in_user(uifr, compat_ptr(arg), sizeof(struct ifreq32))); return -EFAULT; - dev = dev_get_by_index(ifr32.ifr_ifindex); - if (!dev) - return -ENODEV; + err = sys_ioctl(fd, SIOCGIFNAME, (unsigned long)uifr); + if (err) + return err; - strlcpy(ifr32.ifr_name, dev->name, sizeof(ifr32.ifr_name)); - dev_put(dev); - - err = copy_to_user(compat_ptr(arg), &ifr32, sizeof(ifr32)); - return (err ? -EFAULT : 0); + if (copy_in_user(compat_ptr(arg), uifr, sizeof(struct ifreq32))) + return -EFAULT; + + return 0; } static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg) @@ -668,53 +661,6 @@ out: #endif #ifdef CONFIG_BLOCK -struct hd_geometry32 { - unsigned char heads; - unsigned char sectors; - unsigned short cylinders; - u32 start; -}; - -static int hdio_getgeo(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - struct hd_geometry geo; - struct hd_geometry32 __user *ugeo; - int err; - - set_fs (KERNEL_DS); - err = sys_ioctl(fd, HDIO_GETGEO, (unsigned long)&geo); - set_fs (old_fs); - ugeo = compat_ptr(arg); - if (!err) { - err = copy_to_user (ugeo, &geo, 4); - err |= __put_user (geo.start, &ugeo->start); - if (err) - err = -EFAULT; - } - return err; -} - -static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - unsigned long kval; - unsigned int __user *uvp; - int error; - - set_fs(KERNEL_DS); - error = sys_ioctl(fd, cmd, (long)&kval); - set_fs(old_fs); - - if(error == 0) { - uvp = compat_ptr(arg); - if(put_user(kval, uvp)) - error = -EFAULT; - } - return error; -} - - typedef struct sg_io_hdr32 { compat_int_t interface_id; /* [i] 'S' for SCSI generic (required) */ compat_int_t dxfer_direction; /* [i] data transfer direction */ @@ -1089,108 +1035,6 @@ static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) return err ? -EFAULT: 0; } -struct cdrom_read_audio32 { - union cdrom_addr addr; - u8 addr_format; - compat_int_t nframes; - compat_caddr_t buf; -}; - -struct cdrom_generic_command32 { - unsigned char cmd[CDROM_PACKET_SIZE]; - compat_caddr_t buffer; - compat_uint_t buflen; - compat_int_t stat; - compat_caddr_t sense; - unsigned char data_direction; - compat_int_t quiet; - compat_int_t timeout; - compat_caddr_t reserved[1]; -}; - -static int cdrom_do_read_audio(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct cdrom_read_audio __user *cdread_audio; - struct cdrom_read_audio32 __user *cdread_audio32; - __u32 data; - void __user *datap; - - cdread_audio = compat_alloc_user_space(sizeof(*cdread_audio)); - cdread_audio32 = compat_ptr(arg); - - if (copy_in_user(&cdread_audio->addr, - &cdread_audio32->addr, - (sizeof(*cdread_audio32) - - sizeof(compat_caddr_t)))) - return -EFAULT; - - if (get_user(data, &cdread_audio32->buf)) - return -EFAULT; - datap = compat_ptr(data); - if (put_user(datap, &cdread_audio->buf)) - return -EFAULT; - - return sys_ioctl(fd, cmd, (unsigned long) cdread_audio); -} - -static int cdrom_do_generic_command(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct cdrom_generic_command __user *cgc; - struct cdrom_generic_command32 __user *cgc32; - u32 data; - unsigned char dir; - int itmp; - - cgc = compat_alloc_user_space(sizeof(*cgc)); - cgc32 = compat_ptr(arg); - - if (copy_in_user(&cgc->cmd, &cgc32->cmd, sizeof(cgc->cmd)) || - get_user(data, &cgc32->buffer) || - put_user(compat_ptr(data), &cgc->buffer) || - copy_in_user(&cgc->buflen, &cgc32->buflen, - (sizeof(unsigned int) + sizeof(int))) || - get_user(data, &cgc32->sense) || - put_user(compat_ptr(data), &cgc->sense) || - get_user(dir, &cgc32->data_direction) || - put_user(dir, &cgc->data_direction) || - get_user(itmp, &cgc32->quiet) || - put_user(itmp, &cgc->quiet) || - get_user(itmp, &cgc32->timeout) || - put_user(itmp, &cgc->timeout) || - get_user(data, &cgc32->reserved[0]) || - put_user(compat_ptr(data), &cgc->reserved[0])) - return -EFAULT; - - return sys_ioctl(fd, cmd, (unsigned long) cgc); -} - -static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - int err; - - switch(cmd) { - case CDROMREADAUDIO: - err = cdrom_do_read_audio(fd, cmd, arg); - break; - - case CDROM_SEND_PACKET: - err = cdrom_do_generic_command(fd, cmd, arg); - break; - - default: - do { - static int count; - if (++count <= 20) - printk("cdrom_ioctl: Unknown cmd fd(%d) " - "cmd(%08x) arg(%08x)\n", - (int)fd, (unsigned int)cmd, (unsigned int)arg); - } while(0); - err = -EINVAL; - break; - }; - - return err; -} #endif /* CONFIG_BLOCK */ #ifdef CONFIG_VT @@ -1536,71 +1380,11 @@ ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg) return -EINVAL; } -#ifdef CONFIG_BLOCK -static int broken_blkgetsize(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - /* The mkswap binary hard codes it to Intel value :-((( */ - return w_long(fd, BLKGETSIZE, arg); -} - -struct blkpg_ioctl_arg32 { - compat_int_t op; - compat_int_t flags; - compat_int_t datalen; - compat_caddr_t data; -}; - -static int blkpg_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct blkpg_ioctl_arg32 __user *ua32 = compat_ptr(arg); - struct blkpg_ioctl_arg __user *a = compat_alloc_user_space(sizeof(*a)); - compat_caddr_t udata; - compat_int_t n; - int err; - - err = get_user(n, &ua32->op); - err |= put_user(n, &a->op); - err |= get_user(n, &ua32->flags); - err |= put_user(n, &a->flags); - err |= get_user(n, &ua32->datalen); - err |= put_user(n, &a->datalen); - err |= get_user(udata, &ua32->data); - err |= put_user(compat_ptr(udata), &a->data); - if (err) - return err; - - return sys_ioctl(fd, cmd, (unsigned long)a); -} -#endif - static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg) { return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg); } -#ifdef CONFIG_BLOCK -/* Fix sizeof(sizeof()) breakage */ -#define BLKBSZGET_32 _IOR(0x12,112,int) -#define BLKBSZSET_32 _IOW(0x12,113,int) -#define BLKGETSIZE64_32 _IOR(0x12,114,int) - -static int do_blkbszget(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - return sys_ioctl(fd, BLKBSZGET, (unsigned long)compat_ptr(arg)); -} - -static int do_blkbszset(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - return sys_ioctl(fd, BLKBSZSET, (unsigned long)compat_ptr(arg)); -} - -static int do_blkgetsize64(unsigned int fd, unsigned int cmd, - unsigned long arg) -{ - return sys_ioctl(fd, BLKGETSIZE64, (unsigned long)compat_ptr(arg)); -} -#endif - /* Bluetooth ioctls */ #define HCIUARTSETPROTO _IOW('U', 200, int) #define HCIUARTGETPROTO _IOR('U', 201, int) @@ -1620,333 +1404,6 @@ static int do_blkgetsize64(unsigned int fd, unsigned int cmd, #define HIDPGETCONNLIST _IOR('H', 210, int) #define HIDPGETCONNINFO _IOR('H', 211, int) -#ifdef CONFIG_BLOCK -struct floppy_struct32 { - compat_uint_t size; - compat_uint_t sect; - compat_uint_t head; - compat_uint_t track; - compat_uint_t stretch; - unsigned char gap; - unsigned char rate; - unsigned char spec1; - unsigned char fmt_gap; - const compat_caddr_t name; -}; - -struct floppy_drive_params32 { - char cmos; - compat_ulong_t max_dtr; - compat_ulong_t hlt; - compat_ulong_t hut; - compat_ulong_t srt; - compat_ulong_t spinup; - compat_ulong_t spindown; - unsigned char spindown_offset; - unsigned char select_delay; - unsigned char rps; - unsigned char tracks; - compat_ulong_t timeout; - unsigned char interleave_sect; - struct floppy_max_errors max_errors; - char flags; - char read_track; - short autodetect[8]; - compat_int_t checkfreq; - compat_int_t native_format; -}; - -struct floppy_drive_struct32 { - signed char flags; - compat_ulong_t spinup_date; - compat_ulong_t select_date; - compat_ulong_t first_read_date; - short probed_format; - short track; - short maxblock; - short maxtrack; - compat_int_t generation; - compat_int_t keep_data; - compat_int_t fd_ref; - compat_int_t fd_device; - compat_int_t last_checked; - compat_caddr_t dmabuf; - compat_int_t bufblocks; -}; - -struct floppy_fdc_state32 { - compat_int_t spec1; - compat_int_t spec2; - compat_int_t dtr; - unsigned char version; - unsigned char dor; - compat_ulong_t address; - unsigned int rawcmd:2; - unsigned int reset:1; - unsigned int need_configure:1; - unsigned int perp_mode:2; - unsigned int has_fifo:1; - unsigned int driver_version; - unsigned char track[4]; -}; - -struct floppy_write_errors32 { - unsigned int write_errors; - compat_ulong_t first_error_sector; - compat_int_t first_error_generation; - compat_ulong_t last_error_sector; - compat_int_t last_error_generation; - compat_uint_t badness; -}; - -#define FDSETPRM32 _IOW(2, 0x42, struct floppy_struct32) -#define FDDEFPRM32 _IOW(2, 0x43, struct floppy_struct32) -#define FDGETPRM32 _IOR(2, 0x04, struct floppy_struct32) -#define FDSETDRVPRM32 _IOW(2, 0x90, struct floppy_drive_params32) -#define FDGETDRVPRM32 _IOR(2, 0x11, struct floppy_drive_params32) -#define FDGETDRVSTAT32 _IOR(2, 0x12, struct floppy_drive_struct32) -#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct floppy_drive_struct32) -#define FDGETFDCSTAT32 _IOR(2, 0x15, struct floppy_fdc_state32) -#define FDWERRORGET32 _IOR(2, 0x17, struct floppy_write_errors32) - -static struct { - unsigned int cmd32; - unsigned int cmd; -} fd_ioctl_trans_table[] = { - { FDSETPRM32, FDSETPRM }, - { FDDEFPRM32, FDDEFPRM }, - { FDGETPRM32, FDGETPRM }, - { FDSETDRVPRM32, FDSETDRVPRM }, - { FDGETDRVPRM32, FDGETDRVPRM }, - { FDGETDRVSTAT32, FDGETDRVSTAT }, - { FDPOLLDRVSTAT32, FDPOLLDRVSTAT }, - { FDGETFDCSTAT32, FDGETFDCSTAT }, - { FDWERRORGET32, FDWERRORGET } -}; - -#define NR_FD_IOCTL_TRANS ARRAY_SIZE(fd_ioctl_trans_table) - -static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - void *karg = NULL; - unsigned int kcmd = 0; - int i, err; - - for (i = 0; i < NR_FD_IOCTL_TRANS; i++) - if (cmd == fd_ioctl_trans_table[i].cmd32) { - kcmd = fd_ioctl_trans_table[i].cmd; - break; - } - if (!kcmd) - return -EINVAL; - - switch (cmd) { - case FDSETPRM32: - case FDDEFPRM32: - case FDGETPRM32: - { - compat_uptr_t name; - struct floppy_struct32 __user *uf; - struct floppy_struct *f; - - uf = compat_ptr(arg); - f = karg = kmalloc(sizeof(struct floppy_struct), GFP_KERNEL); - if (!karg) - return -ENOMEM; - if (cmd == FDGETPRM32) - break; - err = __get_user(f->size, &uf->size); - err |= __get_user(f->sect, &uf->sect); - err |= __get_user(f->head, &uf->head); - err |= __get_user(f->track, &uf->track); - err |= __get_user(f->stretch, &uf->stretch); - err |= __get_user(f->gap, &uf->gap); - err |= __get_user(f->rate, &uf->rate); - err |= __get_user(f->spec1, &uf->spec1); - err |= __get_user(f->fmt_gap, &uf->fmt_gap); - err |= __get_user(name, &uf->name); - f->name = compat_ptr(name); - if (err) { - err = -EFAULT; - goto out; - } - break; - } - case FDSETDRVPRM32: - case FDGETDRVPRM32: - { - struct floppy_drive_params32 __user *uf; - struct floppy_drive_params *f; - - uf = compat_ptr(arg); - f = karg = kmalloc(sizeof(struct floppy_drive_params), GFP_KERNEL); - if (!karg) - return -ENOMEM; - if (cmd == FDGETDRVPRM32) - break; - err = __get_user(f->cmos, &uf->cmos); - err |= __get_user(f->max_dtr, &uf->max_dtr); - err |= __get_user(f->hlt, &uf->hlt); - err |= __get_user(f->hut, &uf->hut); - err |= __get_user(f->srt, &uf->srt); - err |= __get_user(f->spinup, &uf->spinup); - err |= __get_user(f->spindown, &uf->spindown); - err |= __get_user(f->spindown_offset, &uf->spindown_offset); - err |= __get_user(f->select_delay, &uf->select_delay); - err |= __get_user(f->rps, &uf->rps); - err |= __get_user(f->tracks, &uf->tracks); - err |= __get_user(f->timeout, &uf->timeout); - err |= __get_user(f->interleave_sect, &uf->interleave_sect); - err |= __copy_from_user(&f->max_errors, &uf->max_errors, sizeof(f->max_errors)); - err |= __get_user(f->flags, &uf->flags); - err |= __get_user(f->read_track, &uf->read_track); - err |= __copy_from_user(f->autodetect, uf->autodetect, sizeof(f->autodetect)); - err |= __get_user(f->checkfreq, &uf->checkfreq); - err |= __get_user(f->native_format, &uf->native_format); - if (err) { - err = -EFAULT; - goto out; - } - break; - } - case FDGETDRVSTAT32: - case FDPOLLDRVSTAT32: - karg = kmalloc(sizeof(struct floppy_drive_struct), GFP_KERNEL); - if (!karg) - return -ENOMEM; - break; - case FDGETFDCSTAT32: - karg = kmalloc(sizeof(struct floppy_fdc_state), GFP_KERNEL); - if (!karg) - return -ENOMEM; - break; - case FDWERRORGET32: - karg = kmalloc(sizeof(struct floppy_write_errors), GFP_KERNEL); - if (!karg) - return -ENOMEM; - break; - default: - return -EINVAL; - } - set_fs (KERNEL_DS); - err = sys_ioctl (fd, kcmd, (unsigned long)karg); - set_fs (old_fs); - if (err) - goto out; - switch (cmd) { - case FDGETPRM32: - { - struct floppy_struct *f = karg; - struct floppy_struct32 __user *uf = compat_ptr(arg); - - err = __put_user(f->size, &uf->size); - err |= __put_user(f->sect, &uf->sect); - err |= __put_user(f->head, &uf->head); - err |= __put_user(f->track, &uf->track); - err |= __put_user(f->stretch, &uf->stretch); - err |= __put_user(f->gap, &uf->gap); - err |= __put_user(f->rate, &uf->rate); - err |= __put_user(f->spec1, &uf->spec1); - err |= __put_user(f->fmt_gap, &uf->fmt_gap); - err |= __put_user((u64)f->name, (compat_caddr_t __user *)&uf->name); - break; - } - case FDGETDRVPRM32: - { - struct floppy_drive_params32 __user *uf; - struct floppy_drive_params *f = karg; - - uf = compat_ptr(arg); - err = __put_user(f->cmos, &uf->cmos); - err |= __put_user(f->max_dtr, &uf->max_dtr); - err |= __put_user(f->hlt, &uf->hlt); - err |= __put_user(f->hut, &uf->hut); - err |= __put_user(f->srt, &uf->srt); - err |= __put_user(f->spinup, &uf->spinup); - err |= __put_user(f->spindown, &uf->spindown); - err |= __put_user(f->spindown_offset, &uf->spindown_offset); - err |= __put_user(f->select_delay, &uf->select_delay); - err |= __put_user(f->rps, &uf->rps); - err |= __put_user(f->tracks, &uf->tracks); - err |= __put_user(f->timeout, &uf->timeout); - err |= __put_user(f->interleave_sect, &uf->interleave_sect); - err |= __copy_to_user(&uf->max_errors, &f->max_errors, sizeof(f->max_errors)); - err |= __put_user(f->flags, &uf->flags); - err |= __put_user(f->read_track, &uf->read_track); - err |= __copy_to_user(uf->autodetect, f->autodetect, sizeof(f->autodetect)); - err |= __put_user(f->checkfreq, &uf->checkfreq); - err |= __put_user(f->native_format, &uf->native_format); - break; - } - case FDGETDRVSTAT32: - case FDPOLLDRVSTAT32: - { - struct floppy_drive_struct32 __user *uf; - struct floppy_drive_struct *f = karg; - - uf = compat_ptr(arg); - err = __put_user(f->flags, &uf->flags); - err |= __put_user(f->spinup_date, &uf->spinup_date); - err |= __put_user(f->select_date, &uf->select_date); - err |= __put_user(f->first_read_date, &uf->first_read_date); - err |= __put_user(f->probed_format, &uf->probed_format); - err |= __put_user(f->track, &uf->track); - err |= __put_user(f->maxblock, &uf->maxblock); - err |= __put_user(f->maxtrack, &uf->maxtrack); - err |= __put_user(f->generation, &uf->generation); - err |= __put_user(f->keep_data, &uf->keep_data); - err |= __put_user(f->fd_ref, &uf->fd_ref); - err |= __put_user(f->fd_device, &uf->fd_device); - err |= __put_user(f->last_checked, &uf->last_checked); - err |= __put_user((u64)f->dmabuf, &uf->dmabuf); - err |= __put_user((u64)f->bufblocks, &uf->bufblocks); - break; - } - case FDGETFDCSTAT32: - { - struct floppy_fdc_state32 __user *uf; - struct floppy_fdc_state *f = karg; - - uf = compat_ptr(arg); - err = __put_user(f->spec1, &uf->spec1); - err |= __put_user(f->spec2, &uf->spec2); - err |= __put_user(f->dtr, &uf->dtr); - err |= __put_user(f->version, &uf->version); - err |= __put_user(f->dor, &uf->dor); - err |= __put_user(f->address, &uf->address); - err |= __copy_to_user((char __user *)&uf->address + sizeof(uf->address), - (char *)&f->address + sizeof(f->address), sizeof(int)); - err |= __put_user(f->driver_version, &uf->driver_version); - err |= __copy_to_user(uf->track, f->track, sizeof(f->track)); - break; - } - case FDWERRORGET32: - { - struct floppy_write_errors32 __user *uf; - struct floppy_write_errors *f = karg; - - uf = compat_ptr(arg); - err = __put_user(f->write_errors, &uf->write_errors); - err |= __put_user(f->first_error_sector, &uf->first_error_sector); - err |= __put_user(f->first_error_generation, &uf->first_error_generation); - err |= __put_user(f->last_error_sector, &uf->last_error_sector); - err |= __put_user(f->last_error_generation, &uf->last_error_generation); - err |= __put_user(f->badness, &uf->badness); - break; - } - default: - break; - } - if (err) - err = -EFAULT; - -out: - kfree(karg); - return err; -} -#endif - struct mtd_oob_buf32 { u_int32_t start; u_int32_t length; @@ -2506,60 +1963,6 @@ COMPATIBLE_IOCTL(FIONREAD) /* This is also TIOCINQ */ /* 0x00 */ COMPATIBLE_IOCTL(FIBMAP) COMPATIBLE_IOCTL(FIGETBSZ) -/* 0x03 -- HD/IDE ioctl's used by hdparm and friends. - * Some need translations, these do not. - */ -COMPATIBLE_IOCTL(HDIO_GET_IDENTITY) -COMPATIBLE_IOCTL(HDIO_DRIVE_TASK) -COMPATIBLE_IOCTL(HDIO_DRIVE_CMD) -ULONG_IOCTL(HDIO_SET_MULTCOUNT) -ULONG_IOCTL(HDIO_SET_UNMASKINTR) -ULONG_IOCTL(HDIO_SET_KEEPSETTINGS) -ULONG_IOCTL(HDIO_SET_32BIT) -ULONG_IOCTL(HDIO_SET_NOWERR) -ULONG_IOCTL(HDIO_SET_DMA) -ULONG_IOCTL(HDIO_SET_PIO_MODE) -ULONG_IOCTL(HDIO_SET_NICE) -ULONG_IOCTL(HDIO_SET_WCACHE) -ULONG_IOCTL(HDIO_SET_ACOUSTIC) -ULONG_IOCTL(HDIO_SET_BUSSTATE) -ULONG_IOCTL(HDIO_SET_ADDRESS) -COMPATIBLE_IOCTL(HDIO_SCAN_HWIF) -/* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */ -COMPATIBLE_IOCTL(0x330) -/* 0x02 -- Floppy ioctls */ -COMPATIBLE_IOCTL(FDMSGON) -COMPATIBLE_IOCTL(FDMSGOFF) -COMPATIBLE_IOCTL(FDSETEMSGTRESH) -COMPATIBLE_IOCTL(FDFLUSH) -COMPATIBLE_IOCTL(FDWERRORCLR) -COMPATIBLE_IOCTL(FDSETMAXERRS) -COMPATIBLE_IOCTL(FDGETMAXERRS) -COMPATIBLE_IOCTL(FDGETDRVTYP) -COMPATIBLE_IOCTL(FDEJECT) -COMPATIBLE_IOCTL(FDCLRPRM) -COMPATIBLE_IOCTL(FDFMTBEG) -COMPATIBLE_IOCTL(FDFMTEND) -COMPATIBLE_IOCTL(FDRESET) -COMPATIBLE_IOCTL(FDTWADDLE) -COMPATIBLE_IOCTL(FDFMTTRK) -COMPATIBLE_IOCTL(FDRAWCMD) -/* 0x12 */ -#ifdef CONFIG_BLOCK -COMPATIBLE_IOCTL(BLKRASET) -COMPATIBLE_IOCTL(BLKROSET) -COMPATIBLE_IOCTL(BLKROGET) -COMPATIBLE_IOCTL(BLKRRPART) -COMPATIBLE_IOCTL(BLKFLSBUF) -COMPATIBLE_IOCTL(BLKSECTSET) -COMPATIBLE_IOCTL(BLKSSZGET) -COMPATIBLE_IOCTL(BLKTRACESTART) -COMPATIBLE_IOCTL(BLKTRACESTOP) -COMPATIBLE_IOCTL(BLKTRACESETUP) -COMPATIBLE_IOCTL(BLKTRACETEARDOWN) -ULONG_IOCTL(BLKRASET) -ULONG_IOCTL(BLKFRASET) -#endif /* RAID */ COMPATIBLE_IOCTL(RAID_VERSION) COMPATIBLE_IOCTL(GET_ARRAY_INFO) @@ -2807,50 +2210,6 @@ COMPATIBLE_IOCTL(PPGETMODE) COMPATIBLE_IOCTL(PPGETPHASE) COMPATIBLE_IOCTL(PPGETFLAGS) COMPATIBLE_IOCTL(PPSETFLAGS) -/* CDROM stuff */ -COMPATIBLE_IOCTL(CDROMPAUSE) -COMPATIBLE_IOCTL(CDROMRESUME) -COMPATIBLE_IOCTL(CDROMPLAYMSF) -COMPATIBLE_IOCTL(CDROMPLAYTRKIND) -COMPATIBLE_IOCTL(CDROMREADTOCHDR) -COMPATIBLE_IOCTL(CDROMREADTOCENTRY) -COMPATIBLE_IOCTL(CDROMSTOP) -COMPATIBLE_IOCTL(CDROMSTART) -COMPATIBLE_IOCTL(CDROMEJECT) -COMPATIBLE_IOCTL(CDROMVOLCTRL) -COMPATIBLE_IOCTL(CDROMSUBCHNL) -ULONG_IOCTL(CDROMEJECT_SW) -COMPATIBLE_IOCTL(CDROMMULTISESSION) -COMPATIBLE_IOCTL(CDROM_GET_MCN) -COMPATIBLE_IOCTL(CDROMRESET) -COMPATIBLE_IOCTL(CDROMVOLREAD) -COMPATIBLE_IOCTL(CDROMSEEK) -COMPATIBLE_IOCTL(CDROMPLAYBLK) -COMPATIBLE_IOCTL(CDROMCLOSETRAY) -ULONG_IOCTL(CDROM_SET_OPTIONS) -ULONG_IOCTL(CDROM_CLEAR_OPTIONS) -ULONG_IOCTL(CDROM_SELECT_SPEED) -ULONG_IOCTL(CDROM_SELECT_DISC) -ULONG_IOCTL(CDROM_MEDIA_CHANGED) -ULONG_IOCTL(CDROM_DRIVE_STATUS) -COMPATIBLE_IOCTL(CDROM_DISC_STATUS) -COMPATIBLE_IOCTL(CDROM_CHANGER_NSLOTS) -ULONG_IOCTL(CDROM_LOCKDOOR) -ULONG_IOCTL(CDROM_DEBUG) -COMPATIBLE_IOCTL(CDROM_GET_CAPABILITY) -/* Ignore cdrom.h about these next 5 ioctls, they absolutely do - * not take a struct cdrom_read, instead they take a struct cdrom_msf - * which is compatible. - */ -COMPATIBLE_IOCTL(CDROMREADMODE2) -COMPATIBLE_IOCTL(CDROMREADMODE1) -COMPATIBLE_IOCTL(CDROMREADRAW) -COMPATIBLE_IOCTL(CDROMREADCOOKED) -COMPATIBLE_IOCTL(CDROMREADALL) -/* DVD ioctls */ -COMPATIBLE_IOCTL(DVD_READ_STRUCT) -COMPATIBLE_IOCTL(DVD_WRITE_STRUCT) -COMPATIBLE_IOCTL(DVD_AUTH) /* pktcdvd */ COMPATIBLE_IOCTL(PACKET_CTRL_CMD) /* Big A */ @@ -3336,33 +2695,6 @@ HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp) HANDLE_IOCTL(SIOCGSTAMPNS, do_siocgstampns) #endif #ifdef CONFIG_BLOCK -HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo) -HANDLE_IOCTL(BLKRAGET, w_long) -HANDLE_IOCTL(BLKGETSIZE, w_long) -HANDLE_IOCTL(0x1260, broken_blkgetsize) -HANDLE_IOCTL(BLKFRAGET, w_long) -HANDLE_IOCTL(BLKSECTGET, w_long) -HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_UNMASKINTR, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_MULTCOUNT, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_KEEPSETTINGS, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_32BIT, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_NOWERR, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_DMA, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_NICE, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_WCACHE, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_ACOUSTIC, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_ADDRESS, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_BUSSTATE, hdio_ioctl_trans) -HANDLE_IOCTL(FDSETPRM32, fd_ioctl_trans) -HANDLE_IOCTL(FDDEFPRM32, fd_ioctl_trans) -HANDLE_IOCTL(FDGETPRM32, fd_ioctl_trans) -HANDLE_IOCTL(FDSETDRVPRM32, fd_ioctl_trans) -HANDLE_IOCTL(FDGETDRVPRM32, fd_ioctl_trans) -HANDLE_IOCTL(FDGETDRVSTAT32, fd_ioctl_trans) -HANDLE_IOCTL(FDPOLLDRVSTAT32, fd_ioctl_trans) -HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_trans) -HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans) HANDLE_IOCTL(SG_IO,sg_ioctl_trans) HANDLE_IOCTL(SG_GET_REQUEST_TABLE, sg_grt_trans) #endif @@ -3373,8 +2705,6 @@ HANDLE_IOCTL(PPPIOCSACTIVE32, ppp_sock_fprog_ioctl_trans) #ifdef CONFIG_BLOCK HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans) HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans) -HANDLE_IOCTL(CDROMREADAUDIO, cdrom_ioctl_trans) -HANDLE_IOCTL(CDROM_SEND_PACKET, cdrom_ioctl_trans) #endif #define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int) HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout) @@ -3415,9 +2745,6 @@ HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl) HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl) /* block stuff */ #ifdef CONFIG_BLOCK -HANDLE_IOCTL(BLKBSZGET_32, do_blkbszget) -HANDLE_IOCTL(BLKBSZSET_32, do_blkbszset) -HANDLE_IOCTL(BLKGETSIZE64_32, do_blkgetsize64) /* Raw devices */ HANDLE_IOCTL(RAW_SETBIND, raw_ioctl) HANDLE_IOCTL(RAW_GETBIND, raw_ioctl) @@ -3674,7 +3001,7 @@ static int __init init_sys32_ioctl(void) int i; for (i = 0; i < ARRAY_SIZE(ioctl_start); i++) { - if (ioctl_start[i].next != 0) { + if (ioctl_start[i].next) { printk("ioctl translation %d bad\n",i); return -1; } diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h index 3b0185fdf9a4..cca98609aa7f 100644 --- a/fs/configfs/configfs_internal.h +++ b/fs/configfs/configfs_internal.h @@ -56,6 +56,8 @@ extern int configfs_is_root(struct config_item *item); extern struct inode * configfs_new_inode(mode_t mode, struct configfs_dirent *); extern int configfs_create(struct dentry *, int mode, int (*init)(struct inode *)); +extern int configfs_inode_init(void); +extern void configfs_inode_exit(void); extern int configfs_create_file(struct config_item *, const struct configfs_attribute *); extern int configfs_make_dirent(struct configfs_dirent *, diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 2f436d4f1d6d..50ed691098bc 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -142,7 +142,7 @@ static int init_dir(struct inode * inode) return 0; } -static int init_file(struct inode * inode) +static int configfs_init_file(struct inode * inode) { inode->i_size = PAGE_SIZE; inode->i_fop = &configfs_file_operations; @@ -283,7 +283,8 @@ static int configfs_attach_attr(struct configfs_dirent * sd, struct dentry * den dentry->d_fsdata = configfs_get(sd); sd->s_dentry = dentry; - error = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG, init_file); + error = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG, + configfs_init_file); if (error) { configfs_put(sd); return error; diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c index ddc003a9d214..4c1ebff778ee 100644 --- a/fs/configfs/inode.c +++ b/fs/configfs/inode.c @@ -41,8 +41,8 @@ extern struct super_block * configfs_sb; static const struct address_space_operations configfs_aops = { .readpage = simple_readpage, - .prepare_write = simple_prepare_write, - .commit_write = simple_commit_write + .write_begin = simple_write_begin, + .write_end = simple_write_end, }; static struct backing_dev_info configfs_backing_dev_info = { @@ -256,4 +256,12 @@ void configfs_hash_and_remove(struct dentry * dir, const char * name) mutex_unlock(&dir->d_inode->i_mutex); } +int __init configfs_inode_init(void) +{ + return bdi_init(&configfs_backing_dev_info); +} +void __exit configfs_inode_exit(void) +{ + bdi_destroy(&configfs_backing_dev_info); +} diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c index 871b0cb61839..3bf0278ea843 100644 --- a/fs/configfs/mount.c +++ b/fs/configfs/mount.c @@ -154,8 +154,16 @@ static int __init configfs_init(void) subsystem_unregister(&config_subsys); kmem_cache_destroy(configfs_dir_cachep); configfs_dir_cachep = NULL; + goto out; } + err = configfs_inode_init(); + if (err) { + unregister_filesystem(&configfs_fs_type); + subsystem_unregister(&config_subsys); + kmem_cache_destroy(configfs_dir_cachep); + configfs_dir_cachep = NULL; + } out: return err; } @@ -166,6 +174,7 @@ static void __exit configfs_exit(void) subsystem_unregister(&config_subsys); kmem_cache_destroy(configfs_dir_cachep); configfs_dir_cachep = NULL; + configfs_inode_exit(); } MODULE_AUTHOR("Oracle"); diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 3d194a2be3f5..350680fd7da7 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -148,7 +148,7 @@ static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned i { struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping; struct page *pages[BLKS_PER_BUF]; - unsigned i, blocknr, buffer, unread; + unsigned i, blocknr, buffer; unsigned long devsize; char *data; @@ -175,7 +175,6 @@ static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned i devsize = mapping->host->i_size >> PAGE_CACHE_SHIFT; /* Ok, read in BLKS_PER_BUF pages completely first. */ - unread = 0; for (i = 0; i < BLKS_PER_BUF; i++) { struct page *page = NULL; @@ -258,12 +257,21 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent) /* Do sanity checks on the superblock */ if (super.magic != CRAMFS_MAGIC) { + /* check for wrong endianess */ + if (super.magic == CRAMFS_MAGIC_WEND) { + if (!silent) + printk(KERN_ERR "cramfs: wrong endianess\n"); + goto out; + } + /* check at 512 byte offset */ mutex_lock(&read_mutex); memcpy(&super, cramfs_read(sb, 512, sizeof(super)), sizeof(super)); mutex_unlock(&read_mutex); if (super.magic != CRAMFS_MAGIC) { - if (!silent) + if (super.magic == CRAMFS_MAGIC_WEND && !silent) + printk(KERN_ERR "cramfs: wrong endianess\n"); + else if (!silent) printk(KERN_ERR "cramfs: wrong magic\n"); goto out; } @@ -353,7 +361,7 @@ static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir) if (offset & 3) return -EINVAL; - buf = kmalloc(256, GFP_KERNEL); + buf = kmalloc(CRAMFS_MAXPATHLEN, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -367,7 +375,7 @@ static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir) int namelen, error; mutex_lock(&read_mutex); - de = cramfs_read(sb, OFFSET(inode) + offset, sizeof(*de)+256); + de = cramfs_read(sb, OFFSET(inode) + offset, sizeof(*de)+CRAMFS_MAXPATHLEN); name = (char *)(de+1); /* @@ -417,7 +425,7 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, s char *name; int namelen, retval; - de = cramfs_read(dir->i_sb, OFFSET(dir) + offset, sizeof(*de)+256); + de = cramfs_read(dir->i_sb, OFFSET(dir) + offset, sizeof(*de)+CRAMFS_MAXPATHLEN); name = (char *)(de+1); /* Try to take advantage of sorted directories */ diff --git a/fs/dcache.c b/fs/dcache.c index 678d39deb607..5489b2d98a00 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -381,20 +381,17 @@ restart: * Throw away a dentry - free the inode, dput the parent. This requires that * the LRU list has already been removed. * - * If prune_parents is true, try to prune ancestors as well. + * Try to prune ancestors as well. This is necessary to prevent + * quadratic behavior of shrink_dcache_parent(), but is also expected + * to be beneficial in reducing dentry cache fragmentation. * * Called with dcache_lock, drops it and then regains. * Called with dentry->d_lock held, drops it. */ -static void prune_one_dentry(struct dentry * dentry, int prune_parents) +static void prune_one_dentry(struct dentry * dentry) { __d_drop(dentry); dentry = d_kill(dentry); - if (!prune_parents) { - dput(dentry); - spin_lock(&dcache_lock); - return; - } /* * Prune ancestors. Locking is simpler than in dput(), @@ -422,7 +419,6 @@ static void prune_one_dentry(struct dentry * dentry, int prune_parents) * @count: number of entries to try and free * @sb: if given, ignore dentries for other superblocks * which are being unmounted. - * @prune_parents: if true, try to prune ancestors as well in one go * * Shrink the dcache. This is done when we need * more memory, or simply when we need to unmount @@ -433,7 +429,7 @@ static void prune_one_dentry(struct dentry * dentry, int prune_parents) * all the dentries are in use. */ -static void prune_dcache(int count, struct super_block *sb, int prune_parents) +static void prune_dcache(int count, struct super_block *sb) { spin_lock(&dcache_lock); for (; count ; count--) { @@ -493,7 +489,7 @@ static void prune_dcache(int count, struct super_block *sb, int prune_parents) * without taking the s_umount lock (I already hold it). */ if (sb && dentry->d_sb == sb) { - prune_one_dentry(dentry, prune_parents); + prune_one_dentry(dentry); continue; } /* @@ -508,7 +504,7 @@ static void prune_dcache(int count, struct super_block *sb, int prune_parents) s_umount = &dentry->d_sb->s_umount; if (down_read_trylock(s_umount)) { if (dentry->d_sb->s_root != NULL) { - prune_one_dentry(dentry, prune_parents); + prune_one_dentry(dentry); up_read(s_umount); continue; } @@ -557,18 +553,18 @@ void shrink_dcache_sb(struct super_block * sb) * superblock to the most recent end of the unused list. */ spin_lock(&dcache_lock); - list_for_each_safe(tmp, next, &dentry_unused) { + list_for_each_prev_safe(tmp, next, &dentry_unused) { dentry = list_entry(tmp, struct dentry, d_lru); if (dentry->d_sb != sb) continue; - list_move(tmp, &dentry_unused); + list_move_tail(tmp, &dentry_unused); } /* * Pass two ... free the dentries for this superblock. */ repeat: - list_for_each_safe(tmp, next, &dentry_unused) { + list_for_each_prev_safe(tmp, next, &dentry_unused) { dentry = list_entry(tmp, struct dentry, d_lru); if (dentry->d_sb != sb) continue; @@ -579,7 +575,7 @@ repeat: spin_unlock(&dentry->d_lock); continue; } - prune_one_dentry(dentry, 1); + prune_one_dentry(dentry); cond_resched_lock(&dcache_lock); goto repeat; } @@ -858,7 +854,7 @@ void shrink_dcache_parent(struct dentry * parent) int found; while ((found = select_parent(parent)) != 0) - prune_dcache(found, parent->d_sb, 1); + prune_dcache(found, parent->d_sb); } /* @@ -878,7 +874,7 @@ static int shrink_dcache_memory(int nr, gfp_t gfp_mask) if (nr) { if (!(gfp_mask & __GFP_FS)) return -1; - prune_dcache(nr, NULL, 1); + prune_dcache(nr, NULL); } return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure; } @@ -903,7 +899,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) struct dentry *dentry; char *dname; - dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL); + dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL); if (!dentry) return NULL; @@ -1514,8 +1510,8 @@ static void switch_names(struct dentry *dentry, struct dentry *target) * This forceful removal will result in ugly /proc output if * somebody holds a file open that got deleted due to a rename. * We could be nicer about the deleted file, and let it show - * up under the name it got deleted rather than the name that - * deleted it. + * up under the name it had before it was deleted rather than + * under the original name of the file that was moved on top of it. */ /* @@ -1546,7 +1542,7 @@ static void d_move_locked(struct dentry * dentry, struct dentry * target) } /* Move the dentry to the target hash queue, if on different bucket */ - if (dentry->d_flags & DCACHE_UNHASHED) + if (d_unhashed(dentry)) goto already_unhashed; hlist_del_rcu(&dentry->d_hash); @@ -2108,7 +2104,7 @@ static void __init dcache_init_early(void) INIT_HLIST_HEAD(&dentry_hashtable[loop]); } -static void __init dcache_init(unsigned long mempages) +static void __init dcache_init(void) { int loop; @@ -2170,10 +2166,10 @@ void __init vfs_caches_init(unsigned long mempages) filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); - dcache_init(mempages); - inode_init(mempages); + dcache_init(); + inode_init(); files_init(mempages); - mnt_init(mempages); + mnt_init(); bdev_cache_init(); chrdev_init(); } diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 2e124e0075c5..fa6b7f7ff914 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -221,6 +221,71 @@ struct dentry *debugfs_create_u64(const char *name, mode_t mode, } EXPORT_SYMBOL_GPL(debugfs_create_u64); +DEFINE_SIMPLE_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%02llx\n"); + +DEFINE_SIMPLE_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, "0x%04llx\n"); + +DEFINE_SIMPLE_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%08llx\n"); + +/* + * debugfs_create_x{8,16,32} - create a debugfs file that is used to read and write an unsigned {8,16,32}-bit value + * + * These functions are exactly the same as the above functions (but use a hex + * output for the decimal challenged). For details look at the above unsigned + * decimal functions. + */ + +/** + * debugfs_create_x8 - create a debugfs file that is used to read and write an unsigned 8-bit value + * @name: a pointer to a string containing the name of the file to create. + * @mode: the permission that the file should have + * @parent: a pointer to the parent dentry for this file. This should be a + * directory dentry if set. If this parameter is %NULL, then the + * file will be created in the root of the debugfs filesystem. + * @value: a pointer to the variable that the file should read to and write + * from. + */ +struct dentry *debugfs_create_x8(const char *name, mode_t mode, + struct dentry *parent, u8 *value) +{ + return debugfs_create_file(name, mode, parent, value, &fops_x8); +} +EXPORT_SYMBOL_GPL(debugfs_create_x8); + +/** + * debugfs_create_x16 - create a debugfs file that is used to read and write an unsigned 16-bit value + * @name: a pointer to a string containing the name of the file to create. + * @mode: the permission that the file should have + * @parent: a pointer to the parent dentry for this file. This should be a + * directory dentry if set. If this parameter is %NULL, then the + * file will be created in the root of the debugfs filesystem. + * @value: a pointer to the variable that the file should read to and write + * from. + */ +struct dentry *debugfs_create_x16(const char *name, mode_t mode, + struct dentry *parent, u16 *value) +{ + return debugfs_create_file(name, mode, parent, value, &fops_x16); +} +EXPORT_SYMBOL_GPL(debugfs_create_x16); + +/** + * debugfs_create_x32 - create a debugfs file that is used to read and write an unsigned 32-bit value + * @name: a pointer to a string containing the name of the file to create. + * @mode: the permission that the file should have + * @parent: a pointer to the parent dentry for this file. This should be a + * directory dentry if set. If this parameter is %NULL, then the + * file will be created in the root of the debugfs filesystem. + * @value: a pointer to the variable that the file should read to and write + * from. + */ +struct dentry *debugfs_create_x32(const char *name, mode_t mode, + struct dentry *parent, u32 *value) +{ + return debugfs_create_file(name, mode, parent, value, &fops_x32); +} +EXPORT_SYMBOL_GPL(debugfs_create_x32); + static ssize_t read_file_bool(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { diff --git a/fs/direct-io.c b/fs/direct-io.c index 901dc55e9f54..acf0da1bd257 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -163,7 +163,7 @@ static int dio_refill_pages(struct dio *dio) up_read(¤t->mm->mmap_sem); if (ret < 0 && dio->blocks_available && (dio->rw & WRITE)) { - struct page *page = ZERO_PAGE(dio->curr_user_address); + struct page *page = ZERO_PAGE(0); /* * A memory fault, but the filesystem has some outstanding * mapped blocks. We need to use those blocks up to avoid @@ -264,15 +264,12 @@ static int dio_bio_complete(struct dio *dio, struct bio *bio); /* * Asynchronous IO callback. */ -static int dio_bio_end_aio(struct bio *bio, unsigned int bytes_done, int error) +static void dio_bio_end_aio(struct bio *bio, int error) { struct dio *dio = bio->bi_private; unsigned long remaining; unsigned long flags; - if (bio->bi_size) - return 1; - /* cleanup the bio */ dio_bio_complete(dio, bio); @@ -287,8 +284,6 @@ static int dio_bio_end_aio(struct bio *bio, unsigned int bytes_done, int error) aio_complete(dio->iocb, ret, 0); kfree(dio); } - - return 0; } /* @@ -298,21 +293,17 @@ static int dio_bio_end_aio(struct bio *bio, unsigned int bytes_done, int error) * During I/O bi_private points at the dio. After I/O, bi_private is used to * implement a singly-linked list of completed BIOs, at dio->bio_list. */ -static int dio_bio_end_io(struct bio *bio, unsigned int bytes_done, int error) +static void dio_bio_end_io(struct bio *bio, int error) { struct dio *dio = bio->bi_private; unsigned long flags; - if (bio->bi_size) - return 1; - spin_lock_irqsave(&dio->bio_lock, flags); bio->bi_private = dio->bio_list; dio->bio_list = bio; if (--dio->refcount == 1 && dio->waiter) wake_up_process(dio->waiter); spin_unlock_irqrestore(&dio->bio_lock, flags); - return 0; } static int @@ -772,7 +763,7 @@ static void dio_zero_block(struct dio *dio, int end) this_chunk_bytes = this_chunk_blocks << dio->blkbits; - page = ZERO_PAGE(dio->curr_user_address); + page = ZERO_PAGE(0); if (submit_page_section(dio, page, 0, this_chunk_bytes, dio->next_block_for_io)) return; diff --git a/fs/dlm/Kconfig b/fs/dlm/Kconfig index 54bcc00ec8df..2dbb422e8116 100644 --- a/fs/dlm/Kconfig +++ b/fs/dlm/Kconfig @@ -1,8 +1,6 @@ -menu "Distributed Lock Manager" - depends on EXPERIMENTAL && INET - -config DLM +menuconfig DLM tristate "Distributed Lock Manager (DLM)" + depends on EXPERIMENTAL && INET depends on SYSFS && (IPV6 || IPV6=n) select CONFIGFS_FS select IP_SCTP @@ -17,5 +15,3 @@ config DLM_DEBUG Under the debugfs mount point, the name of each lockspace will appear as a file in the "dlm" directory. The output is the list of resource and locks the local node knows about. - -endmenu diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index 74901e981e10..d2fc2384c3be 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h @@ -491,6 +491,7 @@ struct dlm_ls { uint64_t ls_recover_seq; struct dlm_recover *ls_recover_args; struct rw_semaphore ls_in_recovery; /* block local requests */ + struct rw_semaphore ls_recv_active; /* block dlm_recv */ struct list_head ls_requestqueue;/* queue remote requests */ struct mutex ls_requestqueue_mutex; char *ls_recover_buf; diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 2082daf083d8..3915b8e14146 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -3638,55 +3638,8 @@ static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms) dlm_put_lkb(lkb); } -int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery) +static void _receive_message(struct dlm_ls *ls, struct dlm_message *ms) { - struct dlm_message *ms = (struct dlm_message *) hd; - struct dlm_ls *ls; - int error = 0; - - if (!recovery) - dlm_message_in(ms); - - ls = dlm_find_lockspace_global(hd->h_lockspace); - if (!ls) { - log_print("drop message %d from %d for unknown lockspace %d", - ms->m_type, nodeid, hd->h_lockspace); - return -EINVAL; - } - - /* recovery may have just ended leaving a bunch of backed-up requests - in the requestqueue; wait while dlm_recoverd clears them */ - - if (!recovery) - dlm_wait_requestqueue(ls); - - /* recovery may have just started while there were a bunch of - in-flight requests -- save them in requestqueue to be processed - after recovery. we can't let dlm_recvd block on the recovery - lock. if dlm_recoverd is calling this function to clear the - requestqueue, it needs to be interrupted (-EINTR) if another - recovery operation is starting. */ - - while (1) { - if (dlm_locking_stopped(ls)) { - if (recovery) { - error = -EINTR; - goto out; - } - error = dlm_add_requestqueue(ls, nodeid, hd); - if (error == -EAGAIN) - continue; - else { - error = -EINTR; - goto out; - } - } - - if (dlm_lock_recovery_try(ls)) - break; - schedule(); - } - switch (ms->m_type) { /* messages sent to a master node */ @@ -3761,17 +3714,90 @@ int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery) log_error(ls, "unknown message type %d", ms->m_type); } - dlm_unlock_recovery(ls); - out: - dlm_put_lockspace(ls); dlm_astd_wake(); - return error; } +/* If the lockspace is in recovery mode (locking stopped), then normal + messages are saved on the requestqueue for processing after recovery is + done. When not in recovery mode, we wait for dlm_recoverd to drain saved + messages off the requestqueue before we process new ones. This occurs right + after recovery completes when we transition from saving all messages on + requestqueue, to processing all the saved messages, to processing new + messages as they arrive. */ -/* - * Recovery related - */ +static void dlm_receive_message(struct dlm_ls *ls, struct dlm_message *ms, + int nodeid) +{ + if (dlm_locking_stopped(ls)) { + dlm_add_requestqueue(ls, nodeid, (struct dlm_header *) ms); + } else { + dlm_wait_requestqueue(ls); + _receive_message(ls, ms); + } +} + +/* This is called by dlm_recoverd to process messages that were saved on + the requestqueue. */ + +void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms) +{ + _receive_message(ls, ms); +} + +/* This is called by the midcomms layer when something is received for + the lockspace. It could be either a MSG (normal message sent as part of + standard locking activity) or an RCOM (recovery message sent as part of + lockspace recovery). */ + +void dlm_receive_buffer(struct dlm_header *hd, int nodeid) +{ + struct dlm_message *ms = (struct dlm_message *) hd; + struct dlm_rcom *rc = (struct dlm_rcom *) hd; + struct dlm_ls *ls; + int type = 0; + + switch (hd->h_cmd) { + case DLM_MSG: + dlm_message_in(ms); + type = ms->m_type; + break; + case DLM_RCOM: + dlm_rcom_in(rc); + type = rc->rc_type; + break; + default: + log_print("invalid h_cmd %d from %u", hd->h_cmd, nodeid); + return; + } + + if (hd->h_nodeid != nodeid) { + log_print("invalid h_nodeid %d from %d lockspace %x", + hd->h_nodeid, nodeid, hd->h_lockspace); + return; + } + + ls = dlm_find_lockspace_global(hd->h_lockspace); + if (!ls) { + log_print("invalid h_lockspace %x from %d cmd %d type %d", + hd->h_lockspace, nodeid, hd->h_cmd, type); + + if (hd->h_cmd == DLM_RCOM && type == DLM_RCOM_STATUS) + dlm_send_ls_not_ready(nodeid, rc); + return; + } + + /* this rwsem allows dlm_ls_stop() to wait for all dlm_recv threads to + be inactive (in this ls) before transitioning to recovery mode */ + + down_read(&ls->ls_recv_active); + if (hd->h_cmd == DLM_MSG) + dlm_receive_message(ls, ms, nodeid); + else + dlm_receive_rcom(ls, rc, nodeid); + up_read(&ls->ls_recv_active); + + dlm_put_lockspace(ls); +} static void recover_convert_waiter(struct dlm_ls *ls, struct dlm_lkb *lkb) { @@ -4429,7 +4455,8 @@ int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, if (lvb_in && ua->lksb.sb_lvbptr) memcpy(ua->lksb.sb_lvbptr, lvb_in, DLM_USER_LVB_LEN); - ua->castparam = ua_tmp->castparam; + if (ua_tmp->castparam) + ua->castparam = ua_tmp->castparam; ua->user_lksb = ua_tmp->user_lksb; error = set_unlock_args(flags, ua, &args); @@ -4474,7 +4501,8 @@ int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, goto out; ua = (struct dlm_user_args *)lkb->lkb_astparam; - ua->castparam = ua_tmp->castparam; + if (ua_tmp->castparam) + ua->castparam = ua_tmp->castparam; ua->user_lksb = ua_tmp->user_lksb; error = set_unlock_args(flags, ua, &args); diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h index 1720313c22df..ada04680a1e5 100644 --- a/fs/dlm/lock.h +++ b/fs/dlm/lock.h @@ -16,7 +16,8 @@ void dlm_print_rsb(struct dlm_rsb *r); void dlm_dump_rsb(struct dlm_rsb *r); void dlm_print_lkb(struct dlm_lkb *lkb); -int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery); +void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms); +void dlm_receive_buffer(struct dlm_header *hd, int nodeid); int dlm_modes_compat(int mode1, int mode2); int dlm_find_rsb(struct dlm_ls *ls, char *name, int namelen, unsigned int flags, struct dlm_rsb **r_ret); diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 1dc72105ab12..6353a8384520 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -167,7 +167,6 @@ static struct kobj_type dlm_ktype = { }; static struct kset dlm_kset = { - .kobj = {.name = "dlm",}, .ktype = &dlm_ktype, }; @@ -228,6 +227,7 @@ int dlm_lockspace_init(void) INIT_LIST_HEAD(&lslist); spin_lock_init(&lslist_lock); + kobject_set_name(&dlm_kset.kobj, "dlm"); kobj_set_kset_s(&dlm_kset, kernel_subsys); error = kset_register(&dlm_kset); if (error) @@ -519,6 +519,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, ls->ls_recover_seq = 0; ls->ls_recover_args = NULL; init_rwsem(&ls->ls_in_recovery); + init_rwsem(&ls->ls_recv_active); INIT_LIST_HEAD(&ls->ls_requestqueue); mutex_init(&ls->ls_requestqueue_mutex); mutex_init(&ls->ls_clear_proc_locks); diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 9e9d2e82f40f..58bf3f5cdbe2 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -334,18 +334,8 @@ static void close_connection(struct connection *con, bool and_other) con->rx_page = NULL; } - /* If we are an 'othercon' then NULL the pointer to us - from the parent and tidy ourself up */ - if (test_bit(CF_IS_OTHERCON, &con->flags)) { - struct connection *parent = __nodeid2con(con->nodeid, 0); - parent->othercon = NULL; - kmem_cache_free(con_cache, con); - } - else { - /* Parent connections get reused */ - con->retries = 0; - mutex_unlock(&con->sock_mutex); - } + con->retries = 0; + mutex_unlock(&con->sock_mutex); } /* We only send shutdown messages to nodes that are not part of the cluster */ @@ -731,6 +721,8 @@ static int tcp_accept_from_sock(struct connection *con) INIT_WORK(&othercon->swork, process_send_sockets); INIT_WORK(&othercon->rwork, process_recv_sockets); set_bit(CF_IS_OTHERCON, &othercon->flags); + } + if (!othercon->sock) { newcon->othercon = othercon; othercon->sock = newsock; newsock->sk->sk_user_data = othercon; @@ -1272,14 +1264,15 @@ static void send_to_sock(struct connection *con) if (len) { ret = sendpage(con->sock, e->page, offset, len, msg_flags); - if (ret == -EAGAIN || ret == 0) + if (ret == -EAGAIN || ret == 0) { + cond_resched(); goto out; + } if (ret <= 0) goto send_error; - } else { + } /* Don't starve people filling buffers */ cond_resched(); - } spin_lock(&con->writequeue_lock); e->offset += ret; diff --git a/fs/dlm/member.c b/fs/dlm/member.c index d09977528f69..e9cdcab306e2 100644 --- a/fs/dlm/member.c +++ b/fs/dlm/member.c @@ -18,10 +18,6 @@ #include "rcom.h" #include "config.h" -/* - * Following called by dlm_recoverd thread - */ - static void add_ordered_member(struct dlm_ls *ls, struct dlm_member *new) { struct dlm_member *memb = NULL; @@ -250,18 +246,30 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out) return error; } -/* - * Following called from lockspace.c - */ +/* Userspace guarantees that dlm_ls_stop() has completed on all nodes before + dlm_ls_start() is called on any of them to start the new recovery. */ int dlm_ls_stop(struct dlm_ls *ls) { int new; /* - * A stop cancels any recovery that's in progress (see RECOVERY_STOP, - * dlm_recovery_stopped()) and prevents any new locks from being - * processed (see RUNNING, dlm_locking_stopped()). + * Prevent dlm_recv from being in the middle of something when we do + * the stop. This includes ensuring dlm_recv isn't processing a + * recovery message (rcom), while dlm_recoverd is aborting and + * resetting things from an in-progress recovery. i.e. we want + * dlm_recoverd to abort its recovery without worrying about dlm_recv + * processing an rcom at the same time. Stopping dlm_recv also makes + * it easy for dlm_receive_message() to check locking stopped and add a + * message to the requestqueue without races. + */ + + down_write(&ls->ls_recv_active); + + /* + * Abort any recovery that's in progress (see RECOVERY_STOP, + * dlm_recovery_stopped()) and tell any other threads running in the + * dlm to quit any processing (see RUNNING, dlm_locking_stopped()). */ spin_lock(&ls->ls_recover_lock); @@ -271,8 +279,14 @@ int dlm_ls_stop(struct dlm_ls *ls) spin_unlock(&ls->ls_recover_lock); /* + * Let dlm_recv run again, now any normal messages will be saved on the + * requestqueue for later. + */ + + up_write(&ls->ls_recv_active); + + /* * This in_recovery lock does two things: - * * 1) Keeps this function from returning until all threads are out * of locking routines and locking is truely stopped. * 2) Keeps any new requests from being processed until it's unlocked @@ -284,9 +298,8 @@ int dlm_ls_stop(struct dlm_ls *ls) /* * The recoverd suspend/resume makes sure that dlm_recoverd (if - * running) has noticed the clearing of RUNNING above and quit - * processing the previous recovery. This will be true for all nodes - * before any nodes start the new recovery. + * running) has noticed RECOVERY_STOP above and quit processing the + * previous recovery. */ dlm_recoverd_suspend(ls); diff --git a/fs/dlm/midcomms.c b/fs/dlm/midcomms.c index a5126e0c68a6..f8c69dda16a0 100644 --- a/fs/dlm/midcomms.c +++ b/fs/dlm/midcomms.c @@ -2,7 +2,7 @@ ******************************************************************************* ** ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. -** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. ** ** This copyrighted material is made available to anyone wishing to use, ** modify, copy, or redistribute it subject to the terms and conditions @@ -27,7 +27,6 @@ #include "dlm_internal.h" #include "lowcomms.h" #include "config.h" -#include "rcom.h" #include "lock.h" #include "midcomms.h" @@ -117,19 +116,7 @@ int dlm_process_incoming_buffer(int nodeid, const void *base, offset &= (limit - 1); len -= msglen; - switch (msg->h_cmd) { - case DLM_MSG: - dlm_receive_message(msg, nodeid, 0); - break; - - case DLM_RCOM: - dlm_receive_rcom(msg, nodeid); - break; - - default: - log_print("unknown msg type %x from %u: %u %u %u %u", - msg->h_cmd, nodeid, msglen, len, offset, ret); - } + dlm_receive_buffer(msg, nodeid); } if (msg != (struct dlm_header *) __tmp) diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c index 188b91c027e4..ae2fd97fa4ad 100644 --- a/fs/dlm/rcom.c +++ b/fs/dlm/rcom.c @@ -2,7 +2,7 @@ ******************************************************************************* ** ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. -** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. ** ** This copyrighted material is made available to anyone wishing to use, ** modify, copy, or redistribute it subject to the terms and conditions @@ -386,7 +386,10 @@ static void receive_rcom_lock_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in) dlm_recover_process_copy(ls, rc_in); } -static int send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in) +/* If the lockspace doesn't exist then still send a status message + back; it's possible that it just doesn't have its global_id yet. */ + +int dlm_send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in) { struct dlm_rcom *rc; struct rcom_config *rf; @@ -446,28 +449,11 @@ static int is_old_reply(struct dlm_ls *ls, struct dlm_rcom *rc) return rv; } -/* Called by dlm_recvd; corresponds to dlm_receive_message() but special +/* Called by dlm_recv; corresponds to dlm_receive_message() but special recovery-only comms are sent through here. */ -void dlm_receive_rcom(struct dlm_header *hd, int nodeid) +void dlm_receive_rcom(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid) { - struct dlm_rcom *rc = (struct dlm_rcom *) hd; - struct dlm_ls *ls; - - dlm_rcom_in(rc); - - /* If the lockspace doesn't exist then still send a status message - back; it's possible that it just doesn't have its global_id yet. */ - - ls = dlm_find_lockspace_global(hd->h_lockspace); - if (!ls) { - log_print("lockspace %x from %d type %x not found", - hd->h_lockspace, nodeid, rc->rc_type); - if (rc->rc_type == DLM_RCOM_STATUS) - send_ls_not_ready(nodeid, rc); - return; - } - if (dlm_recovery_stopped(ls) && (rc->rc_type != DLM_RCOM_STATUS)) { log_debug(ls, "ignoring recovery message %x from %d", rc->rc_type, nodeid); @@ -477,12 +463,6 @@ void dlm_receive_rcom(struct dlm_header *hd, int nodeid) if (is_old_reply(ls, rc)) goto out; - if (nodeid != rc->rc_header.h_nodeid) { - log_error(ls, "bad rcom nodeid %d from %d", - rc->rc_header.h_nodeid, nodeid); - goto out; - } - switch (rc->rc_type) { case DLM_RCOM_STATUS: receive_rcom_status(ls, rc); @@ -520,6 +500,6 @@ void dlm_receive_rcom(struct dlm_header *hd, int nodeid) DLM_ASSERT(0, printk("rc_type=%x\n", rc->rc_type);); } out: - dlm_put_lockspace(ls); + return; } diff --git a/fs/dlm/rcom.h b/fs/dlm/rcom.h index d7984321ff41..b09abd29ba38 100644 --- a/fs/dlm/rcom.h +++ b/fs/dlm/rcom.h @@ -2,7 +2,7 @@ ******************************************************************************* ** ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. -** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. ** ** This copyrighted material is made available to anyone wishing to use, ** modify, copy, or redistribute it subject to the terms and conditions @@ -18,7 +18,8 @@ int dlm_rcom_status(struct dlm_ls *ls, int nodeid); int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name,int last_len); int dlm_send_rcom_lookup(struct dlm_rsb *r, int dir_nodeid); int dlm_send_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb); -void dlm_receive_rcom(struct dlm_header *hd, int nodeid); +void dlm_receive_rcom(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid); +int dlm_send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in); #endif diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c index 66575997861c..4b89e20eebe7 100644 --- a/fs/dlm/recoverd.c +++ b/fs/dlm/recoverd.c @@ -24,19 +24,28 @@ /* If the start for which we're re-enabling locking (seq) has been superseded - by a newer stop (ls_recover_seq), we need to leave locking disabled. */ + by a newer stop (ls_recover_seq), we need to leave locking disabled. + + We suspend dlm_recv threads here to avoid the race where dlm_recv a) sees + locking stopped and b) adds a message to the requestqueue, but dlm_recoverd + enables locking and clears the requestqueue between a and b. */ static int enable_locking(struct dlm_ls *ls, uint64_t seq) { int error = -EINTR; + down_write(&ls->ls_recv_active); + spin_lock(&ls->ls_recover_lock); if (ls->ls_recover_seq == seq) { set_bit(LSFL_RUNNING, &ls->ls_flags); + /* unblocks processes waiting to enter the dlm */ up_write(&ls->ls_in_recovery); error = 0; } spin_unlock(&ls->ls_recover_lock); + + up_write(&ls->ls_recv_active); return error; } diff --git a/fs/dlm/requestqueue.c b/fs/dlm/requestqueue.c index 65008d79c96d..0de04f17ccea 100644 --- a/fs/dlm/requestqueue.c +++ b/fs/dlm/requestqueue.c @@ -1,7 +1,7 @@ /****************************************************************************** ******************************************************************************* ** -** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. ** ** This copyrighted material is made available to anyone wishing to use, ** modify, copy, or redistribute it subject to the terms and conditions @@ -20,7 +20,7 @@ struct rq_entry { struct list_head list; int nodeid; - char request[1]; + char request[0]; }; /* @@ -30,42 +30,39 @@ struct rq_entry { * lockspace is enabled on some while still suspended on others. */ -int dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd) +void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd) { struct rq_entry *e; int length = hd->h_length; - int rv = 0; e = kmalloc(sizeof(struct rq_entry) + length, GFP_KERNEL); if (!e) { - log_print("dlm_add_requestqueue: out of memory\n"); - return 0; + log_print("dlm_add_requestqueue: out of memory len %d", length); + return; } e->nodeid = nodeid; memcpy(e->request, hd, length); - /* We need to check dlm_locking_stopped() after taking the mutex to - avoid a race where dlm_recoverd enables locking and runs - process_requestqueue between our earlier dlm_locking_stopped check - and this addition to the requestqueue. */ - mutex_lock(&ls->ls_requestqueue_mutex); - if (dlm_locking_stopped(ls)) - list_add_tail(&e->list, &ls->ls_requestqueue); - else { - log_debug(ls, "dlm_add_requestqueue skip from %d", nodeid); - kfree(e); - rv = -EAGAIN; - } + list_add_tail(&e->list, &ls->ls_requestqueue); mutex_unlock(&ls->ls_requestqueue_mutex); - return rv; } +/* + * Called by dlm_recoverd to process normal messages saved while recovery was + * happening. Normal locking has been enabled before this is called. dlm_recv + * upon receiving a message, will wait for all saved messages to be drained + * here before processing the message it got. If a new dlm_ls_stop() arrives + * while we're processing these saved messages, it may block trying to suspend + * dlm_recv if dlm_recv is waiting for us in dlm_wait_requestqueue. In that + * case, we don't abort since locking_stopped is still 0. If dlm_recv is not + * waiting for us, then this processing may be aborted due to locking_stopped. + */ + int dlm_process_requestqueue(struct dlm_ls *ls) { struct rq_entry *e; - struct dlm_header *hd; int error = 0; mutex_lock(&ls->ls_requestqueue_mutex); @@ -79,14 +76,7 @@ int dlm_process_requestqueue(struct dlm_ls *ls) e = list_entry(ls->ls_requestqueue.next, struct rq_entry, list); mutex_unlock(&ls->ls_requestqueue_mutex); - hd = (struct dlm_header *) e->request; - error = dlm_receive_message(hd, e->nodeid, 1); - - if (error == -EINTR) { - /* entry is left on requestqueue */ - log_debug(ls, "process_requestqueue abort eintr"); - break; - } + dlm_receive_message_saved(ls, (struct dlm_message *)e->request); mutex_lock(&ls->ls_requestqueue_mutex); list_del(&e->list); @@ -106,10 +96,12 @@ int dlm_process_requestqueue(struct dlm_ls *ls) /* * After recovery is done, locking is resumed and dlm_recoverd takes all the - * saved requests and processes them as they would have been by dlm_recvd. At - * the same time, dlm_recvd will start receiving new requests from remote - * nodes. We want to delay dlm_recvd processing new requests until - * dlm_recoverd has finished processing the old saved requests. + * saved requests and processes them as they would have been by dlm_recv. At + * the same time, dlm_recv will start receiving new requests from remote nodes. + * We want to delay dlm_recv processing new requests until dlm_recoverd has + * finished processing the old saved requests. We don't check for locking + * stopped here because dlm_ls_stop won't stop locking until it's suspended us + * (dlm_recv). */ void dlm_wait_requestqueue(struct dlm_ls *ls) @@ -118,8 +110,6 @@ void dlm_wait_requestqueue(struct dlm_ls *ls) mutex_lock(&ls->ls_requestqueue_mutex); if (list_empty(&ls->ls_requestqueue)) break; - if (dlm_locking_stopped(ls)) - break; mutex_unlock(&ls->ls_requestqueue_mutex); schedule(); } diff --git a/fs/dlm/requestqueue.h b/fs/dlm/requestqueue.h index 6a53ea03335d..aba34fc05ee4 100644 --- a/fs/dlm/requestqueue.h +++ b/fs/dlm/requestqueue.h @@ -1,7 +1,7 @@ /****************************************************************************** ******************************************************************************* ** -** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. ** ** This copyrighted material is made available to anyone wishing to use, ** modify, copy, or redistribute it subject to the terms and conditions @@ -13,7 +13,7 @@ #ifndef __REQUESTQUEUE_DOT_H__ #define __REQUESTQUEUE_DOT_H__ -int dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd); +void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd); int dlm_process_requestqueue(struct dlm_ls *ls); void dlm_wait_requestqueue(struct dlm_ls *ls); void dlm_purge_requestqueue(struct dlm_ls *ls); diff --git a/fs/dlm/user.c b/fs/dlm/user.c index 6438941ab1f8..4f741546f4bb 100644 --- a/fs/dlm/user.c +++ b/fs/dlm/user.c @@ -456,7 +456,7 @@ static int check_version(struct dlm_write_request *req) printk(KERN_DEBUG "dlm: process %s (%d) version mismatch " "user (%d.%d.%d) kernel (%d.%d.%d)\n", current->comm, - current->pid, + task_pid_nr(current), req->version[0], req->version[1], req->version[2], diff --git a/fs/dquot.c b/fs/dquot.c index de9a29f64ff3..2809768d9c41 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -79,6 +79,10 @@ #include <linux/capability.h> #include <linux/quotaops.h> #include <linux/writeback.h> /* for inode_lock, oddly enough.. */ +#ifdef CONFIG_QUOTA_NETLINK_INTERFACE +#include <net/netlink.h> +#include <net/genetlink.h> +#endif #include <asm/uaccess.h> @@ -823,6 +827,7 @@ static inline void dquot_decr_space(struct dquot *dquot, qsize_t number) clear_bit(DQ_BLKS_B, &dquot->dq_flags); } +#ifdef CONFIG_PRINT_QUOTA_WARNING static int flag_print_warnings = 1; static inline int need_print_warning(struct dquot *dquot) @@ -839,22 +844,15 @@ static inline int need_print_warning(struct dquot *dquot) return 0; } -/* Values of warnings */ -#define NOWARN 0 -#define IHARDWARN 1 -#define ISOFTLONGWARN 2 -#define ISOFTWARN 3 -#define BHARDWARN 4 -#define BSOFTLONGWARN 5 -#define BSOFTWARN 6 - /* Print warning to user which exceeded quota */ static void print_warning(struct dquot *dquot, const char warntype) { char *msg = NULL; struct tty_struct *tty; - int flag = (warntype == BHARDWARN || warntype == BSOFTLONGWARN) ? DQ_BLKS_B : - ((warntype == IHARDWARN || warntype == ISOFTLONGWARN) ? DQ_INODES_B : 0); + int flag = (warntype == QUOTA_NL_BHARDWARN || + warntype == QUOTA_NL_BSOFTLONGWARN) ? DQ_BLKS_B : + ((warntype == QUOTA_NL_IHARDWARN || + warntype == QUOTA_NL_ISOFTLONGWARN) ? DQ_INODES_B : 0); if (!need_print_warning(dquot) || (flag && test_and_set_bit(flag, &dquot->dq_flags))) return; @@ -864,28 +862,28 @@ static void print_warning(struct dquot *dquot, const char warntype) if (!tty) goto out_lock; tty_write_message(tty, dquot->dq_sb->s_id); - if (warntype == ISOFTWARN || warntype == BSOFTWARN) + if (warntype == QUOTA_NL_ISOFTWARN || warntype == QUOTA_NL_BSOFTWARN) tty_write_message(tty, ": warning, "); else tty_write_message(tty, ": write failed, "); tty_write_message(tty, quotatypes[dquot->dq_type]); switch (warntype) { - case IHARDWARN: + case QUOTA_NL_IHARDWARN: msg = " file limit reached.\r\n"; break; - case ISOFTLONGWARN: + case QUOTA_NL_ISOFTLONGWARN: msg = " file quota exceeded too long.\r\n"; break; - case ISOFTWARN: + case QUOTA_NL_ISOFTWARN: msg = " file quota exceeded.\r\n"; break; - case BHARDWARN: + case QUOTA_NL_BHARDWARN: msg = " block limit reached.\r\n"; break; - case BSOFTLONGWARN: + case QUOTA_NL_BSOFTLONGWARN: msg = " block quota exceeded too long.\r\n"; break; - case BSOFTWARN: + case QUOTA_NL_BSOFTWARN: msg = " block quota exceeded.\r\n"; break; } @@ -893,14 +891,93 @@ static void print_warning(struct dquot *dquot, const char warntype) out_lock: mutex_unlock(&tty_mutex); } +#endif + +#ifdef CONFIG_QUOTA_NETLINK_INTERFACE + +/* Size of quota netlink message - actually an upperbound for buffer size */ +#define QUOTA_NL_MSG_SIZE 32 + +/* Netlink family structure for quota */ +static struct genl_family quota_genl_family = { + .id = GENL_ID_GENERATE, + .hdrsize = 0, + .name = "VFS_DQUOT", + .version = 1, + .maxattr = QUOTA_NL_A_MAX, +}; + +/* Send warning to userspace about user which exceeded quota */ +static void send_warning(const struct dquot *dquot, const char warntype) +{ + static atomic_t seq; + struct sk_buff *skb; + void *msg_head; + int ret; + + /* We have to allocate using GFP_NOFS as we are called from a + * filesystem performing write and thus further recursion into + * the fs to free some data could cause deadlocks. */ + skb = genlmsg_new(QUOTA_NL_MSG_SIZE, GFP_NOFS); + if (!skb) { + printk(KERN_ERR + "VFS: Not enough memory to send quota warning.\n"); + return; + } + msg_head = genlmsg_put(skb, 0, atomic_add_return(1, &seq), + "a_genl_family, 0, QUOTA_NL_C_WARNING); + if (!msg_head) { + printk(KERN_ERR + "VFS: Cannot store netlink header in quota warning.\n"); + goto err_out; + } + ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, dquot->dq_type); + if (ret) + goto attr_err_out; + ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, dquot->dq_id); + if (ret) + goto attr_err_out; + ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype); + if (ret) + goto attr_err_out; + ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MAJOR, + MAJOR(dquot->dq_sb->s_dev)); + if (ret) + goto attr_err_out; + ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR, + MINOR(dquot->dq_sb->s_dev)); + if (ret) + goto attr_err_out; + ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current->user->uid); + if (ret) + goto attr_err_out; + genlmsg_end(skb, msg_head); + + ret = genlmsg_multicast(skb, 0, quota_genl_family.id, GFP_NOFS); + if (ret < 0 && ret != -ESRCH) + printk(KERN_ERR + "VFS: Failed to send notification message: %d\n", ret); + return; +attr_err_out: + printk(KERN_ERR "VFS: Failed to compose quota message: %d\n", ret); +err_out: + kfree_skb(skb); +} +#endif static inline void flush_warnings(struct dquot **dquots, char *warntype) { int i; for (i = 0; i < MAXQUOTAS; i++) - if (dquots[i] != NODQUOT && warntype[i] != NOWARN) + if (dquots[i] != NODQUOT && warntype[i] != QUOTA_NL_NOWARN) { +#ifdef CONFIG_PRINT_QUOTA_WARNING print_warning(dquots[i], warntype[i]); +#endif +#ifdef CONFIG_QUOTA_NETLINK_INTERFACE + send_warning(dquots[i], warntype[i]); +#endif + } } static inline char ignore_hardlimit(struct dquot *dquot) @@ -914,14 +991,14 @@ static inline char ignore_hardlimit(struct dquot *dquot) /* needs dq_data_lock */ static int check_idq(struct dquot *dquot, ulong inodes, char *warntype) { - *warntype = NOWARN; + *warntype = QUOTA_NL_NOWARN; if (inodes <= 0 || test_bit(DQ_FAKE_B, &dquot->dq_flags)) return QUOTA_OK; if (dquot->dq_dqb.dqb_ihardlimit && (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_ihardlimit && !ignore_hardlimit(dquot)) { - *warntype = IHARDWARN; + *warntype = QUOTA_NL_IHARDWARN; return NO_QUOTA; } @@ -929,14 +1006,14 @@ static int check_idq(struct dquot *dquot, ulong inodes, char *warntype) (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_isoftlimit && dquot->dq_dqb.dqb_itime && get_seconds() >= dquot->dq_dqb.dqb_itime && !ignore_hardlimit(dquot)) { - *warntype = ISOFTLONGWARN; + *warntype = QUOTA_NL_ISOFTLONGWARN; return NO_QUOTA; } if (dquot->dq_dqb.dqb_isoftlimit && (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_isoftlimit && dquot->dq_dqb.dqb_itime == 0) { - *warntype = ISOFTWARN; + *warntype = QUOTA_NL_ISOFTWARN; dquot->dq_dqb.dqb_itime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace; } @@ -946,7 +1023,7 @@ static int check_idq(struct dquot *dquot, ulong inodes, char *warntype) /* needs dq_data_lock */ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype) { - *warntype = 0; + *warntype = QUOTA_NL_NOWARN; if (space <= 0 || test_bit(DQ_FAKE_B, &dquot->dq_flags)) return QUOTA_OK; @@ -954,7 +1031,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bhardlimit && !ignore_hardlimit(dquot)) { if (!prealloc) - *warntype = BHARDWARN; + *warntype = QUOTA_NL_BHARDWARN; return NO_QUOTA; } @@ -963,7 +1040,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war dquot->dq_dqb.dqb_btime && get_seconds() >= dquot->dq_dqb.dqb_btime && !ignore_hardlimit(dquot)) { if (!prealloc) - *warntype = BSOFTLONGWARN; + *warntype = QUOTA_NL_BSOFTLONGWARN; return NO_QUOTA; } @@ -971,7 +1048,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bsoftlimit && dquot->dq_dqb.dqb_btime == 0) { if (!prealloc) { - *warntype = BSOFTWARN; + *warntype = QUOTA_NL_BSOFTWARN; dquot->dq_dqb.dqb_btime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace; } else @@ -1066,7 +1143,7 @@ out_add: return QUOTA_OK; } for (cnt = 0; cnt < MAXQUOTAS; cnt++) - warntype[cnt] = NOWARN; + warntype[cnt] = QUOTA_NL_NOWARN; down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); if (IS_NOQUOTA(inode)) { /* Now we can do reliable test... */ @@ -1112,7 +1189,7 @@ int dquot_alloc_inode(const struct inode *inode, unsigned long number) if (IS_NOQUOTA(inode)) return QUOTA_OK; for (cnt = 0; cnt < MAXQUOTAS; cnt++) - warntype[cnt] = NOWARN; + warntype[cnt] = QUOTA_NL_NOWARN; down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); if (IS_NOQUOTA(inode)) { up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); @@ -1234,7 +1311,7 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr) /* Clear the arrays */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { transfer_to[cnt] = transfer_from[cnt] = NODQUOT; - warntype[cnt] = NOWARN; + warntype[cnt] = QUOTA_NL_NOWARN; } down_write(&sb_dqopt(inode->i_sb)->dqptr_sem); /* Now recheck reliably when holding dqptr_sem */ @@ -1808,6 +1885,7 @@ static ctl_table fs_dqstats_table[] = { .mode = 0444, .proc_handler = &proc_dointvec, }, +#ifdef CONFIG_PRINT_QUOTA_WARNING { .ctl_name = FS_DQ_WARNINGS, .procname = "warnings", @@ -1816,6 +1894,7 @@ static ctl_table fs_dqstats_table[] = { .mode = 0644, .proc_handler = &proc_dointvec, }, +#endif { .ctl_name = 0 }, }; @@ -1877,6 +1956,11 @@ static int __init dquot_init(void) register_shrinker(&dqcache_shrinker); +#ifdef CONFIG_QUOTA_NETLINK_INTERFACE + if (genl_register_family("a_genl_family) != 0) + printk(KERN_ERR "VFS: Failed to create quota netlink interface.\n"); +#endif + return 0; } module_init(dquot_init); diff --git a/fs/ecryptfs/Makefile b/fs/ecryptfs/Makefile index 1f1107237eab..768857015516 100644 --- a/fs/ecryptfs/Makefile +++ b/fs/ecryptfs/Makefile @@ -4,4 +4,4 @@ obj-$(CONFIG_ECRYPT_FS) += ecryptfs.o -ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o crypto.o keystore.o messaging.o netlink.o debug.o +ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o read_write.o crypto.o keystore.o messaging.o netlink.o debug.o diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index 6ac630625b70..1ae90ef2c74d 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -123,9 +123,9 @@ out: return rc; } -int ecryptfs_crypto_api_algify_cipher_name(char **algified_name, - char *cipher_name, - char *chaining_modifier) +static int ecryptfs_crypto_api_algify_cipher_name(char **algified_name, + char *cipher_name, + char *chaining_modifier) { int cipher_name_len = strlen(cipher_name); int chaining_modifier_len = strlen(chaining_modifier); @@ -149,7 +149,7 @@ out: * ecryptfs_derive_iv * @iv: destination for the derived iv vale * @crypt_stat: Pointer to crypt_stat struct for the current inode - * @offset: Offset of the page whose's iv we are to derive + * @offset: Offset of the extent whose IV we are to derive * * Generate the initialization vector from the given root IV and page * offset. @@ -157,7 +157,7 @@ out: * Returns zero on success; non-zero on error. */ static int ecryptfs_derive_iv(char *iv, struct ecryptfs_crypt_stat *crypt_stat, - pgoff_t offset) + loff_t offset) { int rc = 0; char dst[MD5_DIGEST_SIZE]; @@ -173,7 +173,7 @@ static int ecryptfs_derive_iv(char *iv, struct ecryptfs_crypt_stat *crypt_stat, * hashing business. -Halcrow */ memcpy(src, crypt_stat->root_iv, crypt_stat->iv_bytes); memset((src + crypt_stat->iv_bytes), 0, 16); - snprintf((src + crypt_stat->iv_bytes), 16, "%ld", offset); + snprintf((src + crypt_stat->iv_bytes), 16, "%lld", offset); if (unlikely(ecryptfs_verbosity > 0)) { ecryptfs_printk(KERN_DEBUG, "source:\n"); ecryptfs_dump_hex(src, (crypt_stat->iv_bytes + 16)); @@ -204,6 +204,8 @@ void ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat) { memset((void *)crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat)); + INIT_LIST_HEAD(&crypt_stat->keysig_list); + mutex_init(&crypt_stat->keysig_list_mutex); mutex_init(&crypt_stat->cs_mutex); mutex_init(&crypt_stat->cs_tfm_mutex); mutex_init(&crypt_stat->cs_hash_tfm_mutex); @@ -211,27 +213,48 @@ ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat) } /** - * ecryptfs_destruct_crypt_stat + * ecryptfs_destroy_crypt_stat * @crypt_stat: Pointer to the crypt_stat struct to initialize. * * Releases all memory associated with a crypt_stat struct. */ -void ecryptfs_destruct_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat) +void ecryptfs_destroy_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat) { + struct ecryptfs_key_sig *key_sig, *key_sig_tmp; + if (crypt_stat->tfm) crypto_free_blkcipher(crypt_stat->tfm); if (crypt_stat->hash_tfm) crypto_free_hash(crypt_stat->hash_tfm); + mutex_lock(&crypt_stat->keysig_list_mutex); + list_for_each_entry_safe(key_sig, key_sig_tmp, + &crypt_stat->keysig_list, crypt_stat_list) { + list_del(&key_sig->crypt_stat_list); + kmem_cache_free(ecryptfs_key_sig_cache, key_sig); + } + mutex_unlock(&crypt_stat->keysig_list_mutex); memset(crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat)); } -void ecryptfs_destruct_mount_crypt_stat( +void ecryptfs_destroy_mount_crypt_stat( struct ecryptfs_mount_crypt_stat *mount_crypt_stat) { - if (mount_crypt_stat->global_auth_tok_key) - key_put(mount_crypt_stat->global_auth_tok_key); - if (mount_crypt_stat->global_key_tfm) - crypto_free_blkcipher(mount_crypt_stat->global_key_tfm); + struct ecryptfs_global_auth_tok *auth_tok, *auth_tok_tmp; + + if (!(mount_crypt_stat->flags & ECRYPTFS_MOUNT_CRYPT_STAT_INITIALIZED)) + return; + mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex); + list_for_each_entry_safe(auth_tok, auth_tok_tmp, + &mount_crypt_stat->global_auth_tok_list, + mount_crypt_stat_list) { + list_del(&auth_tok->mount_crypt_stat_list); + mount_crypt_stat->num_global_auth_toks--; + if (auth_tok->global_auth_tok_key + && !(auth_tok->flags & ECRYPTFS_AUTH_TOK_INVALID)) + key_put(auth_tok->global_auth_tok_key); + kmem_cache_free(ecryptfs_global_auth_tok_cache, auth_tok); + } + mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex); memset(mount_crypt_stat, 0, sizeof(struct ecryptfs_mount_crypt_stat)); } @@ -330,114 +353,82 @@ out: return rc; } -static void -ecryptfs_extent_to_lwr_pg_idx_and_offset(unsigned long *lower_page_idx, - int *byte_offset, - struct ecryptfs_crypt_stat *crypt_stat, - unsigned long extent_num) +/** + * ecryptfs_lower_offset_for_extent + * + * Convert an eCryptfs page index into a lower byte offset + */ +void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num, + struct ecryptfs_crypt_stat *crypt_stat) { - unsigned long lower_extent_num; - int extents_occupied_by_headers_at_front; - int bytes_occupied_by_headers_at_front; - int extent_offset; - int extents_per_page; - - bytes_occupied_by_headers_at_front = - ( crypt_stat->header_extent_size - * crypt_stat->num_header_extents_at_front ); - extents_occupied_by_headers_at_front = - ( bytes_occupied_by_headers_at_front - / crypt_stat->extent_size ); - lower_extent_num = extents_occupied_by_headers_at_front + extent_num; - extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size; - (*lower_page_idx) = lower_extent_num / extents_per_page; - extent_offset = lower_extent_num % extents_per_page; - (*byte_offset) = extent_offset * crypt_stat->extent_size; - ecryptfs_printk(KERN_DEBUG, " * crypt_stat->header_extent_size = " - "[%d]\n", crypt_stat->header_extent_size); - ecryptfs_printk(KERN_DEBUG, " * crypt_stat->" - "num_header_extents_at_front = [%d]\n", - crypt_stat->num_header_extents_at_front); - ecryptfs_printk(KERN_DEBUG, " * extents_occupied_by_headers_at_" - "front = [%d]\n", extents_occupied_by_headers_at_front); - ecryptfs_printk(KERN_DEBUG, " * lower_extent_num = [0x%.16x]\n", - lower_extent_num); - ecryptfs_printk(KERN_DEBUG, " * extents_per_page = [%d]\n", - extents_per_page); - ecryptfs_printk(KERN_DEBUG, " * (*lower_page_idx) = [0x%.16x]\n", - (*lower_page_idx)); - ecryptfs_printk(KERN_DEBUG, " * extent_offset = [%d]\n", - extent_offset); - ecryptfs_printk(KERN_DEBUG, " * (*byte_offset) = [%d]\n", - (*byte_offset)); + (*offset) = ((crypt_stat->extent_size + * crypt_stat->num_header_extents_at_front) + + (crypt_stat->extent_size * extent_num)); } -static int ecryptfs_write_out_page(struct ecryptfs_page_crypt_context *ctx, - struct page *lower_page, - struct inode *lower_inode, - int byte_offset_in_page, int bytes_to_write) +/** + * ecryptfs_encrypt_extent + * @enc_extent_page: Allocated page into which to encrypt the data in + * @page + * @crypt_stat: crypt_stat containing cryptographic context for the + * encryption operation + * @page: Page containing plaintext data extent to encrypt + * @extent_offset: Page extent offset for use in generating IV + * + * Encrypts one extent of data. + * + * Return zero on success; non-zero otherwise + */ +static int ecryptfs_encrypt_extent(struct page *enc_extent_page, + struct ecryptfs_crypt_stat *crypt_stat, + struct page *page, + unsigned long extent_offset) { - int rc = 0; + loff_t extent_base; + char extent_iv[ECRYPTFS_MAX_IV_BYTES]; + int rc; - if (ctx->mode == ECRYPTFS_PREPARE_COMMIT_MODE) { - rc = ecryptfs_commit_lower_page(lower_page, lower_inode, - ctx->param.lower_file, - byte_offset_in_page, - bytes_to_write); - if (rc) { - ecryptfs_printk(KERN_ERR, "Error calling lower " - "commit; rc = [%d]\n", rc); - goto out; - } - } else { - rc = ecryptfs_writepage_and_release_lower_page(lower_page, - lower_inode, - ctx->param.wbc); - if (rc) { - ecryptfs_printk(KERN_ERR, "Error calling lower " - "writepage(); rc = [%d]\n", rc); - goto out; - } + extent_base = (((loff_t)page->index) + * (PAGE_CACHE_SIZE / crypt_stat->extent_size)); + rc = ecryptfs_derive_iv(extent_iv, crypt_stat, + (extent_base + extent_offset)); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error attempting to " + "derive IV for extent [0x%.16x]; " + "rc = [%d]\n", (extent_base + extent_offset), + rc); + goto out; } -out: - return rc; -} - -static int ecryptfs_read_in_page(struct ecryptfs_page_crypt_context *ctx, - struct page **lower_page, - struct inode *lower_inode, - unsigned long lower_page_idx, - int byte_offset_in_page) -{ - int rc = 0; - - if (ctx->mode == ECRYPTFS_PREPARE_COMMIT_MODE) { - /* TODO: Limit this to only the data extents that are - * needed */ - rc = ecryptfs_get_lower_page(lower_page, lower_inode, - ctx->param.lower_file, - lower_page_idx, - byte_offset_in_page, - (PAGE_CACHE_SIZE - - byte_offset_in_page)); - if (rc) { - ecryptfs_printk( - KERN_ERR, "Error attempting to grab, map, " - "and prepare_write lower page with index " - "[0x%.16x]; rc = [%d]\n", lower_page_idx, rc); - goto out; - } - } else { - *lower_page = grab_cache_page(lower_inode->i_mapping, - lower_page_idx); - if (!(*lower_page)) { - rc = -EINVAL; - ecryptfs_printk( - KERN_ERR, "Error attempting to grab and map " - "lower page with index [0x%.16x]; rc = [%d]\n", - lower_page_idx, rc); - goto out; - } + if (unlikely(ecryptfs_verbosity > 0)) { + ecryptfs_printk(KERN_DEBUG, "Encrypting extent " + "with iv:\n"); + ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes); + ecryptfs_printk(KERN_DEBUG, "First 8 bytes before " + "encryption:\n"); + ecryptfs_dump_hex((char *) + (page_address(page) + + (extent_offset * crypt_stat->extent_size)), + 8); + } + rc = ecryptfs_encrypt_page_offset(crypt_stat, enc_extent_page, 0, + page, (extent_offset + * crypt_stat->extent_size), + crypt_stat->extent_size, extent_iv); + if (rc < 0) { + printk(KERN_ERR "%s: Error attempting to encrypt page with " + "page->index = [%ld], extent_offset = [%ld]; " + "rc = [%d]\n", __FUNCTION__, page->index, extent_offset, + rc); + goto out; + } + rc = 0; + if (unlikely(ecryptfs_verbosity > 0)) { + ecryptfs_printk(KERN_DEBUG, "Encrypt extent [0x%.16x]; " + "rc = [%d]\n", (extent_base + extent_offset), + rc); + ecryptfs_printk(KERN_DEBUG, "First 8 bytes after " + "encryption:\n"); + ecryptfs_dump_hex((char *)(page_address(enc_extent_page)), 8); } out: return rc; @@ -445,7 +436,9 @@ out: /** * ecryptfs_encrypt_page - * @ctx: The context of the page + * @page: Page mapped from the eCryptfs inode for the file; contains + * decrypted content that needs to be encrypted (to a temporary + * page; not in place) and written out to the lower file * * Encrypt an eCryptfs page. This is done on a per-extent basis. Note * that eCryptfs pages may straddle the lower pages -- for instance, @@ -455,128 +448,122 @@ out: * file, 24K of page 0 of the lower file will be read and decrypted, * and then 8K of page 1 of the lower file will be read and decrypted. * - * The actual operations performed on each page depends on the - * contents of the ecryptfs_page_crypt_context struct. - * * Returns zero on success; negative on error */ -int ecryptfs_encrypt_page(struct ecryptfs_page_crypt_context *ctx) +int ecryptfs_encrypt_page(struct page *page) { - char extent_iv[ECRYPTFS_MAX_IV_BYTES]; - unsigned long base_extent; - unsigned long extent_offset = 0; - unsigned long lower_page_idx = 0; - unsigned long prior_lower_page_idx = 0; - struct page *lower_page; - struct inode *lower_inode; - struct ecryptfs_inode_info *inode_info; + struct inode *ecryptfs_inode; struct ecryptfs_crypt_stat *crypt_stat; + char *enc_extent_virt = NULL; + struct page *enc_extent_page; + loff_t extent_offset; int rc = 0; - int lower_byte_offset = 0; - int orig_byte_offset = 0; - int num_extents_per_page; -#define ECRYPTFS_PAGE_STATE_UNREAD 0 -#define ECRYPTFS_PAGE_STATE_READ 1 -#define ECRYPTFS_PAGE_STATE_MODIFIED 2 -#define ECRYPTFS_PAGE_STATE_WRITTEN 3 - int page_state; - - lower_inode = ecryptfs_inode_to_lower(ctx->page->mapping->host); - inode_info = ecryptfs_inode_to_private(ctx->page->mapping->host); - crypt_stat = &inode_info->crypt_stat; + + ecryptfs_inode = page->mapping->host; + crypt_stat = + &(ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat); if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { - rc = ecryptfs_copy_page_to_lower(ctx->page, lower_inode, - ctx->param.lower_file); + rc = ecryptfs_write_lower_page_segment(ecryptfs_inode, page, + 0, PAGE_CACHE_SIZE); if (rc) - ecryptfs_printk(KERN_ERR, "Error attempting to copy " - "page at index [0x%.16x]\n", - ctx->page->index); + printk(KERN_ERR "%s: Error attempting to copy " + "page at index [%ld]\n", __FUNCTION__, + page->index); goto out; } - num_extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size; - base_extent = (ctx->page->index * num_extents_per_page); - page_state = ECRYPTFS_PAGE_STATE_UNREAD; - while (extent_offset < num_extents_per_page) { - ecryptfs_extent_to_lwr_pg_idx_and_offset( - &lower_page_idx, &lower_byte_offset, crypt_stat, - (base_extent + extent_offset)); - if (prior_lower_page_idx != lower_page_idx - && page_state == ECRYPTFS_PAGE_STATE_MODIFIED) { - rc = ecryptfs_write_out_page(ctx, lower_page, - lower_inode, - orig_byte_offset, - (PAGE_CACHE_SIZE - - orig_byte_offset)); - if (rc) { - ecryptfs_printk(KERN_ERR, "Error attempting " - "to write out page; rc = [%d]" - "\n", rc); - goto out; - } - page_state = ECRYPTFS_PAGE_STATE_WRITTEN; - } - if (page_state == ECRYPTFS_PAGE_STATE_UNREAD - || page_state == ECRYPTFS_PAGE_STATE_WRITTEN) { - rc = ecryptfs_read_in_page(ctx, &lower_page, - lower_inode, lower_page_idx, - lower_byte_offset); - if (rc) { - ecryptfs_printk(KERN_ERR, "Error attempting " - "to read in lower page with " - "index [0x%.16x]; rc = [%d]\n", - lower_page_idx, rc); - goto out; - } - orig_byte_offset = lower_byte_offset; - prior_lower_page_idx = lower_page_idx; - page_state = ECRYPTFS_PAGE_STATE_READ; - } - BUG_ON(!(page_state == ECRYPTFS_PAGE_STATE_MODIFIED - || page_state == ECRYPTFS_PAGE_STATE_READ)); - rc = ecryptfs_derive_iv(extent_iv, crypt_stat, - (base_extent + extent_offset)); + enc_extent_virt = kmalloc(PAGE_CACHE_SIZE, GFP_USER); + if (!enc_extent_virt) { + rc = -ENOMEM; + ecryptfs_printk(KERN_ERR, "Error allocating memory for " + "encrypted extent\n"); + goto out; + } + enc_extent_page = virt_to_page(enc_extent_virt); + for (extent_offset = 0; + extent_offset < (PAGE_CACHE_SIZE / crypt_stat->extent_size); + extent_offset++) { + loff_t offset; + + rc = ecryptfs_encrypt_extent(enc_extent_page, crypt_stat, page, + extent_offset); if (rc) { - ecryptfs_printk(KERN_ERR, "Error attempting to " - "derive IV for extent [0x%.16x]; " - "rc = [%d]\n", - (base_extent + extent_offset), rc); + printk(KERN_ERR "%s: Error encrypting extent; " + "rc = [%d]\n", __FUNCTION__, rc); goto out; } - if (unlikely(ecryptfs_verbosity > 0)) { - ecryptfs_printk(KERN_DEBUG, "Encrypting extent " - "with iv:\n"); - ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes); - ecryptfs_printk(KERN_DEBUG, "First 8 bytes before " - "encryption:\n"); - ecryptfs_dump_hex((char *) - (page_address(ctx->page) - + (extent_offset - * crypt_stat->extent_size)), 8); - } - rc = ecryptfs_encrypt_page_offset( - crypt_stat, lower_page, lower_byte_offset, ctx->page, - (extent_offset * crypt_stat->extent_size), - crypt_stat->extent_size, extent_iv); - ecryptfs_printk(KERN_DEBUG, "Encrypt extent [0x%.16x]; " - "rc = [%d]\n", - (base_extent + extent_offset), rc); - if (unlikely(ecryptfs_verbosity > 0)) { - ecryptfs_printk(KERN_DEBUG, "First 8 bytes after " - "encryption:\n"); - ecryptfs_dump_hex((char *)(page_address(lower_page) - + lower_byte_offset), 8); + ecryptfs_lower_offset_for_extent( + &offset, ((((loff_t)page->index) + * (PAGE_CACHE_SIZE + / crypt_stat->extent_size)) + + extent_offset), crypt_stat); + rc = ecryptfs_write_lower(ecryptfs_inode, enc_extent_virt, + offset, crypt_stat->extent_size); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error attempting " + "to write lower page; rc = [%d]" + "\n", rc); + goto out; } - page_state = ECRYPTFS_PAGE_STATE_MODIFIED; extent_offset++; } - BUG_ON(orig_byte_offset != 0); - rc = ecryptfs_write_out_page(ctx, lower_page, lower_inode, 0, - (lower_byte_offset - + crypt_stat->extent_size)); +out: + kfree(enc_extent_virt); + return rc; +} + +static int ecryptfs_decrypt_extent(struct page *page, + struct ecryptfs_crypt_stat *crypt_stat, + struct page *enc_extent_page, + unsigned long extent_offset) +{ + loff_t extent_base; + char extent_iv[ECRYPTFS_MAX_IV_BYTES]; + int rc; + + extent_base = (((loff_t)page->index) + * (PAGE_CACHE_SIZE / crypt_stat->extent_size)); + rc = ecryptfs_derive_iv(extent_iv, crypt_stat, + (extent_base + extent_offset)); if (rc) { - ecryptfs_printk(KERN_ERR, "Error attempting to write out " - "page; rc = [%d]\n", rc); - goto out; + ecryptfs_printk(KERN_ERR, "Error attempting to " + "derive IV for extent [0x%.16x]; " + "rc = [%d]\n", (extent_base + extent_offset), + rc); + goto out; + } + if (unlikely(ecryptfs_verbosity > 0)) { + ecryptfs_printk(KERN_DEBUG, "Decrypting extent " + "with iv:\n"); + ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes); + ecryptfs_printk(KERN_DEBUG, "First 8 bytes before " + "decryption:\n"); + ecryptfs_dump_hex((char *) + (page_address(enc_extent_page) + + (extent_offset * crypt_stat->extent_size)), + 8); + } + rc = ecryptfs_decrypt_page_offset(crypt_stat, page, + (extent_offset + * crypt_stat->extent_size), + enc_extent_page, 0, + crypt_stat->extent_size, extent_iv); + if (rc < 0) { + printk(KERN_ERR "%s: Error attempting to decrypt to page with " + "page->index = [%ld], extent_offset = [%ld]; " + "rc = [%d]\n", __FUNCTION__, page->index, extent_offset, + rc); + goto out; + } + rc = 0; + if (unlikely(ecryptfs_verbosity > 0)) { + ecryptfs_printk(KERN_DEBUG, "Decrypt extent [0x%.16x]; " + "rc = [%d]\n", (extent_base + extent_offset), + rc); + ecryptfs_printk(KERN_DEBUG, "First 8 bytes after " + "decryption:\n"); + ecryptfs_dump_hex((char *)(page_address(page) + + (extent_offset + * crypt_stat->extent_size)), 8); } out: return rc; @@ -584,8 +571,9 @@ out: /** * ecryptfs_decrypt_page - * @file: The ecryptfs file - * @page: The page in ecryptfs to decrypt + * @page: Page mapped from the eCryptfs inode for the file; data read + * and decrypted from the lower file will be written into this + * page * * Decrypt an eCryptfs page. This is done on a per-extent basis. Note * that eCryptfs pages may straddle the lower pages -- for instance, @@ -597,108 +585,75 @@ out: * * Returns zero on success; negative on error */ -int ecryptfs_decrypt_page(struct file *file, struct page *page) +int ecryptfs_decrypt_page(struct page *page) { - char extent_iv[ECRYPTFS_MAX_IV_BYTES]; - unsigned long base_extent; - unsigned long extent_offset = 0; - unsigned long lower_page_idx = 0; - unsigned long prior_lower_page_idx = 0; - struct page *lower_page; - char *lower_page_virt = NULL; - struct inode *lower_inode; + struct inode *ecryptfs_inode; struct ecryptfs_crypt_stat *crypt_stat; + char *enc_extent_virt = NULL; + struct page *enc_extent_page; + unsigned long extent_offset; int rc = 0; - int byte_offset; - int num_extents_per_page; - int page_state; - crypt_stat = &(ecryptfs_inode_to_private( - page->mapping->host)->crypt_stat); - lower_inode = ecryptfs_inode_to_lower(page->mapping->host); + ecryptfs_inode = page->mapping->host; + crypt_stat = + &(ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat); if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { - rc = ecryptfs_do_readpage(file, page, page->index); + rc = ecryptfs_read_lower_page_segment(page, page->index, 0, + PAGE_CACHE_SIZE, + ecryptfs_inode); if (rc) - ecryptfs_printk(KERN_ERR, "Error attempting to copy " - "page at index [0x%.16x]\n", - page->index); + printk(KERN_ERR "%s: Error attempting to copy " + "page at index [%ld]\n", __FUNCTION__, + page->index); goto out; } - num_extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size; - base_extent = (page->index * num_extents_per_page); - lower_page_virt = kmem_cache_alloc(ecryptfs_lower_page_cache, - GFP_KERNEL); - if (!lower_page_virt) { + enc_extent_virt = kmalloc(PAGE_CACHE_SIZE, GFP_USER); + if (!enc_extent_virt) { rc = -ENOMEM; - ecryptfs_printk(KERN_ERR, "Error getting page for encrypted " - "lower page(s)\n"); + ecryptfs_printk(KERN_ERR, "Error allocating memory for " + "encrypted extent\n"); goto out; } - lower_page = virt_to_page(lower_page_virt); - page_state = ECRYPTFS_PAGE_STATE_UNREAD; - while (extent_offset < num_extents_per_page) { - ecryptfs_extent_to_lwr_pg_idx_and_offset( - &lower_page_idx, &byte_offset, crypt_stat, - (base_extent + extent_offset)); - if (prior_lower_page_idx != lower_page_idx - || page_state == ECRYPTFS_PAGE_STATE_UNREAD) { - rc = ecryptfs_do_readpage(file, lower_page, - lower_page_idx); - if (rc) { - ecryptfs_printk(KERN_ERR, "Error reading " - "lower encrypted page; rc = " - "[%d]\n", rc); - goto out; - } - prior_lower_page_idx = lower_page_idx; - page_state = ECRYPTFS_PAGE_STATE_READ; - } - rc = ecryptfs_derive_iv(extent_iv, crypt_stat, - (base_extent + extent_offset)); + enc_extent_page = virt_to_page(enc_extent_virt); + for (extent_offset = 0; + extent_offset < (PAGE_CACHE_SIZE / crypt_stat->extent_size); + extent_offset++) { + loff_t offset; + + ecryptfs_lower_offset_for_extent( + &offset, ((page->index * (PAGE_CACHE_SIZE + / crypt_stat->extent_size)) + + extent_offset), crypt_stat); + rc = ecryptfs_read_lower(enc_extent_virt, offset, + crypt_stat->extent_size, + ecryptfs_inode); if (rc) { - ecryptfs_printk(KERN_ERR, "Error attempting to " - "derive IV for extent [0x%.16x]; rc = " - "[%d]\n", - (base_extent + extent_offset), rc); + ecryptfs_printk(KERN_ERR, "Error attempting " + "to read lower page; rc = [%d]" + "\n", rc); goto out; } - if (unlikely(ecryptfs_verbosity > 0)) { - ecryptfs_printk(KERN_DEBUG, "Decrypting extent " - "with iv:\n"); - ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes); - ecryptfs_printk(KERN_DEBUG, "First 8 bytes before " - "decryption:\n"); - ecryptfs_dump_hex((lower_page_virt + byte_offset), 8); - } - rc = ecryptfs_decrypt_page_offset(crypt_stat, page, - (extent_offset - * crypt_stat->extent_size), - lower_page, byte_offset, - crypt_stat->extent_size, - extent_iv); - if (rc != crypt_stat->extent_size) { - ecryptfs_printk(KERN_ERR, "Error attempting to " - "decrypt extent [0x%.16x]\n", - (base_extent + extent_offset)); + rc = ecryptfs_decrypt_extent(page, crypt_stat, enc_extent_page, + extent_offset); + if (rc) { + printk(KERN_ERR "%s: Error encrypting extent; " + "rc = [%d]\n", __FUNCTION__, rc); goto out; } - rc = 0; - if (unlikely(ecryptfs_verbosity > 0)) { - ecryptfs_printk(KERN_DEBUG, "First 8 bytes after " - "decryption:\n"); - ecryptfs_dump_hex((char *)(page_address(page) - + byte_offset), 8); - } extent_offset++; } out: - if (lower_page_virt) - kmem_cache_free(ecryptfs_lower_page_cache, lower_page_virt); + kfree(enc_extent_virt); return rc; } /** * decrypt_scatterlist + * @crypt_stat: Cryptographic context + * @dest_sg: The destination scatterlist to decrypt into + * @src_sg: The source scatterlist to decrypt from + * @size: The number of bytes to decrypt + * @iv: The initialization vector to use for the decryption * * Returns the number of bytes decrypted; negative value on error */ @@ -740,6 +695,13 @@ out: /** * ecryptfs_encrypt_page_offset + * @crypt_stat: The cryptographic context + * @dst_page: The page to encrypt into + * @dst_offset: The offset in the page to encrypt into + * @src_page: The page to encrypt from + * @src_offset: The offset in the page to encrypt from + * @size: The number of bytes to encrypt + * @iv: The initialization vector to use for the encryption * * Returns the number of bytes encrypted */ @@ -762,6 +724,13 @@ ecryptfs_encrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat, /** * ecryptfs_decrypt_page_offset + * @crypt_stat: The cryptographic context + * @dst_page: The page to decrypt into + * @dst_offset: The offset in the page to decrypt into + * @src_page: The page to decrypt from + * @src_offset: The offset in the page to decrypt from + * @size: The number of bytes to decrypt + * @iv: The initialization vector to use for the decryption * * Returns the number of bytes decrypted */ @@ -857,15 +826,17 @@ void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat) crypt_stat->extent_size = ECRYPTFS_DEFAULT_EXTENT_SIZE; set_extent_mask_and_shift(crypt_stat); crypt_stat->iv_bytes = ECRYPTFS_DEFAULT_IV_BYTES; - if (PAGE_CACHE_SIZE <= ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) { - crypt_stat->header_extent_size = - ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE; - } else - crypt_stat->header_extent_size = PAGE_CACHE_SIZE; if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) crypt_stat->num_header_extents_at_front = 0; - else - crypt_stat->num_header_extents_at_front = 1; + else { + if (PAGE_CACHE_SIZE <= ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) + crypt_stat->num_header_extents_at_front = + (ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE + / crypt_stat->extent_size); + else + crypt_stat->num_header_extents_at_front = + (PAGE_CACHE_SIZE / crypt_stat->extent_size); + } } /** @@ -917,6 +888,8 @@ static void ecryptfs_generate_new_key(struct ecryptfs_crypt_stat *crypt_stat) /** * ecryptfs_copy_mount_wide_flags_to_inode_flags + * @crypt_stat: The inode's cryptographic context + * @mount_crypt_stat: The mount point's cryptographic context * * This function propagates the mount-wide flags to individual inode * flags. @@ -931,9 +904,34 @@ static void ecryptfs_copy_mount_wide_flags_to_inode_flags( crypt_stat->flags |= ECRYPTFS_VIEW_AS_ENCRYPTED; } +static int ecryptfs_copy_mount_wide_sigs_to_inode_sigs( + struct ecryptfs_crypt_stat *crypt_stat, + struct ecryptfs_mount_crypt_stat *mount_crypt_stat) +{ + struct ecryptfs_global_auth_tok *global_auth_tok; + int rc = 0; + + mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex); + list_for_each_entry(global_auth_tok, + &mount_crypt_stat->global_auth_tok_list, + mount_crypt_stat_list) { + rc = ecryptfs_add_keysig(crypt_stat, global_auth_tok->sig); + if (rc) { + printk(KERN_ERR "Error adding keysig; rc = [%d]\n", rc); + mutex_unlock( + &mount_crypt_stat->global_auth_tok_list_mutex); + goto out; + } + } + mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex); +out: + return rc; +} + /** * ecryptfs_set_default_crypt_stat_vals - * @crypt_stat + * @crypt_stat: The inode's cryptographic context + * @mount_crypt_stat: The mount point's cryptographic context * * Default values in the event that policy does not override them. */ @@ -953,7 +951,7 @@ static void ecryptfs_set_default_crypt_stat_vals( /** * ecryptfs_new_file_context - * @ecryptfs_dentry + * @ecryptfs_dentry: The eCryptfs dentry * * If the crypto context for the file has not yet been established, * this is where we do that. Establishing a new crypto context @@ -970,49 +968,42 @@ static void ecryptfs_set_default_crypt_stat_vals( * * Returns zero on success; non-zero otherwise */ -/* Associate an authentication token(s) with the file */ int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry) { - int rc = 0; struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = &ecryptfs_superblock_to_private( ecryptfs_dentry->d_sb)->mount_crypt_stat; int cipher_name_len; + int rc = 0; ecryptfs_set_default_crypt_stat_vals(crypt_stat, mount_crypt_stat); - /* See if there are mount crypt options */ - if (mount_crypt_stat->global_auth_tok) { - ecryptfs_printk(KERN_DEBUG, "Initializing context for new " - "file using mount_crypt_stat\n"); - crypt_stat->flags |= ECRYPTFS_ENCRYPTED; - crypt_stat->flags |= ECRYPTFS_KEY_VALID; - ecryptfs_copy_mount_wide_flags_to_inode_flags(crypt_stat, - mount_crypt_stat); - memcpy(crypt_stat->keysigs[crypt_stat->num_keysigs++], - mount_crypt_stat->global_auth_tok_sig, - ECRYPTFS_SIG_SIZE_HEX); - cipher_name_len = - strlen(mount_crypt_stat->global_default_cipher_name); - memcpy(crypt_stat->cipher, - mount_crypt_stat->global_default_cipher_name, - cipher_name_len); - crypt_stat->cipher[cipher_name_len] = '\0'; - crypt_stat->key_size = - mount_crypt_stat->global_default_cipher_key_size; - ecryptfs_generate_new_key(crypt_stat); - } else - /* We should not encounter this scenario since we - * should detect lack of global_auth_tok at mount time - * TODO: Applies to 0.1 release only; remove in future - * release */ - BUG(); + crypt_stat->flags |= (ECRYPTFS_ENCRYPTED | ECRYPTFS_KEY_VALID); + ecryptfs_copy_mount_wide_flags_to_inode_flags(crypt_stat, + mount_crypt_stat); + rc = ecryptfs_copy_mount_wide_sigs_to_inode_sigs(crypt_stat, + mount_crypt_stat); + if (rc) { + printk(KERN_ERR "Error attempting to copy mount-wide key sigs " + "to the inode key sigs; rc = [%d]\n", rc); + goto out; + } + cipher_name_len = + strlen(mount_crypt_stat->global_default_cipher_name); + memcpy(crypt_stat->cipher, + mount_crypt_stat->global_default_cipher_name, + cipher_name_len); + crypt_stat->cipher[cipher_name_len] = '\0'; + crypt_stat->key_size = + mount_crypt_stat->global_default_cipher_key_size; + ecryptfs_generate_new_key(crypt_stat); rc = ecryptfs_init_crypt_ctx(crypt_stat); if (rc) ecryptfs_printk(KERN_ERR, "Error initializing cryptographic " "context for cipher [%s]: rc = [%d]\n", crypt_stat->cipher, rc); +out: return rc; } @@ -1054,7 +1045,7 @@ static struct ecryptfs_flag_map_elem ecryptfs_flag_map[] = { /** * ecryptfs_process_flags - * @crypt_stat + * @crypt_stat: The cryptographic context * @page_virt: Source data to be parsed * @bytes_read: Updated with the number of bytes read * @@ -1142,7 +1133,7 @@ ecryptfs_cipher_code_str_map[] = { /** * ecryptfs_code_for_cipher_string - * @str: The string representing the cipher name + * @crypt_stat: The cryptographic context * * Returns zero on no match, or the cipher code on match */ @@ -1198,59 +1189,28 @@ int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code) return rc; } -/** - * ecryptfs_read_header_region - * @data - * @dentry - * @nd - * - * Returns zero on success; non-zero otherwise - */ -static int ecryptfs_read_header_region(char *data, struct dentry *dentry, - struct vfsmount *mnt) +int ecryptfs_read_and_validate_header_region(char *data, + struct inode *ecryptfs_inode) { - struct file *lower_file; - mm_segment_t oldfs; + struct ecryptfs_crypt_stat *crypt_stat = + &(ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat); int rc; - if ((rc = ecryptfs_open_lower_file(&lower_file, dentry, mnt, - O_RDONLY))) { - printk(KERN_ERR - "Error opening lower_file to read header region\n"); - goto out; - } - lower_file->f_pos = 0; - oldfs = get_fs(); - set_fs(get_ds()); - /* For releases 0.1 and 0.2, all of the header information - * fits in the first data extent-sized region. */ - rc = lower_file->f_op->read(lower_file, (char __user *)data, - ECRYPTFS_DEFAULT_EXTENT_SIZE, &lower_file->f_pos); - set_fs(oldfs); - if ((rc = ecryptfs_close_lower_file(lower_file))) { - printk(KERN_ERR "Error closing lower_file\n"); + rc = ecryptfs_read_lower(data, 0, crypt_stat->extent_size, + ecryptfs_inode); + if (rc) { + printk(KERN_ERR "%s: Error reading header region; rc = [%d]\n", + __FUNCTION__, rc); goto out; } - rc = 0; -out: - return rc; -} - -int ecryptfs_read_and_validate_header_region(char *data, struct dentry *dentry, - struct vfsmount *mnt) -{ - int rc; - - rc = ecryptfs_read_header_region(data, dentry, mnt); - if (rc) - goto out; - if (!contains_ecryptfs_marker(data + ECRYPTFS_FILE_SIZE_BYTES)) + if (!contains_ecryptfs_marker(data + ECRYPTFS_FILE_SIZE_BYTES)) { rc = -EINVAL; + ecryptfs_printk(KERN_DEBUG, "Valid marker not found\n"); + } out: return rc; } - void ecryptfs_write_header_metadata(char *virt, struct ecryptfs_crypt_stat *crypt_stat, @@ -1259,7 +1219,7 @@ ecryptfs_write_header_metadata(char *virt, u32 header_extent_size; u16 num_header_extents_at_front; - header_extent_size = (u32)crypt_stat->header_extent_size; + header_extent_size = (u32)crypt_stat->extent_size; num_header_extents_at_front = (u16)crypt_stat->num_header_extents_at_front; header_extent_size = cpu_to_be32(header_extent_size); @@ -1276,9 +1236,10 @@ struct kmem_cache *ecryptfs_header_cache_2; /** * ecryptfs_write_headers_virt - * @page_virt - * @crypt_stat - * @ecryptfs_dentry + * @page_virt: The virtual address to write the headers to + * @size: Set to the number of bytes written by this function + * @crypt_stat: The cryptographic context + * @ecryptfs_dentry: The eCryptfs dentry * * Format version: 1 * @@ -1332,53 +1293,50 @@ static int ecryptfs_write_headers_virt(char *page_virt, size_t *size, return rc; } -static int ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat, - struct file *lower_file, - char *page_virt) +static int +ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat, + struct dentry *ecryptfs_dentry, + char *page_virt) { - mm_segment_t oldfs; int current_header_page; int header_pages; - ssize_t size; - int rc = 0; + int rc; - lower_file->f_pos = 0; - oldfs = get_fs(); - set_fs(get_ds()); - size = vfs_write(lower_file, (char __user *)page_virt, PAGE_CACHE_SIZE, - &lower_file->f_pos); - if (size < 0) { - rc = (int)size; - printk(KERN_ERR "Error attempting to write lower page; " - "rc = [%d]\n", rc); - set_fs(oldfs); + rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, page_virt, + 0, PAGE_CACHE_SIZE); + if (rc) { + printk(KERN_ERR "%s: Error attempting to write header " + "information to lower file; rc = [%d]\n", __FUNCTION__, + rc); goto out; } - header_pages = ((crypt_stat->header_extent_size + header_pages = ((crypt_stat->extent_size * crypt_stat->num_header_extents_at_front) / PAGE_CACHE_SIZE); memset(page_virt, 0, PAGE_CACHE_SIZE); current_header_page = 1; while (current_header_page < header_pages) { - size = vfs_write(lower_file, (char __user *)page_virt, - PAGE_CACHE_SIZE, &lower_file->f_pos); - if (size < 0) { - rc = (int)size; - printk(KERN_ERR "Error attempting to write lower page; " - "rc = [%d]\n", rc); - set_fs(oldfs); + loff_t offset; + + offset = (((loff_t)current_header_page) << PAGE_CACHE_SHIFT); + if ((rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, + page_virt, offset, + PAGE_CACHE_SIZE))) { + printk(KERN_ERR "%s: Error attempting to write header " + "information to lower file; rc = [%d]\n", + __FUNCTION__, rc); goto out; } current_header_page++; } - set_fs(oldfs); out: return rc; } -static int ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry, - struct ecryptfs_crypt_stat *crypt_stat, - char *page_virt, size_t size) +static int +ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry, + struct ecryptfs_crypt_stat *crypt_stat, + char *page_virt, size_t size) { int rc; @@ -1389,7 +1347,7 @@ static int ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry, /** * ecryptfs_write_metadata - * @lower_file: The lower file struct, which was returned from dentry_open + * @ecryptfs_dentry: The eCryptfs dentry * * Write the file headers out. This will likely involve a userspace * callout, in which the session key is encrypted with one or more @@ -1397,22 +1355,21 @@ static int ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry, * retrieved via a prompt. Exactly what happens at this point should * be policy-dependent. * + * TODO: Support header information spanning multiple pages + * * Returns zero on success; non-zero on error */ -int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry, - struct file *lower_file) +int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry) { - struct ecryptfs_crypt_stat *crypt_stat; + struct ecryptfs_crypt_stat *crypt_stat = + &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat; char *page_virt; - size_t size; + size_t size = 0; int rc = 0; - crypt_stat = &ecryptfs_inode_to_private( - ecryptfs_dentry->d_inode)->crypt_stat; if (likely(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { if (!(crypt_stat->flags & ECRYPTFS_KEY_VALID)) { - ecryptfs_printk(KERN_DEBUG, "Key is " - "invalid; bailing out\n"); + printk(KERN_ERR "Key is invalid; bailing out\n"); rc = -EINVAL; goto out; } @@ -1441,7 +1398,8 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry, crypt_stat, page_virt, size); else - rc = ecryptfs_write_metadata_to_contents(crypt_stat, lower_file, + rc = ecryptfs_write_metadata_to_contents(crypt_stat, + ecryptfs_dentry, page_virt); if (rc) { printk(KERN_ERR "Error writing metadata out to lower file; " @@ -1464,28 +1422,28 @@ static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat, u32 header_extent_size; u16 num_header_extents_at_front; - memcpy(&header_extent_size, virt, 4); + memcpy(&header_extent_size, virt, sizeof(u32)); header_extent_size = be32_to_cpu(header_extent_size); - virt += 4; - memcpy(&num_header_extents_at_front, virt, 2); + virt += sizeof(u32); + memcpy(&num_header_extents_at_front, virt, sizeof(u16)); num_header_extents_at_front = be16_to_cpu(num_header_extents_at_front); - crypt_stat->header_extent_size = (int)header_extent_size; crypt_stat->num_header_extents_at_front = (int)num_header_extents_at_front; - (*bytes_read) = 6; + (*bytes_read) = (sizeof(u32) + sizeof(u16)); if ((validate_header_size == ECRYPTFS_VALIDATE_HEADER_SIZE) - && ((crypt_stat->header_extent_size + && ((crypt_stat->extent_size * crypt_stat->num_header_extents_at_front) < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)) { rc = -EINVAL; - ecryptfs_printk(KERN_WARNING, "Invalid header extent size: " - "[%d]\n", crypt_stat->header_extent_size); + printk(KERN_WARNING "Invalid number of header extents: [%zd]\n", + crypt_stat->num_header_extents_at_front); } return rc; } /** * set_default_header_data + * @crypt_stat: The cryptographic context * * For version 0 file format; this function is only for backwards * compatibility for files created with the prior versions of @@ -1493,12 +1451,15 @@ static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat, */ static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat) { - crypt_stat->header_extent_size = 4096; - crypt_stat->num_header_extents_at_front = 1; + crypt_stat->num_header_extents_at_front = 2; } /** * ecryptfs_read_headers_virt + * @page_virt: The virtual address into which to read the headers + * @crypt_stat: The cryptographic context + * @ecryptfs_dentry: The eCryptfs dentry + * @validate_header_size: Whether to validate the header size while reading * * Read/parse the header data. The header format is detailed in the * comment block for the ecryptfs_write_headers_virt() function. @@ -1558,19 +1519,25 @@ out: /** * ecryptfs_read_xattr_region + * @page_virt: The vitual address into which to read the xattr data + * @ecryptfs_inode: The eCryptfs inode * * Attempts to read the crypto metadata from the extended attribute * region of the lower file. + * + * Returns zero on success; non-zero on error */ -int ecryptfs_read_xattr_region(char *page_virt, struct dentry *ecryptfs_dentry) +int ecryptfs_read_xattr_region(char *page_virt, struct inode *ecryptfs_inode) { + struct dentry *lower_dentry = + ecryptfs_inode_to_private(ecryptfs_inode)->lower_file->f_dentry; ssize_t size; int rc = 0; - size = ecryptfs_getxattr(ecryptfs_dentry, ECRYPTFS_XATTR_NAME, - page_virt, ECRYPTFS_DEFAULT_EXTENT_SIZE); + size = ecryptfs_getxattr_lower(lower_dentry, ECRYPTFS_XATTR_NAME, + page_virt, ECRYPTFS_DEFAULT_EXTENT_SIZE); if (size < 0) { - printk(KERN_DEBUG "Error attempting to read the [%s] " + printk(KERN_ERR "Error attempting to read the [%s] " "xattr from the lower file; return value = [%zd]\n", ECRYPTFS_XATTR_NAME, size); rc = -EINVAL; @@ -1585,7 +1552,7 @@ int ecryptfs_read_and_validate_xattr_region(char *page_virt, { int rc; - rc = ecryptfs_read_xattr_region(page_virt, ecryptfs_dentry); + rc = ecryptfs_read_xattr_region(page_virt, ecryptfs_dentry->d_inode); if (rc) goto out; if (!contains_ecryptfs_marker(page_virt + ECRYPTFS_FILE_SIZE_BYTES)) { @@ -1609,15 +1576,13 @@ out: * * Returns zero if valid headers found and parsed; non-zero otherwise */ -int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry, - struct file *lower_file) +int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry) { int rc = 0; char *page_virt = NULL; - mm_segment_t oldfs; - ssize_t bytes_read; + struct inode *ecryptfs_inode = ecryptfs_dentry->d_inode; struct ecryptfs_crypt_stat *crypt_stat = - &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat; + &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = &ecryptfs_superblock_to_private( ecryptfs_dentry->d_sb)->mount_crypt_stat; @@ -1628,27 +1593,18 @@ int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry, page_virt = kmem_cache_alloc(ecryptfs_header_cache_1, GFP_USER); if (!page_virt) { rc = -ENOMEM; - ecryptfs_printk(KERN_ERR, "Unable to allocate page_virt\n"); + printk(KERN_ERR "%s: Unable to allocate page_virt\n", + __FUNCTION__); goto out; } - lower_file->f_pos = 0; - oldfs = get_fs(); - set_fs(get_ds()); - bytes_read = lower_file->f_op->read(lower_file, - (char __user *)page_virt, - ECRYPTFS_DEFAULT_EXTENT_SIZE, - &lower_file->f_pos); - set_fs(oldfs); - if (bytes_read != ECRYPTFS_DEFAULT_EXTENT_SIZE) { - rc = -EINVAL; - goto out; - } - rc = ecryptfs_read_headers_virt(page_virt, crypt_stat, - ecryptfs_dentry, - ECRYPTFS_VALIDATE_HEADER_SIZE); + rc = ecryptfs_read_lower(page_virt, 0, crypt_stat->extent_size, + ecryptfs_inode); + if (!rc) + rc = ecryptfs_read_headers_virt(page_virt, crypt_stat, + ecryptfs_dentry, + ECRYPTFS_VALIDATE_HEADER_SIZE); if (rc) { - rc = ecryptfs_read_xattr_region(page_virt, - ecryptfs_dentry); + rc = ecryptfs_read_xattr_region(page_virt, ecryptfs_inode); if (rc) { printk(KERN_DEBUG "Valid eCryptfs headers not found in " "file header region or xattr region\n"); @@ -1776,7 +1732,7 @@ out: } /** - * ecryptfs_process_cipher - Perform cipher initialization. + * ecryptfs_process_key_cipher - Perform key cipher initialization. * @key_tfm: Crypto context for key material, set by this function * @cipher_name: Name of the cipher * @key_size: Size of the key in bytes @@ -1785,9 +1741,9 @@ out: * should be released by other functions, such as on a superblock put * event, regardless of whether this function succeeds for fails. */ -int -ecryptfs_process_cipher(struct crypto_blkcipher **key_tfm, char *cipher_name, - size_t *key_size) +static int +ecryptfs_process_key_cipher(struct crypto_blkcipher **key_tfm, + char *cipher_name, size_t *key_size) { char dummy_key[ECRYPTFS_MAX_KEY_BYTES]; char *full_alg_name; @@ -1829,3 +1785,100 @@ ecryptfs_process_cipher(struct crypto_blkcipher **key_tfm, char *cipher_name, out: return rc; } + +struct kmem_cache *ecryptfs_key_tfm_cache; +struct list_head key_tfm_list; +struct mutex key_tfm_list_mutex; + +int ecryptfs_init_crypto(void) +{ + mutex_init(&key_tfm_list_mutex); + INIT_LIST_HEAD(&key_tfm_list); + return 0; +} + +int ecryptfs_destroy_crypto(void) +{ + struct ecryptfs_key_tfm *key_tfm, *key_tfm_tmp; + + mutex_lock(&key_tfm_list_mutex); + list_for_each_entry_safe(key_tfm, key_tfm_tmp, &key_tfm_list, + key_tfm_list) { + list_del(&key_tfm->key_tfm_list); + if (key_tfm->key_tfm) + crypto_free_blkcipher(key_tfm->key_tfm); + kmem_cache_free(ecryptfs_key_tfm_cache, key_tfm); + } + mutex_unlock(&key_tfm_list_mutex); + return 0; +} + +int +ecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name, + size_t key_size) +{ + struct ecryptfs_key_tfm *tmp_tfm; + int rc = 0; + + tmp_tfm = kmem_cache_alloc(ecryptfs_key_tfm_cache, GFP_KERNEL); + if (key_tfm != NULL) + (*key_tfm) = tmp_tfm; + if (!tmp_tfm) { + rc = -ENOMEM; + printk(KERN_ERR "Error attempting to allocate from " + "ecryptfs_key_tfm_cache\n"); + goto out; + } + mutex_init(&tmp_tfm->key_tfm_mutex); + strncpy(tmp_tfm->cipher_name, cipher_name, + ECRYPTFS_MAX_CIPHER_NAME_SIZE); + tmp_tfm->key_size = key_size; + rc = ecryptfs_process_key_cipher(&tmp_tfm->key_tfm, + tmp_tfm->cipher_name, + &tmp_tfm->key_size); + if (rc) { + printk(KERN_ERR "Error attempting to initialize key TFM " + "cipher with name = [%s]; rc = [%d]\n", + tmp_tfm->cipher_name, rc); + kmem_cache_free(ecryptfs_key_tfm_cache, tmp_tfm); + if (key_tfm != NULL) + (*key_tfm) = NULL; + goto out; + } + mutex_lock(&key_tfm_list_mutex); + list_add(&tmp_tfm->key_tfm_list, &key_tfm_list); + mutex_unlock(&key_tfm_list_mutex); +out: + return rc; +} + +int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm, + struct mutex **tfm_mutex, + char *cipher_name) +{ + struct ecryptfs_key_tfm *key_tfm; + int rc = 0; + + (*tfm) = NULL; + (*tfm_mutex) = NULL; + mutex_lock(&key_tfm_list_mutex); + list_for_each_entry(key_tfm, &key_tfm_list, key_tfm_list) { + if (strcmp(key_tfm->cipher_name, cipher_name) == 0) { + (*tfm) = key_tfm->key_tfm; + (*tfm_mutex) = &key_tfm->key_tfm_mutex; + mutex_unlock(&key_tfm_list_mutex); + goto out; + } + } + mutex_unlock(&key_tfm_list_mutex); + rc = ecryptfs_add_new_key_tfm(&key_tfm, cipher_name, 0); + if (rc) { + printk(KERN_ERR "Error adding new key_tfm to list; rc = [%d]\n", + rc); + goto out; + } + (*tfm) = key_tfm->key_tfm; + (*tfm_mutex) = &key_tfm->key_tfm_mutex; +out: + return rc; +} diff --git a/fs/ecryptfs/debug.c b/fs/ecryptfs/debug.c index 434c7efd80f8..3d2bdf546ec6 100644 --- a/fs/ecryptfs/debug.c +++ b/fs/ecryptfs/debug.c @@ -38,8 +38,6 @@ void ecryptfs_dump_auth_tok(struct ecryptfs_auth_tok *auth_tok) auth_tok); if (auth_tok->flags & ECRYPTFS_PRIVATE_KEY) { ecryptfs_printk(KERN_DEBUG, " * private key type\n"); - ecryptfs_printk(KERN_DEBUG, " * (NO PRIVATE KEY SUPPORT " - "IN ECRYPTFS VERSION 0.1)\n"); } else { ecryptfs_printk(KERN_DEBUG, " * passphrase type\n"); ecryptfs_to_hex(salt, auth_tok->token.password.salt, diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index 1b9dd9a96f19..ce7a5d4aec36 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h @@ -38,7 +38,7 @@ /* Version verification for shared data structures w/ userspace */ #define ECRYPTFS_VERSION_MAJOR 0x00 #define ECRYPTFS_VERSION_MINOR 0x04 -#define ECRYPTFS_SUPPORTED_FILE_VERSION 0x02 +#define ECRYPTFS_SUPPORTED_FILE_VERSION 0x03 /* These flags indicate which features are supported by the kernel * module; userspace tools such as the mount helper read * ECRYPTFS_VERSIONING_MASK from a sysfs handle in order to determine @@ -48,10 +48,12 @@ #define ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH 0x00000004 #define ECRYPTFS_VERSIONING_POLICY 0x00000008 #define ECRYPTFS_VERSIONING_XATTR 0x00000010 +#define ECRYPTFS_VERSIONING_MULTKEY 0x00000020 #define ECRYPTFS_VERSIONING_MASK (ECRYPTFS_VERSIONING_PASSPHRASE \ | ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH \ | ECRYPTFS_VERSIONING_PUBKEY \ - | ECRYPTFS_VERSIONING_XATTR) + | ECRYPTFS_VERSIONING_XATTR \ + | ECRYPTFS_VERSIONING_MULTKEY) #define ECRYPTFS_MAX_PASSWORD_LENGTH 64 #define ECRYPTFS_MAX_PASSPHRASE_BYTES ECRYPTFS_MAX_PASSWORD_LENGTH #define ECRYPTFS_SALT_SIZE 8 @@ -65,8 +67,7 @@ #define ECRYPTFS_MAX_KEY_BYTES 64 #define ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES 512 #define ECRYPTFS_DEFAULT_IV_BYTES 16 -#define ECRYPTFS_FILE_VERSION 0x02 -#define ECRYPTFS_DEFAULT_HEADER_EXTENT_SIZE 8192 +#define ECRYPTFS_FILE_VERSION 0x03 #define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096 #define ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE 8192 #define ECRYPTFS_DEFAULT_MSG_CTX_ELEMS 32 @@ -144,6 +145,7 @@ struct ecryptfs_private_key { struct ecryptfs_auth_tok { u16 version; /* 8-bit major and 8-bit minor */ u16 token_type; +#define ECRYPTFS_ENCRYPT_ONLY 0x00000001 u32 flags; struct ecryptfs_session_key session_key; u8 reserved[32]; @@ -194,12 +196,11 @@ ecryptfs_get_key_payload_data(struct key *key) #define ECRYPTFS_MAX_KEYSET_SIZE 1024 #define ECRYPTFS_MAX_CIPHER_NAME_SIZE 32 #define ECRYPTFS_MAX_NUM_ENC_KEYS 64 -#define ECRYPTFS_MAX_NUM_KEYSIGS 2 /* TODO: Make this a linked list */ #define ECRYPTFS_MAX_IV_BYTES 16 /* 128 bits */ #define ECRYPTFS_SALT_BYTES 2 #define MAGIC_ECRYPTFS_MARKER 0x3c81b7f5 #define MAGIC_ECRYPTFS_MARKER_SIZE_BYTES 8 /* 4*2 */ -#define ECRYPTFS_FILE_SIZE_BYTES 8 +#define ECRYPTFS_FILE_SIZE_BYTES (sizeof(u64)) #define ECRYPTFS_DEFAULT_CIPHER "aes" #define ECRYPTFS_DEFAULT_KEY_BYTES 16 #define ECRYPTFS_DEFAULT_HASH "md5" @@ -212,6 +213,11 @@ ecryptfs_get_key_payload_data(struct key *key) #define ECRYPTFS_TAG_67_PACKET_TYPE 0x43 #define MD5_DIGEST_SIZE 16 +struct ecryptfs_key_sig { + struct list_head crypt_stat_list; + char keysig[ECRYPTFS_SIG_SIZE_HEX]; +}; + /** * This is the primary struct associated with each encrypted file. * @@ -231,8 +237,6 @@ struct ecryptfs_crypt_stat { u32 flags; unsigned int file_version; size_t iv_bytes; - size_t num_keysigs; - size_t header_extent_size; size_t num_header_extents_at_front; size_t extent_size; /* Data extent size; default is 4096 */ size_t key_size; @@ -245,7 +249,8 @@ struct ecryptfs_crypt_stat { unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE]; unsigned char key[ECRYPTFS_MAX_KEY_BYTES]; unsigned char root_iv[ECRYPTFS_MAX_IV_BYTES]; - unsigned char keysigs[ECRYPTFS_MAX_NUM_KEYSIGS][ECRYPTFS_SIG_SIZE_HEX]; + struct list_head keysig_list; + struct mutex keysig_list_mutex; struct mutex cs_tfm_mutex; struct mutex cs_hash_tfm_mutex; struct mutex cs_mutex; @@ -255,6 +260,8 @@ struct ecryptfs_crypt_stat { struct ecryptfs_inode_info { struct inode vfs_inode; struct inode *wii_inode; + struct file *lower_file; + struct mutex lower_file_mutex; struct ecryptfs_crypt_stat crypt_stat; }; @@ -266,6 +273,59 @@ struct ecryptfs_dentry_info { }; /** + * ecryptfs_global_auth_tok - A key used to encrypt all new files under the mountpoint + * @flags: Status flags + * @mount_crypt_stat_list: These auth_toks hang off the mount-wide + * cryptographic context. Every time a new + * inode comes into existence, eCryptfs copies + * the auth_toks on that list to the set of + * auth_toks on the inode's crypt_stat + * @global_auth_tok_key: The key from the user's keyring for the sig + * @global_auth_tok: The key contents + * @sig: The key identifier + * + * ecryptfs_global_auth_tok structs refer to authentication token keys + * in the user keyring that apply to newly created files. A list of + * these objects hangs off of the mount_crypt_stat struct for any + * given eCryptfs mount. This struct maintains a reference to both the + * key contents and the key itself so that the key can be put on + * unmount. + */ +struct ecryptfs_global_auth_tok { +#define ECRYPTFS_AUTH_TOK_INVALID 0x00000001 + u32 flags; + struct list_head mount_crypt_stat_list; + struct key *global_auth_tok_key; + struct ecryptfs_auth_tok *global_auth_tok; + unsigned char sig[ECRYPTFS_SIG_SIZE_HEX + 1]; +}; + +/** + * ecryptfs_key_tfm - Persistent key tfm + * @key_tfm: crypto API handle to the key + * @key_size: Key size in bytes + * @key_tfm_mutex: Mutex to ensure only one operation in eCryptfs is + * using the persistent TFM at any point in time + * @key_tfm_list: Handle to hang this off the module-wide TFM list + * @cipher_name: String name for the cipher for this TFM + * + * Typically, eCryptfs will use the same ciphers repeatedly throughout + * the course of its operations. In order to avoid unnecessarily + * destroying and initializing the same cipher repeatedly, eCryptfs + * keeps a list of crypto API contexts around to use when needed. + */ +struct ecryptfs_key_tfm { + struct crypto_blkcipher *key_tfm; + size_t key_size; + struct mutex key_tfm_mutex; + struct list_head key_tfm_list; + unsigned char cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1]; +}; + +extern struct list_head key_tfm_list; +extern struct mutex key_tfm_list_mutex; + +/** * This struct is to enable a mount-wide passphrase/salt combo. This * is more or less a stopgap to provide similar functionality to other * crypto filesystems like EncFS or CFS until full policy support is @@ -276,15 +336,14 @@ struct ecryptfs_mount_crypt_stat { #define ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED 0x00000001 #define ECRYPTFS_XATTR_METADATA_ENABLED 0x00000002 #define ECRYPTFS_ENCRYPTED_VIEW_ENABLED 0x00000004 +#define ECRYPTFS_MOUNT_CRYPT_STAT_INITIALIZED 0x00000008 u32 flags; - struct ecryptfs_auth_tok *global_auth_tok; - struct key *global_auth_tok_key; + struct list_head global_auth_tok_list; + struct mutex global_auth_tok_list_mutex; + size_t num_global_auth_toks; size_t global_default_cipher_key_size; - struct crypto_blkcipher *global_key_tfm; - struct mutex global_key_tfm_mutex; unsigned char global_default_cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1]; - unsigned char global_auth_tok_sig[ECRYPTFS_SIG_SIZE_HEX + 1]; }; /* superblock private data. */ @@ -468,6 +527,9 @@ extern struct kmem_cache *ecryptfs_header_cache_2; extern struct kmem_cache *ecryptfs_xattr_cache; extern struct kmem_cache *ecryptfs_lower_page_cache; extern struct kmem_cache *ecryptfs_key_record_cache; +extern struct kmem_cache *ecryptfs_key_sig_cache; +extern struct kmem_cache *ecryptfs_global_auth_tok_cache; +extern struct kmem_cache *ecryptfs_key_tfm_cache; int ecryptfs_interpose(struct dentry *hidden_dentry, struct dentry *this_dentry, struct super_block *sb, @@ -486,44 +548,18 @@ int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg, int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat); void ecryptfs_rotate_iv(unsigned char *iv); void ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat); -void ecryptfs_destruct_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat); -void ecryptfs_destruct_mount_crypt_stat( +void ecryptfs_destroy_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat); +void ecryptfs_destroy_mount_crypt_stat( struct ecryptfs_mount_crypt_stat *mount_crypt_stat); int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat); -int ecryptfs_crypto_api_algify_cipher_name(char **algified_name, - char *cipher_name, - char *chaining_modifier); -#define ECRYPTFS_LOWER_I_MUTEX_NOT_HELD 0 -#define ECRYPTFS_LOWER_I_MUTEX_HELD 1 -int ecryptfs_write_inode_size_to_metadata(struct file *lower_file, - struct inode *lower_inode, - struct inode *inode, - struct dentry *ecryptfs_dentry, - int lower_i_mutex_held); -int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode, - struct file *lower_file, - unsigned long lower_page_index, int byte_offset, - int region_bytes); -int -ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode, - struct file *lower_file, int byte_offset, - int region_size); -int ecryptfs_copy_page_to_lower(struct page *page, struct inode *lower_inode, - struct file *lower_file); -int ecryptfs_do_readpage(struct file *file, struct page *page, - pgoff_t lower_page_index); -int ecryptfs_writepage_and_release_lower_page(struct page *lower_page, - struct inode *lower_inode, - struct writeback_control *wbc); -int ecryptfs_encrypt_page(struct ecryptfs_page_crypt_context *ctx); -int ecryptfs_decrypt_page(struct file *file, struct page *page); -int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry, - struct file *lower_file); -int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry, - struct file *lower_file); +int ecryptfs_write_inode_size_to_metadata(struct inode *ecryptfs_inode); +int ecryptfs_encrypt_page(struct page *page); +int ecryptfs_decrypt_page(struct page *page); +int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry); +int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry); int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry); -int ecryptfs_read_and_validate_header_region(char *data, struct dentry *dentry, - struct vfsmount *mnt); +int ecryptfs_read_and_validate_header_region(char *data, + struct inode *ecryptfs_inode); int ecryptfs_read_and_validate_xattr_region(char *page_virt, struct dentry *ecryptfs_dentry); u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat); @@ -533,27 +569,22 @@ int ecryptfs_generate_key_packet_set(char *dest_base, struct ecryptfs_crypt_stat *crypt_stat, struct dentry *ecryptfs_dentry, size_t *len, size_t max); -int process_request_key_err(long err_code); int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, unsigned char *src, struct dentry *ecryptfs_dentry); int ecryptfs_truncate(struct dentry *dentry, loff_t new_length); -int -ecryptfs_process_cipher(struct crypto_blkcipher **key_tfm, char *cipher_name, - size_t *key_size); int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode); int ecryptfs_inode_set(struct inode *inode, void *lower_inode); void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode); -int ecryptfs_open_lower_file(struct file **lower_file, - struct dentry *lower_dentry, - struct vfsmount *lower_mnt, int flags); -int ecryptfs_close_lower_file(struct file *lower_file); ssize_t ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size); +ssize_t +ecryptfs_getxattr_lower(struct dentry *lower_dentry, const char *name, + void *value, size_t size); int ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags); -int ecryptfs_read_xattr_region(char *page_virt, struct dentry *ecryptfs_dentry); +int ecryptfs_read_xattr_region(char *page_virt, struct inode *ecryptfs_inode); int ecryptfs_process_helo(unsigned int transport, uid_t uid, pid_t pid); int ecryptfs_process_quit(uid_t uid, pid_t pid); int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t uid, @@ -580,7 +611,43 @@ void ecryptfs_write_header_metadata(char *virt, struct ecryptfs_crypt_stat *crypt_stat, size_t *written); +int ecryptfs_add_keysig(struct ecryptfs_crypt_stat *crypt_stat, char *sig); +int +ecryptfs_add_global_auth_tok(struct ecryptfs_mount_crypt_stat *mount_crypt_stat, + char *sig); +int ecryptfs_get_global_auth_tok_for_sig( + struct ecryptfs_global_auth_tok **global_auth_tok, + struct ecryptfs_mount_crypt_stat *mount_crypt_stat, char *sig); +int +ecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name, + size_t key_size); +int ecryptfs_init_crypto(void); +int ecryptfs_destroy_crypto(void); +int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm, + struct mutex **tfm_mutex, + char *cipher_name); +int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key, + struct ecryptfs_auth_tok **auth_tok, + char *sig); int ecryptfs_write_zeros(struct file *file, pgoff_t index, int start, int num_zeros); +void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num, + struct ecryptfs_crypt_stat *crypt_stat); +int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data, + loff_t offset, size_t size); +int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode, + struct page *page_for_lower, + size_t offset_in_page, size_t size); +int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset, + size_t size); +int ecryptfs_read_lower(char *data, loff_t offset, size_t size, + struct inode *ecryptfs_inode); +int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs, + pgoff_t page_index, + size_t offset_in_page, size_t size, + struct inode *ecryptfs_inode); +int ecryptfs_read(char *data, loff_t offset, size_t size, + struct file *ecryptfs_file); +struct page *ecryptfs_get_locked_page(struct file *file, loff_t index); #endif /* #ifndef ECRYPTFS_KERNEL_H */ diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index 94f456fe4d9b..c98c4690a771 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -141,34 +141,6 @@ retry: struct kmem_cache *ecryptfs_file_info_cache; -int ecryptfs_open_lower_file(struct file **lower_file, - struct dentry *lower_dentry, - struct vfsmount *lower_mnt, int flags) -{ - int rc = 0; - - flags |= O_LARGEFILE; - dget(lower_dentry); - mntget(lower_mnt); - *lower_file = dentry_open(lower_dentry, lower_mnt, flags); - if (IS_ERR(*lower_file)) { - printk(KERN_ERR "Error opening lower file for lower_dentry " - "[0x%p], lower_mnt [0x%p], and flags [0x%x]\n", - lower_dentry, lower_mnt, flags); - rc = PTR_ERR(*lower_file); - *lower_file = NULL; - goto out; - } -out: - return rc; -} - -int ecryptfs_close_lower_file(struct file *lower_file) -{ - fput(lower_file); - return 0; -} - /** * ecryptfs_open * @inode: inode speciying file to open @@ -187,11 +159,7 @@ static int ecryptfs_open(struct inode *inode, struct file *file) /* Private value of ecryptfs_dentry allocated in * ecryptfs_lookup() */ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); - struct inode *lower_inode = NULL; - struct file *lower_file = NULL; - struct vfsmount *lower_mnt; struct ecryptfs_file_info *file_info; - int lower_flags; mount_crypt_stat = &ecryptfs_superblock_to_private( ecryptfs_dentry->d_sb)->mount_crypt_stat; @@ -219,25 +187,12 @@ static int ecryptfs_open(struct inode *inode, struct file *file) if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) { ecryptfs_printk(KERN_DEBUG, "Setting flags for stat...\n"); /* Policy code enabled in future release */ - crypt_stat->flags |= ECRYPTFS_POLICY_APPLIED; - crypt_stat->flags |= ECRYPTFS_ENCRYPTED; + crypt_stat->flags |= (ECRYPTFS_POLICY_APPLIED + | ECRYPTFS_ENCRYPTED); } mutex_unlock(&crypt_stat->cs_mutex); - lower_flags = file->f_flags; - if ((lower_flags & O_ACCMODE) == O_WRONLY) - lower_flags = (lower_flags & O_ACCMODE) | O_RDWR; - if (file->f_flags & O_APPEND) - lower_flags &= ~O_APPEND; - lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry); - /* Corresponding fput() in ecryptfs_release() */ - if ((rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, lower_mnt, - lower_flags))) { - ecryptfs_printk(KERN_ERR, "Error opening lower file\n"); - goto out_puts; - } - ecryptfs_set_file_lower(file, lower_file); - /* Isn't this check the same as the one in lookup? */ - lower_inode = lower_dentry->d_inode; + ecryptfs_set_file_lower( + file, ecryptfs_inode_to_private(inode)->lower_file); if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) { ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); @@ -247,7 +202,7 @@ static int ecryptfs_open(struct inode *inode, struct file *file) mutex_lock(&crypt_stat->cs_mutex); if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED) || !(crypt_stat->flags & ECRYPTFS_KEY_VALID)) { - rc = ecryptfs_read_metadata(ecryptfs_dentry, lower_file); + rc = ecryptfs_read_metadata(ecryptfs_dentry); if (rc) { ecryptfs_printk(KERN_DEBUG, "Valid headers not found\n"); @@ -259,7 +214,7 @@ static int ecryptfs_open(struct inode *inode, struct file *file) "and plaintext passthrough mode is not " "enabled; returning -EIO\n"); mutex_unlock(&crypt_stat->cs_mutex); - goto out_puts; + goto out_free; } rc = 0; crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); @@ -271,11 +226,8 @@ static int ecryptfs_open(struct inode *inode, struct file *file) ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = [0x%.16x] " "size: [0x%.16x]\n", inode, inode->i_ino, i_size_read(inode)); - ecryptfs_set_file_lower(file, lower_file); goto out; -out_puts: - mntput(lower_mnt); - dput(lower_dentry); +out_free: kmem_cache_free(ecryptfs_file_info_cache, ecryptfs_file_to_private(file)); out: @@ -295,19 +247,9 @@ static int ecryptfs_flush(struct file *file, fl_owner_t td) static int ecryptfs_release(struct inode *inode, struct file *file) { - struct file *lower_file = ecryptfs_file_to_lower(file); - struct ecryptfs_file_info *file_info = ecryptfs_file_to_private(file); - struct inode *lower_inode = ecryptfs_inode_to_lower(inode); - int rc; - - if ((rc = ecryptfs_close_lower_file(lower_file))) { - printk(KERN_ERR "Error closing lower_file\n"); - goto out; - } - inode->i_blocks = lower_inode->i_blocks; - kmem_cache_free(ecryptfs_file_info_cache, file_info); -out: - return rc; + kmem_cache_free(ecryptfs_file_info_cache, + ecryptfs_file_to_private(file)); + return 0; } static int @@ -338,21 +280,6 @@ static int ecryptfs_fasync(int fd, struct file *file, int flag) return rc; } -static ssize_t ecryptfs_splice_read(struct file *file, loff_t * ppos, - struct pipe_inode_info *pipe, size_t count, - unsigned int flags) -{ - struct file *lower_file = NULL; - int rc = -EINVAL; - - lower_file = ecryptfs_file_to_lower(file); - if (lower_file->f_op && lower_file->f_op->splice_read) - rc = lower_file->f_op->splice_read(lower_file, ppos, pipe, - count, flags); - - return rc; -} - static int ecryptfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); @@ -365,7 +292,7 @@ const struct file_operations ecryptfs_dir_fops = { .release = ecryptfs_release, .fsync = ecryptfs_fsync, .fasync = ecryptfs_fasync, - .splice_read = ecryptfs_splice_read, + .splice_read = generic_file_splice_read, }; const struct file_operations ecryptfs_main_fops = { @@ -382,7 +309,7 @@ const struct file_operations ecryptfs_main_fops = { .release = ecryptfs_release, .fsync = ecryptfs_fsync, .fasync = ecryptfs_fasync, - .splice_read = ecryptfs_splice_read, + .splice_read = generic_file_splice_read, }; static int diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 131954b3fb98..0b1ab016fa2e 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -119,10 +119,23 @@ ecryptfs_do_create(struct inode *directory_inode, } rc = ecryptfs_create_underlying_file(lower_dir_dentry->d_inode, ecryptfs_dentry, mode, nd); - if (unlikely(rc)) { - ecryptfs_printk(KERN_ERR, - "Failure to create underlying file\n"); - goto out_lock; + if (rc) { + struct inode *ecryptfs_inode = ecryptfs_dentry->d_inode; + struct ecryptfs_inode_info *inode_info = + ecryptfs_inode_to_private(ecryptfs_inode); + + printk(KERN_WARNING "%s: Error creating underlying file; " + "rc = [%d]; checking for existing\n", __FUNCTION__, rc); + if (inode_info) { + mutex_lock(&inode_info->lower_file_mutex); + if (!inode_info->lower_file) { + mutex_unlock(&inode_info->lower_file_mutex); + printk(KERN_ERR "%s: Failure to set underlying " + "file; rc = [%d]\n", __FUNCTION__, rc); + goto out_lock; + } + mutex_unlock(&inode_info->lower_file_mutex); + } } rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry, directory_inode->i_sb, 0); @@ -140,39 +153,30 @@ out: /** * grow_file - * @ecryptfs_dentry: the ecryptfs dentry - * @lower_file: The lower file - * @inode: The ecryptfs inode - * @lower_inode: The lower inode + * @ecryptfs_dentry: the eCryptfs dentry * * This is the code which will grow the file to its correct size. */ -static int grow_file(struct dentry *ecryptfs_dentry, struct file *lower_file, - struct inode *inode, struct inode *lower_inode) +static int grow_file(struct dentry *ecryptfs_dentry) { - int rc = 0; + struct inode *ecryptfs_inode = ecryptfs_dentry->d_inode; struct file fake_file; struct ecryptfs_file_info tmp_file_info; + char zero_virt[] = { 0x00 }; + int rc = 0; memset(&fake_file, 0, sizeof(fake_file)); fake_file.f_path.dentry = ecryptfs_dentry; memset(&tmp_file_info, 0, sizeof(tmp_file_info)); ecryptfs_set_file_private(&fake_file, &tmp_file_info); - ecryptfs_set_file_lower(&fake_file, lower_file); - rc = ecryptfs_fill_zeros(&fake_file, 1); - if (rc) { - ecryptfs_inode_to_private(inode)->crypt_stat.flags |= - ECRYPTFS_SECURITY_WARNING; - ecryptfs_printk(KERN_WARNING, "Error attempting to fill zeros " - "in file; rc = [%d]\n", rc); - goto out; - } - i_size_write(inode, 0); - rc = ecryptfs_write_inode_size_to_metadata(lower_file, lower_inode, - inode, ecryptfs_dentry, - ECRYPTFS_LOWER_I_MUTEX_NOT_HELD); - ecryptfs_inode_to_private(inode)->crypt_stat.flags |= ECRYPTFS_NEW_FILE; -out: + ecryptfs_set_file_lower( + &fake_file, + ecryptfs_inode_to_private(ecryptfs_inode)->lower_file); + rc = ecryptfs_write(&fake_file, zero_virt, 0, 1); + i_size_write(ecryptfs_inode, 0); + rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode); + ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat.flags |= + ECRYPTFS_NEW_FILE; return rc; } @@ -186,51 +190,31 @@ out: */ static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry) { + struct ecryptfs_crypt_stat *crypt_stat = + &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat; int rc = 0; - int lower_flags; - struct ecryptfs_crypt_stat *crypt_stat; - struct dentry *lower_dentry; - struct file *lower_file; - struct inode *inode, *lower_inode; - struct vfsmount *lower_mnt; - lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); - ecryptfs_printk(KERN_DEBUG, "lower_dentry->d_name.name = [%s]\n", - lower_dentry->d_name.name); - inode = ecryptfs_dentry->d_inode; - crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; - lower_flags = ((O_CREAT | O_TRUNC) & O_ACCMODE) | O_RDWR; - lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry); - /* Corresponding fput() at end of this function */ - if ((rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, lower_mnt, - lower_flags))) { - ecryptfs_printk(KERN_ERR, - "Error opening dentry; rc = [%i]\n", rc); - goto out; - } - lower_inode = lower_dentry->d_inode; if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) { ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); - goto out_fput; + goto out; } crypt_stat->flags |= ECRYPTFS_NEW_FILE; ecryptfs_printk(KERN_DEBUG, "Initializing crypto context\n"); rc = ecryptfs_new_file_context(ecryptfs_dentry); if (rc) { - ecryptfs_printk(KERN_DEBUG, "Error creating new file " - "context\n"); - goto out_fput; + ecryptfs_printk(KERN_ERR, "Error creating new file " + "context; rc = [%d]\n", rc); + goto out; } - rc = ecryptfs_write_metadata(ecryptfs_dentry, lower_file); + rc = ecryptfs_write_metadata(ecryptfs_dentry); if (rc) { - ecryptfs_printk(KERN_DEBUG, "Error writing headers\n"); - goto out_fput; + printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc); + goto out; } - rc = grow_file(ecryptfs_dentry, lower_file, inode, lower_inode); -out_fput: - if ((rc = ecryptfs_close_lower_file(lower_file))) - printk(KERN_ERR "Error closing lower_file\n"); + rc = grow_file(ecryptfs_dentry); + if (rc) + printk(KERN_ERR "Error growing file; rc = [%d]\n", rc); out: return rc; } @@ -252,6 +236,8 @@ ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry, { int rc; + /* ecryptfs_do_create() calls ecryptfs_interpose(), which opens + * the crypt_stat->lower_file (persistent file) */ rc = ecryptfs_do_create(directory_inode, ecryptfs_dentry, mode, nd); if (unlikely(rc)) { ecryptfs_printk(KERN_WARNING, "Failed to create file in" @@ -374,8 +360,8 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry, crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat; if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) ecryptfs_set_default_sizes(crypt_stat); - rc = ecryptfs_read_and_validate_header_region(page_virt, lower_dentry, - nd->mnt); + rc = ecryptfs_read_and_validate_header_region(page_virt, + dentry->d_inode); if (rc) { rc = ecryptfs_read_and_validate_xattr_region(page_virt, dentry); if (rc) { @@ -392,7 +378,8 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry, dentry->d_sb)->mount_crypt_stat; if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) { if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) - file_size = (crypt_stat->header_extent_size + file_size = ((crypt_stat->extent_size + * crypt_stat->num_header_extents_at_front) + i_size_read(lower_dentry->d_inode)); else file_size = i_size_read(lower_dentry->d_inode); @@ -722,8 +709,8 @@ upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat, { loff_t lower_size; - lower_size = ( crypt_stat->header_extent_size - * crypt_stat->num_header_extents_at_front ); + lower_size = (crypt_stat->extent_size + * crypt_stat->num_header_extents_at_front); if (upper_size != 0) { loff_t num_extents; @@ -752,8 +739,7 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) int rc = 0; struct inode *inode = dentry->d_inode; struct dentry *lower_dentry; - struct vfsmount *lower_mnt; - struct file fake_ecryptfs_file, *lower_file = NULL; + struct file fake_ecryptfs_file; struct ecryptfs_crypt_stat *crypt_stat; loff_t i_size = i_size_read(inode); loff_t lower_size_before_truncate; @@ -776,62 +762,52 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) goto out; } lower_dentry = ecryptfs_dentry_to_lower(dentry); - /* This dget & mntget is released through fput at out_fput: */ - lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); - if ((rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, lower_mnt, - O_RDWR))) { - ecryptfs_printk(KERN_ERR, - "Error opening dentry; rc = [%i]\n", rc); - goto out_free; - } - ecryptfs_set_file_lower(&fake_ecryptfs_file, lower_file); + ecryptfs_set_file_lower( + &fake_ecryptfs_file, + ecryptfs_inode_to_private(dentry->d_inode)->lower_file); /* Switch on growing or shrinking file */ if (new_length > i_size) { - rc = ecryptfs_fill_zeros(&fake_ecryptfs_file, new_length); - if (rc) { - ecryptfs_printk(KERN_ERR, - "Problem with fill_zeros\n"); - goto out_fput; - } - i_size_write(inode, new_length); - rc = ecryptfs_write_inode_size_to_metadata( - lower_file, lower_dentry->d_inode, inode, dentry, - ECRYPTFS_LOWER_I_MUTEX_NOT_HELD); - if (rc) { - printk(KERN_ERR "Problem with " - "ecryptfs_write_inode_size_to_metadata; " - "rc = [%d]\n", rc); - goto out_fput; - } + char zero[] = { 0x00 }; + + /* Write a single 0 at the last position of the file; + * this triggers code that will fill in 0's throughout + * the intermediate portion of the previous end of the + * file and the new and of the file */ + rc = ecryptfs_write(&fake_ecryptfs_file, zero, + (new_length - 1), 1); } else { /* new_length < i_size_read(inode) */ - pgoff_t index = 0; - int end_pos_in_page = -1; + /* We're chopping off all the pages down do the page + * in which new_length is located. Fill in the end of + * that page from (new_length & ~PAGE_CACHE_MASK) to + * PAGE_CACHE_SIZE with zeros. */ + size_t num_zeros = (PAGE_CACHE_SIZE + - (new_length & ~PAGE_CACHE_MASK)); - if (new_length != 0) { - index = ((new_length - 1) >> PAGE_CACHE_SHIFT); - end_pos_in_page = ((new_length - 1) & ~PAGE_CACHE_MASK); - } - if (end_pos_in_page != (PAGE_CACHE_SIZE - 1)) { - if ((rc = ecryptfs_write_zeros(&fake_ecryptfs_file, - index, - (end_pos_in_page + 1), - ((PAGE_CACHE_SIZE - 1) - - end_pos_in_page)))) { + if (num_zeros) { + char *zeros_virt; + + zeros_virt = kzalloc(num_zeros, GFP_KERNEL); + if (!zeros_virt) { + rc = -ENOMEM; + goto out_free; + } + rc = ecryptfs_write(&fake_ecryptfs_file, zeros_virt, + new_length, num_zeros); + kfree(zeros_virt); + if (rc) { printk(KERN_ERR "Error attempting to zero out " "the remainder of the end page on " "reducing truncate; rc = [%d]\n", rc); - goto out_fput; + goto out_free; } } vmtruncate(inode, new_length); - rc = ecryptfs_write_inode_size_to_metadata( - lower_file, lower_dentry->d_inode, inode, dentry, - ECRYPTFS_LOWER_I_MUTEX_NOT_HELD); + rc = ecryptfs_write_inode_size_to_metadata(inode); if (rc) { printk(KERN_ERR "Problem with " "ecryptfs_write_inode_size_to_metadata; " "rc = [%d]\n", rc); - goto out_fput; + goto out_free; } /* We are reducing the size of the ecryptfs file, and need to * know if we need to reduce the size of the lower file. */ @@ -843,13 +819,6 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) vmtruncate(lower_dentry->d_inode, lower_size_after_truncate); } - /* Update the access times */ - lower_dentry->d_inode->i_mtime = lower_dentry->d_inode->i_ctime - = CURRENT_TIME; - mark_inode_dirty_sync(inode); -out_fput: - if ((rc = ecryptfs_close_lower_file(lower_file))) - printk(KERN_ERR "Error closing lower_file\n"); out_free: if (ecryptfs_file_to_private(&fake_ecryptfs_file)) kmem_cache_free(ecryptfs_file_info_cache, @@ -909,23 +878,12 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) else if (S_ISREG(dentry->d_inode->i_mode) && (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED) || !(crypt_stat->flags & ECRYPTFS_KEY_VALID))) { - struct vfsmount *lower_mnt; - struct file *lower_file = NULL; struct ecryptfs_mount_crypt_stat *mount_crypt_stat; - int lower_flags; - - lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); - lower_flags = O_RDONLY; - if ((rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, - lower_mnt, lower_flags))) { - printk(KERN_ERR - "Error opening lower file; rc = [%d]\n", rc); - mutex_unlock(&crypt_stat->cs_mutex); - goto out; - } + mount_crypt_stat = &ecryptfs_superblock_to_private( dentry->d_sb)->mount_crypt_stat; - if ((rc = ecryptfs_read_metadata(dentry, lower_file))) { + rc = ecryptfs_read_metadata(dentry); + if (rc) { if (!(mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { rc = -EIO; @@ -935,16 +893,13 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) "enabled; returning -EIO\n"); mutex_unlock(&crypt_stat->cs_mutex); - fput(lower_file); goto out; } rc = 0; crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); mutex_unlock(&crypt_stat->cs_mutex); - fput(lower_file); goto out; } - fput(lower_file); } mutex_unlock(&crypt_stat->cs_mutex); if (ia->ia_valid & ATTR_SIZE) { @@ -959,6 +914,14 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) if (rc < 0) goto out; } + + /* + * mode change is for clearing setuid/setgid bits. Allow lower fs + * to interpret this in its own way. + */ + if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) + ia->ia_valid &= ~ATTR_MODE; + rc = notify_change(lower_dentry, ia); out: fsstack_copy_attr_all(inode, lower_inode, NULL); @@ -986,13 +949,11 @@ out: } ssize_t -ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value, - size_t size) +ecryptfs_getxattr_lower(struct dentry *lower_dentry, const char *name, + void *value, size_t size) { int rc = 0; - struct dentry *lower_dentry; - lower_dentry = ecryptfs_dentry_to_lower(dentry); if (!lower_dentry->d_inode->i_op->getxattr) { rc = -ENOSYS; goto out; @@ -1005,6 +966,14 @@ out: return rc; } +ssize_t +ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value, + size_t size) +{ + return ecryptfs_getxattr_lower(ecryptfs_dentry_to_lower(dentry), name, + value, size); +} + static ssize_t ecryptfs_listxattr(struct dentry *dentry, char *list, size_t size) { diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c index b550dea8eee6..89d9710dd63d 100644 --- a/fs/ecryptfs/keystore.c +++ b/fs/ecryptfs/keystore.c @@ -39,7 +39,7 @@ * determine the type of error, make appropriate log entries, and * return an error code. */ -int process_request_key_err(long err_code) +static int process_request_key_err(long err_code) { int rc = 0; @@ -71,7 +71,7 @@ int process_request_key_err(long err_code) * address; zero on error * @length_size: The number of bytes occupied by the encoded length * - * Returns Zero on success + * Returns zero on success; non-zero on error */ static int parse_packet_length(unsigned char *data, size_t *size, size_t *length_size) @@ -106,11 +106,11 @@ out: /** * write_packet_length - * @dest: The byte array target into which to write the - * length. Must have at least 5 bytes allocated. + * @dest: The byte array target into which to write the length. Must + * have at least 5 bytes allocated. * @size: The length to write. - * @packet_size_length: The number of bytes used to encode the - * packet length is written to this address. + * @packet_size_length: The number of bytes used to encode the packet + * length is written to this address. * * Returns zero on success; non-zero on error. */ @@ -396,26 +396,53 @@ out: return rc; } +static int +ecryptfs_get_auth_tok_sig(char **sig, struct ecryptfs_auth_tok *auth_tok) +{ + int rc = 0; + + (*sig) = NULL; + switch (auth_tok->token_type) { + case ECRYPTFS_PASSWORD: + (*sig) = auth_tok->token.password.signature; + break; + case ECRYPTFS_PRIVATE_KEY: + (*sig) = auth_tok->token.private_key.signature; + break; + default: + printk(KERN_ERR "Cannot get sig for auth_tok of type [%d]\n", + auth_tok->token_type); + rc = -EINVAL; + } + return rc; +} + /** - * decrypt_pki_encrypted_session_key - Decrypt the session key with - * the given auth_tok. + * decrypt_pki_encrypted_session_key - Decrypt the session key with the given auth_tok. + * @auth_tok: The key authentication token used to decrypt the session key + * @crypt_stat: The cryptographic context * - * Returns Zero on success; non-zero error otherwise. + * Returns zero on success; non-zero error otherwise. */ -static int decrypt_pki_encrypted_session_key( - struct ecryptfs_mount_crypt_stat *mount_crypt_stat, - struct ecryptfs_auth_tok *auth_tok, - struct ecryptfs_crypt_stat *crypt_stat) +static int +decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok, + struct ecryptfs_crypt_stat *crypt_stat) { u16 cipher_code = 0; struct ecryptfs_msg_ctx *msg_ctx; struct ecryptfs_message *msg = NULL; + char *auth_tok_sig; char *netlink_message; size_t netlink_message_length; int rc; - rc = write_tag_64_packet(mount_crypt_stat->global_auth_tok_sig, - &(auth_tok->session_key), + rc = ecryptfs_get_auth_tok_sig(&auth_tok_sig, auth_tok); + if (rc) { + printk(KERN_ERR "Unrecognized auth tok type: [%d]\n", + auth_tok->token_type); + goto out; + } + rc = write_tag_64_packet(auth_tok_sig, &(auth_tok->session_key), &netlink_message, &netlink_message_length); if (rc) { ecryptfs_printk(KERN_ERR, "Failed to write tag 64 packet"); @@ -465,40 +492,33 @@ out: static void wipe_auth_tok_list(struct list_head *auth_tok_list_head) { - struct list_head *walker; struct ecryptfs_auth_tok_list_item *auth_tok_list_item; + struct ecryptfs_auth_tok_list_item *auth_tok_list_item_tmp; - walker = auth_tok_list_head->next; - while (walker != auth_tok_list_head) { - auth_tok_list_item = - list_entry(walker, struct ecryptfs_auth_tok_list_item, - list); - walker = auth_tok_list_item->list.next; - memset(auth_tok_list_item, 0, - sizeof(struct ecryptfs_auth_tok_list_item)); + list_for_each_entry_safe(auth_tok_list_item, auth_tok_list_item_tmp, + auth_tok_list_head, list) { + list_del(&auth_tok_list_item->list); kmem_cache_free(ecryptfs_auth_tok_list_item_cache, auth_tok_list_item); } - auth_tok_list_head->next = NULL; } struct kmem_cache *ecryptfs_auth_tok_list_item_cache; - /** * parse_tag_1_packet - * @crypt_stat: The cryptographic context to modify based on packet - * contents. + * @crypt_stat: The cryptographic context to modify based on packet contents * @data: The raw bytes of the packet. * @auth_tok_list: eCryptfs parses packets into authentication tokens; - * a new authentication token will be placed at the end - * of this list for this packet. + * a new authentication token will be placed at the + * end of this list for this packet. * @new_auth_tok: Pointer to a pointer to memory that this function * allocates; sets the memory address of the pointer to * NULL on error. This object is added to the * auth_tok_list. * @packet_size: This function writes the size of the parsed packet * into this memory location; zero on error. + * @max_packet_size: The maximum allowable packet size * * Returns zero on success; non-zero on error. */ @@ -515,72 +535,65 @@ parse_tag_1_packet(struct ecryptfs_crypt_stat *crypt_stat, (*packet_size) = 0; (*new_auth_tok) = NULL; - - /* we check that: - * one byte for the Tag 1 ID flag - * two bytes for the body size - * do not exceed the maximum_packet_size + /** + * This format is inspired by OpenPGP; see RFC 2440 + * packet tag 1 + * + * Tag 1 identifier (1 byte) + * Max Tag 1 packet size (max 3 bytes) + * Version (1 byte) + * Key identifier (8 bytes; ECRYPTFS_SIG_SIZE) + * Cipher identifier (1 byte) + * Encrypted key size (arbitrary) + * + * 12 bytes minimum packet size */ - if (unlikely((*packet_size) + 3 > max_packet_size)) { - ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n"); + if (unlikely(max_packet_size < 12)) { + printk(KERN_ERR "Invalid max packet size; must be >=12\n"); rc = -EINVAL; goto out; } - /* check for Tag 1 identifier - one byte */ if (data[(*packet_size)++] != ECRYPTFS_TAG_1_PACKET_TYPE) { - ecryptfs_printk(KERN_ERR, "Enter w/ first byte != 0x%.2x\n", - ECRYPTFS_TAG_1_PACKET_TYPE); + printk(KERN_ERR "Enter w/ first byte != 0x%.2x\n", + ECRYPTFS_TAG_1_PACKET_TYPE); rc = -EINVAL; goto out; } /* Released: wipe_auth_tok_list called in ecryptfs_parse_packet_set or * at end of function upon failure */ auth_tok_list_item = - kmem_cache_alloc(ecryptfs_auth_tok_list_item_cache, - GFP_KERNEL); + kmem_cache_zalloc(ecryptfs_auth_tok_list_item_cache, + GFP_KERNEL); if (!auth_tok_list_item) { - ecryptfs_printk(KERN_ERR, "Unable to allocate memory\n"); + printk(KERN_ERR "Unable to allocate memory\n"); rc = -ENOMEM; goto out; } - memset(auth_tok_list_item, 0, - sizeof(struct ecryptfs_auth_tok_list_item)); (*new_auth_tok) = &auth_tok_list_item->auth_tok; - /* check for body size - one to two bytes - * - * ***** TAG 1 Packet Format ***** - * | version number | 1 byte | - * | key ID | 8 bytes | - * | public key algorithm | 1 byte | - * | encrypted session key | arbitrary | - */ rc = parse_packet_length(&data[(*packet_size)], &body_size, &length_size); if (rc) { - ecryptfs_printk(KERN_WARNING, "Error parsing packet length; " - "rc = [%d]\n", rc); + printk(KERN_WARNING "Error parsing packet length; " + "rc = [%d]\n", rc); goto out_free; } - if (unlikely(body_size < (0x02 + ECRYPTFS_SIG_SIZE))) { - ecryptfs_printk(KERN_WARNING, "Invalid body size ([%d])\n", - body_size); + if (unlikely(body_size < (ECRYPTFS_SIG_SIZE + 2))) { + printk(KERN_WARNING "Invalid body size ([%td])\n", body_size); rc = -EINVAL; goto out_free; } (*packet_size) += length_size; if (unlikely((*packet_size) + body_size > max_packet_size)) { - ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n"); + printk(KERN_WARNING "Packet size exceeds max\n"); rc = -EINVAL; goto out_free; } - /* Version 3 (from RFC2440) - one byte */ if (unlikely(data[(*packet_size)++] != 0x03)) { - ecryptfs_printk(KERN_DEBUG, "Unknown version number " - "[%d]\n", data[(*packet_size) - 1]); + printk(KERN_WARNING "Unknown version number [%d]\n", + data[(*packet_size) - 1]); rc = -EINVAL; goto out_free; } - /* Read Signature */ ecryptfs_to_hex((*new_auth_tok)->token.private_key.signature, &data[(*packet_size)], ECRYPTFS_SIG_SIZE); *packet_size += ECRYPTFS_SIG_SIZE; @@ -588,27 +601,23 @@ parse_tag_1_packet(struct ecryptfs_crypt_stat *crypt_stat, * know which public key encryption algorithm was used */ (*packet_size)++; (*new_auth_tok)->session_key.encrypted_key_size = - body_size - (0x02 + ECRYPTFS_SIG_SIZE); + body_size - (ECRYPTFS_SIG_SIZE + 2); if ((*new_auth_tok)->session_key.encrypted_key_size > ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) { - ecryptfs_printk(KERN_ERR, "Tag 1 packet contains key larger " - "than ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES"); + printk(KERN_WARNING "Tag 1 packet contains key larger " + "than ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES"); rc = -EINVAL; goto out; } - ecryptfs_printk(KERN_DEBUG, "Encrypted key size = [%d]\n", - (*new_auth_tok)->session_key.encrypted_key_size); memcpy((*new_auth_tok)->session_key.encrypted_key, - &data[(*packet_size)], (body_size - 0x02 - ECRYPTFS_SIG_SIZE)); + &data[(*packet_size)], (body_size - (ECRYPTFS_SIG_SIZE + 2))); (*packet_size) += (*new_auth_tok)->session_key.encrypted_key_size; (*new_auth_tok)->session_key.flags &= ~ECRYPTFS_CONTAINS_DECRYPTED_KEY; (*new_auth_tok)->session_key.flags |= ECRYPTFS_CONTAINS_ENCRYPTED_KEY; (*new_auth_tok)->token_type = ECRYPTFS_PRIVATE_KEY; - (*new_auth_tok)->flags |= ECRYPTFS_PRIVATE_KEY; - /* TODO: Why are we setting this flag here? Don't we want the - * userspace to decrypt the session key? */ + (*new_auth_tok)->flags = 0; (*new_auth_tok)->session_key.flags &= ~(ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT); (*new_auth_tok)->session_key.flags &= @@ -658,22 +667,30 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat, (*packet_size) = 0; (*new_auth_tok) = NULL; - - /* we check that: - * one byte for the Tag 3 ID flag - * two bytes for the body size - * do not exceed the maximum_packet_size + /** + *This format is inspired by OpenPGP; see RFC 2440 + * packet tag 3 + * + * Tag 3 identifier (1 byte) + * Max Tag 3 packet size (max 3 bytes) + * Version (1 byte) + * Cipher code (1 byte) + * S2K specifier (1 byte) + * Hash identifier (1 byte) + * Salt (ECRYPTFS_SALT_SIZE) + * Hash iterations (1 byte) + * Encrypted key (arbitrary) + * + * (ECRYPTFS_SALT_SIZE + 7) minimum packet size */ - if (unlikely((*packet_size) + 3 > max_packet_size)) { - ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n"); + if (max_packet_size < (ECRYPTFS_SALT_SIZE + 7)) { + printk(KERN_ERR "Max packet size too large\n"); rc = -EINVAL; goto out; } - - /* check for Tag 3 identifyer - one byte */ if (data[(*packet_size)++] != ECRYPTFS_TAG_3_PACKET_TYPE) { - ecryptfs_printk(KERN_ERR, "Enter w/ first byte != 0x%.2x\n", - ECRYPTFS_TAG_3_PACKET_TYPE); + printk(KERN_ERR "First byte != 0x%.2x; invalid packet\n", + ECRYPTFS_TAG_3_PACKET_TYPE); rc = -EINVAL; goto out; } @@ -682,56 +699,37 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat, auth_tok_list_item = kmem_cache_zalloc(ecryptfs_auth_tok_list_item_cache, GFP_KERNEL); if (!auth_tok_list_item) { - ecryptfs_printk(KERN_ERR, "Unable to allocate memory\n"); + printk(KERN_ERR "Unable to allocate memory\n"); rc = -ENOMEM; goto out; } (*new_auth_tok) = &auth_tok_list_item->auth_tok; - - /* check for body size - one to two bytes */ rc = parse_packet_length(&data[(*packet_size)], &body_size, &length_size); if (rc) { - ecryptfs_printk(KERN_WARNING, "Error parsing packet length; " - "rc = [%d]\n", rc); + printk(KERN_WARNING "Error parsing packet length; rc = [%d]\n", + rc); goto out_free; } - if (unlikely(body_size < (0x05 + ECRYPTFS_SALT_SIZE))) { - ecryptfs_printk(KERN_WARNING, "Invalid body size ([%d])\n", - body_size); + if (unlikely(body_size < (ECRYPTFS_SALT_SIZE + 5))) { + printk(KERN_WARNING "Invalid body size ([%td])\n", body_size); rc = -EINVAL; goto out_free; } (*packet_size) += length_size; - - /* now we know the length of the remainting Tag 3 packet size: - * 5 fix bytes for: version string, cipher, S2K ID, hash algo, - * number of hash iterations - * ECRYPTFS_SALT_SIZE bytes for salt - * body_size bytes minus the stuff above is the encrypted key size - */ if (unlikely((*packet_size) + body_size > max_packet_size)) { - ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n"); + printk(KERN_ERR "Packet size exceeds max\n"); rc = -EINVAL; goto out_free; } - - /* There are 5 characters of additional information in the - * packet */ (*new_auth_tok)->session_key.encrypted_key_size = - body_size - (0x05 + ECRYPTFS_SALT_SIZE); - ecryptfs_printk(KERN_DEBUG, "Encrypted key size = [%d]\n", - (*new_auth_tok)->session_key.encrypted_key_size); - - /* Version 4 (from RFC2440) - one byte */ + (body_size - (ECRYPTFS_SALT_SIZE + 5)); if (unlikely(data[(*packet_size)++] != 0x04)) { - ecryptfs_printk(KERN_DEBUG, "Unknown version number " - "[%d]\n", data[(*packet_size) - 1]); + printk(KERN_WARNING "Unknown version number [%d]\n", + data[(*packet_size) - 1]); rc = -EINVAL; goto out_free; } - - /* cipher - one byte */ ecryptfs_cipher_code_to_string(crypt_stat->cipher, (u16)data[(*packet_size)]); /* A little extra work to differentiate among the AES key @@ -745,33 +743,26 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat, (*new_auth_tok)->session_key.encrypted_key_size; } ecryptfs_init_crypt_ctx(crypt_stat); - /* S2K identifier 3 (from RFC2440) */ if (unlikely(data[(*packet_size)++] != 0x03)) { - ecryptfs_printk(KERN_ERR, "Only S2K ID 3 is currently " - "supported\n"); + printk(KERN_WARNING "Only S2K ID 3 is currently supported\n"); rc = -ENOSYS; goto out_free; } - /* TODO: finish the hash mapping */ - /* hash algorithm - one byte */ switch (data[(*packet_size)++]) { case 0x01: /* See RFC2440 for these numbers and their mappings */ /* Choose MD5 */ - /* salt - ECRYPTFS_SALT_SIZE bytes */ memcpy((*new_auth_tok)->token.password.salt, &data[(*packet_size)], ECRYPTFS_SALT_SIZE); (*packet_size) += ECRYPTFS_SALT_SIZE; - /* This conversion was taken straight from RFC2440 */ - /* number of hash iterations - one byte */ (*new_auth_tok)->token.password.hash_iterations = ((u32) 16 + (data[(*packet_size)] & 15)) << ((data[(*packet_size)] >> 4) + 6); (*packet_size)++; - - /* encrypted session key - - * (body_size-5-ECRYPTFS_SALT_SIZE) bytes */ + /* Friendly reminder: + * (*new_auth_tok)->session_key.encrypted_key_size = + * (body_size - (ECRYPTFS_SALT_SIZE + 5)); */ memcpy((*new_auth_tok)->session_key.encrypted_key, &data[(*packet_size)], (*new_auth_tok)->session_key.encrypted_key_size); @@ -781,7 +772,7 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat, ~ECRYPTFS_CONTAINS_DECRYPTED_KEY; (*new_auth_tok)->session_key.flags |= ECRYPTFS_CONTAINS_ENCRYPTED_KEY; - (*new_auth_tok)->token.password.hash_algo = 0x01; + (*new_auth_tok)->token.password.hash_algo = 0x01; /* MD5 */ break; default: ecryptfs_printk(KERN_ERR, "Unsupported hash algorithm: " @@ -837,82 +828,61 @@ parse_tag_11_packet(unsigned char *data, unsigned char *contents, (*packet_size) = 0; (*tag_11_contents_size) = 0; - - /* check that: - * one byte for the Tag 11 ID flag - * two bytes for the Tag 11 length - * do not exceed the maximum_packet_size + /* This format is inspired by OpenPGP; see RFC 2440 + * packet tag 11 + * + * Tag 11 identifier (1 byte) + * Max Tag 11 packet size (max 3 bytes) + * Binary format specifier (1 byte) + * Filename length (1 byte) + * Filename ("_CONSOLE") (8 bytes) + * Modification date (4 bytes) + * Literal data (arbitrary) + * + * We need at least 16 bytes of data for the packet to even be + * valid. */ - if (unlikely((*packet_size) + 3 > max_packet_size)) { - ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n"); + if (max_packet_size < 16) { + printk(KERN_ERR "Maximum packet size too small\n"); rc = -EINVAL; goto out; } - - /* check for Tag 11 identifyer - one byte */ if (data[(*packet_size)++] != ECRYPTFS_TAG_11_PACKET_TYPE) { - ecryptfs_printk(KERN_WARNING, - "Invalid tag 11 packet format\n"); + printk(KERN_WARNING "Invalid tag 11 packet format\n"); rc = -EINVAL; goto out; } - - /* get Tag 11 content length - one or two bytes */ rc = parse_packet_length(&data[(*packet_size)], &body_size, &length_size); if (rc) { - ecryptfs_printk(KERN_WARNING, - "Invalid tag 11 packet format\n"); + printk(KERN_WARNING "Invalid tag 11 packet format\n"); goto out; } - (*packet_size) += length_size; - - if (body_size < 13) { - ecryptfs_printk(KERN_WARNING, "Invalid body size ([%d])\n", - body_size); + if (body_size < 14) { + printk(KERN_WARNING "Invalid body size ([%td])\n", body_size); rc = -EINVAL; goto out; } - /* We have 13 bytes of surrounding packet values */ - (*tag_11_contents_size) = (body_size - 13); - - /* now we know the length of the remainting Tag 11 packet size: - * 14 fix bytes for: special flag one, special flag two, - * 12 skipped bytes - * body_size bytes minus the stuff above is the Tag 11 content - */ - /* FIXME why is the body size one byte smaller than the actual - * size of the body? - * this seems to be an error here as well as in - * write_tag_11_packet() */ + (*packet_size) += length_size; + (*tag_11_contents_size) = (body_size - 14); if (unlikely((*packet_size) + body_size + 1 > max_packet_size)) { - ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n"); + printk(KERN_ERR "Packet size exceeds max\n"); rc = -EINVAL; goto out; } - - /* special flag one - one byte */ if (data[(*packet_size)++] != 0x62) { - ecryptfs_printk(KERN_WARNING, "Unrecognizable packet\n"); + printk(KERN_WARNING "Unrecognizable packet\n"); rc = -EINVAL; goto out; } - - /* special flag two - one byte */ if (data[(*packet_size)++] != 0x08) { - ecryptfs_printk(KERN_WARNING, "Unrecognizable packet\n"); + printk(KERN_WARNING "Unrecognizable packet\n"); rc = -EINVAL; goto out; } - - /* skip the next 12 bytes */ - (*packet_size) += 12; /* We don't care about the filename or - * the timestamp */ - - /* get the Tag 11 contents - tag_11_contents_size bytes */ + (*packet_size) += 12; /* Ignore filename and modification date */ memcpy(contents, &data[(*packet_size)], (*tag_11_contents_size)); (*packet_size) += (*tag_11_contents_size); - out: if (rc) { (*packet_size) = 0; @@ -921,130 +891,229 @@ out: return rc; } +static int +ecryptfs_find_global_auth_tok_for_sig( + struct ecryptfs_global_auth_tok **global_auth_tok, + struct ecryptfs_mount_crypt_stat *mount_crypt_stat, char *sig) +{ + struct ecryptfs_global_auth_tok *walker; + int rc = 0; + + (*global_auth_tok) = NULL; + mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex); + list_for_each_entry(walker, + &mount_crypt_stat->global_auth_tok_list, + mount_crypt_stat_list) { + if (memcmp(walker->sig, sig, ECRYPTFS_SIG_SIZE_HEX) == 0) { + (*global_auth_tok) = walker; + goto out; + } + } + rc = -EINVAL; +out: + mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex); + return rc; +} + /** - * decrypt_session_key - Decrypt the session key with the given auth_tok. + * ecryptfs_verify_version + * @version: The version number to confirm * - * Returns Zero on success; non-zero error otherwise. + * Returns zero on good version; non-zero otherwise */ -static int decrypt_session_key(struct ecryptfs_auth_tok *auth_tok, - struct ecryptfs_crypt_stat *crypt_stat) +static int ecryptfs_verify_version(u16 version) { - struct ecryptfs_password *password_s_ptr; - struct scatterlist src_sg[2], dst_sg[2]; - struct mutex *tfm_mutex = NULL; - char *encrypted_session_key; - char *session_key; + int rc = 0; + unsigned char major; + unsigned char minor; + + major = ((version >> 8) & 0xFF); + minor = (version & 0xFF); + if (major != ECRYPTFS_VERSION_MAJOR) { + ecryptfs_printk(KERN_ERR, "Major version number mismatch. " + "Expected [%d]; got [%d]\n", + ECRYPTFS_VERSION_MAJOR, major); + rc = -EINVAL; + goto out; + } + if (minor != ECRYPTFS_VERSION_MINOR) { + ecryptfs_printk(KERN_ERR, "Minor version number mismatch. " + "Expected [%d]; got [%d]\n", + ECRYPTFS_VERSION_MINOR, minor); + rc = -EINVAL; + goto out; + } +out: + return rc; +} + +int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key, + struct ecryptfs_auth_tok **auth_tok, + char *sig) +{ + int rc = 0; + + (*auth_tok_key) = request_key(&key_type_user, sig, NULL); + if (!(*auth_tok_key) || IS_ERR(*auth_tok_key)) { + printk(KERN_ERR "Could not find key with description: [%s]\n", + sig); + process_request_key_err(PTR_ERR(*auth_tok_key)); + rc = -EINVAL; + goto out; + } + (*auth_tok) = ecryptfs_get_key_payload_data(*auth_tok_key); + if (ecryptfs_verify_version((*auth_tok)->version)) { + printk(KERN_ERR + "Data structure version mismatch. " + "Userspace tools must match eCryptfs " + "kernel module with major version [%d] " + "and minor version [%d]\n", + ECRYPTFS_VERSION_MAJOR, + ECRYPTFS_VERSION_MINOR); + rc = -EINVAL; + goto out; + } + if ((*auth_tok)->token_type != ECRYPTFS_PASSWORD + && (*auth_tok)->token_type != ECRYPTFS_PRIVATE_KEY) { + printk(KERN_ERR "Invalid auth_tok structure " + "returned from key query\n"); + rc = -EINVAL; + goto out; + } +out: + return rc; +} + +/** + * ecryptfs_find_auth_tok_for_sig + * @auth_tok: Set to the matching auth_tok; NULL if not found + * @crypt_stat: inode crypt_stat crypto context + * @sig: Sig of auth_tok to find + * + * For now, this function simply looks at the registered auth_tok's + * linked off the mount_crypt_stat, so all the auth_toks that can be + * used must be registered at mount time. This function could + * potentially try a lot harder to find auth_tok's (e.g., by calling + * out to ecryptfsd to dynamically retrieve an auth_tok object) so + * that static registration of auth_tok's will no longer be necessary. + * + * Returns zero on no error; non-zero on error + */ +static int +ecryptfs_find_auth_tok_for_sig( + struct ecryptfs_auth_tok **auth_tok, + struct ecryptfs_crypt_stat *crypt_stat, char *sig) +{ + struct ecryptfs_mount_crypt_stat *mount_crypt_stat = + crypt_stat->mount_crypt_stat; + struct ecryptfs_global_auth_tok *global_auth_tok; + int rc = 0; + + (*auth_tok) = NULL; + if (ecryptfs_find_global_auth_tok_for_sig(&global_auth_tok, + mount_crypt_stat, sig)) { + struct key *auth_tok_key; + + rc = ecryptfs_keyring_auth_tok_for_sig(&auth_tok_key, auth_tok, + sig); + } else + (*auth_tok) = global_auth_tok->global_auth_tok; + return rc; +} + +/** + * decrypt_passphrase_encrypted_session_key - Decrypt the session key with the given auth_tok. + * @auth_tok: The passphrase authentication token to use to encrypt the FEK + * @crypt_stat: The cryptographic context + * + * Returns zero on success; non-zero error otherwise + */ +static int +decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok, + struct ecryptfs_crypt_stat *crypt_stat) +{ + struct scatterlist dst_sg; + struct scatterlist src_sg; + struct mutex *tfm_mutex; struct blkcipher_desc desc = { .flags = CRYPTO_TFM_REQ_MAY_SLEEP }; int rc = 0; - password_s_ptr = &auth_tok->token.password; - if (password_s_ptr->flags & ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET) - ecryptfs_printk(KERN_DEBUG, "Session key encryption key " - "set; skipping key generation\n"); - ecryptfs_printk(KERN_DEBUG, "Session key encryption key (size [%d])" - ":\n", - password_s_ptr->session_key_encryption_key_bytes); - if (ecryptfs_verbosity > 0) - ecryptfs_dump_hex(password_s_ptr->session_key_encryption_key, - password_s_ptr-> - session_key_encryption_key_bytes); - if (!strcmp(crypt_stat->cipher, - crypt_stat->mount_crypt_stat->global_default_cipher_name) - && crypt_stat->mount_crypt_stat->global_key_tfm) { - desc.tfm = crypt_stat->mount_crypt_stat->global_key_tfm; - tfm_mutex = &crypt_stat->mount_crypt_stat->global_key_tfm_mutex; - } else { - char *full_alg_name; - - rc = ecryptfs_crypto_api_algify_cipher_name(&full_alg_name, - crypt_stat->cipher, - "ecb"); - if (rc) - goto out; - desc.tfm = crypto_alloc_blkcipher(full_alg_name, 0, - CRYPTO_ALG_ASYNC); - kfree(full_alg_name); - if (IS_ERR(desc.tfm)) { - rc = PTR_ERR(desc.tfm); - printk(KERN_ERR "Error allocating crypto context; " - "rc = [%d]\n", rc); - goto out; - } - crypto_blkcipher_set_flags(desc.tfm, CRYPTO_TFM_REQ_WEAK_KEY); + if (unlikely(ecryptfs_verbosity > 0)) { + ecryptfs_printk( + KERN_DEBUG, "Session key encryption key (size [%d]):\n", + auth_tok->token.password.session_key_encryption_key_bytes); + ecryptfs_dump_hex( + auth_tok->token.password.session_key_encryption_key, + auth_tok->token.password.session_key_encryption_key_bytes); + } + rc = ecryptfs_get_tfm_and_mutex_for_cipher_name(&desc.tfm, &tfm_mutex, + crypt_stat->cipher); + if (unlikely(rc)) { + printk(KERN_ERR "Internal error whilst attempting to get " + "tfm and mutex for cipher name [%s]; rc = [%d]\n", + crypt_stat->cipher, rc); + goto out; } - if (tfm_mutex) - mutex_lock(tfm_mutex); - rc = crypto_blkcipher_setkey(desc.tfm, - password_s_ptr->session_key_encryption_key, - crypt_stat->key_size); - if (rc < 0) { + rc = virt_to_scatterlist(auth_tok->session_key.encrypted_key, + auth_tok->session_key.encrypted_key_size, + &src_sg, 1); + if (rc != 1) { + printk(KERN_ERR "Internal error whilst attempting to convert " + "auth_tok->session_key.encrypted_key to scatterlist; " + "expected rc = 1; got rc = [%d]. " + "auth_tok->session_key.encrypted_key_size = [%d]\n", rc, + auth_tok->session_key.encrypted_key_size); + goto out; + } + auth_tok->session_key.decrypted_key_size = + auth_tok->session_key.encrypted_key_size; + rc = virt_to_scatterlist(auth_tok->session_key.decrypted_key, + auth_tok->session_key.decrypted_key_size, + &dst_sg, 1); + if (rc != 1) { + printk(KERN_ERR "Internal error whilst attempting to convert " + "auth_tok->session_key.decrypted_key to scatterlist; " + "expected rc = 1; got rc = [%d]\n", rc); + goto out; + } + mutex_lock(tfm_mutex); + rc = crypto_blkcipher_setkey( + desc.tfm, auth_tok->token.password.session_key_encryption_key, + crypt_stat->key_size); + if (unlikely(rc < 0)) { + mutex_unlock(tfm_mutex); printk(KERN_ERR "Error setting key for crypto context\n"); rc = -EINVAL; - goto out_free_tfm; - } - /* TODO: virt_to_scatterlist */ - encrypted_session_key = (char *)__get_free_page(GFP_KERNEL); - if (!encrypted_session_key) { - ecryptfs_printk(KERN_ERR, "Out of memory\n"); - rc = -ENOMEM; - goto out_free_tfm; + goto out; } - session_key = (char *)__get_free_page(GFP_KERNEL); - if (!session_key) { - kfree(encrypted_session_key); - ecryptfs_printk(KERN_ERR, "Out of memory\n"); - rc = -ENOMEM; - goto out_free_tfm; - } - memcpy(encrypted_session_key, auth_tok->session_key.encrypted_key, - auth_tok->session_key.encrypted_key_size); - src_sg[0].page = virt_to_page(encrypted_session_key); - src_sg[0].offset = 0; - BUG_ON(auth_tok->session_key.encrypted_key_size > PAGE_CACHE_SIZE); - src_sg[0].length = auth_tok->session_key.encrypted_key_size; - dst_sg[0].page = virt_to_page(session_key); - dst_sg[0].offset = 0; - auth_tok->session_key.decrypted_key_size = - auth_tok->session_key.encrypted_key_size; - dst_sg[0].length = auth_tok->session_key.encrypted_key_size; - rc = crypto_blkcipher_decrypt(&desc, dst_sg, src_sg, + rc = crypto_blkcipher_decrypt(&desc, &dst_sg, &src_sg, auth_tok->session_key.encrypted_key_size); - if (rc) { + mutex_unlock(tfm_mutex); + if (unlikely(rc)) { printk(KERN_ERR "Error decrypting; rc = [%d]\n", rc); - goto out_free_memory; + goto out; } - auth_tok->session_key.decrypted_key_size = - auth_tok->session_key.encrypted_key_size; - memcpy(auth_tok->session_key.decrypted_key, session_key, - auth_tok->session_key.decrypted_key_size); auth_tok->session_key.flags |= ECRYPTFS_CONTAINS_DECRYPTED_KEY; memcpy(crypt_stat->key, auth_tok->session_key.decrypted_key, auth_tok->session_key.decrypted_key_size); crypt_stat->flags |= ECRYPTFS_KEY_VALID; - ecryptfs_printk(KERN_DEBUG, "Decrypted session key:\n"); - if (ecryptfs_verbosity > 0) + if (unlikely(ecryptfs_verbosity > 0)) { + ecryptfs_printk(KERN_DEBUG, "FEK of size [%d]:\n", + crypt_stat->key_size); ecryptfs_dump_hex(crypt_stat->key, crypt_stat->key_size); -out_free_memory: - memset(encrypted_session_key, 0, PAGE_CACHE_SIZE); - free_page((unsigned long)encrypted_session_key); - memset(session_key, 0, PAGE_CACHE_SIZE); - free_page((unsigned long)session_key); -out_free_tfm: - if (tfm_mutex) - mutex_unlock(tfm_mutex); - else - crypto_free_blkcipher(desc.tfm); + } out: return rc; } /** * ecryptfs_parse_packet_set - * @dest: The header page in memory - * @version: Version of file format, to guide parsing behavior + * @crypt_stat: The cryptographic context + * @src: Virtual address of region of memory containing the packets + * @ecryptfs_dentry: The eCryptfs dentry associated with the packet set * * Get crypt_stat to have the file's session key if the requisite key * is available to decrypt the session key. @@ -1058,25 +1127,22 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, struct dentry *ecryptfs_dentry) { size_t i = 0; - size_t found_auth_tok = 0; + size_t found_auth_tok; size_t next_packet_is_auth_tok_packet; - char sig[ECRYPTFS_SIG_SIZE_HEX]; struct list_head auth_tok_list; - struct list_head *walker; - struct ecryptfs_auth_tok *chosen_auth_tok = NULL; - struct ecryptfs_mount_crypt_stat *mount_crypt_stat = - &ecryptfs_superblock_to_private( - ecryptfs_dentry->d_sb)->mount_crypt_stat; - struct ecryptfs_auth_tok *candidate_auth_tok = NULL; + struct ecryptfs_auth_tok *matching_auth_tok; + struct ecryptfs_auth_tok *candidate_auth_tok; + char *candidate_auth_tok_sig; size_t packet_size; struct ecryptfs_auth_tok *new_auth_tok; unsigned char sig_tmp_space[ECRYPTFS_SIG_SIZE]; + struct ecryptfs_auth_tok_list_item *auth_tok_list_item; size_t tag_11_contents_size; size_t tag_11_packet_size; int rc = 0; INIT_LIST_HEAD(&auth_tok_list); - /* Parse the header to find as many packets as we can, these will be + /* Parse the header to find as many packets as we can; these will be * added the our &auth_tok_list */ next_packet_is_auth_tok_packet = 1; while (next_packet_is_auth_tok_packet) { @@ -1155,73 +1221,85 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, } } if (list_empty(&auth_tok_list)) { - rc = -EINVAL; /* Do not support non-encrypted files in - * the 0.1 release */ + printk(KERN_ERR "The lower file appears to be a non-encrypted " + "eCryptfs file; this is not supported in this version " + "of the eCryptfs kernel module\n"); + rc = -EINVAL; goto out; } - /* If we have a global auth tok, then we should try to use - * it */ - if (mount_crypt_stat->global_auth_tok) { - memcpy(sig, mount_crypt_stat->global_auth_tok_sig, - ECRYPTFS_SIG_SIZE_HEX); - chosen_auth_tok = mount_crypt_stat->global_auth_tok; - } else - BUG(); /* We should always have a global auth tok in - * the 0.1 release */ - /* Scan list to see if our chosen_auth_tok works */ - list_for_each(walker, &auth_tok_list) { - struct ecryptfs_auth_tok_list_item *auth_tok_list_item; - auth_tok_list_item = - list_entry(walker, struct ecryptfs_auth_tok_list_item, - list); + /* auth_tok_list contains the set of authentication tokens + * parsed from the metadata. We need to find a matching + * authentication token that has the secret component(s) + * necessary to decrypt the EFEK in the auth_tok parsed from + * the metadata. There may be several potential matches, but + * just one will be sufficient to decrypt to get the FEK. */ +find_next_matching_auth_tok: + found_auth_tok = 0; + list_for_each_entry(auth_tok_list_item, &auth_tok_list, list) { candidate_auth_tok = &auth_tok_list_item->auth_tok; if (unlikely(ecryptfs_verbosity > 0)) { ecryptfs_printk(KERN_DEBUG, "Considering cadidate auth tok:\n"); ecryptfs_dump_auth_tok(candidate_auth_tok); } - /* TODO: Replace ECRYPTFS_SIG_SIZE_HEX w/ dynamic value */ - if (candidate_auth_tok->token_type == ECRYPTFS_PASSWORD - && !strncmp(candidate_auth_tok->token.password.signature, - sig, ECRYPTFS_SIG_SIZE_HEX)) { - found_auth_tok = 1; - goto leave_list; - /* TODO: Transfer the common salt into the - * crypt_stat salt */ - } else if ((candidate_auth_tok->token_type - == ECRYPTFS_PRIVATE_KEY) - && !strncmp(candidate_auth_tok->token.private_key.signature, - sig, ECRYPTFS_SIG_SIZE_HEX)) { + rc = ecryptfs_get_auth_tok_sig(&candidate_auth_tok_sig, + candidate_auth_tok); + if (rc) { + printk(KERN_ERR + "Unrecognized candidate auth tok type: [%d]\n", + candidate_auth_tok->token_type); + rc = -EINVAL; + goto out_wipe_list; + } + ecryptfs_find_auth_tok_for_sig(&matching_auth_tok, crypt_stat, + candidate_auth_tok_sig); + if (matching_auth_tok) { found_auth_tok = 1; - goto leave_list; + goto found_matching_auth_tok; } } if (!found_auth_tok) { - ecryptfs_printk(KERN_ERR, "Could not find authentication " - "token on temporary list for sig [%.*s]\n", - ECRYPTFS_SIG_SIZE_HEX, sig); + ecryptfs_printk(KERN_ERR, "Could not find a usable " + "authentication token\n"); rc = -EIO; goto out_wipe_list; } -leave_list: - rc = -ENOTSUPP; +found_matching_auth_tok: if (candidate_auth_tok->token_type == ECRYPTFS_PRIVATE_KEY) { memcpy(&(candidate_auth_tok->token.private_key), - &(chosen_auth_tok->token.private_key), + &(matching_auth_tok->token.private_key), sizeof(struct ecryptfs_private_key)); - rc = decrypt_pki_encrypted_session_key(mount_crypt_stat, - candidate_auth_tok, + rc = decrypt_pki_encrypted_session_key(candidate_auth_tok, crypt_stat); } else if (candidate_auth_tok->token_type == ECRYPTFS_PASSWORD) { memcpy(&(candidate_auth_tok->token.password), - &(chosen_auth_tok->token.password), + &(matching_auth_tok->token.password), sizeof(struct ecryptfs_password)); - rc = decrypt_session_key(candidate_auth_tok, crypt_stat); + rc = decrypt_passphrase_encrypted_session_key( + candidate_auth_tok, crypt_stat); } if (rc) { - ecryptfs_printk(KERN_ERR, "Error decrypting the " - "session key; rc = [%d]\n", rc); - goto out_wipe_list; + struct ecryptfs_auth_tok_list_item *auth_tok_list_item_tmp; + + ecryptfs_printk(KERN_WARNING, "Error decrypting the " + "session key for authentication token with sig " + "[%.*s]; rc = [%d]. Removing auth tok " + "candidate from the list and searching for " + "the next match.\n", candidate_auth_tok_sig, + ECRYPTFS_SIG_SIZE_HEX, rc); + list_for_each_entry_safe(auth_tok_list_item, + auth_tok_list_item_tmp, + &auth_tok_list, list) { + if (candidate_auth_tok + == &auth_tok_list_item->auth_tok) { + list_del(&auth_tok_list_item->list); + kmem_cache_free( + ecryptfs_auth_tok_list_item_cache, + auth_tok_list_item); + goto find_next_matching_auth_tok; + } + } + BUG(); } rc = ecryptfs_compute_root_iv(crypt_stat); if (rc) { @@ -1240,6 +1318,7 @@ out_wipe_list: out: return rc; } + static int pki_encrypt_session_key(struct ecryptfs_auth_tok *auth_tok, struct ecryptfs_crypt_stat *crypt_stat, @@ -1284,22 +1363,25 @@ out: /** * write_tag_1_packet - Write an RFC2440-compatible tag 1 (public key) packet * @dest: Buffer into which to write the packet - * @max: Maximum number of bytes that can be writtn + * @remaining_bytes: Maximum number of bytes that can be writtn + * @auth_tok: The authentication token used for generating the tag 1 packet + * @crypt_stat: The cryptographic context + * @key_rec: The key record struct for the tag 1 packet * @packet_size: This function will write the number of bytes that end * up constituting the packet; set to zero on error * * Returns zero on success; non-zero on error. */ static int -write_tag_1_packet(char *dest, size_t max, struct ecryptfs_auth_tok *auth_tok, +write_tag_1_packet(char *dest, size_t *remaining_bytes, + struct ecryptfs_auth_tok *auth_tok, struct ecryptfs_crypt_stat *crypt_stat, - struct ecryptfs_mount_crypt_stat *mount_crypt_stat, struct ecryptfs_key_record *key_rec, size_t *packet_size) { size_t i; size_t encrypted_session_key_valid = 0; - size_t key_rec_size; size_t packet_size_length; + size_t max_packet_size; int rc = 0; (*packet_size) = 0; @@ -1329,37 +1411,23 @@ write_tag_1_packet(char *dest, size_t max, struct ecryptfs_auth_tok *auth_tok, ecryptfs_dump_hex(key_rec->enc_key, key_rec->enc_key_size); } encrypted_session_key_set: - /* Now we have a valid key_rec. Append it to the - * key_rec set. */ - key_rec_size = (sizeof(struct ecryptfs_key_record) - - ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES - + (key_rec->enc_key_size)); - /* TODO: Include a packet size limit as a parameter to this - * function once we have multi-packet headers (for versions - * later than 0.1 */ - if (key_rec_size >= ECRYPTFS_MAX_KEYSET_SIZE) { - ecryptfs_printk(KERN_ERR, "Keyset too large\n"); - rc = -EINVAL; - goto out; - } - /* ***** TAG 1 Packet Format ***** - * | version number | 1 byte | - * | key ID | 8 bytes | - * | public key algorithm | 1 byte | - * | encrypted session key | arbitrary | - */ - if ((0x02 + ECRYPTFS_SIG_SIZE + key_rec->enc_key_size) >= max) { - ecryptfs_printk(KERN_ERR, - "Authentication token is too large\n"); + /* This format is inspired by OpenPGP; see RFC 2440 + * packet tag 1 */ + max_packet_size = (1 /* Tag 1 identifier */ + + 3 /* Max Tag 1 packet size */ + + 1 /* Version */ + + ECRYPTFS_SIG_SIZE /* Key identifier */ + + 1 /* Cipher identifier */ + + key_rec->enc_key_size); /* Encrypted key size */ + if (max_packet_size > (*remaining_bytes)) { + printk(KERN_ERR "Packet length larger than maximum allowable; " + "need up to [%td] bytes, but there are only [%td] " + "available\n", max_packet_size, (*remaining_bytes)); rc = -EINVAL; goto out; } dest[(*packet_size)++] = ECRYPTFS_TAG_1_PACKET_TYPE; - /* This format is inspired by OpenPGP; see RFC 2440 - * packet tag 1 */ - rc = write_packet_length(&dest[(*packet_size)], - (0x02 + ECRYPTFS_SIG_SIZE + - key_rec->enc_key_size), + rc = write_packet_length(&dest[(*packet_size)], (max_packet_size - 4), &packet_size_length); if (rc) { ecryptfs_printk(KERN_ERR, "Error generating tag 1 packet " @@ -1377,13 +1445,15 @@ encrypted_session_key_set: out: if (rc) (*packet_size) = 0; + else + (*remaining_bytes) -= (*packet_size); return rc; } /** * write_tag_11_packet * @dest: Target into which Tag 11 packet is to be written - * @max: Maximum packet length + * @remaining_bytes: Maximum packet length * @contents: Byte array of contents to copy in * @contents_length: Number of bytes in contents * @packet_length: Length of the Tag 11 packet written; zero on error @@ -1391,54 +1461,59 @@ out: * Returns zero on success; non-zero on error. */ static int -write_tag_11_packet(char *dest, int max, char *contents, size_t contents_length, - size_t *packet_length) +write_tag_11_packet(char *dest, size_t *remaining_bytes, char *contents, + size_t contents_length, size_t *packet_length) { size_t packet_size_length; + size_t max_packet_size; int rc = 0; (*packet_length) = 0; - if ((13 + contents_length) > max) { + /* This format is inspired by OpenPGP; see RFC 2440 + * packet tag 11 */ + max_packet_size = (1 /* Tag 11 identifier */ + + 3 /* Max Tag 11 packet size */ + + 1 /* Binary format specifier */ + + 1 /* Filename length */ + + 8 /* Filename ("_CONSOLE") */ + + 4 /* Modification date */ + + contents_length); /* Literal data */ + if (max_packet_size > (*remaining_bytes)) { + printk(KERN_ERR "Packet length larger than maximum allowable; " + "need up to [%td] bytes, but there are only [%td] " + "available\n", max_packet_size, (*remaining_bytes)); rc = -EINVAL; - ecryptfs_printk(KERN_ERR, "Packet length larger than " - "maximum allowable\n"); goto out; } - /* General packet header */ - /* Packet tag */ dest[(*packet_length)++] = ECRYPTFS_TAG_11_PACKET_TYPE; - /* Packet length */ rc = write_packet_length(&dest[(*packet_length)], - (13 + contents_length), &packet_size_length); + (max_packet_size - 4), &packet_size_length); if (rc) { - ecryptfs_printk(KERN_ERR, "Error generating tag 11 packet " - "header; cannot generate packet length\n"); + printk(KERN_ERR "Error generating tag 11 packet header; cannot " + "generate packet length. rc = [%d]\n", rc); goto out; } (*packet_length) += packet_size_length; - /* Tag 11 specific */ - /* One-octet field that describes how the data is formatted */ - dest[(*packet_length)++] = 0x62; /* binary data */ - /* One-octet filename length followed by filename */ + dest[(*packet_length)++] = 0x62; /* binary data format specifier */ dest[(*packet_length)++] = 8; memcpy(&dest[(*packet_length)], "_CONSOLE", 8); (*packet_length) += 8; - /* Four-octet number indicating modification date */ memset(&dest[(*packet_length)], 0x00, 4); (*packet_length) += 4; - /* Remainder is literal data */ memcpy(&dest[(*packet_length)], contents, contents_length); (*packet_length) += contents_length; out: if (rc) (*packet_length) = 0; + else + (*remaining_bytes) -= (*packet_length); return rc; } /** * write_tag_3_packet * @dest: Buffer into which to write the packet - * @max: Maximum number of bytes that can be written + * @remaining_bytes: Maximum number of bytes that can be written * @auth_tok: Authentication token * @crypt_stat: The cryptographic context * @key_rec: encrypted key @@ -1448,19 +1523,22 @@ write_tag_11_packet(char *dest, int max, char *contents, size_t contents_length, * Returns zero on success; non-zero on error. */ static int -write_tag_3_packet(char *dest, size_t max, struct ecryptfs_auth_tok *auth_tok, +write_tag_3_packet(char *dest, size_t *remaining_bytes, + struct ecryptfs_auth_tok *auth_tok, struct ecryptfs_crypt_stat *crypt_stat, struct ecryptfs_key_record *key_rec, size_t *packet_size) { size_t i; size_t encrypted_session_key_valid = 0; char session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES]; - struct scatterlist dest_sg[2]; - struct scatterlist src_sg[2]; + struct scatterlist dst_sg; + struct scatterlist src_sg; struct mutex *tfm_mutex = NULL; - size_t key_rec_size; - size_t packet_size_length; size_t cipher_code; + size_t packet_size_length; + size_t max_packet_size; + struct ecryptfs_mount_crypt_stat *mount_crypt_stat = + crypt_stat->mount_crypt_stat; struct blkcipher_desc desc = { .tfm = NULL, .flags = CRYPTO_TFM_REQ_MAY_SLEEP @@ -1470,16 +1548,25 @@ write_tag_3_packet(char *dest, size_t max, struct ecryptfs_auth_tok *auth_tok, (*packet_size) = 0; ecryptfs_from_hex(key_rec->sig, auth_tok->token.password.signature, ECRYPTFS_SIG_SIZE); - encrypted_session_key_valid = 0; - for (i = 0; i < crypt_stat->key_size; i++) - encrypted_session_key_valid |= - auth_tok->session_key.encrypted_key[i]; - if (encrypted_session_key_valid) { - memcpy(key_rec->enc_key, - auth_tok->session_key.encrypted_key, - auth_tok->session_key.encrypted_key_size); - goto encrypted_session_key_set; + rc = ecryptfs_get_tfm_and_mutex_for_cipher_name(&desc.tfm, &tfm_mutex, + crypt_stat->cipher); + if (unlikely(rc)) { + printk(KERN_ERR "Internal error whilst attempting to get " + "tfm and mutex for cipher name [%s]; rc = [%d]\n", + crypt_stat->cipher, rc); + goto out; + } + if (mount_crypt_stat->global_default_cipher_key_size == 0) { + struct blkcipher_alg *alg = crypto_blkcipher_alg(desc.tfm); + + printk(KERN_WARNING "No key size specified at mount; " + "defaulting to [%d]\n", alg->max_keysize); + mount_crypt_stat->global_default_cipher_key_size = + alg->max_keysize; } + if (crypt_stat->key_size == 0) + crypt_stat->key_size = + mount_crypt_stat->global_default_cipher_key_size; if (auth_tok->session_key.encrypted_key_size == 0) auth_tok->session_key.encrypted_key_size = crypt_stat->key_size; @@ -1487,9 +1574,24 @@ write_tag_3_packet(char *dest, size_t max, struct ecryptfs_auth_tok *auth_tok, && strcmp("aes", crypt_stat->cipher) == 0) { memset((crypt_stat->key + 24), 0, 8); auth_tok->session_key.encrypted_key_size = 32; - } + } else + auth_tok->session_key.encrypted_key_size = crypt_stat->key_size; key_rec->enc_key_size = auth_tok->session_key.encrypted_key_size; + encrypted_session_key_valid = 0; + for (i = 0; i < auth_tok->session_key.encrypted_key_size; i++) + encrypted_session_key_valid |= + auth_tok->session_key.encrypted_key[i]; + if (encrypted_session_key_valid) { + ecryptfs_printk(KERN_DEBUG, "encrypted_session_key_valid != 0; " + "using auth_tok->session_key.encrypted_key, " + "where key_rec->enc_key_size = [%d]\n", + key_rec->enc_key_size); + memcpy(key_rec->enc_key, + auth_tok->session_key.encrypted_key, + key_rec->enc_key_size); + goto encrypted_session_key_set; + } if (auth_tok->token.password.flags & ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET) { ecryptfs_printk(KERN_DEBUG, "Using previously generated " @@ -1508,54 +1610,32 @@ write_tag_3_packet(char *dest, size_t max, struct ecryptfs_auth_tok *auth_tok, ecryptfs_printk(KERN_DEBUG, "Session key encryption key:\n"); ecryptfs_dump_hex(session_key_encryption_key, 16); } - rc = virt_to_scatterlist(crypt_stat->key, - key_rec->enc_key_size, src_sg, 2); - if (!rc) { + rc = virt_to_scatterlist(crypt_stat->key, key_rec->enc_key_size, + &src_sg, 1); + if (rc != 1) { ecryptfs_printk(KERN_ERR, "Error generating scatterlist " - "for crypt_stat session key\n"); + "for crypt_stat session key; expected rc = 1; " + "got rc = [%d]. key_rec->enc_key_size = [%d]\n", + rc, key_rec->enc_key_size); rc = -ENOMEM; goto out; } - rc = virt_to_scatterlist(key_rec->enc_key, - key_rec->enc_key_size, dest_sg, 2); - if (!rc) { + rc = virt_to_scatterlist(key_rec->enc_key, key_rec->enc_key_size, + &dst_sg, 1); + if (rc != 1) { ecryptfs_printk(KERN_ERR, "Error generating scatterlist " - "for crypt_stat encrypted session key\n"); + "for crypt_stat encrypted session key; " + "expected rc = 1; got rc = [%d]. " + "key_rec->enc_key_size = [%d]\n", rc, + key_rec->enc_key_size); rc = -ENOMEM; goto out; } - if (!strcmp(crypt_stat->cipher, - crypt_stat->mount_crypt_stat->global_default_cipher_name) - && crypt_stat->mount_crypt_stat->global_key_tfm) { - desc.tfm = crypt_stat->mount_crypt_stat->global_key_tfm; - tfm_mutex = &crypt_stat->mount_crypt_stat->global_key_tfm_mutex; - } else { - char *full_alg_name; - - rc = ecryptfs_crypto_api_algify_cipher_name(&full_alg_name, - crypt_stat->cipher, - "ecb"); - if (rc) - goto out; - desc.tfm = crypto_alloc_blkcipher(full_alg_name, 0, - CRYPTO_ALG_ASYNC); - kfree(full_alg_name); - if (IS_ERR(desc.tfm)) { - rc = PTR_ERR(desc.tfm); - ecryptfs_printk(KERN_ERR, "Could not initialize crypto " - "context for cipher [%s]; rc = [%d]\n", - crypt_stat->cipher, rc); - goto out; - } - crypto_blkcipher_set_flags(desc.tfm, CRYPTO_TFM_REQ_WEAK_KEY); - } - if (tfm_mutex) - mutex_lock(tfm_mutex); + mutex_lock(tfm_mutex); rc = crypto_blkcipher_setkey(desc.tfm, session_key_encryption_key, crypt_stat->key_size); if (rc < 0) { - if (tfm_mutex) - mutex_unlock(tfm_mutex); + mutex_unlock(tfm_mutex); ecryptfs_printk(KERN_ERR, "Error setting key for crypto " "context; rc = [%d]\n", rc); goto out; @@ -1563,56 +1643,53 @@ write_tag_3_packet(char *dest, size_t max, struct ecryptfs_auth_tok *auth_tok, rc = 0; ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes of the key\n", crypt_stat->key_size); - rc = crypto_blkcipher_encrypt(&desc, dest_sg, src_sg, + rc = crypto_blkcipher_encrypt(&desc, &dst_sg, &src_sg, (*key_rec).enc_key_size); + mutex_unlock(tfm_mutex); if (rc) { printk(KERN_ERR "Error encrypting; rc = [%d]\n", rc); goto out; } - if (tfm_mutex) - mutex_unlock(tfm_mutex); ecryptfs_printk(KERN_DEBUG, "This should be the encrypted key:\n"); - if (ecryptfs_verbosity > 0) + if (ecryptfs_verbosity > 0) { + ecryptfs_printk(KERN_DEBUG, "EFEK of size [%d]:\n", + key_rec->enc_key_size); ecryptfs_dump_hex(key_rec->enc_key, key_rec->enc_key_size); -encrypted_session_key_set: - /* Now we have a valid key_rec. Append it to the - * key_rec set. */ - key_rec_size = (sizeof(struct ecryptfs_key_record) - - ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES - + (key_rec->enc_key_size)); - /* TODO: Include a packet size limit as a parameter to this - * function once we have multi-packet headers (for versions - * later than 0.1 */ - if (key_rec_size >= ECRYPTFS_MAX_KEYSET_SIZE) { - ecryptfs_printk(KERN_ERR, "Keyset too large\n"); - rc = -EINVAL; - goto out; } - /* TODO: Packet size limit */ - /* We have 5 bytes of surrounding packet data */ - if ((0x05 + ECRYPTFS_SALT_SIZE - + key_rec->enc_key_size) >= max) { - ecryptfs_printk(KERN_ERR, "Authentication token is too " - "large\n"); +encrypted_session_key_set: + /* This format is inspired by OpenPGP; see RFC 2440 + * packet tag 3 */ + max_packet_size = (1 /* Tag 3 identifier */ + + 3 /* Max Tag 3 packet size */ + + 1 /* Version */ + + 1 /* Cipher code */ + + 1 /* S2K specifier */ + + 1 /* Hash identifier */ + + ECRYPTFS_SALT_SIZE /* Salt */ + + 1 /* Hash iterations */ + + key_rec->enc_key_size); /* Encrypted key size */ + if (max_packet_size > (*remaining_bytes)) { + printk(KERN_ERR "Packet too large; need up to [%td] bytes, but " + "there are only [%td] available\n", max_packet_size, + (*remaining_bytes)); rc = -EINVAL; goto out; } - /* This format is inspired by OpenPGP; see RFC 2440 - * packet tag 3 */ dest[(*packet_size)++] = ECRYPTFS_TAG_3_PACKET_TYPE; - /* ver+cipher+s2k+hash+salt+iter+enc_key */ - rc = write_packet_length(&dest[(*packet_size)], - (0x05 + ECRYPTFS_SALT_SIZE - + key_rec->enc_key_size), + /* Chop off the Tag 3 identifier(1) and Tag 3 packet size(3) + * to get the number of octets in the actual Tag 3 packet */ + rc = write_packet_length(&dest[(*packet_size)], (max_packet_size - 4), &packet_size_length); if (rc) { - ecryptfs_printk(KERN_ERR, "Error generating tag 3 packet " - "header; cannot generate packet length\n"); + printk(KERN_ERR "Error generating tag 3 packet header; cannot " + "generate packet length. rc = [%d]\n", rc); goto out; } (*packet_size) += packet_size_length; dest[(*packet_size)++] = 0x04; /* version 4 */ + /* TODO: Break from RFC2440 so that arbitrary ciphers can be + * specified with strings */ cipher_code = ecryptfs_code_for_cipher_string(crypt_stat); if (cipher_code == 0) { ecryptfs_printk(KERN_WARNING, "Unable to generate code for " @@ -1631,10 +1708,10 @@ encrypted_session_key_set: key_rec->enc_key_size); (*packet_size) += key_rec->enc_key_size; out: - if (desc.tfm && !tfm_mutex) - crypto_free_blkcipher(desc.tfm); if (rc) (*packet_size) = 0; + else + (*remaining_bytes) -= (*packet_size); return rc; } @@ -1642,7 +1719,7 @@ struct kmem_cache *ecryptfs_key_record_cache; /** * ecryptfs_generate_key_packet_set - * @dest: Virtual address from which to write the key record set + * @dest_base: Virtual address from which to write the key record set * @crypt_stat: The cryptographic context from which the * authentication tokens will be retrieved * @ecryptfs_dentry: The dentry, used to retrieve the mount crypt stat @@ -1662,24 +1739,43 @@ ecryptfs_generate_key_packet_set(char *dest_base, size_t max) { struct ecryptfs_auth_tok *auth_tok; + struct ecryptfs_global_auth_tok *global_auth_tok; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = &ecryptfs_superblock_to_private( ecryptfs_dentry->d_sb)->mount_crypt_stat; size_t written; struct ecryptfs_key_record *key_rec; + struct ecryptfs_key_sig *key_sig; int rc = 0; (*len) = 0; + mutex_lock(&crypt_stat->keysig_list_mutex); key_rec = kmem_cache_alloc(ecryptfs_key_record_cache, GFP_KERNEL); if (!key_rec) { rc = -ENOMEM; goto out; } - if (mount_crypt_stat->global_auth_tok) { - auth_tok = mount_crypt_stat->global_auth_tok; + list_for_each_entry(key_sig, &crypt_stat->keysig_list, + crypt_stat_list) { + memset(key_rec, 0, sizeof(*key_rec)); + rc = ecryptfs_find_global_auth_tok_for_sig(&global_auth_tok, + mount_crypt_stat, + key_sig->keysig); + if (rc) { + printk(KERN_ERR "Error attempting to get the global " + "auth_tok; rc = [%d]\n", rc); + goto out_free; + } + if (global_auth_tok->flags & ECRYPTFS_AUTH_TOK_INVALID) { + printk(KERN_WARNING + "Skipping invalid auth tok with sig = [%s]\n", + global_auth_tok->sig); + continue; + } + auth_tok = global_auth_tok->global_auth_tok; if (auth_tok->token_type == ECRYPTFS_PASSWORD) { rc = write_tag_3_packet((dest_base + (*len)), - max, auth_tok, + &max, auth_tok, crypt_stat, key_rec, &written); if (rc) { @@ -1689,10 +1785,9 @@ ecryptfs_generate_key_packet_set(char *dest_base, } (*len) += written; /* Write auth tok signature packet */ - rc = write_tag_11_packet( - (dest_base + (*len)), - (max - (*len)), - key_rec->sig, ECRYPTFS_SIG_SIZE, &written); + rc = write_tag_11_packet((dest_base + (*len)), &max, + key_rec->sig, + ECRYPTFS_SIG_SIZE, &written); if (rc) { ecryptfs_printk(KERN_ERR, "Error writing " "auth tok signature packet\n"); @@ -1701,9 +1796,8 @@ ecryptfs_generate_key_packet_set(char *dest_base, (*len) += written; } else if (auth_tok->token_type == ECRYPTFS_PRIVATE_KEY) { rc = write_tag_1_packet(dest_base + (*len), - max, auth_tok, - crypt_stat,mount_crypt_stat, - key_rec, &written); + &max, auth_tok, + crypt_stat, key_rec, &written); if (rc) { ecryptfs_printk(KERN_WARNING, "Error " "writing tag 1 packet\n"); @@ -1716,19 +1810,69 @@ ecryptfs_generate_key_packet_set(char *dest_base, rc = -EINVAL; goto out_free; } - } else - BUG(); - if (likely((max - (*len)) > 0)) { + } + if (likely(max > 0)) { dest_base[(*len)] = 0x00; } else { ecryptfs_printk(KERN_ERR, "Error writing boundary byte\n"); rc = -EIO; } - out_free: kmem_cache_free(ecryptfs_key_record_cache, key_rec); out: if (rc) (*len) = 0; + mutex_unlock(&crypt_stat->keysig_list_mutex); return rc; } + +struct kmem_cache *ecryptfs_key_sig_cache; + +int ecryptfs_add_keysig(struct ecryptfs_crypt_stat *crypt_stat, char *sig) +{ + struct ecryptfs_key_sig *new_key_sig; + int rc = 0; + + new_key_sig = kmem_cache_alloc(ecryptfs_key_sig_cache, GFP_KERNEL); + if (!new_key_sig) { + rc = -ENOMEM; + printk(KERN_ERR + "Error allocating from ecryptfs_key_sig_cache\n"); + goto out; + } + memcpy(new_key_sig->keysig, sig, ECRYPTFS_SIG_SIZE_HEX); + mutex_lock(&crypt_stat->keysig_list_mutex); + list_add(&new_key_sig->crypt_stat_list, &crypt_stat->keysig_list); + mutex_unlock(&crypt_stat->keysig_list_mutex); +out: + return rc; +} + +struct kmem_cache *ecryptfs_global_auth_tok_cache; + +int +ecryptfs_add_global_auth_tok(struct ecryptfs_mount_crypt_stat *mount_crypt_stat, + char *sig) +{ + struct ecryptfs_global_auth_tok *new_auth_tok; + int rc = 0; + + new_auth_tok = kmem_cache_alloc(ecryptfs_global_auth_tok_cache, + GFP_KERNEL); + if (!new_auth_tok) { + rc = -ENOMEM; + printk(KERN_ERR "Error allocating from " + "ecryptfs_global_auth_tok_cache\n"); + goto out; + } + memcpy(new_auth_tok->sig, sig, ECRYPTFS_SIG_SIZE_HEX); + new_auth_tok->sig[ECRYPTFS_SIG_SIZE_HEX] = '\0'; + mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex); + list_add(&new_auth_tok->mount_crypt_stat_list, + &mount_crypt_stat->global_auth_tok_list); + mount_crypt_stat->num_global_auth_toks++; + mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex); +out: + return rc; +} + diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index a98497264fe8..b83a512b7e08 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -32,7 +32,6 @@ #include <linux/crypto.h> #include <linux/netlink.h> #include <linux/mount.h> -#include <linux/dcache.h> #include <linux/pagemap.h> #include <linux/key.h> #include <linux/parser.h> @@ -99,6 +98,64 @@ void __ecryptfs_printk(const char *fmt, ...) } /** + * ecryptfs_init_persistent_file + * @ecryptfs_dentry: Fully initialized eCryptfs dentry object, with + * the lower dentry and the lower mount set + * + * eCryptfs only ever keeps a single open file for every lower + * inode. All I/O operations to the lower inode occur through that + * file. When the first eCryptfs dentry that interposes with the first + * lower dentry for that inode is created, this function creates the + * persistent file struct and associates it with the eCryptfs + * inode. When the eCryptfs inode is destroyed, the file is closed. + * + * The persistent file will be opened with read/write permissions, if + * possible. Otherwise, it is opened read-only. + * + * This function does nothing if a lower persistent file is already + * associated with the eCryptfs inode. + * + * Returns zero on success; non-zero otherwise + */ +int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry) +{ + struct ecryptfs_inode_info *inode_info = + ecryptfs_inode_to_private(ecryptfs_dentry->d_inode); + int rc = 0; + + mutex_lock(&inode_info->lower_file_mutex); + if (!inode_info->lower_file) { + struct dentry *lower_dentry; + struct vfsmount *lower_mnt = + ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry); + + lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); + /* Corresponding dput() and mntput() are done when the + * persistent file is fput() when the eCryptfs inode + * is destroyed. */ + dget(lower_dentry); + mntget(lower_mnt); + inode_info->lower_file = dentry_open(lower_dentry, + lower_mnt, + (O_RDWR | O_LARGEFILE)); + if (IS_ERR(inode_info->lower_file)) + inode_info->lower_file = dentry_open(lower_dentry, + lower_mnt, + (O_RDONLY + | O_LARGEFILE)); + if (IS_ERR(inode_info->lower_file)) { + printk(KERN_ERR "Error opening lower persistent file " + "for lower_dentry [0x%p] and lower_mnt [0x%p]\n", + lower_dentry, lower_mnt); + rc = PTR_ERR(inode_info->lower_file); + inode_info->lower_file = NULL; + } + } + mutex_unlock(&inode_info->lower_file_mutex); + return rc; +} + +/** * ecryptfs_interpose * @lower_dentry: Existing dentry in the lower filesystem * @dentry: ecryptfs' dentry @@ -155,6 +212,13 @@ int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry, /* This size will be overwritten for real files w/ headers and * other metadata */ fsstack_copy_inode_size(inode, lower_inode); + rc = ecryptfs_init_persistent_file(dentry); + if (rc) { + printk(KERN_ERR "%s: Error attempting to initialize the " + "persistent file for the dentry with name [%s]; " + "rc = [%d]\n", __FUNCTION__, dentry->d_name.name, rc); + goto out; + } out: return rc; } @@ -179,38 +243,41 @@ static match_table_t tokens = { {ecryptfs_opt_err, NULL} }; -/** - * ecryptfs_verify_version - * @version: The version number to confirm - * - * Returns zero on good version; non-zero otherwise - */ -static int ecryptfs_verify_version(u16 version) +static int ecryptfs_init_global_auth_toks( + struct ecryptfs_mount_crypt_stat *mount_crypt_stat) { + struct ecryptfs_global_auth_tok *global_auth_tok; int rc = 0; - unsigned char major; - unsigned char minor; - - major = ((version >> 8) & 0xFF); - minor = (version & 0xFF); - if (major != ECRYPTFS_VERSION_MAJOR) { - ecryptfs_printk(KERN_ERR, "Major version number mismatch. " - "Expected [%d]; got [%d]\n", - ECRYPTFS_VERSION_MAJOR, major); - rc = -EINVAL; - goto out; - } - if (minor != ECRYPTFS_VERSION_MINOR) { - ecryptfs_printk(KERN_ERR, "Minor version number mismatch. " - "Expected [%d]; got [%d]\n", - ECRYPTFS_VERSION_MINOR, minor); - rc = -EINVAL; - goto out; + + list_for_each_entry(global_auth_tok, + &mount_crypt_stat->global_auth_tok_list, + mount_crypt_stat_list) { + rc = ecryptfs_keyring_auth_tok_for_sig( + &global_auth_tok->global_auth_tok_key, + &global_auth_tok->global_auth_tok, + global_auth_tok->sig); + if (rc) { + printk(KERN_ERR "Could not find valid key in user " + "session keyring for sig specified in mount " + "option: [%s]\n", global_auth_tok->sig); + global_auth_tok->flags |= ECRYPTFS_AUTH_TOK_INVALID; + rc = 0; + } else + global_auth_tok->flags &= ~ECRYPTFS_AUTH_TOK_INVALID; } -out: return rc; } +static void ecryptfs_init_mount_crypt_stat( + struct ecryptfs_mount_crypt_stat *mount_crypt_stat) +{ + memset((void *)mount_crypt_stat, 0, + sizeof(struct ecryptfs_mount_crypt_stat)); + INIT_LIST_HEAD(&mount_crypt_stat->global_auth_tok_list); + mutex_init(&mount_crypt_stat->global_auth_tok_list_mutex); + mount_crypt_stat->flags |= ECRYPTFS_MOUNT_CRYPT_STAT_INITIALIZED; +} + /** * ecryptfs_parse_options * @sb: The ecryptfs super block @@ -238,14 +305,11 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options) int cipher_name_set = 0; int cipher_key_bytes; int cipher_key_bytes_set = 0; - struct key *auth_tok_key = NULL; - struct ecryptfs_auth_tok *auth_tok = NULL; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = &ecryptfs_superblock_to_private(sb)->mount_crypt_stat; substring_t args[MAX_OPT_ARGS]; int token; char *sig_src; - char *sig_dst; char *debug_src; char *cipher_name_dst; char *cipher_name_src; @@ -256,6 +320,7 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options) rc = -EINVAL; goto out; } + ecryptfs_init_mount_crypt_stat(mount_crypt_stat); while ((p = strsep(&options, ",")) != NULL) { if (!*p) continue; @@ -264,14 +329,13 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options) case ecryptfs_opt_sig: case ecryptfs_opt_ecryptfs_sig: sig_src = args[0].from; - sig_dst = - mount_crypt_stat->global_auth_tok_sig; - memcpy(sig_dst, sig_src, ECRYPTFS_SIG_SIZE_HEX); - sig_dst[ECRYPTFS_SIG_SIZE_HEX] = '\0'; - ecryptfs_printk(KERN_DEBUG, - "The mount_crypt_stat " - "global_auth_tok_sig set to: " - "[%s]\n", sig_dst); + rc = ecryptfs_add_global_auth_tok(mount_crypt_stat, + sig_src); + if (rc) { + printk(KERN_ERR "Error attempting to register " + "global sig; rc = [%d]\n", rc); + goto out; + } sig_set = 1; break; case ecryptfs_opt_debug: @@ -333,12 +397,10 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options) p); } } - /* Do not support lack of mount-wide signature in 0.1 - * release */ if (!sig_set) { rc = -EINVAL; - ecryptfs_printk(KERN_ERR, "You must supply a valid " - "passphrase auth tok signature as a mount " + ecryptfs_printk(KERN_ERR, "You must supply at least one valid " + "auth tok signature as a mount " "parameter; see the eCryptfs README\n"); goto out; } @@ -358,55 +420,23 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options) if (!cipher_key_bytes_set) { mount_crypt_stat->global_default_cipher_key_size = 0; } - rc = ecryptfs_process_cipher( - &mount_crypt_stat->global_key_tfm, - mount_crypt_stat->global_default_cipher_name, - &mount_crypt_stat->global_default_cipher_key_size); + rc = ecryptfs_add_new_key_tfm( + NULL, mount_crypt_stat->global_default_cipher_name, + mount_crypt_stat->global_default_cipher_key_size); if (rc) { - printk(KERN_ERR "Error attempting to initialize cipher [%s] " - "with key size [%Zd] bytes; rc = [%d]\n", + printk(KERN_ERR "Error attempting to initialize cipher with " + "name = [%s] and key size = [%td]; rc = [%d]\n", mount_crypt_stat->global_default_cipher_name, mount_crypt_stat->global_default_cipher_key_size, rc); - mount_crypt_stat->global_key_tfm = NULL; - mount_crypt_stat->global_auth_tok_key = NULL; rc = -EINVAL; goto out; } - mutex_init(&mount_crypt_stat->global_key_tfm_mutex); - ecryptfs_printk(KERN_DEBUG, "Requesting the key with description: " - "[%s]\n", mount_crypt_stat->global_auth_tok_sig); - /* The reference to this key is held until umount is done The - * call to key_put is done in ecryptfs_put_super() */ - auth_tok_key = request_key(&key_type_user, - mount_crypt_stat->global_auth_tok_sig, - NULL); - if (!auth_tok_key || IS_ERR(auth_tok_key)) { - ecryptfs_printk(KERN_ERR, "Could not find key with " - "description: [%s]\n", - mount_crypt_stat->global_auth_tok_sig); - process_request_key_err(PTR_ERR(auth_tok_key)); - rc = -EINVAL; - goto out; - } - auth_tok = ecryptfs_get_key_payload_data(auth_tok_key); - if (ecryptfs_verify_version(auth_tok->version)) { - ecryptfs_printk(KERN_ERR, "Data structure version mismatch. " - "Userspace tools must match eCryptfs kernel " - "module with major version [%d] and minor " - "version [%d]\n", ECRYPTFS_VERSION_MAJOR, - ECRYPTFS_VERSION_MINOR); - rc = -EINVAL; - goto out; - } - if (auth_tok->token_type != ECRYPTFS_PASSWORD - && auth_tok->token_type != ECRYPTFS_PRIVATE_KEY) { - ecryptfs_printk(KERN_ERR, "Invalid auth_tok structure " - "returned from key query\n"); - rc = -EINVAL; - goto out; + rc = ecryptfs_init_global_auth_toks(mount_crypt_stat); + if (rc) { + printk(KERN_WARNING "One or more global auth toks could not " + "properly register; rc = [%d]\n", rc); } - mount_crypt_stat->global_auth_tok_key = auth_tok_key; - mount_crypt_stat->global_auth_tok = auth_tok; + rc = 0; out: return rc; } @@ -495,7 +525,8 @@ static int ecryptfs_read_super(struct super_block *sb, const char *dev_name) sb->s_maxbytes = lower_root->d_sb->s_maxbytes; ecryptfs_set_dentry_lower(sb->s_root, lower_root); ecryptfs_set_dentry_lower_mnt(sb->s_root, lower_mnt); - if ((rc = ecryptfs_interpose(lower_root, sb->s_root, sb, 0))) + rc = ecryptfs_interpose(lower_root, sb->s_root, sb, 0); + if (rc) goto out_free; rc = 0; goto out; @@ -579,7 +610,7 @@ static struct file_system_type ecryptfs_fs_type = { * Initializes the ecryptfs_inode_info_cache when it is created */ static void -inode_info_init_once(void *vptr, struct kmem_cache *cachep, unsigned long flags) +inode_info_init_once(struct kmem_cache *cachep, void *vptr) { struct ecryptfs_inode_info *ei = (struct ecryptfs_inode_info *)vptr; @@ -590,7 +621,7 @@ static struct ecryptfs_cache_info { struct kmem_cache **cache; const char *name; size_t size; - void (*ctor)(void*, struct kmem_cache *, unsigned long); + void (*ctor)(struct kmem_cache *cache, void *obj); } ecryptfs_cache_infos[] = { { .cache = &ecryptfs_auth_tok_list_item_cache, @@ -639,15 +670,25 @@ static struct ecryptfs_cache_info { .size = PAGE_CACHE_SIZE, }, { - .cache = &ecryptfs_lower_page_cache, - .name = "ecryptfs_lower_page_cache", - .size = PAGE_CACHE_SIZE, - }, - { .cache = &ecryptfs_key_record_cache, .name = "ecryptfs_key_record_cache", .size = sizeof(struct ecryptfs_key_record), }, + { + .cache = &ecryptfs_key_sig_cache, + .name = "ecryptfs_key_sig_cache", + .size = sizeof(struct ecryptfs_key_sig), + }, + { + .cache = &ecryptfs_global_auth_tok_cache, + .name = "ecryptfs_global_auth_tok_cache", + .size = sizeof(struct ecryptfs_global_auth_tok), + }, + { + .cache = &ecryptfs_key_tfm_cache, + .name = "ecryptfs_key_tfm_cache", + .size = sizeof(struct ecryptfs_key_tfm), + }, }; static void ecryptfs_free_kmem_caches(void) @@ -750,7 +791,8 @@ static struct ecryptfs_version_str_map_elem { {ECRYPTFS_VERSIONING_PUBKEY, "pubkey"}, {ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH, "plaintext passthrough"}, {ECRYPTFS_VERSIONING_POLICY, "policy"}, - {ECRYPTFS_VERSIONING_XATTR, "metadata in extended attribute"} + {ECRYPTFS_VERSIONING_XATTR, "metadata in extended attribute"}, + {ECRYPTFS_VERSIONING_MULTKEY, "multiple keys per file"} }; static ssize_t version_str_show(struct ecryptfs_obj *obj, char *buff) @@ -786,7 +828,8 @@ static int do_sysfs_registration(void) { int rc; - if ((rc = subsystem_register(&ecryptfs_subsys))) { + rc = subsystem_register(&ecryptfs_subsys); + if (rc) { printk(KERN_ERR "Unable to register ecryptfs sysfs subsystem\n"); goto out; @@ -845,33 +888,49 @@ static int __init ecryptfs_init(void) rc = register_filesystem(&ecryptfs_fs_type); if (rc) { printk(KERN_ERR "Failed to register filesystem\n"); - ecryptfs_free_kmem_caches(); - goto out; + goto out_free_kmem_caches; } kobj_set_kset_s(&ecryptfs_subsys, fs_subsys); rc = do_sysfs_registration(); if (rc) { printk(KERN_ERR "sysfs registration failed\n"); - unregister_filesystem(&ecryptfs_fs_type); - ecryptfs_free_kmem_caches(); - goto out; + goto out_unregister_filesystem; } rc = ecryptfs_init_messaging(ecryptfs_transport); if (rc) { ecryptfs_printk(KERN_ERR, "Failure occured while attempting to " "initialize the eCryptfs netlink socket\n"); - do_sysfs_unregistration(); - unregister_filesystem(&ecryptfs_fs_type); - ecryptfs_free_kmem_caches(); + goto out_do_sysfs_unregistration; + } + rc = ecryptfs_init_crypto(); + if (rc) { + printk(KERN_ERR "Failure whilst attempting to init crypto; " + "rc = [%d]\n", rc); + goto out_release_messaging; } + goto out; +out_release_messaging: + ecryptfs_release_messaging(ecryptfs_transport); +out_do_sysfs_unregistration: + do_sysfs_unregistration(); +out_unregister_filesystem: + unregister_filesystem(&ecryptfs_fs_type); +out_free_kmem_caches: + ecryptfs_free_kmem_caches(); out: return rc; } static void __exit ecryptfs_exit(void) { - do_sysfs_unregistration(); + int rc; + + rc = ecryptfs_destroy_crypto(); + if (rc) + printk(KERN_ERR "Failure whilst attempting to destroy crypto; " + "rc = [%d]\n", rc); ecryptfs_release_messaging(ecryptfs_transport); + do_sysfs_unregistration(); unregister_filesystem(&ecryptfs_fs_type); ecryptfs_free_kmem_caches(); } diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c index a9d87c47f72d..a96d341d154d 100644 --- a/fs/ecryptfs/messaging.c +++ b/fs/ecryptfs/messaging.c @@ -419,8 +419,9 @@ int ecryptfs_init_messaging(unsigned int transport) } mutex_init(&ecryptfs_daemon_id_hash_mux); mutex_lock(&ecryptfs_daemon_id_hash_mux); - ecryptfs_hash_buckets = 0; - while (ecryptfs_number_of_users >> ++ecryptfs_hash_buckets); + ecryptfs_hash_buckets = 1; + while (ecryptfs_number_of_users >> ecryptfs_hash_buckets) + ecryptfs_hash_buckets++; ecryptfs_daemon_id_hash = kmalloc(sizeof(struct hlist_head) * ecryptfs_hash_buckets, GFP_KERNEL); if (!ecryptfs_daemon_id_hash) { diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c index fd3f94d4a668..16a7a555f392 100644 --- a/fs/ecryptfs/mmap.c +++ b/fs/ecryptfs/mmap.c @@ -37,130 +37,27 @@ struct kmem_cache *ecryptfs_lower_page_cache; /** - * ecryptfs_get1page + * ecryptfs_get_locked_page * * Get one page from cache or lower f/s, return error otherwise. * - * Returns unlocked and up-to-date page (if ok), with increased + * Returns locked and up-to-date page (if ok), with increased * refcnt. */ -static struct page *ecryptfs_get1page(struct file *file, int index) +struct page *ecryptfs_get_locked_page(struct file *file, loff_t index) { struct dentry *dentry; struct inode *inode; struct address_space *mapping; + struct page *page; dentry = file->f_path.dentry; inode = dentry->d_inode; mapping = inode->i_mapping; - return read_mapping_page(mapping, index, (void *)file); -} - -/** - * ecryptfs_fill_zeros - * @file: The ecryptfs file - * @new_length: The new length of the data in the underlying file; - * everything between the prior end of the file and the - * new end of the file will be filled with zero's. - * new_length must be greater than current length - * - * Function for handling lseek-ing past the end of the file. - * - * This function does not support shrinking, only growing a file. - * - * Returns zero on success; non-zero otherwise. - */ -int ecryptfs_fill_zeros(struct file *file, loff_t new_length) -{ - int rc = 0; - struct dentry *dentry = file->f_path.dentry; - struct inode *inode = dentry->d_inode; - pgoff_t old_end_page_index = 0; - pgoff_t index = old_end_page_index; - int old_end_pos_in_page = -1; - pgoff_t new_end_page_index; - int new_end_pos_in_page; - loff_t cur_length = i_size_read(inode); - - if (cur_length != 0) { - index = old_end_page_index = - ((cur_length - 1) >> PAGE_CACHE_SHIFT); - old_end_pos_in_page = ((cur_length - 1) & ~PAGE_CACHE_MASK); - } - new_end_page_index = ((new_length - 1) >> PAGE_CACHE_SHIFT); - new_end_pos_in_page = ((new_length - 1) & ~PAGE_CACHE_MASK); - ecryptfs_printk(KERN_DEBUG, "old_end_page_index = [0x%.16x]; " - "old_end_pos_in_page = [%d]; " - "new_end_page_index = [0x%.16x]; " - "new_end_pos_in_page = [%d]\n", - old_end_page_index, old_end_pos_in_page, - new_end_page_index, new_end_pos_in_page); - if (old_end_page_index == new_end_page_index) { - /* Start and end are in the same page; we just need to - * set a portion of the existing page to zero's */ - rc = ecryptfs_write_zeros(file, index, - (old_end_pos_in_page + 1), - (new_end_pos_in_page - - old_end_pos_in_page)); - if (rc) - ecryptfs_printk(KERN_ERR, "ecryptfs_write_zeros(" - "file=[%p], " - "index=[0x%.16x], " - "old_end_pos_in_page=[d], " - "(PAGE_CACHE_SIZE - new_end_pos_in_page" - "=[%d]" - ")=[d]) returned [%d]\n", file, index, - old_end_pos_in_page, - new_end_pos_in_page, - (PAGE_CACHE_SIZE - new_end_pos_in_page), - rc); - goto out; - } - /* Fill the remainder of the previous last page with zeros */ - rc = ecryptfs_write_zeros(file, index, (old_end_pos_in_page + 1), - ((PAGE_CACHE_SIZE - 1) - old_end_pos_in_page)); - if (rc) { - ecryptfs_printk(KERN_ERR, "ecryptfs_write_zeros(file=[%p], " - "index=[0x%.16x], old_end_pos_in_page=[d], " - "(PAGE_CACHE_SIZE - old_end_pos_in_page)=[d]) " - "returned [%d]\n", file, index, - old_end_pos_in_page, - (PAGE_CACHE_SIZE - old_end_pos_in_page), rc); - goto out; - } - index++; - while (index < new_end_page_index) { - /* Fill all intermediate pages with zeros */ - rc = ecryptfs_write_zeros(file, index, 0, PAGE_CACHE_SIZE); - if (rc) { - ecryptfs_printk(KERN_ERR, "ecryptfs_write_zeros(" - "file=[%p], " - "index=[0x%.16x], " - "old_end_pos_in_page=[d], " - "(PAGE_CACHE_SIZE - new_end_pos_in_page" - "=[%d]" - ")=[d]) returned [%d]\n", file, index, - old_end_pos_in_page, - new_end_pos_in_page, - (PAGE_CACHE_SIZE - new_end_pos_in_page), - rc); - goto out; - } - index++; - } - /* Fill the portion at the beginning of the last new page with - * zero's */ - rc = ecryptfs_write_zeros(file, index, 0, (new_end_pos_in_page + 1)); - if (rc) { - ecryptfs_printk(KERN_ERR, "ecryptfs_write_zeros(file=" - "[%p], index=[0x%.16x], 0, " - "new_end_pos_in_page=[%d]" - "returned [%d]\n", file, index, - new_end_pos_in_page, rc); - goto out; - } -out: - return rc; + page = read_mapping_page(mapping, index, (void *)file); + if (!IS_ERR(page)) + lock_page(page); + return page; } /** @@ -171,13 +68,9 @@ out: */ static int ecryptfs_writepage(struct page *page, struct writeback_control *wbc) { - struct ecryptfs_page_crypt_context ctx; int rc; - ctx.page = page; - ctx.mode = ECRYPTFS_WRITEPAGE_MODE; - ctx.param.wbc = wbc; - rc = ecryptfs_encrypt_page(&ctx); + rc = ecryptfs_encrypt_page(page); if (rc) { ecryptfs_printk(KERN_WARNING, "Error encrypting " "page (upper index [0x%.16x])\n", page->index); @@ -191,58 +84,6 @@ out: } /** - * Reads the data from the lower file file at index lower_page_index - * and copies that data into page. - * - * @param page Page to fill - * @param lower_page_index Index of the page in the lower file to get - */ -int ecryptfs_do_readpage(struct file *file, struct page *page, - pgoff_t lower_page_index) -{ - int rc; - struct dentry *dentry; - struct file *lower_file; - struct dentry *lower_dentry; - struct inode *inode; - struct inode *lower_inode; - char *page_data; - struct page *lower_page = NULL; - char *lower_page_data; - const struct address_space_operations *lower_a_ops; - - dentry = file->f_path.dentry; - lower_file = ecryptfs_file_to_lower(file); - lower_dentry = ecryptfs_dentry_to_lower(dentry); - inode = dentry->d_inode; - lower_inode = ecryptfs_inode_to_lower(inode); - lower_a_ops = lower_inode->i_mapping->a_ops; - lower_page = read_cache_page(lower_inode->i_mapping, lower_page_index, - (filler_t *)lower_a_ops->readpage, - (void *)lower_file); - if (IS_ERR(lower_page)) { - rc = PTR_ERR(lower_page); - lower_page = NULL; - ecryptfs_printk(KERN_ERR, "Error reading from page cache\n"); - goto out; - } - page_data = kmap_atomic(page, KM_USER0); - lower_page_data = kmap_atomic(lower_page, KM_USER1); - memcpy(page_data, lower_page_data, PAGE_CACHE_SIZE); - kunmap_atomic(lower_page_data, KM_USER1); - kunmap_atomic(page_data, KM_USER0); - flush_dcache_page(page); - rc = 0; -out: - if (likely(lower_page)) - page_cache_release(lower_page); - if (rc == 0) - SetPageUptodate(page); - else - ClearPageUptodate(page); - return rc; -} -/** * Header Extent: * Octets 0-7: Unencrypted file size (big-endian) * Octets 8-15: eCryptfs special marker @@ -271,9 +112,77 @@ static void set_header_info(char *page_virt, } /** + * ecryptfs_copy_up_encrypted_with_header + * @page: Sort of a ``virtual'' representation of the encrypted lower + * file. The actual lower file does not have the metadata in + * the header. This is locked. + * @crypt_stat: The eCryptfs inode's cryptographic context + * + * The ``view'' is the version of the file that userspace winds up + * seeing, with the header information inserted. + */ +static int +ecryptfs_copy_up_encrypted_with_header(struct page *page, + struct ecryptfs_crypt_stat *crypt_stat) +{ + loff_t extent_num_in_page = 0; + loff_t num_extents_per_page = (PAGE_CACHE_SIZE + / crypt_stat->extent_size); + int rc = 0; + + while (extent_num_in_page < num_extents_per_page) { + loff_t view_extent_num = ((((loff_t)page->index) + * num_extents_per_page) + + extent_num_in_page); + + if (view_extent_num < crypt_stat->num_header_extents_at_front) { + /* This is a header extent */ + char *page_virt; + + page_virt = kmap_atomic(page, KM_USER0); + memset(page_virt, 0, PAGE_CACHE_SIZE); + /* TODO: Support more than one header extent */ + if (view_extent_num == 0) { + rc = ecryptfs_read_xattr_region( + page_virt, page->mapping->host); + set_header_info(page_virt, crypt_stat); + } + kunmap_atomic(page_virt, KM_USER0); + flush_dcache_page(page); + if (rc) { + printk(KERN_ERR "%s: Error reading xattr " + "region; rc = [%d]\n", __FUNCTION__, rc); + goto out; + } + } else { + /* This is an encrypted data extent */ + loff_t lower_offset = + ((view_extent_num - + crypt_stat->num_header_extents_at_front) + * crypt_stat->extent_size); + + rc = ecryptfs_read_lower_page_segment( + page, (lower_offset >> PAGE_CACHE_SHIFT), + (lower_offset & ~PAGE_CACHE_MASK), + crypt_stat->extent_size, page->mapping->host); + if (rc) { + printk(KERN_ERR "%s: Error attempting to read " + "extent at offset [%lld] in the lower " + "file; rc = [%d]\n", __FUNCTION__, + lower_offset, rc); + goto out; + } + } + extent_num_in_page++; + } +out: + return rc; +} + +/** * ecryptfs_readpage - * @file: This is an ecryptfs file - * @page: ecryptfs associated page to stick the read data into + * @file: An eCryptfs file + * @page: Page from eCryptfs inode mapping into which to stick the read data * * Read in a page, decrypting if necessary. * @@ -281,59 +190,35 @@ static void set_header_info(char *page_virt, */ static int ecryptfs_readpage(struct file *file, struct page *page) { + struct ecryptfs_crypt_stat *crypt_stat = + &ecryptfs_inode_to_private(file->f_path.dentry->d_inode)->crypt_stat; int rc = 0; - struct ecryptfs_crypt_stat *crypt_stat; - BUG_ON(!(file && file->f_path.dentry && file->f_path.dentry->d_inode)); - crypt_stat = &ecryptfs_inode_to_private(file->f_path.dentry->d_inode) - ->crypt_stat; if (!crypt_stat || !(crypt_stat->flags & ECRYPTFS_ENCRYPTED) || (crypt_stat->flags & ECRYPTFS_NEW_FILE)) { ecryptfs_printk(KERN_DEBUG, "Passing through unencrypted page\n"); - rc = ecryptfs_do_readpage(file, page, page->index); - if (rc) { - ecryptfs_printk(KERN_ERR, "Error reading page; rc = " - "[%d]\n", rc); - goto out; - } + rc = ecryptfs_read_lower_page_segment(page, page->index, 0, + PAGE_CACHE_SIZE, + page->mapping->host); } else if (crypt_stat->flags & ECRYPTFS_VIEW_AS_ENCRYPTED) { if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) { - int num_pages_in_header_region = - (crypt_stat->header_extent_size - / PAGE_CACHE_SIZE); - - if (page->index < num_pages_in_header_region) { - char *page_virt; - - page_virt = kmap_atomic(page, KM_USER0); - memset(page_virt, 0, PAGE_CACHE_SIZE); - if (page->index == 0) { - rc = ecryptfs_read_xattr_region( - page_virt, file->f_path.dentry); - set_header_info(page_virt, crypt_stat); - } - kunmap_atomic(page_virt, KM_USER0); - flush_dcache_page(page); - if (rc) { - printk(KERN_ERR "Error reading xattr " - "region\n"); - goto out; - } - } else { - rc = ecryptfs_do_readpage( - file, page, - (page->index - - num_pages_in_header_region)); - if (rc) { - printk(KERN_ERR "Error reading page; " - "rc = [%d]\n", rc); - goto out; - } + rc = ecryptfs_copy_up_encrypted_with_header(page, + crypt_stat); + if (rc) { + printk(KERN_ERR "%s: Error attempting to copy " + "the encrypted content from the lower " + "file whilst inserting the metadata " + "from the xattr into the header; rc = " + "[%d]\n", __FUNCTION__, rc); + goto out; } + } else { - rc = ecryptfs_do_readpage(file, page, page->index); + rc = ecryptfs_read_lower_page_segment( + page, page->index, 0, PAGE_CACHE_SIZE, + page->mapping->host); if (rc) { printk(KERN_ERR "Error reading page; rc = " "[%d]\n", rc); @@ -341,17 +226,18 @@ static int ecryptfs_readpage(struct file *file, struct page *page) } } } else { - rc = ecryptfs_decrypt_page(file, page); + rc = ecryptfs_decrypt_page(page); if (rc) { ecryptfs_printk(KERN_ERR, "Error decrypting page; " "rc = [%d]\n", rc); goto out; } } - SetPageUptodate(page); out: if (rc) ClearPageUptodate(page); + else + SetPageUptodate(page); ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n", page->index); unlock_page(page); @@ -377,27 +263,6 @@ out: return 0; } -/** - * eCryptfs does not currently support holes. When writing after a - * seek past the end of the file, eCryptfs fills in 0's through to the - * current location. The code to fill in the 0's to all the - * intermediate pages calls ecryptfs_prepare_write_no_truncate(). - */ -static int -ecryptfs_prepare_write_no_truncate(struct file *file, struct page *page, - unsigned from, unsigned to) -{ - int rc = 0; - - if (from == 0 && to == PAGE_CACHE_SIZE) - goto out; /* If we are writing a full page, it will be - up to date. */ - if (!PageUptodate(page)) - rc = ecryptfs_do_readpage(file, page, page->index); -out: - return rc; -} - static int ecryptfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) { @@ -406,10 +271,21 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page, if (from == 0 && to == PAGE_CACHE_SIZE) goto out; /* If we are writing a full page, it will be up to date. */ - if (!PageUptodate(page)) - rc = ecryptfs_do_readpage(file, page, page->index); + if (!PageUptodate(page)) { + rc = ecryptfs_read_lower_page_segment(page, page->index, 0, + PAGE_CACHE_SIZE, + page->mapping->host); + if (rc) { + printk(KERN_ERR "%s: Error attemping to read lower " + "page segment; rc = [%d]\n", __FUNCTION__, rc); + ClearPageUptodate(page); + goto out; + } else + SetPageUptodate(page); + } if (page->index != 0) { - loff_t end_of_prev_pg_pos = page_offset(page) - 1; + loff_t end_of_prev_pg_pos = + (((loff_t)page->index << PAGE_CACHE_SHIFT) - 1); if (end_of_prev_pg_pos > i_size_read(page->mapping->host)) { rc = ecryptfs_truncate(file->f_path.dentry, @@ -428,32 +304,6 @@ out: return rc; } -int ecryptfs_writepage_and_release_lower_page(struct page *lower_page, - struct inode *lower_inode, - struct writeback_control *wbc) -{ - int rc = 0; - - rc = lower_inode->i_mapping->a_ops->writepage(lower_page, wbc); - if (rc) { - ecryptfs_printk(KERN_ERR, "Error calling lower writepage(); " - "rc = [%d]\n", rc); - goto out; - } - lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME; - page_cache_release(lower_page); -out: - return rc; -} - -static -void ecryptfs_release_lower_page(struct page *lower_page, int page_locked) -{ - if (page_locked) - unlock_page(lower_page); - page_cache_release(lower_page); -} - /** * ecryptfs_write_inode_size_to_header * @@ -461,67 +311,48 @@ void ecryptfs_release_lower_page(struct page *lower_page, int page_locked) * * Returns zero on success; non-zero on error. */ -static int ecryptfs_write_inode_size_to_header(struct file *lower_file, - struct inode *lower_inode, - struct inode *inode) +static int ecryptfs_write_inode_size_to_header(struct inode *ecryptfs_inode) { - int rc = 0; - struct page *header_page; - char *header_virt; - const struct address_space_operations *lower_a_ops; u64 file_size; + char *file_size_virt; + int rc; -retry: - header_page = grab_cache_page(lower_inode->i_mapping, 0); - if (!header_page) { - ecryptfs_printk(KERN_ERR, "grab_cache_page for " - "lower_page_index 0 failed\n"); - rc = -EINVAL; - goto out; - } - lower_a_ops = lower_inode->i_mapping->a_ops; - rc = lower_a_ops->prepare_write(lower_file, header_page, 0, 8); - if (rc) { - if (rc == AOP_TRUNCATED_PAGE) { - ecryptfs_release_lower_page(header_page, 0); - goto retry; - } else - ecryptfs_release_lower_page(header_page, 1); + file_size_virt = kmalloc(sizeof(u64), GFP_KERNEL); + if (!file_size_virt) { + rc = -ENOMEM; goto out; } - file_size = (u64)i_size_read(inode); - ecryptfs_printk(KERN_DEBUG, "Writing size: [0x%.16x]\n", file_size); + file_size = (u64)i_size_read(ecryptfs_inode); file_size = cpu_to_be64(file_size); - header_virt = kmap_atomic(header_page, KM_USER0); - memcpy(header_virt, &file_size, sizeof(u64)); - kunmap_atomic(header_virt, KM_USER0); - flush_dcache_page(header_page); - rc = lower_a_ops->commit_write(lower_file, header_page, 0, 8); - if (rc < 0) - ecryptfs_printk(KERN_ERR, "Error commiting header page " - "write\n"); - if (rc == AOP_TRUNCATED_PAGE) { - ecryptfs_release_lower_page(header_page, 0); - goto retry; - } else - ecryptfs_release_lower_page(header_page, 1); - lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME; - mark_inode_dirty_sync(inode); + memcpy(file_size_virt, &file_size, sizeof(u64)); + rc = ecryptfs_write_lower(ecryptfs_inode, file_size_virt, 0, + sizeof(u64)); + kfree(file_size_virt); + if (rc) + printk(KERN_ERR "%s: Error writing file size to header; " + "rc = [%d]\n", __FUNCTION__, rc); out: return rc; } -static int ecryptfs_write_inode_size_to_xattr(struct inode *lower_inode, - struct inode *inode, - struct dentry *ecryptfs_dentry, - int lower_i_mutex_held) +struct kmem_cache *ecryptfs_xattr_cache; + +static int ecryptfs_write_inode_size_to_xattr(struct inode *ecryptfs_inode) { ssize_t size; void *xattr_virt; - struct dentry *lower_dentry; + struct dentry *lower_dentry = + ecryptfs_inode_to_private(ecryptfs_inode)->lower_file->f_dentry; + struct inode *lower_inode = lower_dentry->d_inode; u64 file_size; int rc; + if (!lower_inode->i_op->getxattr || !lower_inode->i_op->setxattr) { + printk(KERN_WARNING + "No support for setting xattr in lower filesystem\n"); + rc = -ENOSYS; + goto out; + } xattr_virt = kmem_cache_alloc(ecryptfs_xattr_cache, GFP_KERNEL); if (!xattr_virt) { printk(KERN_ERR "Out of memory whilst attempting to write " @@ -529,35 +360,17 @@ static int ecryptfs_write_inode_size_to_xattr(struct inode *lower_inode, rc = -ENOMEM; goto out; } - lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); - if (!lower_dentry->d_inode->i_op->getxattr || - !lower_dentry->d_inode->i_op->setxattr) { - printk(KERN_WARNING - "No support for setting xattr in lower filesystem\n"); - rc = -ENOSYS; - kmem_cache_free(ecryptfs_xattr_cache, xattr_virt); - goto out; - } - if (!lower_i_mutex_held) - mutex_lock(&lower_dentry->d_inode->i_mutex); - size = lower_dentry->d_inode->i_op->getxattr(lower_dentry, - ECRYPTFS_XATTR_NAME, - xattr_virt, - PAGE_CACHE_SIZE); - if (!lower_i_mutex_held) - mutex_unlock(&lower_dentry->d_inode->i_mutex); + mutex_lock(&lower_inode->i_mutex); + size = lower_inode->i_op->getxattr(lower_dentry, ECRYPTFS_XATTR_NAME, + xattr_virt, PAGE_CACHE_SIZE); if (size < 0) size = 8; - file_size = (u64)i_size_read(inode); + file_size = (u64)i_size_read(ecryptfs_inode); file_size = cpu_to_be64(file_size); memcpy(xattr_virt, &file_size, sizeof(u64)); - if (!lower_i_mutex_held) - mutex_lock(&lower_dentry->d_inode->i_mutex); - rc = lower_dentry->d_inode->i_op->setxattr(lower_dentry, - ECRYPTFS_XATTR_NAME, - xattr_virt, size, 0); - if (!lower_i_mutex_held) - mutex_unlock(&lower_dentry->d_inode->i_mutex); + rc = lower_inode->i_op->setxattr(lower_dentry, ECRYPTFS_XATTR_NAME, + xattr_virt, size, 0); + mutex_unlock(&lower_inode->i_mutex); if (rc) printk(KERN_ERR "Error whilst attempting to write inode size " "to lower file xattr; rc = [%d]\n", rc); @@ -566,122 +379,18 @@ out: return rc; } -int -ecryptfs_write_inode_size_to_metadata(struct file *lower_file, - struct inode *lower_inode, - struct inode *inode, - struct dentry *ecryptfs_dentry, - int lower_i_mutex_held) +int ecryptfs_write_inode_size_to_metadata(struct inode *ecryptfs_inode) { struct ecryptfs_crypt_stat *crypt_stat; - crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; + crypt_stat = &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat; if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) - return ecryptfs_write_inode_size_to_xattr(lower_inode, inode, - ecryptfs_dentry, - lower_i_mutex_held); + return ecryptfs_write_inode_size_to_xattr(ecryptfs_inode); else - return ecryptfs_write_inode_size_to_header(lower_file, - lower_inode, - inode); -} - -int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode, - struct file *lower_file, - unsigned long lower_page_index, int byte_offset, - int region_bytes) -{ - int rc = 0; - -retry: - *lower_page = grab_cache_page(lower_inode->i_mapping, lower_page_index); - if (!(*lower_page)) { - rc = -EINVAL; - ecryptfs_printk(KERN_ERR, "Error attempting to grab " - "lower page with index [0x%.16x]\n", - lower_page_index); - goto out; - } - rc = lower_inode->i_mapping->a_ops->prepare_write(lower_file, - (*lower_page), - byte_offset, - region_bytes); - if (rc) { - if (rc == AOP_TRUNCATED_PAGE) { - ecryptfs_release_lower_page(*lower_page, 0); - goto retry; - } else { - ecryptfs_printk(KERN_ERR, "prepare_write for " - "lower_page_index = [0x%.16x] failed; rc = " - "[%d]\n", lower_page_index, rc); - ecryptfs_release_lower_page(*lower_page, 1); - (*lower_page) = NULL; - } - } -out: - return rc; -} - -/** - * ecryptfs_commit_lower_page - * - * Returns zero on success; non-zero on error - */ -int -ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode, - struct file *lower_file, int byte_offset, - int region_size) -{ - int page_locked = 1; - int rc = 0; - - rc = lower_inode->i_mapping->a_ops->commit_write( - lower_file, lower_page, byte_offset, region_size); - if (rc == AOP_TRUNCATED_PAGE) - page_locked = 0; - if (rc < 0) { - ecryptfs_printk(KERN_ERR, - "Error committing write; rc = [%d]\n", rc); - } else - rc = 0; - ecryptfs_release_lower_page(lower_page, page_locked); - return rc; + return ecryptfs_write_inode_size_to_header(ecryptfs_inode); } /** - * ecryptfs_copy_page_to_lower - * - * Used for plaintext pass-through; no page index interpolation - * required. - */ -int ecryptfs_copy_page_to_lower(struct page *page, struct inode *lower_inode, - struct file *lower_file) -{ - int rc = 0; - struct page *lower_page; - - rc = ecryptfs_get_lower_page(&lower_page, lower_inode, lower_file, - page->index, 0, PAGE_CACHE_SIZE); - if (rc) { - ecryptfs_printk(KERN_ERR, "Error attempting to get page " - "at index [0x%.16x]\n", page->index); - goto out; - } - /* TODO: aops */ - memcpy((char *)page_address(lower_page), page_address(page), - PAGE_CACHE_SIZE); - rc = ecryptfs_commit_lower_page(lower_page, lower_inode, lower_file, - 0, PAGE_CACHE_SIZE); - if (rc) - ecryptfs_printk(KERN_ERR, "Error attempting to commit page " - "at index [0x%.16x]\n", page->index); -out: - return rc; -} - -struct kmem_cache *ecryptfs_xattr_cache; - -/** * ecryptfs_commit_write * @file: The eCryptfs file object * @page: The eCryptfs page @@ -695,20 +404,12 @@ struct kmem_cache *ecryptfs_xattr_cache; static int ecryptfs_commit_write(struct file *file, struct page *page, unsigned from, unsigned to) { - struct ecryptfs_page_crypt_context ctx; loff_t pos; - struct inode *inode; - struct inode *lower_inode; - struct file *lower_file; - struct ecryptfs_crypt_stat *crypt_stat; + struct inode *ecryptfs_inode = page->mapping->host; + struct ecryptfs_crypt_stat *crypt_stat = + &ecryptfs_inode_to_private(file->f_path.dentry->d_inode)->crypt_stat; int rc; - inode = page->mapping->host; - lower_inode = ecryptfs_inode_to_lower(inode); - lower_file = ecryptfs_file_to_lower(file); - mutex_lock(&lower_inode->i_mutex); - crypt_stat = &ecryptfs_inode_to_private(file->f_path.dentry->d_inode) - ->crypt_stat; if (crypt_stat->flags & ECRYPTFS_NEW_FILE) { ecryptfs_printk(KERN_DEBUG, "ECRYPTFS_NEW_FILE flag set in " "crypt_stat at memory location [%p]\n", crypt_stat); @@ -718,6 +419,7 @@ static int ecryptfs_commit_write(struct file *file, struct page *page, ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page" "(page w/ index = [0x%.16x], to = [%d])\n", page->index, to); + /* Fills in zeros if 'to' goes beyond inode size */ rc = fill_zeros_to_end_of_page(page, to); if (rc) { ecryptfs_printk(KERN_WARNING, "Error attempting to fill " @@ -725,82 +427,22 @@ static int ecryptfs_commit_write(struct file *file, struct page *page, page->index); goto out; } - ctx.page = page; - ctx.mode = ECRYPTFS_PREPARE_COMMIT_MODE; - ctx.param.lower_file = lower_file; - rc = ecryptfs_encrypt_page(&ctx); + rc = ecryptfs_encrypt_page(page); if (rc) { ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper " "index [0x%.16x])\n", page->index); goto out; } - inode->i_blocks = lower_inode->i_blocks; - pos = page_offset(page) + to; - if (pos > i_size_read(inode)) { - i_size_write(inode, pos); + pos = (((loff_t)page->index) << PAGE_CACHE_SHIFT) + to; + if (pos > i_size_read(ecryptfs_inode)) { + i_size_write(ecryptfs_inode, pos); ecryptfs_printk(KERN_DEBUG, "Expanded file size to " - "[0x%.16x]\n", i_size_read(inode)); + "[0x%.16x]\n", i_size_read(ecryptfs_inode)); } - rc = ecryptfs_write_inode_size_to_metadata(lower_file, lower_inode, - inode, file->f_dentry, - ECRYPTFS_LOWER_I_MUTEX_HELD); + rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode); if (rc) printk(KERN_ERR "Error writing inode size to metadata; " "rc = [%d]\n", rc); - lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME; - mark_inode_dirty_sync(inode); -out: - if (rc < 0) - ClearPageUptodate(page); - else - SetPageUptodate(page); - mutex_unlock(&lower_inode->i_mutex); - return rc; -} - -/** - * ecryptfs_write_zeros - * @file: The ecryptfs file - * @index: The index in which we are writing - * @start: The position after the last block of data - * @num_zeros: The number of zeros to write - * - * Write a specified number of zero's to a page. - * - * (start + num_zeros) must be less than or equal to PAGE_CACHE_SIZE - */ -int -ecryptfs_write_zeros(struct file *file, pgoff_t index, int start, int num_zeros) -{ - int rc = 0; - struct page *tmp_page; - - tmp_page = ecryptfs_get1page(file, index); - if (IS_ERR(tmp_page)) { - ecryptfs_printk(KERN_ERR, "Error getting page at index " - "[0x%.16x]\n", index); - rc = PTR_ERR(tmp_page); - goto out; - } - if ((rc = ecryptfs_prepare_write_no_truncate(file, tmp_page, start, - (start + num_zeros)))) { - ecryptfs_printk(KERN_ERR, "Error preparing to write zero's " - "to page at index [0x%.16x]\n", - index); - page_cache_release(tmp_page); - goto out; - } - zero_user_page(tmp_page, start, num_zeros, KM_USER0); - rc = ecryptfs_commit_write(file, tmp_page, start, start + num_zeros); - if (rc < 0) { - ecryptfs_printk(KERN_ERR, "Error attempting to write zero's " - "to remainder of page at index [0x%.16x]\n", - index); - page_cache_release(tmp_page); - goto out; - } - rc = 0; - page_cache_release(tmp_page); out: return rc; } @@ -819,34 +461,10 @@ static sector_t ecryptfs_bmap(struct address_space *mapping, sector_t block) return rc; } -static void ecryptfs_sync_page(struct page *page) -{ - struct inode *inode; - struct inode *lower_inode; - struct page *lower_page; - - inode = page->mapping->host; - lower_inode = ecryptfs_inode_to_lower(inode); - /* NOTE: Recently swapped with grab_cache_page(), since - * sync_page() just makes sure that pending I/O gets done. */ - lower_page = find_lock_page(lower_inode->i_mapping, page->index); - if (!lower_page) { - ecryptfs_printk(KERN_DEBUG, "find_lock_page failed\n"); - return; - } - if (lower_page->mapping->a_ops->sync_page) - lower_page->mapping->a_ops->sync_page(lower_page); - ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n", - lower_page->index); - unlock_page(lower_page); - page_cache_release(lower_page); -} - struct address_space_operations ecryptfs_aops = { .writepage = ecryptfs_writepage, .readpage = ecryptfs_readpage, .prepare_write = ecryptfs_prepare_write, .commit_write = ecryptfs_commit_write, .bmap = ecryptfs_bmap, - .sync_page = ecryptfs_sync_page, }; diff --git a/fs/ecryptfs/netlink.c b/fs/ecryptfs/netlink.c index fe9186312d7c..9aa345121e09 100644 --- a/fs/ecryptfs/netlink.c +++ b/fs/ecryptfs/netlink.c @@ -165,22 +165,10 @@ static int ecryptfs_process_nl_quit(struct sk_buff *skb) * it to its desired netlink context element and wake up the process * that is waiting for a response. */ -static void ecryptfs_receive_nl_message(struct sock *sk, int len) +static void ecryptfs_receive_nl_message(struct sk_buff *skb) { - struct sk_buff *skb; struct nlmsghdr *nlh; - int rc = 0; /* skb_recv_datagram requires this */ -receive: - skb = skb_recv_datagram(sk, 0, 0, &rc); - if (rc == -EINTR) - goto receive; - else if (rc < 0) { - ecryptfs_printk(KERN_ERR, "Error occurred while " - "receiving eCryptfs netlink message; " - "rc = [%d]\n", rc); - return; - } nlh = nlmsg_hdr(skb); if (!NLMSG_OK(nlh, skb->len)) { ecryptfs_printk(KERN_ERR, "Received corrupt netlink " @@ -227,7 +215,7 @@ int ecryptfs_init_netlink(void) { int rc; - ecryptfs_nl_sock = netlink_kernel_create(NETLINK_ECRYPTFS, 0, + ecryptfs_nl_sock = netlink_kernel_create(&init_net, NETLINK_ECRYPTFS, 0, ecryptfs_receive_nl_message, NULL, THIS_MODULE); if (!ecryptfs_nl_sock) { diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c new file mode 100644 index 000000000000..2150edf9a58e --- /dev/null +++ b/fs/ecryptfs/read_write.c @@ -0,0 +1,358 @@ +/** + * eCryptfs: Linux filesystem encryption layer + * + * Copyright (C) 2007 International Business Machines Corp. + * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <linux/fs.h> +#include <linux/pagemap.h> +#include "ecryptfs_kernel.h" + +/** + * ecryptfs_write_lower + * @ecryptfs_inode: The eCryptfs inode + * @data: Data to write + * @offset: Byte offset in the lower file to which to write the data + * @size: Number of bytes from @data to write at @offset in the lower + * file + * + * Write data to the lower file. + * + * Returns zero on success; non-zero on error + */ +int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data, + loff_t offset, size_t size) +{ + struct ecryptfs_inode_info *inode_info; + ssize_t octets_written; + mm_segment_t fs_save; + int rc = 0; + + inode_info = ecryptfs_inode_to_private(ecryptfs_inode); + mutex_lock(&inode_info->lower_file_mutex); + BUG_ON(!inode_info->lower_file); + inode_info->lower_file->f_pos = offset; + fs_save = get_fs(); + set_fs(get_ds()); + octets_written = vfs_write(inode_info->lower_file, data, size, + &inode_info->lower_file->f_pos); + set_fs(fs_save); + if (octets_written < 0) { + printk(KERN_ERR "%s: octets_written = [%td]; " + "expected [%td]\n", __FUNCTION__, octets_written, size); + rc = -EINVAL; + } + mutex_unlock(&inode_info->lower_file_mutex); + mark_inode_dirty_sync(ecryptfs_inode); + return rc; +} + +/** + * ecryptfs_write_lower_page_segment + * @ecryptfs_inode: The eCryptfs inode + * @page_for_lower: The page containing the data to be written to the + * lower file + * @offset_in_page: The offset in the @page_for_lower from which to + * start writing the data + * @size: The amount of data from @page_for_lower to write to the + * lower file + * + * Determines the byte offset in the file for the given page and + * offset within the page, maps the page, and makes the call to write + * the contents of @page_for_lower to the lower inode. + * + * Returns zero on success; non-zero otherwise + */ +int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode, + struct page *page_for_lower, + size_t offset_in_page, size_t size) +{ + char *virt; + loff_t offset; + int rc; + + offset = ((((off_t)page_for_lower->index) << PAGE_CACHE_SHIFT) + + offset_in_page); + virt = kmap(page_for_lower); + rc = ecryptfs_write_lower(ecryptfs_inode, virt, offset, size); + kunmap(page_for_lower); + return rc; +} + +/** + * ecryptfs_write + * @ecryptfs_file: The eCryptfs file into which to write + * @data: Virtual address where data to write is located + * @offset: Offset in the eCryptfs file at which to begin writing the + * data from @data + * @size: The number of bytes to write from @data + * + * Write an arbitrary amount of data to an arbitrary location in the + * eCryptfs inode page cache. This is done on a page-by-page, and then + * by an extent-by-extent, basis; individual extents are encrypted and + * written to the lower page cache (via VFS writes). This function + * takes care of all the address translation to locations in the lower + * filesystem; it also handles truncate events, writing out zeros + * where necessary. + * + * Returns zero on success; non-zero otherwise + */ +int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset, + size_t size) +{ + struct page *ecryptfs_page; + char *ecryptfs_page_virt; + loff_t ecryptfs_file_size = + i_size_read(ecryptfs_file->f_dentry->d_inode); + loff_t data_offset = 0; + loff_t pos; + int rc = 0; + + if (offset > ecryptfs_file_size) + pos = ecryptfs_file_size; + else + pos = offset; + while (pos < (offset + size)) { + pgoff_t ecryptfs_page_idx = (pos >> PAGE_CACHE_SHIFT); + size_t start_offset_in_page = (pos & ~PAGE_CACHE_MASK); + size_t num_bytes = (PAGE_CACHE_SIZE - start_offset_in_page); + size_t total_remaining_bytes = ((offset + size) - pos); + + if (num_bytes > total_remaining_bytes) + num_bytes = total_remaining_bytes; + if (pos < offset) { + size_t total_remaining_zeros = (offset - pos); + + if (num_bytes > total_remaining_zeros) + num_bytes = total_remaining_zeros; + } + ecryptfs_page = ecryptfs_get_locked_page(ecryptfs_file, + ecryptfs_page_idx); + if (IS_ERR(ecryptfs_page)) { + rc = PTR_ERR(ecryptfs_page); + printk(KERN_ERR "%s: Error getting page at " + "index [%ld] from eCryptfs inode " + "mapping; rc = [%d]\n", __FUNCTION__, + ecryptfs_page_idx, rc); + goto out; + } + if (start_offset_in_page) { + /* Read in the page from the lower + * into the eCryptfs inode page cache, + * decrypting */ + rc = ecryptfs_decrypt_page(ecryptfs_page); + if (rc) { + printk(KERN_ERR "%s: Error decrypting " + "page; rc = [%d]\n", + __FUNCTION__, rc); + ClearPageUptodate(ecryptfs_page); + page_cache_release(ecryptfs_page); + goto out; + } + } + ecryptfs_page_virt = kmap_atomic(ecryptfs_page, KM_USER0); + if (pos >= offset) { + memcpy(((char *)ecryptfs_page_virt + + start_offset_in_page), + (data + data_offset), num_bytes); + data_offset += num_bytes; + } else { + /* We are extending past the previous end of the file. + * Fill in zero values up to the start of where we + * will be writing data. */ + memset(((char *)ecryptfs_page_virt + + start_offset_in_page), 0, num_bytes); + } + kunmap_atomic(ecryptfs_page_virt, KM_USER0); + flush_dcache_page(ecryptfs_page); + SetPageUptodate(ecryptfs_page); + unlock_page(ecryptfs_page); + rc = ecryptfs_encrypt_page(ecryptfs_page); + page_cache_release(ecryptfs_page); + if (rc) { + printk(KERN_ERR "%s: Error encrypting " + "page; rc = [%d]\n", __FUNCTION__, rc); + goto out; + } + pos += num_bytes; + } + if ((offset + size) > ecryptfs_file_size) { + i_size_write(ecryptfs_file->f_dentry->d_inode, (offset + size)); + rc = ecryptfs_write_inode_size_to_metadata( + ecryptfs_file->f_dentry->d_inode); + if (rc) { + printk(KERN_ERR "Problem with " + "ecryptfs_write_inode_size_to_metadata; " + "rc = [%d]\n", rc); + goto out; + } + } +out: + return rc; +} + +/** + * ecryptfs_read_lower + * @data: The read data is stored here by this function + * @offset: Byte offset in the lower file from which to read the data + * @size: Number of bytes to read from @offset of the lower file and + * store into @data + * @ecryptfs_inode: The eCryptfs inode + * + * Read @size bytes of data at byte offset @offset from the lower + * inode into memory location @data. + * + * Returns zero on success; non-zero on error + */ +int ecryptfs_read_lower(char *data, loff_t offset, size_t size, + struct inode *ecryptfs_inode) +{ + struct ecryptfs_inode_info *inode_info = + ecryptfs_inode_to_private(ecryptfs_inode); + ssize_t octets_read; + mm_segment_t fs_save; + int rc = 0; + + mutex_lock(&inode_info->lower_file_mutex); + BUG_ON(!inode_info->lower_file); + inode_info->lower_file->f_pos = offset; + fs_save = get_fs(); + set_fs(get_ds()); + octets_read = vfs_read(inode_info->lower_file, data, size, + &inode_info->lower_file->f_pos); + set_fs(fs_save); + if (octets_read < 0) { + printk(KERN_ERR "%s: octets_read = [%td]; " + "expected [%td]\n", __FUNCTION__, octets_read, size); + rc = -EINVAL; + } + mutex_unlock(&inode_info->lower_file_mutex); + return rc; +} + +/** + * ecryptfs_read_lower_page_segment + * @page_for_ecryptfs: The page into which data for eCryptfs will be + * written + * @offset_in_page: Offset in @page_for_ecryptfs from which to start + * writing + * @size: The number of bytes to write into @page_for_ecryptfs + * @ecryptfs_inode: The eCryptfs inode + * + * Determines the byte offset in the file for the given page and + * offset within the page, maps the page, and makes the call to read + * the contents of @page_for_ecryptfs from the lower inode. + * + * Returns zero on success; non-zero otherwise + */ +int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs, + pgoff_t page_index, + size_t offset_in_page, size_t size, + struct inode *ecryptfs_inode) +{ + char *virt; + loff_t offset; + int rc; + + offset = ((((loff_t)page_index) << PAGE_CACHE_SHIFT) + offset_in_page); + virt = kmap(page_for_ecryptfs); + rc = ecryptfs_read_lower(virt, offset, size, ecryptfs_inode); + kunmap(page_for_ecryptfs); + flush_dcache_page(page_for_ecryptfs); + return rc; +} + +/** + * ecryptfs_read + * @data: The virtual address into which to write the data read (and + * possibly decrypted) from the lower file + * @offset: The offset in the decrypted view of the file from which to + * read into @data + * @size: The number of bytes to read into @data + * @ecryptfs_file: The eCryptfs file from which to read + * + * Read an arbitrary amount of data from an arbitrary location in the + * eCryptfs page cache. This is done on an extent-by-extent basis; + * individual extents are decrypted and read from the lower page + * cache (via VFS reads). This function takes care of all the + * address translation to locations in the lower filesystem. + * + * Returns zero on success; non-zero otherwise + */ +int ecryptfs_read(char *data, loff_t offset, size_t size, + struct file *ecryptfs_file) +{ + struct page *ecryptfs_page; + char *ecryptfs_page_virt; + loff_t ecryptfs_file_size = + i_size_read(ecryptfs_file->f_dentry->d_inode); + loff_t data_offset = 0; + loff_t pos; + int rc = 0; + + if ((offset + size) > ecryptfs_file_size) { + rc = -EINVAL; + printk(KERN_ERR "%s: Attempt to read data past the end of the " + "file; offset = [%lld]; size = [%td]; " + "ecryptfs_file_size = [%lld]\n", + __FUNCTION__, offset, size, ecryptfs_file_size); + goto out; + } + pos = offset; + while (pos < (offset + size)) { + pgoff_t ecryptfs_page_idx = (pos >> PAGE_CACHE_SHIFT); + size_t start_offset_in_page = (pos & ~PAGE_CACHE_MASK); + size_t num_bytes = (PAGE_CACHE_SIZE - start_offset_in_page); + size_t total_remaining_bytes = ((offset + size) - pos); + + if (num_bytes > total_remaining_bytes) + num_bytes = total_remaining_bytes; + ecryptfs_page = ecryptfs_get_locked_page(ecryptfs_file, + ecryptfs_page_idx); + if (IS_ERR(ecryptfs_page)) { + rc = PTR_ERR(ecryptfs_page); + printk(KERN_ERR "%s: Error getting page at " + "index [%ld] from eCryptfs inode " + "mapping; rc = [%d]\n", __FUNCTION__, + ecryptfs_page_idx, rc); + goto out; + } + rc = ecryptfs_decrypt_page(ecryptfs_page); + if (rc) { + printk(KERN_ERR "%s: Error decrypting " + "page; rc = [%d]\n", __FUNCTION__, rc); + ClearPageUptodate(ecryptfs_page); + page_cache_release(ecryptfs_page); + goto out; + } + ecryptfs_page_virt = kmap_atomic(ecryptfs_page, KM_USER0); + memcpy((data + data_offset), + ((char *)ecryptfs_page_virt + start_offset_in_page), + num_bytes); + kunmap_atomic(ecryptfs_page_virt, KM_USER0); + flush_dcache_page(ecryptfs_page); + SetPageUptodate(ecryptfs_page); + unlock_page(ecryptfs_page); + page_cache_release(ecryptfs_page); + pos += num_bytes; + data_offset += num_bytes; + } +out: + return rc; +} diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c index 7b3f0cc09a6f..f8cdab2bee3d 100644 --- a/fs/ecryptfs/super.c +++ b/fs/ecryptfs/super.c @@ -27,6 +27,7 @@ #include <linux/mount.h> #include <linux/key.h> #include <linux/seq_file.h> +#include <linux/file.h> #include <linux/crypto.h> #include "ecryptfs_kernel.h" @@ -46,15 +47,16 @@ struct kmem_cache *ecryptfs_inode_info_cache; */ static struct inode *ecryptfs_alloc_inode(struct super_block *sb) { - struct ecryptfs_inode_info *ecryptfs_inode; + struct ecryptfs_inode_info *inode_info; struct inode *inode = NULL; - ecryptfs_inode = kmem_cache_alloc(ecryptfs_inode_info_cache, - GFP_KERNEL); - if (unlikely(!ecryptfs_inode)) + inode_info = kmem_cache_alloc(ecryptfs_inode_info_cache, GFP_KERNEL); + if (unlikely(!inode_info)) goto out; - ecryptfs_init_crypt_stat(&ecryptfs_inode->crypt_stat); - inode = &ecryptfs_inode->vfs_inode; + ecryptfs_init_crypt_stat(&inode_info->crypt_stat); + mutex_init(&inode_info->lower_file_mutex); + inode_info->lower_file = NULL; + inode = &inode_info->vfs_inode; out: return inode; } @@ -63,9 +65,10 @@ out: * ecryptfs_destroy_inode * @inode: The ecryptfs inode * - * This is used during the final destruction of the inode. - * All allocation of memory related to the inode, including allocated - * memory in the crypt_stat struct, will be released here. + * This is used during the final destruction of the inode. All + * allocation of memory related to the inode, including allocated + * memory in the crypt_stat struct, will be released here. This + * function also fput()'s the persistent file for the lower inode. * There should be no chance that this deallocation will be missed. */ static void ecryptfs_destroy_inode(struct inode *inode) @@ -73,7 +76,21 @@ static void ecryptfs_destroy_inode(struct inode *inode) struct ecryptfs_inode_info *inode_info; inode_info = ecryptfs_inode_to_private(inode); - ecryptfs_destruct_crypt_stat(&inode_info->crypt_stat); + mutex_lock(&inode_info->lower_file_mutex); + if (inode_info->lower_file) { + struct dentry *lower_dentry = + inode_info->lower_file->f_dentry; + + BUG_ON(!lower_dentry); + if (lower_dentry->d_inode) { + fput(inode_info->lower_file); + inode_info->lower_file = NULL; + d_drop(lower_dentry); + d_delete(lower_dentry); + } + } + mutex_unlock(&inode_info->lower_file_mutex); + ecryptfs_destroy_crypt_stat(&inode_info->crypt_stat); kmem_cache_free(ecryptfs_inode_info_cache, inode_info); } @@ -104,7 +121,7 @@ static void ecryptfs_put_super(struct super_block *sb) { struct ecryptfs_sb_info *sb_info = ecryptfs_superblock_to_private(sb); - ecryptfs_destruct_mount_crypt_stat(&sb_info->mount_crypt_stat); + ecryptfs_destroy_mount_crypt_stat(&sb_info->mount_crypt_stat); kmem_cache_free(ecryptfs_sb_info_cache, sb_info); ecryptfs_set_superblock_private(sb, NULL); } diff --git a/fs/efs/super.c b/fs/efs/super.c index ce4acb8ff819..25d0326c5f1c 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c @@ -69,7 +69,7 @@ static void efs_destroy_inode(struct inode *inode) kmem_cache_free(efs_inode_cachep, INODE_INFO(inode)); } -static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(struct kmem_cache *cachep, void *foo) { struct efs_inode_info *ei = (struct efs_inode_info *) foo; diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 77b9953624f4..34f68f3a069a 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -325,15 +325,14 @@ static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq) int wake_nests = 0; unsigned long flags; struct task_struct *this_task = current; - struct list_head *lsthead = &psw->wake_task_list, *lnk; + struct list_head *lsthead = &psw->wake_task_list; struct wake_task_node *tncur; struct wake_task_node tnode; spin_lock_irqsave(&psw->lock, flags); /* Try to see if the current task is already inside this wakeup call */ - list_for_each(lnk, lsthead) { - tncur = list_entry(lnk, struct wake_task_node, llink); + list_for_each_entry(tncur, lsthead, llink) { if (tncur->wq == wq || (tncur->task == this_task && ++wake_nests > EP_MAX_POLLWAKE_NESTS)) { @@ -463,7 +462,7 @@ static void ep_free(struct eventpoll *ep) * holding "epmutex" we can be sure that no file cleanup code will hit * us during this operation. So we can avoid the lock on "ep->lock". */ - while ((rbp = rb_first(&ep->rbr)) != 0) { + while ((rbp = rb_first(&ep->rbr)) != NULL) { epi = rb_entry(rbp, struct epitem, rbn); ep_remove(ep, epi); } diff --git a/fs/exec.c b/fs/exec.c index 073b0b8c6d05..2c942e2d14ea 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -29,6 +29,7 @@ #include <linux/stat.h> #include <linux/fcntl.h> #include <linux/smp_lock.h> +#include <linux/string.h> #include <linux/init.h> #include <linux/pagemap.h> #include <linux/highmem.h> @@ -63,52 +64,28 @@ int core_uses_pid; char core_pattern[CORENAME_MAX_SIZE] = "core"; int suid_dumpable = 0; -EXPORT_SYMBOL(suid_dumpable); /* The maximal length of core_pattern is also specified in sysctl.c */ -static struct linux_binfmt *formats; +static LIST_HEAD(formats); static DEFINE_RWLOCK(binfmt_lock); int register_binfmt(struct linux_binfmt * fmt) { - struct linux_binfmt ** tmp = &formats; - if (!fmt) return -EINVAL; - if (fmt->next) - return -EBUSY; write_lock(&binfmt_lock); - while (*tmp) { - if (fmt == *tmp) { - write_unlock(&binfmt_lock); - return -EBUSY; - } - tmp = &(*tmp)->next; - } - fmt->next = formats; - formats = fmt; + list_add(&fmt->lh, &formats); write_unlock(&binfmt_lock); return 0; } EXPORT_SYMBOL(register_binfmt); -int unregister_binfmt(struct linux_binfmt * fmt) +void unregister_binfmt(struct linux_binfmt * fmt) { - struct linux_binfmt ** tmp = &formats; - write_lock(&binfmt_lock); - while (*tmp) { - if (fmt == *tmp) { - *tmp = fmt->next; - fmt->next = NULL; - write_unlock(&binfmt_lock); - return 0; - } - tmp = &(*tmp)->next; - } + list_del(&fmt->lh); write_unlock(&binfmt_lock); - return -EINVAL; } EXPORT_SYMBOL(unregister_binfmt); @@ -134,9 +111,6 @@ asmlinkage long sys_uselib(const char __user * library) if (error) goto out; - error = -EACCES; - if (nd.mnt->mnt_flags & MNT_NOEXEC) - goto exit; error = -EINVAL; if (!S_ISREG(nd.dentry->d_inode->i_mode)) goto exit; @@ -155,7 +129,7 @@ asmlinkage long sys_uselib(const char __user * library) struct linux_binfmt * fmt; read_lock(&binfmt_lock); - for (fmt = formats ; fmt ; fmt = fmt->next) { + list_for_each_entry(fmt, &formats, lh) { if (!fmt->load_shlib) continue; if (!try_module_get(fmt->module)) @@ -260,7 +234,7 @@ static int __bprm_mm_init(struct linux_binprm *bprm) vma->vm_start = vma->vm_end - PAGE_SIZE; vma->vm_flags = VM_STACK_FLAGS; - vma->vm_page_prot = protection_map[vma->vm_flags & 0x7]; + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); err = insert_vm_struct(mm, vma); if (err) { up_write(&mm->mmap_sem); @@ -680,8 +654,7 @@ struct file *open_exec(const char *name) if (!err) { struct inode *inode = nd.dentry->d_inode; file = ERR_PTR(-EACCES); - if (!(nd.mnt->mnt_flags & MNT_NOEXEC) && - S_ISREG(inode->i_mode)) { + if (S_ISREG(inode->i_mode)) { int err = vfs_permission(&nd, MAY_EXEC); file = ERR_PTR(err); if (!err) { @@ -773,24 +746,11 @@ static int exec_mmap(struct mm_struct *mm) static int de_thread(struct task_struct *tsk) { struct signal_struct *sig = tsk->signal; - struct sighand_struct *newsighand, *oldsighand = tsk->sighand; + struct sighand_struct *oldsighand = tsk->sighand; spinlock_t *lock = &oldsighand->siglock; struct task_struct *leader = NULL; int count; - /* - * If we don't share sighandlers, then we aren't sharing anything - * and we can just re-use it all. - */ - if (atomic_read(&oldsighand->count) <= 1) { - exit_itimers(sig); - return 0; - } - - newsighand = kmem_cache_alloc(sighand_cachep, GFP_KERNEL); - if (!newsighand) - return -ENOMEM; - if (thread_group_empty(tsk)) goto no_thread_group; @@ -807,7 +767,6 @@ static int de_thread(struct task_struct *tsk) */ spin_unlock_irq(lock); read_unlock(&tasklist_lock); - kmem_cache_free(sighand_cachep, newsighand); return -EAGAIN; } @@ -816,8 +775,8 @@ static int de_thread(struct task_struct *tsk) * Reparenting needs write_lock on tasklist_lock, * so it is safe to do it under read_lock. */ - if (unlikely(tsk->group_leader == child_reaper(tsk))) - tsk->nsproxy->pid_ns->child_reaper = tsk; + if (unlikely(tsk->group_leader == task_child_reaper(tsk))) + task_active_pid_ns(tsk)->child_reaper = tsk; zap_other_threads(tsk); read_unlock(&tasklist_lock); @@ -841,16 +800,15 @@ static int de_thread(struct task_struct *tsk) hrtimer_restart(&sig->real_timer); spin_lock_irq(lock); } + + sig->notify_count = count; + sig->group_exit_task = tsk; while (atomic_read(&sig->count) > count) { - sig->group_exit_task = tsk; - sig->notify_count = count; __set_current_state(TASK_UNINTERRUPTIBLE); spin_unlock_irq(lock); schedule(); spin_lock_irq(lock); } - sig->group_exit_task = NULL; - sig->notify_count = 0; spin_unlock_irq(lock); /* @@ -859,14 +817,17 @@ static int de_thread(struct task_struct *tsk) * and to assume its PID: */ if (!thread_group_leader(tsk)) { - /* - * Wait for the thread group leader to be a zombie. - * It should already be zombie at this point, most - * of the time. - */ leader = tsk->group_leader; - while (leader->exit_state != EXIT_ZOMBIE) - yield(); + + sig->notify_count = -1; + for (;;) { + write_lock_irq(&tasklist_lock); + if (likely(leader->exit_state)) + break; + __set_current_state(TASK_UNINTERRUPTIBLE); + write_unlock_irq(&tasklist_lock); + schedule(); + } /* * The only record we have of the real-time age of a @@ -880,10 +841,8 @@ static int de_thread(struct task_struct *tsk) */ tsk->start_time = leader->start_time; - write_lock_irq(&tasklist_lock); - - BUG_ON(leader->tgid != tsk->tgid); - BUG_ON(tsk->pid == tsk->tgid); + BUG_ON(!same_thread_group(leader, tsk)); + BUG_ON(has_group_leader_pid(tsk)); /* * An exec() starts a new thread group with the * TGID of the previous thread group. Rehash the @@ -898,7 +857,7 @@ static int de_thread(struct task_struct *tsk) */ detach_pid(tsk, PIDTYPE_PID); tsk->pid = leader->pid; - attach_pid(tsk, PIDTYPE_PID, find_pid(tsk->pid)); + attach_pid(tsk, PIDTYPE_PID, task_pid(leader)); transfer_pid(leader, tsk, PIDTYPE_PGID); transfer_pid(leader, tsk, PIDTYPE_SID); list_replace_rcu(&leader->tasks, &tsk->tasks); @@ -914,6 +873,8 @@ static int de_thread(struct task_struct *tsk) write_unlock_irq(&tasklist_lock); } + sig->group_exit_task = NULL; + sig->notify_count = 0; /* * There may be one thread left which is just exiting, * but it's safe to stop telling the group to kill themselves. @@ -925,29 +886,23 @@ no_thread_group: if (leader) release_task(leader); - if (atomic_read(&oldsighand->count) == 1) { - /* - * Now that we nuked the rest of the thread group, - * it turns out we are not sharing sighand any more either. - * So we can just keep it. - */ - kmem_cache_free(sighand_cachep, newsighand); - } else { + if (atomic_read(&oldsighand->count) != 1) { + struct sighand_struct *newsighand; /* - * Move our state over to newsighand and switch it in. + * This ->sighand is shared with the CLONE_SIGHAND + * but not CLONE_THREAD task, switch to the new one. */ + newsighand = kmem_cache_alloc(sighand_cachep, GFP_KERNEL); + if (!newsighand) + return -ENOMEM; + atomic_set(&newsighand->count, 1); memcpy(newsighand->action, oldsighand->action, sizeof(newsighand->action)); write_lock_irq(&tasklist_lock); spin_lock(&oldsighand->siglock); - spin_lock_nested(&newsighand->siglock, SINGLE_DEPTH_NESTING); - rcu_assign_pointer(tsk->sighand, newsighand); - recalc_sigpending(); - - spin_unlock(&newsighand->siglock); spin_unlock(&oldsighand->siglock); write_unlock_irq(&tasklist_lock); @@ -957,12 +912,11 @@ no_thread_group: BUG_ON(!thread_group_leader(tsk)); return 0; } - + /* * These functions flushes out all traces of the currently running executable * so that a new one can be started */ - static void flush_old_files(struct files_struct * files) { long j = -1; @@ -1284,7 +1238,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) retval = -ENOENT; for (try=0; try<2; try++) { read_lock(&binfmt_lock); - for (fmt = formats ; fmt ; fmt = fmt->next) { + list_for_each_entry(fmt, &formats, lh) { int (*fn)(struct linux_binprm *, struct pt_regs *) = fmt->load_binary; if (!fn) continue; @@ -1479,7 +1433,7 @@ static int format_corename(char *corename, const char *pattern, long signr) case 'p': pid_in_pattern = 1; rc = snprintf(out_ptr, out_end - out_ptr, - "%d", current->tgid); + "%d", task_tgid_vnr(current)); if (rc > out_end - out_ptr) goto out; out_ptr += rc; @@ -1537,6 +1491,14 @@ static int format_corename(char *corename, const char *pattern, long signr) goto out; out_ptr += rc; break; + /* core limit size */ + case 'c': + rc = snprintf(out_ptr, out_end - out_ptr, + "%lu", current->signal->rlim[RLIMIT_CORE].rlim_cur); + if (rc > out_end - out_ptr) + goto out; + out_ptr += rc; + break; default: break; } @@ -1551,7 +1513,7 @@ static int format_corename(char *corename, const char *pattern, long signr) if (!ispipe && !pid_in_pattern && (core_uses_pid || atomic_read(¤t->mm->mm_users) != 1)) { rc = snprintf(out_ptr, out_end - out_ptr, - ".%d", current->tgid); + ".%d", task_tgid_vnr(current)); if (rc > out_end - out_ptr) goto out; out_ptr += rc; @@ -1699,7 +1661,6 @@ void set_dumpable(struct mm_struct *mm, int value) break; } } -EXPORT_SYMBOL_GPL(set_dumpable); int get_dumpable(struct mm_struct *mm) { @@ -1720,6 +1681,10 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) int fsuid = current->fsuid; int flag = 0; int ispipe = 0; + unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; + char **helper_argv = NULL; + int helper_argc = 0; + char *delimit; audit_core_dumps(signr); @@ -1753,9 +1718,6 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) */ clear_thread_flag(TIF_SIGPENDING); - if (current->signal->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump) - goto fail_unlock; - /* * lock_kernel() because format_corename() is controlled by sysctl, which * uses lock_kernel() @@ -1763,9 +1725,39 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) lock_kernel(); ispipe = format_corename(corename, core_pattern, signr); unlock_kernel(); + /* + * Don't bother to check the RLIMIT_CORE value if core_pattern points + * to a pipe. Since we're not writing directly to the filesystem + * RLIMIT_CORE doesn't really apply, as no actual core file will be + * created unless the pipe reader choses to write out the core file + * at which point file size limits and permissions will be imposed + * as it does with any other process + */ + if ((!ispipe) && (core_limit < binfmt->min_coredump)) + goto fail_unlock; + if (ispipe) { + helper_argv = argv_split(GFP_KERNEL, corename+1, &helper_argc); + /* Terminate the string before the first option */ + delimit = strchr(corename, ' '); + if (delimit) + *delimit = '\0'; + delimit = strrchr(helper_argv[0], '/'); + if (delimit) + delimit++; + else + delimit = helper_argv[0]; + if (!strcmp(delimit, current->comm)) { + printk(KERN_NOTICE "Recursive core dump detected, " + "aborting\n"); + goto fail_unlock; + } + + core_limit = RLIM_INFINITY; + /* SIGPIPE can happen, but it's just never processed */ - if(call_usermodehelper_pipe(corename+1, NULL, NULL, &file)) { + if (call_usermodehelper_pipe(corename+1, helper_argv, NULL, + &file)) { printk(KERN_INFO "Core dump to %s pipe failed\n", corename); goto fail_unlock; @@ -1793,13 +1785,16 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) if (!ispipe && do_truncate(file->f_path.dentry, 0, 0, file) != 0) goto close_fail; - retval = binfmt->core_dump(signr, regs, file); + retval = binfmt->core_dump(signr, regs, file, core_limit); if (retval) current->signal->group_exit_code |= 0x80; close_fail: filp_close(file, NULL); fail_unlock: + if (helper_argv) + argv_free(helper_argv); + current->fsuid = fsuid; complete_all(&mm->core_done); fail: diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index baf71dd721fa..18a42de25b55 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -69,6 +69,14 @@ struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb, return desc + offset; } +static inline int +block_in_use(unsigned long block, struct super_block *sb, unsigned char *map) +{ + return ext2_test_bit ((block - + le32_to_cpu(EXT2_SB(sb)->s_es->s_first_data_block)) % + EXT2_BLOCKS_PER_GROUP(sb), map); +} + /* * Read the bitmap for a given block_group, reading into the specified * slot in the superblock's bitmap cache. @@ -78,55 +86,51 @@ struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb, static struct buffer_head * read_block_bitmap(struct super_block *sb, unsigned int block_group) { + int i; struct ext2_group_desc * desc; struct buffer_head * bh = NULL; - + unsigned int bitmap_blk; + desc = ext2_get_group_desc (sb, block_group, NULL); if (!desc) - goto error_out; - bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap)); + return NULL; + bitmap_blk = le32_to_cpu(desc->bg_block_bitmap); + bh = sb_bread(sb, bitmap_blk); if (!bh) - ext2_error (sb, "read_block_bitmap", + ext2_error (sb, __FUNCTION__, "Cannot read block bitmap - " "block_group = %d, block_bitmap = %u", block_group, le32_to_cpu(desc->bg_block_bitmap)); -error_out: - return bh; -} - -/* - * Set sb->s_dirt here because the superblock was "logically" altered. We - * need to recalculate its free blocks count and flush it out. - */ -static int reserve_blocks(struct super_block *sb, int count) -{ - struct ext2_sb_info *sbi = EXT2_SB(sb); - struct ext2_super_block *es = sbi->s_es; - unsigned free_blocks; - unsigned root_blocks; - - free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); - root_blocks = le32_to_cpu(es->s_r_blocks_count); - if (free_blocks < count) - count = free_blocks; - - if (free_blocks < root_blocks + count && !capable(CAP_SYS_RESOURCE) && - sbi->s_resuid != current->fsuid && - (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) { - /* - * We are too close to reserve and we are not privileged. - * Can we allocate anything at all? - */ - if (free_blocks > root_blocks) - count = free_blocks - root_blocks; - else - return 0; + /* check whether block bitmap block number is set */ + if (!block_in_use(bitmap_blk, sb, bh->b_data)) { + /* bad block bitmap */ + goto error_out; } + /* check whether the inode bitmap block number is set */ + bitmap_blk = le32_to_cpu(desc->bg_inode_bitmap); + if (!block_in_use(bitmap_blk, sb, bh->b_data)) { + /* bad block bitmap */ + goto error_out; + } + /* check whether the inode table block number is set */ + bitmap_blk = le32_to_cpu(desc->bg_inode_table); + for (i = 0; i < EXT2_SB(sb)->s_itb_per_group; i++, bitmap_blk++) { + if (!block_in_use(bitmap_blk, sb, bh->b_data)) { + /* bad block bitmap */ + goto error_out; + } + } + + return bh; - percpu_counter_mod(&sbi->s_freeblocks_counter, -count); - sb->s_dirt = 1; - return count; +error_out: + brelse(bh); + ext2_error(sb, __FUNCTION__, + "Invalid block bitmap - " + "block_group = %d, block = %u", + block_group, bitmap_blk); + return NULL; } static void release_blocks(struct super_block *sb, int count) @@ -134,30 +138,12 @@ static void release_blocks(struct super_block *sb, int count) if (count) { struct ext2_sb_info *sbi = EXT2_SB(sb); - percpu_counter_mod(&sbi->s_freeblocks_counter, count); + percpu_counter_add(&sbi->s_freeblocks_counter, count); sb->s_dirt = 1; } } -static int group_reserve_blocks(struct ext2_sb_info *sbi, int group_no, - struct ext2_group_desc *desc, struct buffer_head *bh, int count) -{ - unsigned free_blocks; - - if (!desc->bg_free_blocks_count) - return 0; - - spin_lock(sb_bgl_lock(sbi, group_no)); - free_blocks = le16_to_cpu(desc->bg_free_blocks_count); - if (free_blocks < count) - count = free_blocks; - desc->bg_free_blocks_count = cpu_to_le16(free_blocks - count); - spin_unlock(sb_bgl_lock(sbi, group_no)); - mark_buffer_dirty(bh); - return count; -} - -static void group_release_blocks(struct super_block *sb, int group_no, +static void group_adjust_blocks(struct super_block *sb, int group_no, struct ext2_group_desc *desc, struct buffer_head *bh, int count) { if (count) { @@ -173,7 +159,306 @@ static void group_release_blocks(struct super_block *sb, int group_no, } } -/* Free given blocks, update quota and i_blocks field */ +/* + * The reservation window structure operations + * -------------------------------------------- + * Operations include: + * dump, find, add, remove, is_empty, find_next_reservable_window, etc. + * + * We use a red-black tree to represent per-filesystem reservation + * windows. + * + */ + +/** + * __rsv_window_dump() -- Dump the filesystem block allocation reservation map + * @rb_root: root of per-filesystem reservation rb tree + * @verbose: verbose mode + * @fn: function which wishes to dump the reservation map + * + * If verbose is turned on, it will print the whole block reservation + * windows(start, end). Otherwise, it will only print out the "bad" windows, + * those windows that overlap with their immediate neighbors. + */ +#if 1 +static void __rsv_window_dump(struct rb_root *root, int verbose, + const char *fn) +{ + struct rb_node *n; + struct ext2_reserve_window_node *rsv, *prev; + int bad; + +restart: + n = rb_first(root); + bad = 0; + prev = NULL; + + printk("Block Allocation Reservation Windows Map (%s):\n", fn); + while (n) { + rsv = rb_entry(n, struct ext2_reserve_window_node, rsv_node); + if (verbose) + printk("reservation window 0x%p " + "start: %lu, end: %lu\n", + rsv, rsv->rsv_start, rsv->rsv_end); + if (rsv->rsv_start && rsv->rsv_start >= rsv->rsv_end) { + printk("Bad reservation %p (start >= end)\n", + rsv); + bad = 1; + } + if (prev && prev->rsv_end >= rsv->rsv_start) { + printk("Bad reservation %p (prev->end >= start)\n", + rsv); + bad = 1; + } + if (bad) { + if (!verbose) { + printk("Restarting reservation walk in verbose mode\n"); + verbose = 1; + goto restart; + } + } + n = rb_next(n); + prev = rsv; + } + printk("Window map complete.\n"); + if (bad) + BUG(); +} +#define rsv_window_dump(root, verbose) \ + __rsv_window_dump((root), (verbose), __FUNCTION__) +#else +#define rsv_window_dump(root, verbose) do {} while (0) +#endif + +/** + * goal_in_my_reservation() + * @rsv: inode's reservation window + * @grp_goal: given goal block relative to the allocation block group + * @group: the current allocation block group + * @sb: filesystem super block + * + * Test if the given goal block (group relative) is within the file's + * own block reservation window range. + * + * If the reservation window is outside the goal allocation group, return 0; + * grp_goal (given goal block) could be -1, which means no specific + * goal block. In this case, always return 1. + * If the goal block is within the reservation window, return 1; + * otherwise, return 0; + */ +static int +goal_in_my_reservation(struct ext2_reserve_window *rsv, ext2_grpblk_t grp_goal, + unsigned int group, struct super_block * sb) +{ + ext2_fsblk_t group_first_block, group_last_block; + + group_first_block = ext2_group_first_block_no(sb, group); + group_last_block = group_first_block + EXT2_BLOCKS_PER_GROUP(sb) - 1; + + if ((rsv->_rsv_start > group_last_block) || + (rsv->_rsv_end < group_first_block)) + return 0; + if ((grp_goal >= 0) && ((grp_goal + group_first_block < rsv->_rsv_start) + || (grp_goal + group_first_block > rsv->_rsv_end))) + return 0; + return 1; +} + +/** + * search_reserve_window() + * @rb_root: root of reservation tree + * @goal: target allocation block + * + * Find the reserved window which includes the goal, or the previous one + * if the goal is not in any window. + * Returns NULL if there are no windows or if all windows start after the goal. + */ +static struct ext2_reserve_window_node * +search_reserve_window(struct rb_root *root, ext2_fsblk_t goal) +{ + struct rb_node *n = root->rb_node; + struct ext2_reserve_window_node *rsv; + + if (!n) + return NULL; + + do { + rsv = rb_entry(n, struct ext2_reserve_window_node, rsv_node); + + if (goal < rsv->rsv_start) + n = n->rb_left; + else if (goal > rsv->rsv_end) + n = n->rb_right; + else + return rsv; + } while (n); + /* + * We've fallen off the end of the tree: the goal wasn't inside + * any particular node. OK, the previous node must be to one + * side of the interval containing the goal. If it's the RHS, + * we need to back up one. + */ + if (rsv->rsv_start > goal) { + n = rb_prev(&rsv->rsv_node); + rsv = rb_entry(n, struct ext2_reserve_window_node, rsv_node); + } + return rsv; +} + +/* + * ext2_rsv_window_add() -- Insert a window to the block reservation rb tree. + * @sb: super block + * @rsv: reservation window to add + * + * Must be called with rsv_lock held. + */ +void ext2_rsv_window_add(struct super_block *sb, + struct ext2_reserve_window_node *rsv) +{ + struct rb_root *root = &EXT2_SB(sb)->s_rsv_window_root; + struct rb_node *node = &rsv->rsv_node; + ext2_fsblk_t start = rsv->rsv_start; + + struct rb_node ** p = &root->rb_node; + struct rb_node * parent = NULL; + struct ext2_reserve_window_node *this; + + while (*p) + { + parent = *p; + this = rb_entry(parent, struct ext2_reserve_window_node, rsv_node); + + if (start < this->rsv_start) + p = &(*p)->rb_left; + else if (start > this->rsv_end) + p = &(*p)->rb_right; + else { + rsv_window_dump(root, 1); + BUG(); + } + } + + rb_link_node(node, parent, p); + rb_insert_color(node, root); +} + +/** + * rsv_window_remove() -- unlink a window from the reservation rb tree + * @sb: super block + * @rsv: reservation window to remove + * + * Mark the block reservation window as not allocated, and unlink it + * from the filesystem reservation window rb tree. Must be called with + * rsv_lock held. + */ +static void rsv_window_remove(struct super_block *sb, + struct ext2_reserve_window_node *rsv) +{ + rsv->rsv_start = EXT2_RESERVE_WINDOW_NOT_ALLOCATED; + rsv->rsv_end = EXT2_RESERVE_WINDOW_NOT_ALLOCATED; + rsv->rsv_alloc_hit = 0; + rb_erase(&rsv->rsv_node, &EXT2_SB(sb)->s_rsv_window_root); +} + +/* + * rsv_is_empty() -- Check if the reservation window is allocated. + * @rsv: given reservation window to check + * + * returns 1 if the end block is EXT2_RESERVE_WINDOW_NOT_ALLOCATED. + */ +static inline int rsv_is_empty(struct ext2_reserve_window *rsv) +{ + /* a valid reservation end block could not be 0 */ + return (rsv->_rsv_end == EXT2_RESERVE_WINDOW_NOT_ALLOCATED); +} + +/** + * ext2_init_block_alloc_info() + * @inode: file inode structure + * + * Allocate and initialize the reservation window structure, and + * link the window to the ext2 inode structure at last + * + * The reservation window structure is only dynamically allocated + * and linked to ext2 inode the first time the open file + * needs a new block. So, before every ext2_new_block(s) call, for + * regular files, we should check whether the reservation window + * structure exists or not. In the latter case, this function is called. + * Fail to do so will result in block reservation being turned off for that + * open file. + * + * This function is called from ext2_get_blocks_handle(), also called + * when setting the reservation window size through ioctl before the file + * is open for write (needs block allocation). + * + * Needs truncate_mutex protection prior to calling this function. + */ +void ext2_init_block_alloc_info(struct inode *inode) +{ + struct ext2_inode_info *ei = EXT2_I(inode); + struct ext2_block_alloc_info *block_i = ei->i_block_alloc_info; + struct super_block *sb = inode->i_sb; + + block_i = kmalloc(sizeof(*block_i), GFP_NOFS); + if (block_i) { + struct ext2_reserve_window_node *rsv = &block_i->rsv_window_node; + + rsv->rsv_start = EXT2_RESERVE_WINDOW_NOT_ALLOCATED; + rsv->rsv_end = EXT2_RESERVE_WINDOW_NOT_ALLOCATED; + + /* + * if filesystem is mounted with NORESERVATION, the goal + * reservation window size is set to zero to indicate + * block reservation is off + */ + if (!test_opt(sb, RESERVATION)) + rsv->rsv_goal_size = 0; + else + rsv->rsv_goal_size = EXT2_DEFAULT_RESERVE_BLOCKS; + rsv->rsv_alloc_hit = 0; + block_i->last_alloc_logical_block = 0; + block_i->last_alloc_physical_block = 0; + } + ei->i_block_alloc_info = block_i; +} + +/** + * ext2_discard_reservation() + * @inode: inode + * + * Discard(free) block reservation window on last file close, or truncate + * or at last iput(). + * + * It is being called in three cases: + * ext2_release_file(): last writer closes the file + * ext2_clear_inode(): last iput(), when nobody links to this file. + * ext2_truncate(): when the block indirect map is about to change. + */ +void ext2_discard_reservation(struct inode *inode) +{ + struct ext2_inode_info *ei = EXT2_I(inode); + struct ext2_block_alloc_info *block_i = ei->i_block_alloc_info; + struct ext2_reserve_window_node *rsv; + spinlock_t *rsv_lock = &EXT2_SB(inode->i_sb)->s_rsv_window_lock; + + if (!block_i) + return; + + rsv = &block_i->rsv_window_node; + if (!rsv_is_empty(&rsv->rsv_window)) { + spin_lock(rsv_lock); + if (!rsv_is_empty(&rsv->rsv_window)) + rsv_window_remove(inode->i_sb, rsv); + spin_unlock(rsv_lock); + } +} + +/** + * ext2_free_blocks_sb() -- Free given blocks and update quota and i_blocks + * @inode: inode + * @block: start physcial block to free + * @count: number of blocks to free + */ void ext2_free_blocks (struct inode * inode, unsigned long block, unsigned long count) { @@ -248,7 +533,7 @@ do_more: if (sb->s_flags & MS_SYNCHRONOUS) sync_dirty_buffer(bitmap_bh); - group_release_blocks(sb, block_group, desc, bh2, group_freed); + group_adjust_blocks(sb, block_group, desc, bh2, group_freed); freed += group_freed; if (overflow) { @@ -262,16 +547,46 @@ error_return: DQUOT_FREE_BLOCK(inode, freed); } -static int grab_block(spinlock_t *lock, char *map, unsigned size, int goal) +/** + * bitmap_search_next_usable_block() + * @start: the starting block (group relative) of the search + * @bh: bufferhead contains the block group bitmap + * @maxblocks: the ending block (group relative) of the reservation + * + * The bitmap search --- search forward through the actual bitmap on disk until + * we find a bit free. + */ +static ext2_grpblk_t +bitmap_search_next_usable_block(ext2_grpblk_t start, struct buffer_head *bh, + ext2_grpblk_t maxblocks) { - int k; - char *p, *r; + ext2_grpblk_t next; - if (!ext2_test_bit(goal, map)) - goto got_it; + next = ext2_find_next_zero_bit(bh->b_data, maxblocks, start); + if (next >= maxblocks) + return -1; + return next; +} -repeat: - if (goal) { +/** + * find_next_usable_block() + * @start: the starting block (group relative) to find next + * allocatable block in bitmap. + * @bh: bufferhead contains the block group bitmap + * @maxblocks: the ending block (group relative) for the search + * + * Find an allocatable block in a bitmap. We perform the "most + * appropriate allocation" algorithm of looking for a free block near + * the initial goal; then for a free byte somewhere in the bitmap; + * then for any free bit in the bitmap. + */ +static ext2_grpblk_t +find_next_usable_block(int start, struct buffer_head *bh, int maxblocks) +{ + ext2_grpblk_t here, next; + char *p, *r; + + if (start > 0) { /* * The goal was occupied; search forward for a free * block within the next XX blocks. @@ -280,249 +595,812 @@ repeat: * less than EXT2_BLOCKS_PER_GROUP. Aligning up to the * next 64-bit boundary is simple.. */ - k = (goal + 63) & ~63; - goal = ext2_find_next_zero_bit(map, k, goal); - if (goal < k) - goto got_it; + ext2_grpblk_t end_goal = (start + 63) & ~63; + if (end_goal > maxblocks) + end_goal = maxblocks; + here = ext2_find_next_zero_bit(bh->b_data, end_goal, start); + if (here < end_goal) + return here; + ext2_debug("Bit not found near goal\n"); + } + + here = start; + if (here < 0) + here = 0; + + p = ((char *)bh->b_data) + (here >> 3); + r = memscan(p, 0, ((maxblocks + 7) >> 3) - (here >> 3)); + next = (r - ((char *)bh->b_data)) << 3; + + if (next < maxblocks && next >= here) + return next; + + here = bitmap_search_next_usable_block(here, bh, maxblocks); + return here; +} + +/* + * ext2_try_to_allocate() + * @sb: superblock + * @handle: handle to this transaction + * @group: given allocation block group + * @bitmap_bh: bufferhead holds the block bitmap + * @grp_goal: given target block within the group + * @count: target number of blocks to allocate + * @my_rsv: reservation window + * + * Attempt to allocate blocks within a give range. Set the range of allocation + * first, then find the first free bit(s) from the bitmap (within the range), + * and at last, allocate the blocks by claiming the found free bit as allocated. + * + * To set the range of this allocation: + * if there is a reservation window, only try to allocate block(s) + * from the file's own reservation window; + * Otherwise, the allocation range starts from the give goal block, + * ends at the block group's last block. + * + * If we failed to allocate the desired block then we may end up crossing to a + * new bitmap. + */ +static int +ext2_try_to_allocate(struct super_block *sb, int group, + struct buffer_head *bitmap_bh, ext2_grpblk_t grp_goal, + unsigned long *count, + struct ext2_reserve_window *my_rsv) +{ + ext2_fsblk_t group_first_block; + ext2_grpblk_t start, end; + unsigned long num = 0; + + /* we do allocation within the reservation window if we have a window */ + if (my_rsv) { + group_first_block = ext2_group_first_block_no(sb, group); + if (my_rsv->_rsv_start >= group_first_block) + start = my_rsv->_rsv_start - group_first_block; + else + /* reservation window cross group boundary */ + start = 0; + end = my_rsv->_rsv_end - group_first_block + 1; + if (end > EXT2_BLOCKS_PER_GROUP(sb)) + /* reservation window crosses group boundary */ + end = EXT2_BLOCKS_PER_GROUP(sb); + if ((start <= grp_goal) && (grp_goal < end)) + start = grp_goal; + else + grp_goal = -1; + } else { + if (grp_goal > 0) + start = grp_goal; + else + start = 0; + end = EXT2_BLOCKS_PER_GROUP(sb); + } + + BUG_ON(start > EXT2_BLOCKS_PER_GROUP(sb)); + +repeat: + if (grp_goal < 0) { + grp_goal = find_next_usable_block(start, bitmap_bh, end); + if (grp_goal < 0) + goto fail_access; + if (!my_rsv) { + int i; + + for (i = 0; i < 7 && grp_goal > start && + !ext2_test_bit(grp_goal - 1, + bitmap_bh->b_data); + i++, grp_goal--) + ; + } + } + start = grp_goal; + + if (ext2_set_bit_atomic(sb_bgl_lock(EXT2_SB(sb), group), grp_goal, + bitmap_bh->b_data)) { + /* + * The block was allocated by another thread, or it was + * allocated and then freed by another thread + */ + start++; + grp_goal++; + if (start >= end) + goto fail_access; + goto repeat; + } + num++; + grp_goal++; + while (num < *count && grp_goal < end + && !ext2_set_bit_atomic(sb_bgl_lock(EXT2_SB(sb), group), + grp_goal, bitmap_bh->b_data)) { + num++; + grp_goal++; + } + *count = num; + return grp_goal - num; +fail_access: + *count = num; + return -1; +} + +/** + * find_next_reservable_window(): + * find a reservable space within the given range. + * It does not allocate the reservation window for now: + * alloc_new_reservation() will do the work later. + * + * @search_head: the head of the searching list; + * This is not necessarily the list head of the whole filesystem + * + * We have both head and start_block to assist the search + * for the reservable space. The list starts from head, + * but we will shift to the place where start_block is, + * then start from there, when looking for a reservable space. + * + * @size: the target new reservation window size + * + * @group_first_block: the first block we consider to start + * the real search from + * + * @last_block: + * the maximum block number that our goal reservable space + * could start from. This is normally the last block in this + * group. The search will end when we found the start of next + * possible reservable space is out of this boundary. + * This could handle the cross boundary reservation window + * request. + * + * basically we search from the given range, rather than the whole + * reservation double linked list, (start_block, last_block) + * to find a free region that is of my size and has not + * been reserved. + * + */ +static int find_next_reservable_window( + struct ext2_reserve_window_node *search_head, + struct ext2_reserve_window_node *my_rsv, + struct super_block * sb, + ext2_fsblk_t start_block, + ext2_fsblk_t last_block) +{ + struct rb_node *next; + struct ext2_reserve_window_node *rsv, *prev; + ext2_fsblk_t cur; + int size = my_rsv->rsv_goal_size; + + /* TODO: make the start of the reservation window byte-aligned */ + /* cur = *start_block & ~7;*/ + cur = start_block; + rsv = search_head; + if (!rsv) + return -1; + + while (1) { + if (cur <= rsv->rsv_end) + cur = rsv->rsv_end + 1; + + /* TODO? + * in the case we could not find a reservable space + * that is what is expected, during the re-search, we could + * remember what's the largest reservable space we could have + * and return that one. + * + * For now it will fail if we could not find the reservable + * space with expected-size (or more)... + */ + if (cur > last_block) + return -1; /* fail */ + + prev = rsv; + next = rb_next(&rsv->rsv_node); + rsv = rb_entry(next,struct ext2_reserve_window_node,rsv_node); + + /* + * Reached the last reservation, we can just append to the + * previous one. + */ + if (!next) + break; + + if (cur + size <= rsv->rsv_start) { + /* + * Found a reserveable space big enough. We could + * have a reservation across the group boundary here + */ + break; + } + } + /* + * we come here either : + * when we reach the end of the whole list, + * and there is empty reservable space after last entry in the list. + * append it to the end of the list. + * + * or we found one reservable space in the middle of the list, + * return the reservation window that we could append to. + * succeed. + */ + + if ((prev != my_rsv) && (!rsv_is_empty(&my_rsv->rsv_window))) + rsv_window_remove(sb, my_rsv); + + /* + * Let's book the whole avaliable window for now. We will check the + * disk bitmap later and then, if there are free blocks then we adjust + * the window size if it's larger than requested. + * Otherwise, we will remove this node from the tree next time + * call find_next_reservable_window. + */ + my_rsv->rsv_start = cur; + my_rsv->rsv_end = cur + size - 1; + my_rsv->rsv_alloc_hit = 0; + + if (prev != my_rsv) + ext2_rsv_window_add(sb, my_rsv); + + return 0; +} + +/** + * alloc_new_reservation()--allocate a new reservation window + * + * To make a new reservation, we search part of the filesystem + * reservation list (the list that inside the group). We try to + * allocate a new reservation window near the allocation goal, + * or the beginning of the group, if there is no goal. + * + * We first find a reservable space after the goal, then from + * there, we check the bitmap for the first free block after + * it. If there is no free block until the end of group, then the + * whole group is full, we failed. Otherwise, check if the free + * block is inside the expected reservable space, if so, we + * succeed. + * If the first free block is outside the reservable space, then + * start from the first free block, we search for next available + * space, and go on. + * + * on succeed, a new reservation will be found and inserted into the list + * It contains at least one free block, and it does not overlap with other + * reservation windows. + * + * failed: we failed to find a reservation window in this group + * + * @rsv: the reservation + * + * @grp_goal: The goal (group-relative). It is where the search for a + * free reservable space should start from. + * if we have a goal(goal >0 ), then start from there, + * no goal(goal = -1), we start from the first block + * of the group. + * + * @sb: the super block + * @group: the group we are trying to allocate in + * @bitmap_bh: the block group block bitmap + * + */ +static int alloc_new_reservation(struct ext2_reserve_window_node *my_rsv, + ext2_grpblk_t grp_goal, struct super_block *sb, + unsigned int group, struct buffer_head *bitmap_bh) +{ + struct ext2_reserve_window_node *search_head; + ext2_fsblk_t group_first_block, group_end_block, start_block; + ext2_grpblk_t first_free_block; + struct rb_root *fs_rsv_root = &EXT2_SB(sb)->s_rsv_window_root; + unsigned long size; + int ret; + spinlock_t *rsv_lock = &EXT2_SB(sb)->s_rsv_window_lock; + + group_first_block = ext2_group_first_block_no(sb, group); + group_end_block = group_first_block + (EXT2_BLOCKS_PER_GROUP(sb) - 1); + + if (grp_goal < 0) + start_block = group_first_block; + else + start_block = grp_goal + group_first_block; + + size = my_rsv->rsv_goal_size; + + if (!rsv_is_empty(&my_rsv->rsv_window)) { /* - * Search in the remainder of the current group. + * if the old reservation is cross group boundary + * and if the goal is inside the old reservation window, + * we will come here when we just failed to allocate from + * the first part of the window. We still have another part + * that belongs to the next group. In this case, there is no + * point to discard our window and try to allocate a new one + * in this group(which will fail). we should + * keep the reservation window, just simply move on. + * + * Maybe we could shift the start block of the reservation + * window to the first block of next group. */ + + if ((my_rsv->rsv_start <= group_end_block) && + (my_rsv->rsv_end > group_end_block) && + (start_block >= my_rsv->rsv_start)) + return -1; + + if ((my_rsv->rsv_alloc_hit > + (my_rsv->rsv_end - my_rsv->rsv_start + 1) / 2)) { + /* + * if the previously allocation hit ratio is + * greater than 1/2, then we double the size of + * the reservation window the next time, + * otherwise we keep the same size window + */ + size = size * 2; + if (size > EXT2_MAX_RESERVE_BLOCKS) + size = EXT2_MAX_RESERVE_BLOCKS; + my_rsv->rsv_goal_size= size; + } } - p = map + (goal >> 3); - r = memscan(p, 0, (size - goal + 7) >> 3); - k = (r - map) << 3; - if (k < size) { - /* - * We have succeeded in finding a free byte in the block - * bitmap. Now search backwards to find the start of this - * group of free blocks - won't take more than 7 iterations. + spin_lock(rsv_lock); + /* + * shift the search start to the window near the goal block + */ + search_head = search_reserve_window(fs_rsv_root, start_block); + + /* + * find_next_reservable_window() simply finds a reservable window + * inside the given range(start_block, group_end_block). + * + * To make sure the reservation window has a free bit inside it, we + * need to check the bitmap after we found a reservable window. + */ +retry: + ret = find_next_reservable_window(search_head, my_rsv, sb, + start_block, group_end_block); + + if (ret == -1) { + if (!rsv_is_empty(&my_rsv->rsv_window)) + rsv_window_remove(sb, my_rsv); + spin_unlock(rsv_lock); + return -1; + } + + /* + * On success, find_next_reservable_window() returns the + * reservation window where there is a reservable space after it. + * Before we reserve this reservable space, we need + * to make sure there is at least a free block inside this region. + * + * Search the first free bit on the block bitmap. Search starts from + * the start block of the reservable space we just found. + */ + spin_unlock(rsv_lock); + first_free_block = bitmap_search_next_usable_block( + my_rsv->rsv_start - group_first_block, + bitmap_bh, group_end_block - group_first_block + 1); + + if (first_free_block < 0) { + /* + * no free block left on the bitmap, no point + * to reserve the space. return failed. */ - for (goal = k; goal && !ext2_test_bit (goal - 1, map); goal--) - ; - goto got_it; + spin_lock(rsv_lock); + if (!rsv_is_empty(&my_rsv->rsv_window)) + rsv_window_remove(sb, my_rsv); + spin_unlock(rsv_lock); + return -1; /* failed */ } - k = ext2_find_next_zero_bit ((u32 *)map, size, goal); - if (k < size) { - goal = k; - goto got_it; + start_block = first_free_block + group_first_block; + /* + * check if the first free block is within the + * free space we just reserved + */ + if (start_block >= my_rsv->rsv_start && start_block <= my_rsv->rsv_end) + return 0; /* success */ + /* + * if the first free bit we found is out of the reservable space + * continue search for next reservable space, + * start from where the free block is, + * we also shift the list head to where we stopped last time + */ + search_head = my_rsv; + spin_lock(rsv_lock); + goto retry; +} + +/** + * try_to_extend_reservation() + * @my_rsv: given reservation window + * @sb: super block + * @size: the delta to extend + * + * Attempt to expand the reservation window large enough to have + * required number of free blocks + * + * Since ext2_try_to_allocate() will always allocate blocks within + * the reservation window range, if the window size is too small, + * multiple blocks allocation has to stop at the end of the reservation + * window. To make this more efficient, given the total number of + * blocks needed and the current size of the window, we try to + * expand the reservation window size if necessary on a best-effort + * basis before ext2_new_blocks() tries to allocate blocks. + */ +static void try_to_extend_reservation(struct ext2_reserve_window_node *my_rsv, + struct super_block *sb, int size) +{ + struct ext2_reserve_window_node *next_rsv; + struct rb_node *next; + spinlock_t *rsv_lock = &EXT2_SB(sb)->s_rsv_window_lock; + + if (!spin_trylock(rsv_lock)) + return; + + next = rb_next(&my_rsv->rsv_node); + + if (!next) + my_rsv->rsv_end += size; + else { + next_rsv = rb_entry(next, struct ext2_reserve_window_node, rsv_node); + + if ((next_rsv->rsv_start - my_rsv->rsv_end - 1) >= size) + my_rsv->rsv_end += size; + else + my_rsv->rsv_end = next_rsv->rsv_start - 1; } - return -1; -got_it: - if (ext2_set_bit_atomic(lock, goal, (void *) map)) - goto repeat; - return goal; + spin_unlock(rsv_lock); +} + +/** + * ext2_try_to_allocate_with_rsv() + * @sb: superblock + * @group: given allocation block group + * @bitmap_bh: bufferhead holds the block bitmap + * @grp_goal: given target block within the group + * @count: target number of blocks to allocate + * @my_rsv: reservation window + * + * This is the main function used to allocate a new block and its reservation + * window. + * + * Each time when a new block allocation is need, first try to allocate from + * its own reservation. If it does not have a reservation window, instead of + * looking for a free bit on bitmap first, then look up the reservation list to + * see if it is inside somebody else's reservation window, we try to allocate a + * reservation window for it starting from the goal first. Then do the block + * allocation within the reservation window. + * + * This will avoid keeping on searching the reservation list again and + * again when somebody is looking for a free block (without + * reservation), and there are lots of free blocks, but they are all + * being reserved. + * + * We use a red-black tree for the per-filesystem reservation list. + */ +static ext2_grpblk_t +ext2_try_to_allocate_with_rsv(struct super_block *sb, unsigned int group, + struct buffer_head *bitmap_bh, ext2_grpblk_t grp_goal, + struct ext2_reserve_window_node * my_rsv, + unsigned long *count) +{ + ext2_fsblk_t group_first_block, group_last_block; + ext2_grpblk_t ret = 0; + unsigned long num = *count; + + /* + * we don't deal with reservation when + * filesystem is mounted without reservation + * or the file is not a regular file + * or last attempt to allocate a block with reservation turned on failed + */ + if (my_rsv == NULL) { + return ext2_try_to_allocate(sb, group, bitmap_bh, + grp_goal, count, NULL); + } + /* + * grp_goal is a group relative block number (if there is a goal) + * 0 <= grp_goal < EXT2_BLOCKS_PER_GROUP(sb) + * first block is a filesystem wide block number + * first block is the block number of the first block in this group + */ + group_first_block = ext2_group_first_block_no(sb, group); + group_last_block = group_first_block + (EXT2_BLOCKS_PER_GROUP(sb) - 1); + + /* + * Basically we will allocate a new block from inode's reservation + * window. + * + * We need to allocate a new reservation window, if: + * a) inode does not have a reservation window; or + * b) last attempt to allocate a block from existing reservation + * failed; or + * c) we come here with a goal and with a reservation window + * + * We do not need to allocate a new reservation window if we come here + * at the beginning with a goal and the goal is inside the window, or + * we don't have a goal but already have a reservation window. + * then we could go to allocate from the reservation window directly. + */ + while (1) { + if (rsv_is_empty(&my_rsv->rsv_window) || (ret < 0) || + !goal_in_my_reservation(&my_rsv->rsv_window, + grp_goal, group, sb)) { + if (my_rsv->rsv_goal_size < *count) + my_rsv->rsv_goal_size = *count; + ret = alloc_new_reservation(my_rsv, grp_goal, sb, + group, bitmap_bh); + if (ret < 0) + break; /* failed */ + + if (!goal_in_my_reservation(&my_rsv->rsv_window, + grp_goal, group, sb)) + grp_goal = -1; + } else if (grp_goal >= 0) { + int curr = my_rsv->rsv_end - + (grp_goal + group_first_block) + 1; + + if (curr < *count) + try_to_extend_reservation(my_rsv, sb, + *count - curr); + } + + if ((my_rsv->rsv_start > group_last_block) || + (my_rsv->rsv_end < group_first_block)) { + rsv_window_dump(&EXT2_SB(sb)->s_rsv_window_root, 1); + BUG(); + } + ret = ext2_try_to_allocate(sb, group, bitmap_bh, grp_goal, + &num, &my_rsv->rsv_window); + if (ret >= 0) { + my_rsv->rsv_alloc_hit += num; + *count = num; + break; /* succeed */ + } + num = *count; + } + return ret; +} + +/** + * ext2_has_free_blocks() + * @sbi: in-core super block structure. + * + * Check if filesystem has at least 1 free block available for allocation. + */ +static int ext2_has_free_blocks(struct ext2_sb_info *sbi) +{ + ext2_fsblk_t free_blocks, root_blocks; + + free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); + root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count); + if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) && + sbi->s_resuid != current->fsuid && + (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) { + return 0; + } + return 1; } /* - * ext2_new_block uses a goal block to assist allocation. If the goal is + * ext2_new_blocks() -- core block(s) allocation function + * @inode: file inode + * @goal: given target block(filesystem wide) + * @count: target number of blocks to allocate + * @errp: error code + * + * ext2_new_blocks uses a goal block to assist allocation. If the goal is * free, or there is a free block within 32 blocks of the goal, that block * is allocated. Otherwise a forward search is made for a free block; within * each block group the search first looks for an entire free byte in the block * bitmap, and then for any free bit if that fails. * This function also updates quota and i_blocks field. */ -int ext2_new_block(struct inode *inode, unsigned long goal, - u32 *prealloc_count, u32 *prealloc_block, int *err) +ext2_fsblk_t ext2_new_blocks(struct inode *inode, ext2_fsblk_t goal, + unsigned long *count, int *errp) { struct buffer_head *bitmap_bh = NULL; - struct buffer_head *gdp_bh; /* bh2 */ - struct ext2_group_desc *desc; - int group_no; /* i */ - int ret_block; /* j */ - int group_idx; /* k */ - int target_block; /* tmp */ - int block = 0; - struct super_block *sb = inode->i_sb; - struct ext2_sb_info *sbi = EXT2_SB(sb); - struct ext2_super_block *es = sbi->s_es; - unsigned group_size = EXT2_BLOCKS_PER_GROUP(sb); - unsigned prealloc_goal = es->s_prealloc_blocks; - unsigned group_alloc = 0, es_alloc, dq_alloc; - int nr_scanned_groups; - - if (!prealloc_goal--) - prealloc_goal = EXT2_DEFAULT_PREALLOC_BLOCKS - 1; - if (!prealloc_count || *prealloc_count) - prealloc_goal = 0; - - if (DQUOT_ALLOC_BLOCK(inode, 1)) { - *err = -EDQUOT; - goto out; + struct buffer_head *gdp_bh; + int group_no; + int goal_group; + ext2_grpblk_t grp_target_blk; /* blockgroup relative goal block */ + ext2_grpblk_t grp_alloc_blk; /* blockgroup-relative allocated block*/ + ext2_fsblk_t ret_block; /* filesyetem-wide allocated block */ + int bgi; /* blockgroup iteration index */ + int performed_allocation = 0; + ext2_grpblk_t free_blocks; /* number of free blocks in a group */ + struct super_block *sb; + struct ext2_group_desc *gdp; + struct ext2_super_block *es; + struct ext2_sb_info *sbi; + struct ext2_reserve_window_node *my_rsv = NULL; + struct ext2_block_alloc_info *block_i; + unsigned short windowsz = 0; + unsigned long ngroups; + unsigned long num = *count; + + *errp = -ENOSPC; + sb = inode->i_sb; + if (!sb) { + printk("ext2_new_blocks: nonexistent device"); + return 0; } - while (prealloc_goal && DQUOT_PREALLOC_BLOCK(inode, prealloc_goal)) - prealloc_goal--; + /* + * Check quota for allocation of this block. + */ + if (DQUOT_ALLOC_BLOCK(inode, num)) { + *errp = -EDQUOT; + return 0; + } - dq_alloc = prealloc_goal + 1; - es_alloc = reserve_blocks(sb, dq_alloc); - if (!es_alloc) { - *err = -ENOSPC; - goto out_dquot; + sbi = EXT2_SB(sb); + es = EXT2_SB(sb)->s_es; + ext2_debug("goal=%lu.\n", goal); + /* + * Allocate a block from reservation only when + * filesystem is mounted with reservation(default,-o reservation), and + * it's a regular file, and + * the desired window size is greater than 0 (One could use ioctl + * command EXT2_IOC_SETRSVSZ to set the window size to 0 to turn off + * reservation on that particular file) + */ + block_i = EXT2_I(inode)->i_block_alloc_info; + if (block_i) { + windowsz = block_i->rsv_window_node.rsv_goal_size; + if (windowsz > 0) + my_rsv = &block_i->rsv_window_node; } - ext2_debug ("goal=%lu.\n", goal); + if (!ext2_has_free_blocks(sbi)) { + *errp = -ENOSPC; + goto out; + } + /* + * First, test whether the goal block is free. + */ if (goal < le32_to_cpu(es->s_first_data_block) || goal >= le32_to_cpu(es->s_blocks_count)) goal = le32_to_cpu(es->s_first_data_block); - group_no = (goal - le32_to_cpu(es->s_first_data_block)) / group_size; - desc = ext2_get_group_desc (sb, group_no, &gdp_bh); - if (!desc) { - /* - * gdp_bh may still be uninitialised. But group_release_blocks - * will not touch it because group_alloc is zero. - */ + group_no = (goal - le32_to_cpu(es->s_first_data_block)) / + EXT2_BLOCKS_PER_GROUP(sb); + goal_group = group_no; +retry_alloc: + gdp = ext2_get_group_desc(sb, group_no, &gdp_bh); + if (!gdp) goto io_error; - } - group_alloc = group_reserve_blocks(sbi, group_no, desc, - gdp_bh, es_alloc); - if (group_alloc) { - ret_block = ((goal - le32_to_cpu(es->s_first_data_block)) % - group_size); - brelse(bitmap_bh); + free_blocks = le16_to_cpu(gdp->bg_free_blocks_count); + /* + * if there is not enough free blocks to make a new resevation + * turn off reservation for this allocation + */ + if (my_rsv && (free_blocks < windowsz) + && (rsv_is_empty(&my_rsv->rsv_window))) + my_rsv = NULL; + + if (free_blocks > 0) { + grp_target_blk = ((goal - le32_to_cpu(es->s_first_data_block)) % + EXT2_BLOCKS_PER_GROUP(sb)); bitmap_bh = read_block_bitmap(sb, group_no); if (!bitmap_bh) goto io_error; - - ext2_debug("goal is at %d:%d.\n", group_no, ret_block); - - ret_block = grab_block(sb_bgl_lock(sbi, group_no), - bitmap_bh->b_data, group_size, ret_block); - if (ret_block >= 0) - goto got_block; - group_release_blocks(sb, group_no, desc, gdp_bh, group_alloc); - group_alloc = 0; + grp_alloc_blk = ext2_try_to_allocate_with_rsv(sb, group_no, + bitmap_bh, grp_target_blk, + my_rsv, &num); + if (grp_alloc_blk >= 0) + goto allocated; } - ext2_debug ("Bit not found in block group %d.\n", group_no); + ngroups = EXT2_SB(sb)->s_groups_count; + smp_rmb(); /* * Now search the rest of the groups. We assume that - * i and desc correctly point to the last group visited. + * i and gdp correctly point to the last group visited. */ - nr_scanned_groups = 0; -retry: - for (group_idx = 0; !group_alloc && - group_idx < sbi->s_groups_count; group_idx++) { + for (bgi = 0; bgi < ngroups; bgi++) { group_no++; - if (group_no >= sbi->s_groups_count) + if (group_no >= ngroups) group_no = 0; - desc = ext2_get_group_desc(sb, group_no, &gdp_bh); - if (!desc) + gdp = ext2_get_group_desc(sb, group_no, &gdp_bh); + if (!gdp) goto io_error; - group_alloc = group_reserve_blocks(sbi, group_no, desc, - gdp_bh, es_alloc); - } - if (!group_alloc) { - *err = -ENOSPC; - goto out_release; - } - brelse(bitmap_bh); - bitmap_bh = read_block_bitmap(sb, group_no); - if (!bitmap_bh) - goto io_error; - ret_block = grab_block(sb_bgl_lock(sbi, group_no), bitmap_bh->b_data, - group_size, 0); - if (ret_block < 0) { + free_blocks = le16_to_cpu(gdp->bg_free_blocks_count); /* - * If a free block counter is corrupted we can loop inifintely. - * Detect that here. + * skip this group if the number of + * free blocks is less than half of the reservation + * window size. */ - nr_scanned_groups++; - if (nr_scanned_groups > 2 * sbi->s_groups_count) { - ext2_error(sb, "ext2_new_block", - "corrupted free blocks counters"); + if (free_blocks <= (windowsz/2)) + continue; + + brelse(bitmap_bh); + bitmap_bh = read_block_bitmap(sb, group_no); + if (!bitmap_bh) goto io_error; - } /* - * Someone else grabbed the last free block in this blockgroup - * before us. Retry the scan. + * try to allocate block(s) from this group, without a goal(-1). */ - group_release_blocks(sb, group_no, desc, gdp_bh, group_alloc); - group_alloc = 0; - goto retry; + grp_alloc_blk = ext2_try_to_allocate_with_rsv(sb, group_no, + bitmap_bh, -1, my_rsv, &num); + if (grp_alloc_blk >= 0) + goto allocated; + } + /* + * We may end up a bogus ealier ENOSPC error due to + * filesystem is "full" of reservations, but + * there maybe indeed free blocks avaliable on disk + * In this case, we just forget about the reservations + * just do block allocation as without reservations. + */ + if (my_rsv) { + my_rsv = NULL; + windowsz = 0; + group_no = goal_group; + goto retry_alloc; } + /* No space left on the device */ + *errp = -ENOSPC; + goto out; + +allocated: -got_block: ext2_debug("using block group %d(%d)\n", - group_no, desc->bg_free_blocks_count); + group_no, gdp->bg_free_blocks_count); - target_block = ret_block + group_no * group_size + - le32_to_cpu(es->s_first_data_block); + ret_block = grp_alloc_blk + ext2_group_first_block_no(sb, group_no); - if (target_block == le32_to_cpu(desc->bg_block_bitmap) || - target_block == le32_to_cpu(desc->bg_inode_bitmap) || - in_range(target_block, le32_to_cpu(desc->bg_inode_table), - sbi->s_itb_per_group)) - ext2_error (sb, "ext2_new_block", + if (in_range(le32_to_cpu(gdp->bg_block_bitmap), ret_block, num) || + in_range(le32_to_cpu(gdp->bg_inode_bitmap), ret_block, num) || + in_range(ret_block, le32_to_cpu(gdp->bg_inode_table), + EXT2_SB(sb)->s_itb_per_group) || + in_range(ret_block + num - 1, le32_to_cpu(gdp->bg_inode_table), + EXT2_SB(sb)->s_itb_per_group)) + ext2_error(sb, "ext2_new_blocks", "Allocating block in system zone - " - "block = %u", target_block); + "blocks from "E2FSBLK", length %lu", + ret_block, num); + + performed_allocation = 1; - if (target_block >= le32_to_cpu(es->s_blocks_count)) { - ext2_error (sb, "ext2_new_block", - "block(%d) >= blocks count(%d) - " + if (ret_block + num - 1 >= le32_to_cpu(es->s_blocks_count)) { + ext2_error(sb, "ext2_new_blocks", + "block("E2FSBLK") >= blocks count(%d) - " "block_group = %d, es == %p ", ret_block, le32_to_cpu(es->s_blocks_count), group_no, es); - goto io_error; + goto out; } - block = target_block; - /* OK, we _had_ allocated something */ - ext2_debug("found bit %d\n", ret_block); - - dq_alloc--; - es_alloc--; - group_alloc--; - - /* - * Do block preallocation now if required. - */ - write_lock(&EXT2_I(inode)->i_meta_lock); - if (group_alloc && !*prealloc_count) { - unsigned n; - - for (n = 0; n < group_alloc && ++ret_block < group_size; n++) { - if (ext2_set_bit_atomic(sb_bgl_lock(sbi, group_no), - ret_block, - (void*) bitmap_bh->b_data)) - break; - } - *prealloc_block = block + 1; - *prealloc_count = n; - es_alloc -= n; - dq_alloc -= n; - group_alloc -= n; - } - write_unlock(&EXT2_I(inode)->i_meta_lock); + group_adjust_blocks(sb, group_no, gdp, gdp_bh, -num); + percpu_counter_sub(&sbi->s_freeblocks_counter, num); mark_buffer_dirty(bitmap_bh); if (sb->s_flags & MS_SYNCHRONOUS) sync_dirty_buffer(bitmap_bh); - ext2_debug ("allocating block %d. ", block); + *errp = 0; + brelse(bitmap_bh); + DQUOT_FREE_BLOCK(inode, *count-num); + *count = num; + return ret_block; - *err = 0; -out_release: - group_release_blocks(sb, group_no, desc, gdp_bh, group_alloc); - release_blocks(sb, es_alloc); -out_dquot: - DQUOT_FREE_BLOCK(inode, dq_alloc); +io_error: + *errp = -EIO; out: + /* + * Undo the block allocation + */ + if (!performed_allocation) + DQUOT_FREE_BLOCK(inode, *count); brelse(bitmap_bh); - return block; + return 0; +} -io_error: - *err = -EIO; - goto out_release; +ext2_fsblk_t ext2_new_block(struct inode *inode, unsigned long goal, int *errp) +{ + unsigned long count = 1; + + return ext2_new_blocks(inode, goal, &count, errp); } #ifdef EXT2FS_DEBUG -static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}; +static const int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}; unsigned long ext2_count_free (struct buffer_head * map, unsigned int numchars) { @@ -583,13 +1461,6 @@ unsigned long ext2_count_free_blocks (struct super_block * sb) #endif } -static inline int -block_in_use(unsigned long block, struct super_block *sb, unsigned char *map) -{ - return ext2_test_bit ((block - - le32_to_cpu(EXT2_SB(sb)->s_es->s_first_data_block)) % - EXT2_BLOCKS_PER_GROUP(sb), map); -} static inline int test_root(int a, int b) { diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index 2bf49d7ef841..05d9342bb64e 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -22,7 +22,9 @@ */ #include "ext2.h" +#include <linux/buffer_head.h> #include <linux/pagemap.h> +#include <linux/swap.h> typedef struct ext2_dir_entry_2 ext2_dirent; @@ -61,16 +63,25 @@ ext2_last_byte(struct inode *inode, unsigned long page_nr) return last_byte; } -static int ext2_commit_chunk(struct page *page, unsigned from, unsigned to) +static int ext2_commit_chunk(struct page *page, loff_t pos, unsigned len) { - struct inode *dir = page->mapping->host; + struct address_space *mapping = page->mapping; + struct inode *dir = mapping->host; int err = 0; + dir->i_version++; - page->mapping->a_ops->commit_write(NULL, page, from, to); + block_write_end(NULL, mapping, pos, len, len, page, NULL); + + if (pos+len > dir->i_size) { + i_size_write(dir, pos+len); + mark_inode_dirty(dir); + } + if (IS_DIRSYNC(dir)) err = write_one_page(page, 1); else unlock_page(page); + return err; } @@ -412,16 +423,18 @@ ino_t ext2_inode_by_name(struct inode * dir, struct dentry *dentry) void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de, struct page *page, struct inode *inode) { - unsigned from = (char *) de - (char *) page_address(page); - unsigned to = from + le16_to_cpu(de->rec_len); + loff_t pos = page_offset(page) + + (char *) de - (char *) page_address(page); + unsigned len = le16_to_cpu(de->rec_len); int err; lock_page(page); - err = page->mapping->a_ops->prepare_write(NULL, page, from, to); + err = __ext2_write_begin(NULL, page->mapping, pos, len, + AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); BUG_ON(err); de->inode = cpu_to_le32(inode->i_ino); - ext2_set_de_type (de, inode); - err = ext2_commit_chunk(page, from, to); + ext2_set_de_type(de, inode); + err = ext2_commit_chunk(page, pos, len); ext2_put_page(page); dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL; @@ -444,7 +457,7 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode) unsigned long npages = dir_pages(dir); unsigned long n; char *kaddr; - unsigned from, to; + loff_t pos; int err; /* @@ -497,9 +510,10 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode) return -EINVAL; got_it: - from = (char*)de - (char*)page_address(page); - to = from + rec_len; - err = page->mapping->a_ops->prepare_write(NULL, page, from, to); + pos = page_offset(page) + + (char*)de - (char*)page_address(page); + err = __ext2_write_begin(NULL, page->mapping, pos, rec_len, 0, + &page, NULL); if (err) goto out_unlock; if (de->inode) { @@ -509,10 +523,10 @@ got_it: de = de1; } de->name_len = namelen; - memcpy (de->name, name, namelen); + memcpy(de->name, name, namelen); de->inode = cpu_to_le32(inode->i_ino); ext2_set_de_type (de, inode); - err = ext2_commit_chunk(page, from, to); + err = ext2_commit_chunk(page, pos, rec_len); dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL; mark_inode_dirty(dir); @@ -537,6 +551,7 @@ int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page ) char *kaddr = page_address(page); unsigned from = ((char*)dir - kaddr) & ~(ext2_chunk_size(inode)-1); unsigned to = ((char*)dir - kaddr) + le16_to_cpu(dir->rec_len); + loff_t pos; ext2_dirent * pde = NULL; ext2_dirent * de = (ext2_dirent *) (kaddr + from); int err; @@ -553,13 +568,15 @@ int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page ) } if (pde) from = (char*)pde - (char*)page_address(page); + pos = page_offset(page) + from; lock_page(page); - err = mapping->a_ops->prepare_write(NULL, page, from, to); + err = __ext2_write_begin(NULL, page->mapping, pos, to - from, 0, + &page, NULL); BUG_ON(err); if (pde) - pde->rec_len = cpu_to_le16(to-from); + pde->rec_len = cpu_to_le16(to - from); dir->inode = 0; - err = ext2_commit_chunk(page, from, to); + err = ext2_commit_chunk(page, pos, to - from); inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; EXT2_I(inode)->i_flags &= ~EXT2_BTREE_FL; mark_inode_dirty(inode); @@ -582,7 +599,9 @@ int ext2_make_empty(struct inode *inode, struct inode *parent) if (!page) return -ENOMEM; - err = mapping->a_ops->prepare_write(NULL, page, 0, chunk_size); + + err = __ext2_write_begin(NULL, page->mapping, 0, chunk_size, 0, + &page, NULL); if (err) { unlock_page(page); goto fail; diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index 9fd0ec5ba0d0..7730388c4931 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h @@ -33,22 +33,9 @@ struct ext2_inode_info { */ __u32 i_block_group; - /* - * i_next_alloc_block is the logical (file-relative) number of the - * most-recently-allocated block in this file. Yes, it is misnamed. - * We use this for detecting linearly ascending allocation requests. - */ - __u32 i_next_alloc_block; + /* block reservation info */ + struct ext2_block_alloc_info *i_block_alloc_info; - /* - * i_next_alloc_goal is the *physical* companion to i_next_alloc_block. - * it the the physical block number of the block which was most-recently - * allocated to this file. This give us the goal (target) for the next - * allocation when we detect linearly ascending requests. - */ - __u32 i_next_alloc_goal; - __u32 i_prealloc_block; - __u32 i_prealloc_count; __u32 i_dir_start_lookup; #ifdef CONFIG_EXT2_FS_XATTR /* @@ -65,7 +52,16 @@ struct ext2_inode_info { struct posix_acl *i_default_acl; #endif rwlock_t i_meta_lock; + + /* + * truncate_mutex is for serialising ext2_truncate() against + * ext2_getblock(). It also protects the internals of the inode's + * reservation data structures: ext2_reserve_window and + * ext2_reserve_window_node. + */ + struct mutex truncate_mutex; struct inode vfs_inode; + struct list_head i_orphan; /* unlinked but open inodes */ }; /* @@ -91,8 +87,9 @@ static inline struct ext2_inode_info *EXT2_I(struct inode *inode) /* balloc.c */ extern int ext2_bg_has_super(struct super_block *sb, int group); extern unsigned long ext2_bg_num_gdb(struct super_block *sb, int group); -extern int ext2_new_block (struct inode *, unsigned long, - __u32 *, __u32 *, int *); +extern ext2_fsblk_t ext2_new_block(struct inode *, unsigned long, int *); +extern ext2_fsblk_t ext2_new_blocks(struct inode *, unsigned long, + unsigned long *, int *); extern void ext2_free_blocks (struct inode *, unsigned long, unsigned long); extern unsigned long ext2_count_free_blocks (struct super_block *); @@ -101,6 +98,10 @@ extern void ext2_check_blocks_bitmap (struct super_block *); extern struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb, unsigned int block_group, struct buffer_head ** bh); +extern void ext2_discard_reservation (struct inode *); +extern int ext2_should_retry_alloc(struct super_block *sb, int *retries); +extern void ext2_init_block_alloc_info(struct inode *); +extern void ext2_rsv_window_add(struct super_block *sb, struct ext2_reserve_window_node *rsv); /* dir.c */ extern int ext2_add_link (struct dentry *, struct inode *); @@ -128,12 +129,14 @@ extern int ext2_write_inode (struct inode *, int); extern void ext2_put_inode (struct inode *); extern void ext2_delete_inode (struct inode *); extern int ext2_sync_inode (struct inode *); -extern void ext2_discard_prealloc (struct inode *); extern int ext2_get_block(struct inode *, sector_t, struct buffer_head *, int); extern void ext2_truncate (struct inode *); extern int ext2_setattr (struct dentry *, struct iattr *); extern void ext2_set_inode_flags(struct inode *inode); extern void ext2_get_inode_flags(struct ext2_inode_info *); +int __ext2_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata); /* ioctl.c */ extern int ext2_ioctl (struct inode *, struct file *, unsigned int, diff --git a/fs/ext2/file.c b/fs/ext2/file.c index ab7961260c49..c051798459a1 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -30,8 +30,11 @@ */ static int ext2_release_file (struct inode * inode, struct file * filp) { - if (filp->f_mode & FMODE_WRITE) - ext2_discard_prealloc (inode); + if (filp->f_mode & FMODE_WRITE) { + mutex_lock(&EXT2_I(inode)->truncate_mutex); + ext2_discard_reservation(inode); + mutex_unlock(&EXT2_I(inode)->truncate_mutex); + } return 0; } diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index 2cb545bf0f3c..5deb8b74e649 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c @@ -177,7 +177,6 @@ static void ext2_preread_inode(struct inode *inode) unsigned long block_group; unsigned long offset; unsigned long block; - struct buffer_head *bh; struct ext2_group_desc * gdp; struct backing_dev_info *bdi; @@ -188,7 +187,7 @@ static void ext2_preread_inode(struct inode *inode) return; block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(inode->i_sb); - gdp = ext2_get_group_desc(inode->i_sb, block_group, &bh); + gdp = ext2_get_group_desc(inode->i_sb, block_group, NULL); if (gdp == NULL) return; @@ -217,11 +216,10 @@ static int find_group_dir(struct super_block *sb, struct inode *parent) int ngroups = EXT2_SB(sb)->s_groups_count; int avefreei = ext2_count_free_inodes(sb) / ngroups; struct ext2_group_desc *desc, *best_desc = NULL; - struct buffer_head *bh, *best_bh = NULL; int group, best_group = -1; for (group = 0; group < ngroups; group++) { - desc = ext2_get_group_desc (sb, group, &bh); + desc = ext2_get_group_desc (sb, group, NULL); if (!desc || !desc->bg_free_inodes_count) continue; if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei) @@ -231,7 +229,6 @@ static int find_group_dir(struct super_block *sb, struct inode *parent) le16_to_cpu(best_desc->bg_free_blocks_count))) { best_group = group; best_desc = desc; - best_bh = bh; } } if (!best_desc) @@ -284,7 +281,6 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) int max_debt, max_dirs, min_blocks, min_inodes; int group = -1, i; struct ext2_group_desc *desc; - struct buffer_head *bh; freei = percpu_counter_read_positive(&sbi->s_freeinodes_counter); avefreei = freei / ngroups; @@ -295,7 +291,6 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) if ((parent == sb->s_root->d_inode) || (EXT2_I(parent)->i_flags & EXT2_TOPDIR_FL)) { struct ext2_group_desc *best_desc = NULL; - struct buffer_head *best_bh = NULL; int best_ndir = inodes_per_group; int best_group = -1; @@ -303,7 +298,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) parent_group = (unsigned)group % ngroups; for (i = 0; i < ngroups; i++) { group = (parent_group + i) % ngroups; - desc = ext2_get_group_desc (sb, group, &bh); + desc = ext2_get_group_desc (sb, group, NULL); if (!desc || !desc->bg_free_inodes_count) continue; if (le16_to_cpu(desc->bg_used_dirs_count) >= best_ndir) @@ -315,11 +310,9 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) best_group = group; best_ndir = le16_to_cpu(desc->bg_used_dirs_count); best_desc = desc; - best_bh = bh; } if (best_group >= 0) { desc = best_desc; - bh = best_bh; group = best_group; goto found; } @@ -345,7 +338,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) for (i = 0; i < ngroups; i++) { group = (parent_group + i) % ngroups; - desc = ext2_get_group_desc (sb, group, &bh); + desc = ext2_get_group_desc (sb, group, NULL); if (!desc || !desc->bg_free_inodes_count) continue; if (sbi->s_debts[group] >= max_debt) @@ -362,7 +355,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) fallback: for (i = 0; i < ngroups; i++) { group = (parent_group + i) % ngroups; - desc = ext2_get_group_desc (sb, group, &bh); + desc = ext2_get_group_desc (sb, group, NULL); if (!desc || !desc->bg_free_inodes_count) continue; if (le16_to_cpu(desc->bg_free_inodes_count) >= avefreei) @@ -389,14 +382,13 @@ static int find_group_other(struct super_block *sb, struct inode *parent) int parent_group = EXT2_I(parent)->i_block_group; int ngroups = EXT2_SB(sb)->s_groups_count; struct ext2_group_desc *desc; - struct buffer_head *bh; int group, i; /* * Try to place the inode in its parent directory */ group = parent_group; - desc = ext2_get_group_desc (sb, group, &bh); + desc = ext2_get_group_desc (sb, group, NULL); if (desc && le16_to_cpu(desc->bg_free_inodes_count) && le16_to_cpu(desc->bg_free_blocks_count)) goto found; @@ -420,7 +412,7 @@ static int find_group_other(struct super_block *sb, struct inode *parent) group += i; if (group >= ngroups) group -= ngroups; - desc = ext2_get_group_desc (sb, group, &bh); + desc = ext2_get_group_desc (sb, group, NULL); if (desc && le16_to_cpu(desc->bg_free_inodes_count) && le16_to_cpu(desc->bg_free_blocks_count)) goto found; @@ -434,7 +426,7 @@ static int find_group_other(struct super_block *sb, struct inode *parent) for (i = 0; i < ngroups; i++) { if (++group >= ngroups) group = 0; - desc = ext2_get_group_desc (sb, group, &bh); + desc = ext2_get_group_desc (sb, group, NULL); if (desc && le16_to_cpu(desc->bg_free_inodes_count)) goto found; } @@ -542,7 +534,7 @@ got: goto fail; } - percpu_counter_mod(&sbi->s_freeinodes_counter, -1); + percpu_counter_add(&sbi->s_freeinodes_counter, -1); if (S_ISDIR(mode)) percpu_counter_inc(&sbi->s_dirs_counter); @@ -589,11 +581,8 @@ got: ei->i_file_acl = 0; ei->i_dir_acl = 0; ei->i_dtime = 0; + ei->i_block_alloc_info = NULL; ei->i_block_group = group; - ei->i_next_alloc_block = 0; - ei->i_next_alloc_goal = 0; - ei->i_prealloc_block = 0; - ei->i_prealloc_count = 0; ei->i_dir_start_lookup = 0; ei->i_state = EXT2_STATE_NEW; ext2_set_inode_flags(inode); diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 0079b2cd5314..b1ab32ab5a77 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -54,19 +54,6 @@ static inline int ext2_inode_is_fast_symlink(struct inode *inode) } /* - * Called at each iput(). - * - * The inode may be "bad" if ext2_read_inode() saw an error from - * ext2_get_inode(), so we need to check that to avoid freeing random disk - * blocks. - */ -void ext2_put_inode(struct inode *inode) -{ - if (!is_bad_inode(inode)) - ext2_discard_prealloc(inode); -} - -/* * Called at the last iput() if i_nlink is zero. */ void ext2_delete_inode (struct inode * inode) @@ -89,61 +76,6 @@ no_delete: clear_inode(inode); /* We must guarantee clearing of inode... */ } -void ext2_discard_prealloc (struct inode * inode) -{ -#ifdef EXT2_PREALLOCATE - struct ext2_inode_info *ei = EXT2_I(inode); - write_lock(&ei->i_meta_lock); - if (ei->i_prealloc_count) { - unsigned short total = ei->i_prealloc_count; - unsigned long block = ei->i_prealloc_block; - ei->i_prealloc_count = 0; - ei->i_prealloc_block = 0; - write_unlock(&ei->i_meta_lock); - ext2_free_blocks (inode, block, total); - return; - } else - write_unlock(&ei->i_meta_lock); -#endif -} - -static int ext2_alloc_block (struct inode * inode, unsigned long goal, int *err) -{ -#ifdef EXT2FS_DEBUG - static unsigned long alloc_hits, alloc_attempts; -#endif - unsigned long result; - - -#ifdef EXT2_PREALLOCATE - struct ext2_inode_info *ei = EXT2_I(inode); - write_lock(&ei->i_meta_lock); - if (ei->i_prealloc_count && - (goal == ei->i_prealloc_block || goal + 1 == ei->i_prealloc_block)) - { - result = ei->i_prealloc_block++; - ei->i_prealloc_count--; - write_unlock(&ei->i_meta_lock); - ext2_debug ("preallocation hit (%lu/%lu).\n", - ++alloc_hits, ++alloc_attempts); - } else { - write_unlock(&ei->i_meta_lock); - ext2_discard_prealloc (inode); - ext2_debug ("preallocation miss (%lu/%lu).\n", - alloc_hits, ++alloc_attempts); - if (S_ISREG(inode->i_mode)) - result = ext2_new_block (inode, goal, - &ei->i_prealloc_count, - &ei->i_prealloc_block, err); - else - result = ext2_new_block(inode, goal, NULL, NULL, err); - } -#else - result = ext2_new_block (inode, goal, 0, 0, err); -#endif - return result; -} - typedef struct { __le32 *p; __le32 key; @@ -228,7 +160,8 @@ static int ext2_block_to_path(struct inode *inode, ext2_warning (inode->i_sb, "ext2_block_to_path", "block > big"); } if (boundary) - *boundary = (i_block & (ptrs - 1)) == (final - 1); + *boundary = final - 1 - (i_block & (ptrs - 1)); + return n; } @@ -355,39 +288,129 @@ static unsigned long ext2_find_near(struct inode *inode, Indirect *ind) * @block: block we want * @chain: chain of indirect blocks * @partial: pointer to the last triple within a chain - * @goal: place to store the result. * - * Normally this function find the prefered place for block allocation, - * stores it in *@goal and returns zero. If the branch had been changed - * under us we return -EAGAIN. + * Returns preferred place for a block (the goal). */ static inline int ext2_find_goal(struct inode *inode, long block, Indirect chain[4], - Indirect *partial, - unsigned long *goal) + Indirect *partial) { - struct ext2_inode_info *ei = EXT2_I(inode); - write_lock(&ei->i_meta_lock); - if ((block == ei->i_next_alloc_block + 1) && ei->i_next_alloc_goal) { - ei->i_next_alloc_block++; - ei->i_next_alloc_goal++; - } - if (verify_chain(chain, partial)) { - /* - * try the heuristic for sequential allocation, - * failing that at least try to get decent locality. - */ - if (block == ei->i_next_alloc_block) - *goal = ei->i_next_alloc_goal; - if (!*goal) - *goal = ext2_find_near(inode, partial); - write_unlock(&ei->i_meta_lock); - return 0; + struct ext2_block_alloc_info *block_i; + + block_i = EXT2_I(inode)->i_block_alloc_info; + + /* + * try the heuristic for sequential allocation, + * failing that at least try to get decent locality. + */ + if (block_i && (block == block_i->last_alloc_logical_block + 1) + && (block_i->last_alloc_physical_block != 0)) { + return block_i->last_alloc_physical_block + 1; + } + + return ext2_find_near(inode, partial); +} + +/** + * ext2_blks_to_allocate: Look up the block map and count the number + * of direct blocks need to be allocated for the given branch. + * + * @branch: chain of indirect blocks + * @k: number of blocks need for indirect blocks + * @blks: number of data blocks to be mapped. + * @blocks_to_boundary: the offset in the indirect block + * + * return the total number of blocks to be allocate, including the + * direct and indirect blocks. + */ +static int +ext2_blks_to_allocate(Indirect * branch, int k, unsigned long blks, + int blocks_to_boundary) +{ + unsigned long count = 0; + + /* + * Simple case, [t,d]Indirect block(s) has not allocated yet + * then it's clear blocks on that path have not allocated + */ + if (k > 0) { + /* right now don't hanel cross boundary allocation */ + if (blks < blocks_to_boundary + 1) + count += blks; + else + count += blocks_to_boundary + 1; + return count; + } + + count++; + while (count < blks && count <= blocks_to_boundary + && le32_to_cpu(*(branch[0].p + count)) == 0) { + count++; } - write_unlock(&ei->i_meta_lock); - return -EAGAIN; + return count; +} + +/** + * ext2_alloc_blocks: multiple allocate blocks needed for a branch + * @indirect_blks: the number of blocks need to allocate for indirect + * blocks + * + * @new_blocks: on return it will store the new block numbers for + * the indirect blocks(if needed) and the first direct block, + * @blks: on return it will store the total number of allocated + * direct blocks + */ +static int ext2_alloc_blocks(struct inode *inode, + ext2_fsblk_t goal, int indirect_blks, int blks, + ext2_fsblk_t new_blocks[4], int *err) +{ + int target, i; + unsigned long count = 0; + int index = 0; + ext2_fsblk_t current_block = 0; + int ret = 0; + + /* + * Here we try to allocate the requested multiple blocks at once, + * on a best-effort basis. + * To build a branch, we should allocate blocks for + * the indirect blocks(if not allocated yet), and at least + * the first direct block of this branch. That's the + * minimum number of blocks need to allocate(required) + */ + target = blks + indirect_blks; + + while (1) { + count = target; + /* allocating blocks for indirect blocks and direct blocks */ + current_block = ext2_new_blocks(inode,goal,&count,err); + if (*err) + goto failed_out; + + target -= count; + /* allocate blocks for indirect blocks */ + while (index < indirect_blks && count) { + new_blocks[index++] = current_block++; + count--; + } + + if (count > 0) + break; + } + + /* save the new block number for the first direct block */ + new_blocks[index] = current_block; + + /* total number of blocks allocated for direct blocks */ + ret = count; + *err = 0; + return ret; +failed_out: + for (i = 0; i <index; i++) + ext2_free_blocks(inode, new_blocks[i], 1); + return ret; } /** @@ -416,39 +439,49 @@ static inline int ext2_find_goal(struct inode *inode, */ static int ext2_alloc_branch(struct inode *inode, - int num, - unsigned long goal, - int *offsets, - Indirect *branch) + int indirect_blks, int *blks, ext2_fsblk_t goal, + int *offsets, Indirect *branch) { int blocksize = inode->i_sb->s_blocksize; - int n = 0; - int err; - int i; - int parent = ext2_alloc_block(inode, goal, &err); - - branch[0].key = cpu_to_le32(parent); - if (parent) for (n = 1; n < num; n++) { - struct buffer_head *bh; - /* Allocate the next block */ - int nr = ext2_alloc_block(inode, parent, &err); - if (!nr) - break; - branch[n].key = cpu_to_le32(nr); + int i, n = 0; + int err = 0; + struct buffer_head *bh; + int num; + ext2_fsblk_t new_blocks[4]; + ext2_fsblk_t current_block; + + num = ext2_alloc_blocks(inode, goal, indirect_blks, + *blks, new_blocks, &err); + if (err) + return err; + + branch[0].key = cpu_to_le32(new_blocks[0]); + /* + * metadata blocks and data blocks are allocated. + */ + for (n = 1; n <= indirect_blks; n++) { /* - * Get buffer_head for parent block, zero it out and set - * the pointer to new one, then send parent to disk. + * Get buffer_head for parent block, zero it out + * and set the pointer to new one, then send + * parent to disk. */ - bh = sb_getblk(inode->i_sb, parent); - if (!bh) { - err = -EIO; - break; - } + bh = sb_getblk(inode->i_sb, new_blocks[n-1]); + branch[n].bh = bh; lock_buffer(bh); memset(bh->b_data, 0, blocksize); - branch[n].bh = bh; branch[n].p = (__le32 *) bh->b_data + offsets[n]; + branch[n].key = cpu_to_le32(new_blocks[n]); *branch[n].p = branch[n].key; + if ( n == indirect_blks) { + current_block = new_blocks[n]; + /* + * End of chain, update the last new metablock of + * the chain to point to the new allocated + * data blocks numbers + */ + for (i=1; i < num; i++) + *(branch[n].p + i) = cpu_to_le32(++current_block); + } set_buffer_uptodate(bh); unlock_buffer(bh); mark_buffer_dirty_inode(bh, inode); @@ -458,77 +491,68 @@ static int ext2_alloc_branch(struct inode *inode, */ if (S_ISDIR(inode->i_mode) && IS_DIRSYNC(inode)) sync_dirty_buffer(bh); - parent = nr; } - if (n == num) - return 0; - - /* Allocation failed, free what we already allocated */ - for (i = 1; i < n; i++) - bforget(branch[i].bh); - for (i = 0; i < n; i++) - ext2_free_blocks(inode, le32_to_cpu(branch[i].key), 1); + *blks = num; return err; } /** - * ext2_splice_branch - splice the allocated branch onto inode. - * @inode: owner - * @block: (logical) number of block we are adding - * @chain: chain of indirect blocks (with a missing link - see - * ext2_alloc_branch) - * @where: location of missing link - * @num: number of blocks we are adding + * ext2_splice_branch - splice the allocated branch onto inode. + * @inode: owner + * @block: (logical) number of block we are adding + * @chain: chain of indirect blocks (with a missing link - see + * ext2_alloc_branch) + * @where: location of missing link + * @num: number of indirect blocks we are adding + * @blks: number of direct blocks we are adding * - * This function verifies that chain (up to the missing link) had not - * changed, fills the missing link and does all housekeeping needed in - * inode (->i_blocks, etc.). In case of success we end up with the full - * chain to new block and return 0. Otherwise (== chain had been changed) - * we free the new blocks (forgetting their buffer_heads, indeed) and - * return -EAGAIN. + * This function fills the missing link and does all housekeeping needed in + * inode (->i_blocks, etc.). In case of success we end up with the full + * chain to new block and return 0. */ - -static inline int ext2_splice_branch(struct inode *inode, - long block, - Indirect chain[4], - Indirect *where, - int num) +static void ext2_splice_branch(struct inode *inode, + long block, Indirect *where, int num, int blks) { - struct ext2_inode_info *ei = EXT2_I(inode); int i; + struct ext2_block_alloc_info *block_i; + ext2_fsblk_t current_block; - /* Verify that place we are splicing to is still there and vacant */ - - write_lock(&ei->i_meta_lock); - if (!verify_chain(chain, where-1) || *where->p) - goto changed; + block_i = EXT2_I(inode)->i_block_alloc_info; + /* XXX LOCKING probably should have i_meta_lock ?*/ /* That's it */ *where->p = where->key; - ei->i_next_alloc_block = block; - ei->i_next_alloc_goal = le32_to_cpu(where[num-1].key); - write_unlock(&ei->i_meta_lock); + /* + * Update the host buffer_head or inode to point to more just allocated + * direct blocks blocks + */ + if (num == 0 && blks > 1) { + current_block = le32_to_cpu(where->key) + 1; + for (i = 1; i < blks; i++) + *(where->p + i ) = cpu_to_le32(current_block++); + } + + /* + * update the most recently allocated logical & physical block + * in i_block_alloc_info, to assist find the proper goal block for next + * allocation + */ + if (block_i) { + block_i->last_alloc_logical_block = block + blks - 1; + block_i->last_alloc_physical_block = + le32_to_cpu(where[num].key) + blks - 1; + } /* We are done with atomic stuff, now do the rest of housekeeping */ - inode->i_ctime = CURRENT_TIME_SEC; - /* had we spliced it onto indirect block? */ if (where->bh) mark_buffer_dirty_inode(where->bh, inode); + inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); - return 0; - -changed: - write_unlock(&ei->i_meta_lock); - for (i = 1; i < num; i++) - bforget(where[i].bh); - for (i = 0; i < num; i++) - ext2_free_blocks(inode, le32_to_cpu(where[i].key), 1); - return -EAGAIN; } /* @@ -542,64 +566,99 @@ changed: * That has a nice additional property: no special recovery from the failed * allocations is needed - we simply release blocks and do not touch anything * reachable from inode. + * + * `handle' can be NULL if create == 0. + * + * The BKL may not be held on entry here. Be sure to take it early. + * return > 0, # of blocks mapped or allocated. + * return = 0, if plain lookup failed. + * return < 0, error case. */ - -int ext2_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) +static int ext2_get_blocks(struct inode *inode, + sector_t iblock, unsigned long maxblocks, + struct buffer_head *bh_result, + int create) { int err = -EIO; int offsets[4]; Indirect chain[4]; Indirect *partial; - unsigned long goal; - int left; - int boundary = 0; - int depth = ext2_block_to_path(inode, iblock, offsets, &boundary); + ext2_fsblk_t goal; + int indirect_blks; + int blocks_to_boundary = 0; + int depth; + struct ext2_inode_info *ei = EXT2_I(inode); + int count = 0; + ext2_fsblk_t first_block = 0; - if (depth == 0) - goto out; + depth = ext2_block_to_path(inode,iblock,offsets,&blocks_to_boundary); + if (depth == 0) + return (err); reread: partial = ext2_get_branch(inode, depth, offsets, chain, &err); /* Simplest case - block found, no allocation needed */ if (!partial) { -got_it: - map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key)); - if (boundary) - set_buffer_boundary(bh_result); - /* Clean up and exit */ - partial = chain+depth-1; /* the whole chain */ - goto cleanup; + first_block = le32_to_cpu(chain[depth - 1].key); + clear_buffer_new(bh_result); /* What's this do? */ + count++; + /*map more blocks*/ + while (count < maxblocks && count <= blocks_to_boundary) { + ext2_fsblk_t blk; + + if (!verify_chain(chain, partial)) { + /* + * Indirect block might be removed by + * truncate while we were reading it. + * Handling of that case: forget what we've + * got now, go to reread. + */ + count = 0; + goto changed; + } + blk = le32_to_cpu(*(chain[depth-1].p + count)); + if (blk == first_block + count) + count++; + else + break; + } + goto got_it; } /* Next simple case - plain lookup or failed read of indirect block */ - if (!create || err == -EIO) { -cleanup: - while (partial > chain) { - brelse(partial->bh); - partial--; - } -out: - return err; - } + if (!create || err == -EIO) + goto cleanup; + + mutex_lock(&ei->truncate_mutex); /* - * Indirect block might be removed by truncate while we were - * reading it. Handling of that case (forget what we've got and - * reread) is taken out of the main path. - */ - if (err == -EAGAIN) - goto changed; + * Okay, we need to do block allocation. Lazily initialize the block + * allocation info here if necessary + */ + if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info)) + ext2_init_block_alloc_info(inode); - goal = 0; - if (ext2_find_goal(inode, iblock, chain, partial, &goal) < 0) - goto changed; + goal = ext2_find_goal(inode, iblock, chain, partial); - left = (chain + depth) - partial; - err = ext2_alloc_branch(inode, left, goal, - offsets+(partial-chain), partial); - if (err) + /* the number of blocks need to allocate for [d,t]indirect blocks */ + indirect_blks = (chain + depth) - partial - 1; + /* + * Next look up the indirect map to count the totoal number of + * direct blocks to allocate for this branch. + */ + count = ext2_blks_to_allocate(partial, indirect_blks, + maxblocks, blocks_to_boundary); + /* + * XXX ???? Block out ext2_truncate while we alter the tree + */ + err = ext2_alloc_branch(inode, indirect_blks, &count, goal, + offsets + (partial - chain), partial); + + if (err) { + mutex_unlock(&ei->truncate_mutex); goto cleanup; + } if (ext2_use_xip(inode->i_sb)) { /* @@ -607,16 +666,28 @@ out: */ err = ext2_clear_xip_target (inode, le32_to_cpu(chain[depth-1].key)); - if (err) + if (err) { + mutex_unlock(&ei->truncate_mutex); goto cleanup; + } } - if (ext2_splice_branch(inode, iblock, chain, partial, left) < 0) - goto changed; - + ext2_splice_branch(inode, iblock, partial, indirect_blks, count); + mutex_unlock(&ei->truncate_mutex); set_buffer_new(bh_result); - goto got_it; - +got_it: + map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key)); + if (count > blocks_to_boundary) + set_buffer_boundary(bh_result); + err = count; + /* Clean up and exit */ + partial = chain + depth - 1; /* the whole chain */ +cleanup: + while (partial > chain) { + brelse(partial->bh); + partial--; + } + return err; changed: while (partial > chain) { brelse(partial->bh); @@ -625,6 +696,19 @@ changed: goto reread; } +int ext2_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) +{ + unsigned max_blocks = bh_result->b_size >> inode->i_blkbits; + int ret = ext2_get_blocks(inode, iblock, max_blocks, + bh_result, create); + if (ret > 0) { + bh_result->b_size = (ret << inode->i_blkbits); + ret = 0; + } + return ret; + +} + static int ext2_writepage(struct page *page, struct writeback_control *wbc) { return block_write_full_page(page, ext2_get_block, wbc); @@ -642,18 +726,35 @@ ext2_readpages(struct file *file, struct address_space *mapping, return mpage_readpages(mapping, pages, nr_pages, ext2_get_block); } +int __ext2_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) +{ + return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + ext2_get_block); +} + static int -ext2_prepare_write(struct file *file, struct page *page, - unsigned from, unsigned to) +ext2_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - return block_prepare_write(page,from,to,ext2_get_block); + *pagep = NULL; + return __ext2_write_begin(file, mapping, pos, len, flags, pagep,fsdata); } static int -ext2_nobh_prepare_write(struct file *file, struct page *page, - unsigned from, unsigned to) +ext2_nobh_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - return nobh_prepare_write(page,from,to,ext2_get_block); + /* + * Dir-in-pagecache still uses ext2_write_begin. Would have to rework + * directory handling code to pass around offsets rather than struct + * pages in order to make this work easily. + */ + return nobh_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + ext2_get_block); } static int ext2_nobh_writepage(struct page *page, @@ -689,8 +790,8 @@ const struct address_space_operations ext2_aops = { .readpages = ext2_readpages, .writepage = ext2_writepage, .sync_page = block_sync_page, - .prepare_write = ext2_prepare_write, - .commit_write = generic_commit_write, + .write_begin = ext2_write_begin, + .write_end = generic_write_end, .bmap = ext2_bmap, .direct_IO = ext2_direct_IO, .writepages = ext2_writepages, @@ -707,8 +808,8 @@ const struct address_space_operations ext2_nobh_aops = { .readpages = ext2_readpages, .writepage = ext2_nobh_writepage, .sync_page = block_sync_page, - .prepare_write = ext2_nobh_prepare_write, - .commit_write = nobh_commit_write, + .write_begin = ext2_nobh_write_begin, + .write_end = nobh_write_end, .bmap = ext2_bmap, .direct_IO = ext2_direct_IO, .writepages = ext2_writepages, @@ -896,9 +997,10 @@ static void ext2_free_branches(struct inode *inode, __le32 *p, __le32 *q, int de ext2_free_data(inode, p, q); } -void ext2_truncate (struct inode * inode) +void ext2_truncate(struct inode *inode) { __le32 *i_data = EXT2_I(inode)->i_data; + struct ext2_inode_info *ei = EXT2_I(inode); int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); int offsets[4]; Indirect chain[4]; @@ -916,8 +1018,6 @@ void ext2_truncate (struct inode * inode) if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) return; - ext2_discard_prealloc(inode); - blocksize = inode->i_sb->s_blocksize; iblock = (inode->i_size + blocksize-1) >> EXT2_BLOCK_SIZE_BITS(inode->i_sb); @@ -925,7 +1025,8 @@ void ext2_truncate (struct inode * inode) if (mapping_is_xip(inode->i_mapping)) xip_truncate_page(inode->i_mapping, inode->i_size); else if (test_opt(inode->i_sb, NOBH)) - nobh_truncate_page(inode->i_mapping, inode->i_size); + nobh_truncate_page(inode->i_mapping, + inode->i_size, ext2_get_block); else block_truncate_page(inode->i_mapping, inode->i_size, ext2_get_block); @@ -934,6 +1035,12 @@ void ext2_truncate (struct inode * inode) if (n == 0) return; + /* + * From here we block out all ext2_get_block() callers who want to + * modify the block allocation tree. + */ + mutex_lock(&ei->truncate_mutex); + if (n == 1) { ext2_free_data(inode, i_data+offsets[0], i_data + EXT2_NDIR_BLOCKS); @@ -986,6 +1093,10 @@ do_indirects: case EXT2_TIND_BLOCK: ; } + + ext2_discard_reservation(inode); + + mutex_unlock(&ei->truncate_mutex); inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; if (inode_needs_sync(inode)) { sync_mapping_buffers(inode->i_mapping); @@ -1010,7 +1121,7 @@ static struct ext2_inode *ext2_get_inode(struct super_block *sb, ino_t ino, goto Einval; block_group = (ino - 1) / EXT2_INODES_PER_GROUP(sb); - gdp = ext2_get_group_desc(sb, block_group, &bh); + gdp = ext2_get_group_desc(sb, block_group, NULL); if (!gdp) goto Egdp; /* @@ -1086,6 +1197,8 @@ void ext2_read_inode (struct inode * inode) ei->i_acl = EXT2_ACL_NOT_CACHED; ei->i_default_acl = EXT2_ACL_NOT_CACHED; #endif + ei->i_block_alloc_info = NULL; + if (IS_ERR(raw_inode)) goto bad_inode; @@ -1127,9 +1240,6 @@ void ext2_read_inode (struct inode * inode) ei->i_dtime = 0; inode->i_generation = le32_to_cpu(raw_inode->i_generation); ei->i_state = 0; - ei->i_next_alloc_block = 0; - ei->i_next_alloc_goal = 0; - ei->i_prealloc_count = 0; ei->i_block_group = (ino - 1) / EXT2_INODES_PER_GROUP(inode->i_sb); ei->i_dir_start_lookup = 0; diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c index 3bcd25422ee4..c2324d5fe4ac 100644 --- a/fs/ext2/ioctl.c +++ b/fs/ext2/ioctl.c @@ -22,6 +22,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, { struct ext2_inode_info *ei = EXT2_I(inode); unsigned int flags; + unsigned short rsv_window_size; ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg); @@ -83,6 +84,50 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); return 0; + case EXT2_IOC_GETRSVSZ: + if (test_opt(inode->i_sb, RESERVATION) + && S_ISREG(inode->i_mode) + && ei->i_block_alloc_info) { + rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size; + return put_user(rsv_window_size, (int __user *)arg); + } + return -ENOTTY; + case EXT2_IOC_SETRSVSZ: { + + if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) + return -ENOTTY; + + if (IS_RDONLY(inode)) + return -EROFS; + + if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + return -EACCES; + + if (get_user(rsv_window_size, (int __user *)arg)) + return -EFAULT; + + if (rsv_window_size > EXT2_MAX_RESERVE_BLOCKS) + rsv_window_size = EXT2_MAX_RESERVE_BLOCKS; + + /* + * need to allocate reservation structure for this inode + * before set the window size + */ + /* + * XXX What lock should protect the rsv_goal_size? + * Accessed in ext2_get_block only. ext3 uses i_truncate. + */ + mutex_lock(&ei->truncate_mutex); + if (!ei->i_block_alloc_info) + ext2_init_block_alloc_info(inode); + + if (ei->i_block_alloc_info){ + struct ext2_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node; + rsv->rsv_goal_size = rsv_window_size; + } + mutex_unlock(&ei->truncate_mutex); + return 0; + } default: return -ENOTTY; } diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 639a32c3c9c1..77bd5f9262f9 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -30,6 +30,7 @@ #include <linux/vfs.h> #include <linux/seq_file.h> #include <linux/mount.h> +#include <linux/log2.h> #include <asm/uaccess.h> #include "ext2.h" #include "xattr.h" @@ -148,6 +149,7 @@ static struct inode *ext2_alloc_inode(struct super_block *sb) ei->i_acl = EXT2_ACL_NOT_CACHED; ei->i_default_acl = EXT2_ACL_NOT_CACHED; #endif + ei->i_block_alloc_info = NULL; ei->vfs_inode.i_version = 1; return &ei->vfs_inode; } @@ -157,7 +159,7 @@ static void ext2_destroy_inode(struct inode *inode) kmem_cache_free(ext2_inode_cachep, EXT2_I(inode)); } -static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(struct kmem_cache * cachep, void *foo) { struct ext2_inode_info *ei = (struct ext2_inode_info *) foo; @@ -165,6 +167,7 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag #ifdef CONFIG_EXT2_FS_XATTR init_rwsem(&ei->xattr_sem); #endif + mutex_init(&ei->truncate_mutex); inode_init_once(&ei->vfs_inode); } @@ -187,6 +190,7 @@ static void destroy_inodecache(void) static void ext2_clear_inode(struct inode *inode) { + struct ext2_block_alloc_info *rsv = EXT2_I(inode)->i_block_alloc_info; #ifdef CONFIG_EXT2_FS_POSIX_ACL struct ext2_inode_info *ei = EXT2_I(inode); @@ -199,14 +203,74 @@ static void ext2_clear_inode(struct inode *inode) ei->i_default_acl = EXT2_ACL_NOT_CACHED; } #endif + ext2_discard_reservation(inode); + EXT2_I(inode)->i_block_alloc_info = NULL; + if (unlikely(rsv)) + kfree(rsv); } static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs) { - struct ext2_sb_info *sbi = EXT2_SB(vfs->mnt_sb); + struct super_block *sb = vfs->mnt_sb; + struct ext2_sb_info *sbi = EXT2_SB(sb); + struct ext2_super_block *es = sbi->s_es; + unsigned long def_mount_opts; + + def_mount_opts = le32_to_cpu(es->s_default_mount_opts); - if (sbi->s_mount_opt & EXT2_MOUNT_GRPID) + if (sbi->s_sb_block != 1) + seq_printf(seq, ",sb=%lu", sbi->s_sb_block); + if (test_opt(sb, MINIX_DF)) + seq_puts(seq, ",minixdf"); + if (test_opt(sb, GRPID)) seq_puts(seq, ",grpid"); + if (!test_opt(sb, GRPID) && (def_mount_opts & EXT2_DEFM_BSDGROUPS)) + seq_puts(seq, ",nogrpid"); + if (sbi->s_resuid != EXT2_DEF_RESUID || + le16_to_cpu(es->s_def_resuid) != EXT2_DEF_RESUID) { + seq_printf(seq, ",resuid=%u", sbi->s_resuid); + } + if (sbi->s_resgid != EXT2_DEF_RESGID || + le16_to_cpu(es->s_def_resgid) != EXT2_DEF_RESGID) { + seq_printf(seq, ",resgid=%u", sbi->s_resgid); + } + if (test_opt(sb, ERRORS_CONT)) { + int def_errors = le16_to_cpu(es->s_errors); + + if (def_errors == EXT2_ERRORS_PANIC || + def_errors == EXT2_ERRORS_RO) { + seq_puts(seq, ",errors=continue"); + } + } + if (test_opt(sb, ERRORS_RO)) + seq_puts(seq, ",errors=remount-ro"); + if (test_opt(sb, ERRORS_PANIC)) + seq_puts(seq, ",errors=panic"); + if (test_opt(sb, NO_UID32)) + seq_puts(seq, ",nouid32"); + if (test_opt(sb, DEBUG)) + seq_puts(seq, ",debug"); + if (test_opt(sb, OLDALLOC)) + seq_puts(seq, ",oldalloc"); + +#ifdef CONFIG_EXT2_FS_XATTR + if (test_opt(sb, XATTR_USER)) + seq_puts(seq, ",user_xattr"); + if (!test_opt(sb, XATTR_USER) && + (def_mount_opts & EXT2_DEFM_XATTR_USER)) { + seq_puts(seq, ",nouser_xattr"); + } +#endif + +#ifdef CONFIG_EXT2_FS_POSIX_ACL + if (test_opt(sb, POSIX_ACL)) + seq_puts(seq, ",acl"); + if (!test_opt(sb, POSIX_ACL) && (def_mount_opts & EXT2_DEFM_ACL)) + seq_puts(seq, ",noacl"); +#endif + + if (test_opt(sb, NOBH)) + seq_puts(seq, ",nobh"); #if defined(CONFIG_QUOTA) if (sbi->s_mount_opt & EXT2_MOUNT_USRQUOTA) @@ -234,7 +298,6 @@ static const struct super_operations ext2_sops = { .destroy_inode = ext2_destroy_inode, .read_inode = ext2_read_inode, .write_inode = ext2_write_inode, - .put_inode = ext2_put_inode, .delete_inode = ext2_delete_inode, .put_super = ext2_put_super, .write_super = ext2_write_super, @@ -322,7 +385,7 @@ enum { Opt_err_ro, Opt_nouid32, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh, Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_xip, Opt_ignore, Opt_err, Opt_quota, - Opt_usrquota, Opt_grpquota + Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation }; static match_table_t tokens = { @@ -354,6 +417,8 @@ static match_table_t tokens = { {Opt_ignore, "noquota"}, {Opt_quota, "quota"}, {Opt_usrquota, "usrquota"}, + {Opt_reservation, "reservation"}, + {Opt_noreservation, "noreservation"}, {Opt_err, NULL} }; @@ -486,6 +551,14 @@ static int parse_options (char * options, break; #endif + case Opt_reservation: + set_opt(sbi->s_mount_opt, RESERVATION); + printk("reservations ON\n"); + break; + case Opt_noreservation: + clear_opt(sbi->s_mount_opt, RESERVATION); + printk("reservations OFF\n"); + break; case Opt_ignore: break; default: @@ -653,11 +726,13 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) int db_count; int i, j; __le32 features; + int err; sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); if (!sbi) return -ENOMEM; sb->s_fs_info = sbi; + sbi->s_sb_block = sb_block; /* * See what the current blocksize for the device is, and @@ -725,6 +800,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) sbi->s_resuid = le16_to_cpu(es->s_def_resuid); sbi->s_resgid = le16_to_cpu(es->s_def_resgid); + set_opt(sbi->s_mount_opt, RESERVATION); + if (!parse_options ((char *) data, sbi)) goto failed_mount; @@ -804,7 +881,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) sbi->s_inode_size = le16_to_cpu(es->s_inode_size); sbi->s_first_ino = le32_to_cpu(es->s_first_ino); if ((sbi->s_inode_size < EXT2_GOOD_OLD_INODE_SIZE) || - (sbi->s_inode_size & (sbi->s_inode_size - 1)) || + !is_power_of_2(sbi->s_inode_size) || (sbi->s_inode_size > blocksize)) { printk ("EXT2-fs: unsupported inode size: %d\n", sbi->s_inode_size); @@ -906,12 +983,35 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) get_random_bytes(&sbi->s_next_generation, sizeof(u32)); spin_lock_init(&sbi->s_next_gen_lock); - percpu_counter_init(&sbi->s_freeblocks_counter, + /* per fileystem reservation list head & lock */ + spin_lock_init(&sbi->s_rsv_window_lock); + sbi->s_rsv_window_root = RB_ROOT; + /* + * Add a single, static dummy reservation to the start of the + * reservation window list --- it gives us a placeholder for + * append-at-start-of-list which makes the allocation logic + * _much_ simpler. + */ + sbi->s_rsv_window_head.rsv_start = EXT2_RESERVE_WINDOW_NOT_ALLOCATED; + sbi->s_rsv_window_head.rsv_end = EXT2_RESERVE_WINDOW_NOT_ALLOCATED; + sbi->s_rsv_window_head.rsv_alloc_hit = 0; + sbi->s_rsv_window_head.rsv_goal_size = 0; + ext2_rsv_window_add(sb, &sbi->s_rsv_window_head); + + err = percpu_counter_init(&sbi->s_freeblocks_counter, ext2_count_free_blocks(sb)); - percpu_counter_init(&sbi->s_freeinodes_counter, + if (!err) { + err = percpu_counter_init(&sbi->s_freeinodes_counter, ext2_count_free_inodes(sb)); - percpu_counter_init(&sbi->s_dirs_counter, + } + if (!err) { + err = percpu_counter_init(&sbi->s_dirs_counter, ext2_count_dirs(sb)); + } + if (err) { + printk(KERN_ERR "EXT2-fs: insufficient memory\n"); + goto failed_mount3; + } /* * set up enough so that it can read an inode */ @@ -1193,7 +1293,7 @@ static ssize_t ext2_quota_read(struct super_block *sb, int type, char *data, tmp_bh.b_state = 0; err = ext2_get_block(inode, blk, &tmp_bh, 0); - if (err) + if (err < 0) return err; if (!buffer_mapped(&tmp_bh)) /* A hole? */ memset(data, 0, tocopy); @@ -1232,7 +1332,7 @@ static ssize_t ext2_quota_write(struct super_block *sb, int type, tmp_bh.b_state = 0; err = ext2_get_block(inode, blk, &tmp_bh, 1); - if (err) + if (err < 0) goto out; if (offset || tocopy != EXT2_BLOCK_SIZE(sb)) bh = sb_bread(sb, tmp_bh.b_blocknr); diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c index 247efd0b51d6..3e8683dbb13f 100644 --- a/fs/ext2/xattr.c +++ b/fs/ext2/xattr.c @@ -664,8 +664,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, s_first_data_block) + EXT2_I(inode)->i_block_group * EXT2_BLOCKS_PER_GROUP(sb); - int block = ext2_new_block(inode, goal, - NULL, NULL, &error); + int block = ext2_new_block(inode, goal, &error); if (error) goto cleanup; ea_idebug(inode, "creating block %d", block); diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index ca8aee6efe37..7a87d15523be 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c @@ -80,6 +80,14 @@ struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb, return desc + offset; } +static inline int +block_in_use(ext3_fsblk_t block, struct super_block *sb, unsigned char *map) +{ + return ext3_test_bit ((block - + le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block)) % + EXT3_BLOCKS_PER_GROUP(sb), map); +} + /** * read_block_bitmap() * @sb: super block @@ -93,20 +101,51 @@ struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb, static struct buffer_head * read_block_bitmap(struct super_block *sb, unsigned int block_group) { + int i; struct ext3_group_desc * desc; struct buffer_head * bh = NULL; + ext3_fsblk_t bitmap_blk; desc = ext3_get_group_desc (sb, block_group, NULL); if (!desc) - goto error_out; - bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap)); + return NULL; + bitmap_blk = le32_to_cpu(desc->bg_block_bitmap); + bh = sb_bread(sb, bitmap_blk); if (!bh) - ext3_error (sb, "read_block_bitmap", + ext3_error (sb, __FUNCTION__, "Cannot read block bitmap - " "block_group = %d, block_bitmap = %u", block_group, le32_to_cpu(desc->bg_block_bitmap)); -error_out: + + /* check whether block bitmap block number is set */ + if (!block_in_use(bitmap_blk, sb, bh->b_data)) { + /* bad block bitmap */ + goto error_out; + } + /* check whether the inode bitmap block number is set */ + bitmap_blk = le32_to_cpu(desc->bg_inode_bitmap); + if (!block_in_use(bitmap_blk, sb, bh->b_data)) { + /* bad block bitmap */ + goto error_out; + } + /* check whether the inode table block number is set */ + bitmap_blk = le32_to_cpu(desc->bg_inode_table); + for (i = 0; i < EXT3_SB(sb)->s_itb_per_group; i++, bitmap_blk++) { + if (!block_in_use(bitmap_blk, sb, bh->b_data)) { + /* bad block bitmap */ + goto error_out; + } + } + return bh; + +error_out: + brelse(bh); + ext3_error(sb, __FUNCTION__, + "Invalid block bitmap - " + "block_group = %d, block = %lu", + block_group, bitmap_blk); + return NULL; } /* * The reservation window structure operations @@ -570,7 +609,7 @@ do_more: cpu_to_le16(le16_to_cpu(desc->bg_free_blocks_count) + group_freed); spin_unlock(sb_bgl_lock(sbi, block_group)); - percpu_counter_mod(&sbi->s_freeblocks_counter, count); + percpu_counter_add(&sbi->s_freeblocks_counter, count); /* We dirtied the bitmap block */ BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); @@ -1633,7 +1672,7 @@ allocated: gdp->bg_free_blocks_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)-num); spin_unlock(sb_bgl_lock(sbi, group_no)); - percpu_counter_mod(&sbi->s_freeblocks_counter, -num); + percpu_counter_sub(&sbi->s_freeblocks_counter, num); BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor"); err = ext3_journal_dirty_metadata(handle, gdp_bh); @@ -1733,13 +1772,6 @@ ext3_fsblk_t ext3_count_free_blocks(struct super_block *sb) #endif } -static inline int -block_in_use(ext3_fsblk_t block, struct super_block *sb, unsigned char *map) -{ - return ext3_test_bit ((block - - le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block)) % - EXT3_BLOCKS_PER_GROUP(sb), map); -} static inline int test_root(int a, int b) { diff --git a/fs/ext3/bitmap.c b/fs/ext3/bitmap.c index b9176eed98d1..6afc39d80253 100644 --- a/fs/ext3/bitmap.c +++ b/fs/ext3/bitmap.c @@ -13,7 +13,7 @@ #ifdef EXT3FS_DEBUG -static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}; +static const int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}; unsigned long ext3_count_free (struct buffer_head * map, unsigned int numchars) { diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c index c00723a99f44..c8e4ee3af1d0 100644 --- a/fs/ext3/dir.c +++ b/fs/ext3/dir.c @@ -47,9 +47,7 @@ const struct file_operations ext3_dir_operations = { .compat_ioctl = ext3_compat_ioctl, #endif .fsync = ext3_sync_file, /* BKL held */ -#ifdef CONFIG_EXT3_INDEX .release = ext3_release_dir, -#endif }; @@ -107,7 +105,6 @@ static int ext3_readdir(struct file * filp, sb = inode->i_sb; -#ifdef CONFIG_EXT3_INDEX if (EXT3_HAS_COMPAT_FEATURE(inode->i_sb, EXT3_FEATURE_COMPAT_DIR_INDEX) && ((EXT3_I(inode)->i_flags & EXT3_INDEX_FL) || @@ -123,7 +120,6 @@ static int ext3_readdir(struct file * filp, */ EXT3_I(filp->f_path.dentry->d_inode)->i_flags &= ~EXT3_INDEX_FL; } -#endif stored = 0; offset = filp->f_pos & (sb->s_blocksize - 1); @@ -143,7 +139,7 @@ static int ext3_readdir(struct file * filp, sb->s_bdev->bd_inode->i_mapping, &filp->f_ra, filp, index, 1); - filp->f_ra.prev_index = index; + filp->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT; bh = ext3_bread(NULL, inode, blk, 0, &err); } @@ -210,7 +206,7 @@ revalidate: * not the directory has been modified * during the copy operation. */ - unsigned long version = filp->f_version; + u64 version = filp->f_version; error = filldir(dirent, de->name, de->name_len, @@ -232,7 +228,6 @@ out: return ret; } -#ifdef CONFIG_EXT3_INDEX /* * These functions convert from the major/minor hash to an f_pos * value. @@ -518,5 +513,3 @@ static int ext3_release_dir (struct inode * inode, struct file * filp) return 0; } - -#endif diff --git a/fs/ext3/fsync.c b/fs/ext3/fsync.c index dd1fd3c0fc05..a588e23841d4 100644 --- a/fs/ext3/fsync.c +++ b/fs/ext3/fsync.c @@ -47,7 +47,7 @@ int ext3_sync_file(struct file * file, struct dentry *dentry, int datasync) struct inode *inode = dentry->d_inode; int ret = 0; - J_ASSERT(ext3_journal_current_handle() == 0); + J_ASSERT(ext3_journal_current_handle() == NULL); /* * data=writeback: diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c index e45dbd651736..1bc8cd89c51d 100644 --- a/fs/ext3/ialloc.c +++ b/fs/ext3/ialloc.c @@ -204,14 +204,13 @@ static int find_group_dir(struct super_block *sb, struct inode *parent) int ngroups = EXT3_SB(sb)->s_groups_count; unsigned int freei, avefreei; struct ext3_group_desc *desc, *best_desc = NULL; - struct buffer_head *bh; int group, best_group = -1; freei = percpu_counter_read_positive(&EXT3_SB(sb)->s_freeinodes_counter); avefreei = freei / ngroups; for (group = 0; group < ngroups; group++) { - desc = ext3_get_group_desc (sb, group, &bh); + desc = ext3_get_group_desc (sb, group, NULL); if (!desc || !desc->bg_free_inodes_count) continue; if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei) @@ -269,7 +268,6 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) ext3_grpblk_t min_blocks; int group = -1, i; struct ext3_group_desc *desc; - struct buffer_head *bh; freei = percpu_counter_read_positive(&sbi->s_freeinodes_counter); avefreei = freei / ngroups; @@ -286,7 +284,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) parent_group = (unsigned)group % ngroups; for (i = 0; i < ngroups; i++) { group = (parent_group + i) % ngroups; - desc = ext3_get_group_desc (sb, group, &bh); + desc = ext3_get_group_desc (sb, group, NULL); if (!desc || !desc->bg_free_inodes_count) continue; if (le16_to_cpu(desc->bg_used_dirs_count) >= best_ndir) @@ -319,7 +317,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) for (i = 0; i < ngroups; i++) { group = (parent_group + i) % ngroups; - desc = ext3_get_group_desc (sb, group, &bh); + desc = ext3_get_group_desc (sb, group, NULL); if (!desc || !desc->bg_free_inodes_count) continue; if (le16_to_cpu(desc->bg_used_dirs_count) >= max_dirs) @@ -334,7 +332,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) fallback: for (i = 0; i < ngroups; i++) { group = (parent_group + i) % ngroups; - desc = ext3_get_group_desc (sb, group, &bh); + desc = ext3_get_group_desc (sb, group, NULL); if (!desc || !desc->bg_free_inodes_count) continue; if (le16_to_cpu(desc->bg_free_inodes_count) >= avefreei) @@ -358,14 +356,13 @@ static int find_group_other(struct super_block *sb, struct inode *parent) int parent_group = EXT3_I(parent)->i_block_group; int ngroups = EXT3_SB(sb)->s_groups_count; struct ext3_group_desc *desc; - struct buffer_head *bh; int group, i; /* * Try to place the inode in its parent directory */ group = parent_group; - desc = ext3_get_group_desc (sb, group, &bh); + desc = ext3_get_group_desc (sb, group, NULL); if (desc && le16_to_cpu(desc->bg_free_inodes_count) && le16_to_cpu(desc->bg_free_blocks_count)) return group; @@ -389,7 +386,7 @@ static int find_group_other(struct super_block *sb, struct inode *parent) group += i; if (group >= ngroups) group -= ngroups; - desc = ext3_get_group_desc (sb, group, &bh); + desc = ext3_get_group_desc (sb, group, NULL); if (desc && le16_to_cpu(desc->bg_free_inodes_count) && le16_to_cpu(desc->bg_free_blocks_count)) return group; @@ -403,7 +400,7 @@ static int find_group_other(struct super_block *sb, struct inode *parent) for (i = 0; i < ngroups; i++) { if (++group >= ngroups) group = 0; - desc = ext3_get_group_desc (sb, group, &bh); + desc = ext3_get_group_desc (sb, group, NULL); if (desc && le16_to_cpu(desc->bg_free_inodes_count)) return group; } diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index de4e3161e479..9b162cd6c16c 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -1028,7 +1028,7 @@ struct buffer_head *ext3_getblk(handle_t *handle, struct inode *inode, } if (buffer_new(&dummy)) { J_ASSERT(create != 0); - J_ASSERT(handle != 0); + J_ASSERT(handle != NULL); /* * Now that we do not always journal data, we should @@ -1147,51 +1147,68 @@ static int do_journal_get_write_access(handle_t *handle, return ext3_journal_get_write_access(handle, bh); } -static int ext3_prepare_write(struct file *file, struct page *page, - unsigned from, unsigned to) +static int ext3_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - struct inode *inode = page->mapping->host; + struct inode *inode = mapping->host; int ret, needed_blocks = ext3_writepage_trans_blocks(inode); handle_t *handle; int retries = 0; + struct page *page; + pgoff_t index; + unsigned from, to; + + index = pos >> PAGE_CACHE_SHIFT; + from = pos & (PAGE_CACHE_SIZE - 1); + to = from + len; retry: + page = __grab_cache_page(mapping, index); + if (!page) + return -ENOMEM; + *pagep = page; + handle = ext3_journal_start(inode, needed_blocks); if (IS_ERR(handle)) { + unlock_page(page); + page_cache_release(page); ret = PTR_ERR(handle); goto out; } - if (test_opt(inode->i_sb, NOBH) && ext3_should_writeback_data(inode)) - ret = nobh_prepare_write(page, from, to, ext3_get_block); - else - ret = block_prepare_write(page, from, to, ext3_get_block); + ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + ext3_get_block); if (ret) - goto prepare_write_failed; + goto write_begin_failed; if (ext3_should_journal_data(inode)) { ret = walk_page_buffers(handle, page_buffers(page), from, to, NULL, do_journal_get_write_access); } -prepare_write_failed: - if (ret) +write_begin_failed: + if (ret) { ext3_journal_stop(handle); + unlock_page(page); + page_cache_release(page); + } if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) goto retry; out: return ret; } + int ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh) { int err = journal_dirty_data(handle, bh); if (err) ext3_journal_abort_handle(__FUNCTION__, __FUNCTION__, - bh, handle,err); + bh, handle, err); return err; } -/* For commit_write() in data=journal mode */ -static int commit_write_fn(handle_t *handle, struct buffer_head *bh) +/* For write_end() in data=journal mode */ +static int write_end_fn(handle_t *handle, struct buffer_head *bh) { if (!buffer_mapped(bh) || buffer_freed(bh)) return 0; @@ -1200,84 +1217,130 @@ static int commit_write_fn(handle_t *handle, struct buffer_head *bh) } /* + * Generic write_end handler for ordered and writeback ext3 journal modes. + * We can't use generic_write_end, because that unlocks the page and we need to + * unlock the page after ext3_journal_stop, but ext3_journal_stop must run + * after block_write_end. + */ +static int ext3_generic_write_end(struct file *file, + struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) +{ + struct inode *inode = file->f_mapping->host; + + copied = block_write_end(file, mapping, pos, len, copied, page, fsdata); + + if (pos+copied > inode->i_size) { + i_size_write(inode, pos+copied); + mark_inode_dirty(inode); + } + + return copied; +} + +/* * We need to pick up the new inode size which generic_commit_write gave us * `file' can be NULL - eg, when called from page_symlink(). * * ext3 never places buffers on inode->i_mapping->private_list. metadata * buffers are managed internally. */ -static int ext3_ordered_commit_write(struct file *file, struct page *page, - unsigned from, unsigned to) +static int ext3_ordered_write_end(struct file *file, + struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) { handle_t *handle = ext3_journal_current_handle(); - struct inode *inode = page->mapping->host; + struct inode *inode = file->f_mapping->host; + unsigned from, to; int ret = 0, ret2; + from = pos & (PAGE_CACHE_SIZE - 1); + to = from + len; + ret = walk_page_buffers(handle, page_buffers(page), from, to, NULL, ext3_journal_dirty_data); if (ret == 0) { /* - * generic_commit_write() will run mark_inode_dirty() if i_size + * generic_write_end() will run mark_inode_dirty() if i_size * changes. So let's piggyback the i_disksize mark_inode_dirty * into that. */ loff_t new_i_size; - new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + new_i_size = pos + copied; if (new_i_size > EXT3_I(inode)->i_disksize) EXT3_I(inode)->i_disksize = new_i_size; - ret = generic_commit_write(file, page, from, to); + copied = ext3_generic_write_end(file, mapping, pos, len, copied, + page, fsdata); + if (copied < 0) + ret = copied; } ret2 = ext3_journal_stop(handle); if (!ret) ret = ret2; - return ret; + unlock_page(page); + page_cache_release(page); + + return ret ? ret : copied; } -static int ext3_writeback_commit_write(struct file *file, struct page *page, - unsigned from, unsigned to) +static int ext3_writeback_write_end(struct file *file, + struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) { handle_t *handle = ext3_journal_current_handle(); - struct inode *inode = page->mapping->host; + struct inode *inode = file->f_mapping->host; int ret = 0, ret2; loff_t new_i_size; - new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + new_i_size = pos + copied; if (new_i_size > EXT3_I(inode)->i_disksize) EXT3_I(inode)->i_disksize = new_i_size; - if (test_opt(inode->i_sb, NOBH) && ext3_should_writeback_data(inode)) - ret = nobh_commit_write(file, page, from, to); - else - ret = generic_commit_write(file, page, from, to); + copied = ext3_generic_write_end(file, mapping, pos, len, copied, + page, fsdata); + if (copied < 0) + ret = copied; ret2 = ext3_journal_stop(handle); if (!ret) ret = ret2; - return ret; + unlock_page(page); + page_cache_release(page); + + return ret ? ret : copied; } -static int ext3_journalled_commit_write(struct file *file, - struct page *page, unsigned from, unsigned to) +static int ext3_journalled_write_end(struct file *file, + struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) { handle_t *handle = ext3_journal_current_handle(); - struct inode *inode = page->mapping->host; + struct inode *inode = mapping->host; int ret = 0, ret2; int partial = 0; - loff_t pos; + unsigned from, to; - /* - * Here we duplicate the generic_commit_write() functionality - */ - pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + from = pos & (PAGE_CACHE_SIZE - 1); + to = from + len; + + if (copied < len) { + if (!PageUptodate(page)) + copied = 0; + page_zero_new_buffers(page, from+copied, to); + } ret = walk_page_buffers(handle, page_buffers(page), from, - to, &partial, commit_write_fn); + to, &partial, write_end_fn); if (!partial) SetPageUptodate(page); - if (pos > inode->i_size) - i_size_write(inode, pos); + if (pos+copied > inode->i_size) + i_size_write(inode, pos+copied); EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; if (inode->i_size > EXT3_I(inode)->i_disksize) { EXT3_I(inode)->i_disksize = inode->i_size; @@ -1285,10 +1348,14 @@ static int ext3_journalled_commit_write(struct file *file, if (!ret) ret = ret2; } + ret2 = ext3_journal_stop(handle); if (!ret) ret = ret2; - return ret; + unlock_page(page); + page_cache_release(page); + + return ret ? ret : copied; } /* @@ -1546,7 +1613,7 @@ static int ext3_journalled_writepage(struct page *page, PAGE_CACHE_SIZE, NULL, do_journal_get_write_access); err = walk_page_buffers(handle, page_buffers(page), 0, - PAGE_CACHE_SIZE, NULL, commit_write_fn); + PAGE_CACHE_SIZE, NULL, write_end_fn); if (ret == 0) ret = err; EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; @@ -1706,8 +1773,8 @@ static const struct address_space_operations ext3_ordered_aops = { .readpages = ext3_readpages, .writepage = ext3_ordered_writepage, .sync_page = block_sync_page, - .prepare_write = ext3_prepare_write, - .commit_write = ext3_ordered_commit_write, + .write_begin = ext3_write_begin, + .write_end = ext3_ordered_write_end, .bmap = ext3_bmap, .invalidatepage = ext3_invalidatepage, .releasepage = ext3_releasepage, @@ -1720,8 +1787,8 @@ static const struct address_space_operations ext3_writeback_aops = { .readpages = ext3_readpages, .writepage = ext3_writeback_writepage, .sync_page = block_sync_page, - .prepare_write = ext3_prepare_write, - .commit_write = ext3_writeback_commit_write, + .write_begin = ext3_write_begin, + .write_end = ext3_writeback_write_end, .bmap = ext3_bmap, .invalidatepage = ext3_invalidatepage, .releasepage = ext3_releasepage, @@ -1734,8 +1801,8 @@ static const struct address_space_operations ext3_journalled_aops = { .readpages = ext3_readpages, .writepage = ext3_journalled_writepage, .sync_page = block_sync_page, - .prepare_write = ext3_prepare_write, - .commit_write = ext3_journalled_commit_write, + .write_begin = ext3_write_begin, + .write_end = ext3_journalled_write_end, .set_page_dirty = ext3_journalled_set_page_dirty, .bmap = ext3_bmap, .invalidatepage = ext3_invalidatepage, @@ -2887,7 +2954,7 @@ int ext3_write_inode(struct inode *inode, int wait) return 0; if (ext3_journal_current_handle()) { - jbd_debug(0, "called recursively, non-PF_MEMALLOC!\n"); + jbd_debug(1, "called recursively, non-PF_MEMALLOC!\n"); dump_stack(); return -EIO; } diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index c1fa1908dba0..ec8170adac53 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -144,7 +144,6 @@ struct dx_map_entry u16 size; }; -#ifdef CONFIG_EXT3_INDEX static inline unsigned dx_get_block (struct dx_entry *entry); static void dx_set_block (struct dx_entry *entry, unsigned value); static inline unsigned dx_get_hash (struct dx_entry *entry); @@ -768,8 +767,6 @@ static void dx_insert_block(struct dx_frame *frame, u32 hash, u32 block) dx_set_block(new, block); dx_set_count(entries, count + 1); } -#endif - static void ext3_update_dx_flag(struct inode *inode) { @@ -871,7 +868,6 @@ static struct buffer_head * ext3_find_entry (struct dentry *dentry, name = dentry->d_name.name; if (namelen > EXT3_NAME_LEN) return NULL; -#ifdef CONFIG_EXT3_INDEX if (is_dx(dir)) { bh = ext3_dx_find_entry(dentry, res_dir, &err); /* @@ -883,7 +879,6 @@ static struct buffer_head * ext3_find_entry (struct dentry *dentry, return bh; dxtrace(printk("ext3_find_entry: dx failed, falling back\n")); } -#endif nblocks = dir->i_size >> EXT3_BLOCK_SIZE_BITS(sb); start = EXT3_I(dir)->i_dir_start_lookup; if (start >= nblocks) @@ -959,7 +954,6 @@ cleanup_and_exit: return ret; } -#ifdef CONFIG_EXT3_INDEX static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, struct ext3_dir_entry_2 **res_dir, int *err) { @@ -1027,7 +1021,6 @@ errout: dx_release (frames); return NULL; } -#endif static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) { @@ -1123,7 +1116,6 @@ static inline void ext3_set_de_type(struct super_block *sb, de->file_type = ext3_type_by_mode[(mode & S_IFMT)>>S_SHIFT]; } -#ifdef CONFIG_EXT3_INDEX /* * Move count entries from end of map between two memory locations. * Returns pointer to last entry moved. @@ -1268,7 +1260,6 @@ errout: *error = err; return NULL; } -#endif /* @@ -1366,7 +1357,6 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, return 0; } -#ifdef CONFIG_EXT3_INDEX /* * This converts a one block unindexed directory to a 3 block indexed * directory, and adds the dentry to the indexed directory. @@ -1445,7 +1435,6 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, return add_dirent_to_buf(handle, dentry, inode, de, bh); } -#endif /* * ext3_add_entry() @@ -1466,9 +1455,7 @@ static int ext3_add_entry (handle_t *handle, struct dentry *dentry, struct ext3_dir_entry_2 *de; struct super_block * sb; int retval; -#ifdef CONFIG_EXT3_INDEX int dx_fallback=0; -#endif unsigned blocksize; u32 block, blocks; @@ -1476,7 +1463,6 @@ static int ext3_add_entry (handle_t *handle, struct dentry *dentry, blocksize = sb->s_blocksize; if (!dentry->d_name.len) return -EINVAL; -#ifdef CONFIG_EXT3_INDEX if (is_dx(dir)) { retval = ext3_dx_add_entry(handle, dentry, inode); if (!retval || (retval != ERR_BAD_DX_DIR)) @@ -1485,7 +1471,6 @@ static int ext3_add_entry (handle_t *handle, struct dentry *dentry, dx_fallback++; ext3_mark_inode_dirty(handle, dir); } -#endif blocks = dir->i_size >> sb->s_blocksize_bits; for (block = 0, offset = 0; block < blocks; block++) { bh = ext3_bread(handle, dir, block, 0, &retval); @@ -1495,11 +1480,9 @@ static int ext3_add_entry (handle_t *handle, struct dentry *dentry, if (retval != -ENOSPC) return retval; -#ifdef CONFIG_EXT3_INDEX if (blocks == 1 && !dx_fallback && EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_DIR_INDEX)) return make_indexed_dir(handle, dentry, inode, bh); -#endif brelse(bh); } bh = ext3_append(handle, dir, &block, &retval); @@ -1511,7 +1494,6 @@ static int ext3_add_entry (handle_t *handle, struct dentry *dentry, return add_dirent_to_buf(handle, dentry, inode, de, bh); } -#ifdef CONFIG_EXT3_INDEX /* * Returns 0 for success, or a negative error value */ @@ -1646,7 +1628,6 @@ cleanup: dx_release(frames); return err; } -#endif /* * ext3_delete_entry deletes a directory entry by merging it with the diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c index 2c97e09c6c6b..44de1453c301 100644 --- a/fs/ext3/resize.c +++ b/fs/ext3/resize.c @@ -154,6 +154,34 @@ static void mark_bitmap_end(int start_bit, int end_bit, char *bitmap) } /* + * If we have fewer than thresh credits, extend by EXT3_MAX_TRANS_DATA. + * If that fails, restart the transaction & regain write access for the + * buffer head which is used for block_bitmap modifications. + */ +static int extend_or_restart_transaction(handle_t *handle, int thresh, + struct buffer_head *bh) +{ + int err; + + if (handle->h_buffer_credits >= thresh) + return 0; + + err = ext3_journal_extend(handle, EXT3_MAX_TRANS_DATA); + if (err < 0) + return err; + if (err) { + err = ext3_journal_restart(handle, EXT3_MAX_TRANS_DATA); + if (err) + return err; + err = ext3_journal_get_write_access(handle, bh); + if (err) + return err; + } + + return 0; +} + +/* * Set up the block and inode bitmaps, and the inode table for the new group. * This doesn't need to be part of the main transaction, since we are only * changing blocks outside the actual filesystem. We still do journaling to @@ -175,8 +203,9 @@ static int setup_new_group_blocks(struct super_block *sb, int i; int err = 0, err2; - handle = ext3_journal_start_sb(sb, reserved_gdb + gdblocks + - 2 + sbi->s_itb_per_group); + /* This transaction may be extended/restarted along the way */ + handle = ext3_journal_start_sb(sb, EXT3_MAX_TRANS_DATA); + if (IS_ERR(handle)) return PTR_ERR(handle); @@ -203,6 +232,10 @@ static int setup_new_group_blocks(struct super_block *sb, ext3_debug("update backup group %#04lx (+%d)\n", block, bit); + err = extend_or_restart_transaction(handle, 1, bh); + if (err) + goto exit_bh; + gdb = sb_getblk(sb, block); if (!gdb) { err = -EIO; @@ -212,10 +245,10 @@ static int setup_new_group_blocks(struct super_block *sb, brelse(gdb); goto exit_bh; } - lock_buffer(bh); - memcpy(gdb->b_data, sbi->s_group_desc[i]->b_data, bh->b_size); + lock_buffer(gdb); + memcpy(gdb->b_data, sbi->s_group_desc[i]->b_data, gdb->b_size); set_buffer_uptodate(gdb); - unlock_buffer(bh); + unlock_buffer(gdb); ext3_journal_dirty_metadata(handle, gdb); ext3_set_bit(bit, bh->b_data); brelse(gdb); @@ -228,6 +261,10 @@ static int setup_new_group_blocks(struct super_block *sb, ext3_debug("clear reserved block %#04lx (+%d)\n", block, bit); + err = extend_or_restart_transaction(handle, 1, bh); + if (err) + goto exit_bh; + if (IS_ERR(gdb = bclean(handle, sb, block))) { err = PTR_ERR(bh); goto exit_bh; @@ -249,6 +286,11 @@ static int setup_new_group_blocks(struct super_block *sb, struct buffer_head *it; ext3_debug("clear inode block %#04lx (+%d)\n", block, bit); + + err = extend_or_restart_transaction(handle, 1, bh); + if (err) + goto exit_bh; + if (IS_ERR(it = bclean(handle, sb, block))) { err = PTR_ERR(it); goto exit_bh; @@ -257,6 +299,11 @@ static int setup_new_group_blocks(struct super_block *sb, brelse(it); ext3_set_bit(bit, bh->b_data); } + + err = extend_or_restart_transaction(handle, 2, bh); + if (err) + goto exit_bh; + mark_bitmap_end(input->blocks_count, EXT3_BLOCKS_PER_GROUP(sb), bh->b_data); ext3_journal_dirty_metadata(handle, bh); @@ -884,9 +931,9 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input) input->reserved_blocks); /* Update the free space counts */ - percpu_counter_mod(&sbi->s_freeblocks_counter, + percpu_counter_add(&sbi->s_freeblocks_counter, input->free_blocks_count); - percpu_counter_mod(&sbi->s_freeinodes_counter, + percpu_counter_add(&sbi->s_freeinodes_counter, EXT3_INODES_PER_GROUP(sb)); ext3_journal_dirty_metadata(handle, sbi->s_sbh); diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 9537316a0714..81868c0bc40e 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -472,7 +472,7 @@ static void ext3_destroy_inode(struct inode *inode) kmem_cache_free(ext3_inode_cachep, EXT3_I(inode)); } -static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(struct kmem_cache * cachep, void *foo) { struct ext3_inode_info *ei = (struct ext3_inode_info *) foo; @@ -545,9 +545,78 @@ static inline void ext3_show_quota_options(struct seq_file *seq, struct super_bl #endif } +/* + * Show an option if + * - it's set to a non-default value OR + * - if the per-sb default is different from the global default + */ static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs) { struct super_block *sb = vfs->mnt_sb; + struct ext3_sb_info *sbi = EXT3_SB(sb); + struct ext3_super_block *es = sbi->s_es; + unsigned long def_mount_opts; + + def_mount_opts = le32_to_cpu(es->s_default_mount_opts); + + if (sbi->s_sb_block != 1) + seq_printf(seq, ",sb=%lu", sbi->s_sb_block); + if (test_opt(sb, MINIX_DF)) + seq_puts(seq, ",minixdf"); + if (test_opt(sb, GRPID)) + seq_puts(seq, ",grpid"); + if (!test_opt(sb, GRPID) && (def_mount_opts & EXT3_DEFM_BSDGROUPS)) + seq_puts(seq, ",nogrpid"); + if (sbi->s_resuid != EXT3_DEF_RESUID || + le16_to_cpu(es->s_def_resuid) != EXT3_DEF_RESUID) { + seq_printf(seq, ",resuid=%u", sbi->s_resuid); + } + if (sbi->s_resgid != EXT3_DEF_RESGID || + le16_to_cpu(es->s_def_resgid) != EXT3_DEF_RESGID) { + seq_printf(seq, ",resgid=%u", sbi->s_resgid); + } + if (test_opt(sb, ERRORS_CONT)) { + int def_errors = le16_to_cpu(es->s_errors); + + if (def_errors == EXT3_ERRORS_PANIC || + def_errors == EXT3_ERRORS_RO) { + seq_puts(seq, ",errors=continue"); + } + } + if (test_opt(sb, ERRORS_RO)) + seq_puts(seq, ",errors=remount-ro"); + if (test_opt(sb, ERRORS_PANIC)) + seq_puts(seq, ",errors=panic"); + if (test_opt(sb, NO_UID32)) + seq_puts(seq, ",nouid32"); + if (test_opt(sb, DEBUG)) + seq_puts(seq, ",debug"); + if (test_opt(sb, OLDALLOC)) + seq_puts(seq, ",oldalloc"); +#ifdef CONFIG_EXT3_FS_XATTR + if (test_opt(sb, XATTR_USER)) + seq_puts(seq, ",user_xattr"); + if (!test_opt(sb, XATTR_USER) && + (def_mount_opts & EXT3_DEFM_XATTR_USER)) { + seq_puts(seq, ",nouser_xattr"); + } +#endif +#ifdef CONFIG_EXT3_FS_POSIX_ACL + if (test_opt(sb, POSIX_ACL)) + seq_puts(seq, ",acl"); + if (!test_opt(sb, POSIX_ACL) && (def_mount_opts & EXT3_DEFM_ACL)) + seq_puts(seq, ",noacl"); +#endif + if (!test_opt(sb, RESERVATION)) + seq_puts(seq, ",noreservation"); + if (sbi->s_commit_interval) { + seq_printf(seq, ",commit=%u", + (unsigned) (sbi->s_commit_interval / HZ)); + } + if (test_opt(sb, BARRIER)) + seq_puts(seq, ",barrier=1"); + if (test_opt(sb, NOBH)) + seq_puts(seq, ",nobh"); if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA) seq_puts(seq, ",data=journal"); @@ -1416,6 +1485,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) int i; int needs_recovery; __le32 features; + int err; sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); if (!sbi) @@ -1424,6 +1494,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) sbi->s_mount_opt = 0; sbi->s_resuid = EXT3_DEF_RESUID; sbi->s_resgid = EXT3_DEF_RESGID; + sbi->s_sb_block = sb_block; unlock_kernel(); @@ -1549,7 +1620,11 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) } brelse (bh); - sb_set_blocksize(sb, blocksize); + if (!sb_set_blocksize(sb, blocksize)) { + printk(KERN_ERR "EXT3-fs: bad blocksize %d.\n", + blocksize); + goto out_fail; + } logic_sb_block = (sb_block * EXT3_MIN_BLOCK_SIZE) / blocksize; offset = (sb_block * EXT3_MIN_BLOCK_SIZE) % blocksize; bh = sb_bread(sb, logic_sb_block); @@ -1675,12 +1750,20 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) get_random_bytes(&sbi->s_next_generation, sizeof(u32)); spin_lock_init(&sbi->s_next_gen_lock); - percpu_counter_init(&sbi->s_freeblocks_counter, - ext3_count_free_blocks(sb)); - percpu_counter_init(&sbi->s_freeinodes_counter, - ext3_count_free_inodes(sb)); - percpu_counter_init(&sbi->s_dirs_counter, - ext3_count_dirs(sb)); + err = percpu_counter_init(&sbi->s_freeblocks_counter, + ext3_count_free_blocks(sb)); + if (!err) { + err = percpu_counter_init(&sbi->s_freeinodes_counter, + ext3_count_free_inodes(sb)); + } + if (!err) { + err = percpu_counter_init(&sbi->s_dirs_counter, + ext3_count_dirs(sb)); + } + if (err) { + printk(KERN_ERR "EXT3-fs: insufficient memory\n"); + goto failed_mount3; + } /* per fileystem reservation list head & lock */ spin_lock_init(&sbi->s_rsv_window_lock); @@ -2472,13 +2555,13 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf) buf->f_type = EXT3_SUPER_MAGIC; buf->f_bsize = sb->s_blocksize; buf->f_blocks = le32_to_cpu(es->s_blocks_count) - sbi->s_overhead_last; - buf->f_bfree = percpu_counter_sum(&sbi->s_freeblocks_counter); + buf->f_bfree = percpu_counter_sum_positive(&sbi->s_freeblocks_counter); es->s_free_blocks_count = cpu_to_le32(buf->f_bfree); buf->f_bavail = buf->f_bfree - le32_to_cpu(es->s_r_blocks_count); if (buf->f_bfree < le32_to_cpu(es->s_r_blocks_count)) buf->f_bavail = 0; buf->f_files = le32_to_cpu(es->s_inodes_count); - buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter); + buf->f_ffree = percpu_counter_sum_positive(&sbi->s_freeinodes_counter); es->s_free_inodes_count = cpu_to_le32(buf->f_ffree); buf->f_namelen = EXT3_NAME_LEN; fsid = le64_to_cpup((void *)es->s_uuid) ^ diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index f58cbb26323e..408373819e34 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c @@ -741,12 +741,11 @@ ext3_xattr_block_set(handle_t *handle, struct inode *inode, } } else { /* Allocate a buffer where we construct the new block. */ - s->base = kmalloc(sb->s_blocksize, GFP_KERNEL); + s->base = kzalloc(sb->s_blocksize, GFP_KERNEL); /* assert(header == s->base) */ error = -ENOMEM; if (s->base == NULL) goto cleanup; - memset(s->base, 0, sb->s_blocksize); header(s->base)->h_magic = cpu_to_le32(EXT3_XATTR_MAGIC); header(s->base)->h_blocks = cpu_to_le32(1); header(s->base)->h_refcount = cpu_to_le32(1); diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index e53b4af52f11..e906b65448e2 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -20,6 +20,7 @@ #include <linux/quotaops.h> #include <linux/buffer_head.h> +#include "group.h" /* * balloc.c contains the blocks allocation and deallocation routines */ @@ -42,6 +43,94 @@ void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr, } +/* Initializes an uninitialized block bitmap if given, and returns the + * number of blocks free in the group. */ +unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh, + int block_group, struct ext4_group_desc *gdp) +{ + unsigned long start; + int bit, bit_max; + unsigned free_blocks, group_blocks; + struct ext4_sb_info *sbi = EXT4_SB(sb); + + if (bh) { + J_ASSERT_BH(bh, buffer_locked(bh)); + + /* If checksum is bad mark all blocks used to prevent allocation + * essentially implementing a per-group read-only flag. */ + if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) { + ext4_error(sb, __FUNCTION__, + "Checksum bad for group %u\n", block_group); + gdp->bg_free_blocks_count = 0; + gdp->bg_free_inodes_count = 0; + gdp->bg_itable_unused = 0; + memset(bh->b_data, 0xff, sb->s_blocksize); + return 0; + } + memset(bh->b_data, 0, sb->s_blocksize); + } + + /* Check for superblock and gdt backups in this group */ + bit_max = ext4_bg_has_super(sb, block_group); + + if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG) || + block_group < le32_to_cpu(sbi->s_es->s_first_meta_bg) * + sbi->s_desc_per_block) { + if (bit_max) { + bit_max += ext4_bg_num_gdb(sb, block_group); + bit_max += + le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks); + } + } else { /* For META_BG_BLOCK_GROUPS */ + int group_rel = (block_group - + le32_to_cpu(sbi->s_es->s_first_meta_bg)) % + EXT4_DESC_PER_BLOCK(sb); + if (group_rel == 0 || group_rel == 1 || + (group_rel == EXT4_DESC_PER_BLOCK(sb) - 1)) + bit_max += 1; + } + + if (block_group == sbi->s_groups_count - 1) { + /* + * Even though mke2fs always initialize first and last group + * if some other tool enabled the EXT4_BG_BLOCK_UNINIT we need + * to make sure we calculate the right free blocks + */ + group_blocks = ext4_blocks_count(sbi->s_es) - + le32_to_cpu(sbi->s_es->s_first_data_block) - + (EXT4_BLOCKS_PER_GROUP(sb) * (sbi->s_groups_count -1)); + } else { + group_blocks = EXT4_BLOCKS_PER_GROUP(sb); + } + + free_blocks = group_blocks - bit_max; + + if (bh) { + for (bit = 0; bit < bit_max; bit++) + ext4_set_bit(bit, bh->b_data); + + start = block_group * EXT4_BLOCKS_PER_GROUP(sb) + + le32_to_cpu(sbi->s_es->s_first_data_block); + + /* Set bits for block and inode bitmaps, and inode table */ + ext4_set_bit(ext4_block_bitmap(sb, gdp) - start, bh->b_data); + ext4_set_bit(ext4_inode_bitmap(sb, gdp) - start, bh->b_data); + for (bit = (ext4_inode_table(sb, gdp) - start), + bit_max = bit + sbi->s_itb_per_group; bit < bit_max; bit++) + ext4_set_bit(bit, bh->b_data); + + /* + * Also if the number of blocks within the group is + * less than the blocksize * 8 ( which is the size + * of bitmap ), set rest of the block bitmap to 1 + */ + mark_bitmap_end(group_blocks, sb->s_blocksize * 8, bh->b_data); + } + + return free_blocks - sbi->s_itb_per_group - 2; +} + + /* * The free blocks are managed by bitmaps. A file system contains several * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap @@ -100,6 +189,15 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb, return desc; } +static inline int +block_in_use(ext4_fsblk_t block, struct super_block *sb, unsigned char *map) +{ + ext4_grpblk_t offset; + + ext4_get_group_no_and_offset(sb, block, NULL, &offset); + return ext4_test_bit (offset, map); +} + /** * read_block_bitmap() * @sb: super block @@ -110,24 +208,69 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb, * * Return buffer_head on success or NULL in case of failure. */ -static struct buffer_head * +struct buffer_head * read_block_bitmap(struct super_block *sb, unsigned int block_group) { + int i; struct ext4_group_desc * desc; struct buffer_head * bh = NULL; + ext4_fsblk_t bitmap_blk; - desc = ext4_get_group_desc (sb, block_group, NULL); + desc = ext4_get_group_desc(sb, block_group, NULL); if (!desc) - goto error_out; - bh = sb_bread(sb, ext4_block_bitmap(sb, desc)); + return NULL; + bitmap_blk = ext4_block_bitmap(sb, desc); + if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { + bh = sb_getblk(sb, bitmap_blk); + if (!buffer_uptodate(bh)) { + lock_buffer(bh); + if (!buffer_uptodate(bh)) { + ext4_init_block_bitmap(sb, bh, block_group, + desc); + set_buffer_uptodate(bh); + } + unlock_buffer(bh); + } + } else { + bh = sb_bread(sb, bitmap_blk); + } if (!bh) - ext4_error (sb, "read_block_bitmap", + ext4_error (sb, __FUNCTION__, "Cannot read block bitmap - " "block_group = %d, block_bitmap = %llu", - block_group, - ext4_block_bitmap(sb, desc)); -error_out: + block_group, bitmap_blk); + + /* check whether block bitmap block number is set */ + if (!block_in_use(bitmap_blk, sb, bh->b_data)) { + /* bad block bitmap */ + goto error_out; + } + + /* check whether the inode bitmap block number is set */ + bitmap_blk = ext4_inode_bitmap(sb, desc); + if (!block_in_use(bitmap_blk, sb, bh->b_data)) { + /* bad block bitmap */ + goto error_out; + } + /* check whether the inode table block number is set */ + bitmap_blk = ext4_inode_table(sb, desc); + for (i = 0; i < EXT4_SB(sb)->s_itb_per_group; i++, bitmap_blk++) { + if (!block_in_use(bitmap_blk, sb, bh->b_data)) { + /* bad block bitmap */ + goto error_out; + } + } + return bh; + +error_out: + brelse(bh); + ext4_error(sb, __FUNCTION__, + "Invalid block bitmap - " + "block_group = %d, block = %llu", + block_group, bitmap_blk); + return NULL; + } /* * The reservation window structure operations @@ -586,8 +729,9 @@ do_more: desc->bg_free_blocks_count = cpu_to_le16(le16_to_cpu(desc->bg_free_blocks_count) + group_freed); + desc->bg_checksum = ext4_group_desc_csum(sbi, block_group, desc); spin_unlock(sb_bgl_lock(sbi, block_group)); - percpu_counter_mod(&sbi->s_freeblocks_counter, count); + percpu_counter_add(&sbi->s_freeblocks_counter, count); /* We dirtied the bitmap block */ BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); @@ -1644,10 +1788,13 @@ allocated: ret_block, goal_hits, goal_attempts); spin_lock(sb_bgl_lock(sbi, group_no)); + if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) + gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); gdp->bg_free_blocks_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)-num); + gdp->bg_checksum = ext4_group_desc_csum(sbi, group_no, gdp); spin_unlock(sb_bgl_lock(sbi, group_no)); - percpu_counter_mod(&sbi->s_freeblocks_counter, -num); + percpu_counter_sub(&sbi->s_freeblocks_counter, num); BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor"); err = ext4_journal_dirty_metadata(handle, gdp_bh); @@ -1747,15 +1894,6 @@ ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb) #endif } -static inline int -block_in_use(ext4_fsblk_t block, struct super_block *sb, unsigned char *map) -{ - ext4_grpblk_t offset; - - ext4_get_group_no_and_offset(sb, block, NULL, &offset); - return ext4_test_bit (offset, map); -} - static inline int test_root(int a, int b) { int num = b; diff --git a/fs/ext4/bitmap.c b/fs/ext4/bitmap.c index 11e93c169bcf..420554f8f79d 100644 --- a/fs/ext4/bitmap.c +++ b/fs/ext4/bitmap.c @@ -13,7 +13,7 @@ #ifdef EXT4FS_DEBUG -static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}; +static const int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}; unsigned long ext4_count_free (struct buffer_head * map, unsigned int numchars) { diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index 3ab01c04e00c..f612bef98315 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c @@ -47,9 +47,7 @@ const struct file_operations ext4_dir_operations = { .compat_ioctl = ext4_compat_ioctl, #endif .fsync = ext4_sync_file, /* BKL held */ -#ifdef CONFIG_EXT4_INDEX .release = ext4_release_dir, -#endif }; @@ -107,7 +105,6 @@ static int ext4_readdir(struct file * filp, sb = inode->i_sb; -#ifdef CONFIG_EXT4_INDEX if (EXT4_HAS_COMPAT_FEATURE(inode->i_sb, EXT4_FEATURE_COMPAT_DIR_INDEX) && ((EXT4_I(inode)->i_flags & EXT4_INDEX_FL) || @@ -123,7 +120,6 @@ static int ext4_readdir(struct file * filp, */ EXT4_I(filp->f_path.dentry->d_inode)->i_flags &= ~EXT4_INDEX_FL; } -#endif stored = 0; offset = filp->f_pos & (sb->s_blocksize - 1); @@ -142,7 +138,7 @@ static int ext4_readdir(struct file * filp, sb->s_bdev->bd_inode->i_mapping, &filp->f_ra, filp, index, 1); - filp->f_ra.prev_index = index; + filp->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT; bh = ext4_bread(NULL, inode, blk, 0, &err); } @@ -210,7 +206,7 @@ revalidate: * not the directory has been modified * during the copy operation. */ - unsigned long version = filp->f_version; + u64 version = filp->f_version; error = filldir(dirent, de->name, de->name_len, @@ -232,7 +228,6 @@ out: return ret; } -#ifdef CONFIG_EXT4_INDEX /* * These functions convert from the major/minor hash to an f_pos * value. @@ -518,5 +513,3 @@ static int ext4_release_dir (struct inode * inode, struct file * filp) return 0; } - -#endif diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 78beb096f57d..85287742f2ae 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -33,7 +33,7 @@ #include <linux/fs.h> #include <linux/time.h> #include <linux/ext4_jbd2.h> -#include <linux/jbd.h> +#include <linux/jbd2.h> #include <linux/highuid.h> #include <linux/pagemap.h> #include <linux/quotaops.h> @@ -52,7 +52,7 @@ static ext4_fsblk_t ext_pblock(struct ext4_extent *ex) { ext4_fsblk_t block; - block = le32_to_cpu(ex->ee_start); + block = le32_to_cpu(ex->ee_start_lo); block |= ((ext4_fsblk_t) le16_to_cpu(ex->ee_start_hi) << 31) << 1; return block; } @@ -65,7 +65,7 @@ static ext4_fsblk_t idx_pblock(struct ext4_extent_idx *ix) { ext4_fsblk_t block; - block = le32_to_cpu(ix->ei_leaf); + block = le32_to_cpu(ix->ei_leaf_lo); block |= ((ext4_fsblk_t) le16_to_cpu(ix->ei_leaf_hi) << 31) << 1; return block; } @@ -77,7 +77,7 @@ static ext4_fsblk_t idx_pblock(struct ext4_extent_idx *ix) */ static void ext4_ext_store_pblock(struct ext4_extent *ex, ext4_fsblk_t pb) { - ex->ee_start = cpu_to_le32((unsigned long) (pb & 0xffffffff)); + ex->ee_start_lo = cpu_to_le32((unsigned long) (pb & 0xffffffff)); ex->ee_start_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff); } @@ -88,7 +88,7 @@ static void ext4_ext_store_pblock(struct ext4_extent *ex, ext4_fsblk_t pb) */ static void ext4_idx_store_pblock(struct ext4_extent_idx *ix, ext4_fsblk_t pb) { - ix->ei_leaf = cpu_to_le32((unsigned long) (pb & 0xffffffff)); + ix->ei_leaf_lo = cpu_to_le32((unsigned long) (pb & 0xffffffff)); ix->ei_leaf_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff); } @@ -1409,8 +1409,7 @@ has_space: eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)+1); nearex = path[depth].p_ext; nearex->ee_block = newext->ee_block; - nearex->ee_start = newext->ee_start; - nearex->ee_start_hi = newext->ee_start_hi; + ext4_ext_store_pblock(nearex, ext_pblock(newext)); nearex->ee_len = newext->ee_len; merge: @@ -2177,7 +2176,6 @@ int ext4_ext_convert_to_initialized(handle_t *handle, struct inode *inode, } /* ex2: iblock to iblock + maxblocks-1 : initialised */ ex2->ee_block = cpu_to_le32(iblock); - ex2->ee_start = cpu_to_le32(newblock); ext4_ext_store_pblock(ex2, newblock); ex2->ee_len = cpu_to_le16(allocated); if (ex2 != ex) diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index 2a167d7131fa..8d50879d1c2c 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c @@ -47,7 +47,7 @@ int ext4_sync_file(struct file * file, struct dentry *dentry, int datasync) struct inode *inode = dentry->d_inode; int ret = 0; - J_ASSERT(ext4_journal_current_handle() == 0); + J_ASSERT(ext4_journal_current_handle() == NULL); /* * data=writeback: diff --git a/fs/ext4/group.h b/fs/ext4/group.h new file mode 100644 index 000000000000..1577910bb58b --- /dev/null +++ b/fs/ext4/group.h @@ -0,0 +1,27 @@ +/* + * linux/fs/ext4/group.h + * + * Copyright (C) 2007 Cluster File Systems, Inc + * + * Author: Andreas Dilger <adilger@clusterfs.com> + */ + +#ifndef _LINUX_EXT4_GROUP_H +#define _LINUX_EXT4_GROUP_H + +extern __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 group, + struct ext4_group_desc *gdp); +extern int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 group, + struct ext4_group_desc *gdp); +struct buffer_head *read_block_bitmap(struct super_block *sb, + unsigned int block_group); +extern unsigned ext4_init_block_bitmap(struct super_block *sb, + struct buffer_head *bh, int group, + struct ext4_group_desc *desc); +#define ext4_free_blocks_after_init(sb, group, desc) \ + ext4_init_block_bitmap(sb, NULL, group, desc) +extern unsigned ext4_init_inode_bitmap(struct super_block *sb, + struct buffer_head *bh, int group, + struct ext4_group_desc *desc); +extern void mark_bitmap_end(int start_bit, int end_bit, char *bitmap); +#endif /* _LINUX_EXT4_GROUP_H */ diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 427f83066a0d..c61f37fd3f05 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -28,6 +28,7 @@ #include "xattr.h" #include "acl.h" +#include "group.h" /* * ialloc.c contains the inodes allocation and deallocation routines @@ -43,6 +44,52 @@ * the free blocks count in the block. */ +/* + * To avoid calling the atomic setbit hundreds or thousands of times, we only + * need to use it within a single byte (to ensure we get endianness right). + * We can use memset for the rest of the bitmap as there are no other users. + */ +void mark_bitmap_end(int start_bit, int end_bit, char *bitmap) +{ + int i; + + if (start_bit >= end_bit) + return; + + ext4_debug("mark end bits +%d through +%d used\n", start_bit, end_bit); + for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++) + ext4_set_bit(i, bitmap); + if (i < end_bit) + memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3); +} + +/* Initializes an uninitialized inode bitmap */ +unsigned ext4_init_inode_bitmap(struct super_block *sb, + struct buffer_head *bh, int block_group, + struct ext4_group_desc *gdp) +{ + struct ext4_sb_info *sbi = EXT4_SB(sb); + + J_ASSERT_BH(bh, buffer_locked(bh)); + + /* If checksum is bad mark all blocks and inodes use to prevent + * allocation, essentially implementing a per-group read-only flag. */ + if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) { + ext4_error(sb, __FUNCTION__, "Checksum bad for group %u\n", + block_group); + gdp->bg_free_blocks_count = 0; + gdp->bg_free_inodes_count = 0; + gdp->bg_itable_unused = 0; + memset(bh->b_data, 0xff, sb->s_blocksize); + return 0; + } + + memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8); + mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), EXT4_BLOCKS_PER_GROUP(sb), + bh->b_data); + + return EXT4_INODES_PER_GROUP(sb); +} /* * Read the inode allocation bitmap for a given block_group, reading @@ -59,8 +106,20 @@ read_inode_bitmap(struct super_block * sb, unsigned long block_group) desc = ext4_get_group_desc(sb, block_group, NULL); if (!desc) goto error_out; - - bh = sb_bread(sb, ext4_inode_bitmap(sb, desc)); + if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) { + bh = sb_getblk(sb, ext4_inode_bitmap(sb, desc)); + if (!buffer_uptodate(bh)) { + lock_buffer(bh); + if (!buffer_uptodate(bh)) { + ext4_init_inode_bitmap(sb, bh, block_group, + desc); + set_buffer_uptodate(bh); + } + unlock_buffer(bh); + } + } else { + bh = sb_bread(sb, ext4_inode_bitmap(sb, desc)); + } if (!bh) ext4_error(sb, "read_inode_bitmap", "Cannot read inode bitmap - " @@ -169,6 +228,8 @@ void ext4_free_inode (handle_t *handle, struct inode * inode) if (is_directory) gdp->bg_used_dirs_count = cpu_to_le16( le16_to_cpu(gdp->bg_used_dirs_count) - 1); + gdp->bg_checksum = ext4_group_desc_csum(sbi, + block_group, gdp); spin_unlock(sb_bgl_lock(sbi, block_group)); percpu_counter_inc(&sbi->s_freeinodes_counter); if (is_directory) @@ -204,14 +265,13 @@ static int find_group_dir(struct super_block *sb, struct inode *parent) int ngroups = EXT4_SB(sb)->s_groups_count; unsigned int freei, avefreei; struct ext4_group_desc *desc, *best_desc = NULL; - struct buffer_head *bh; int group, best_group = -1; freei = percpu_counter_read_positive(&EXT4_SB(sb)->s_freeinodes_counter); avefreei = freei / ngroups; for (group = 0; group < ngroups; group++) { - desc = ext4_get_group_desc (sb, group, &bh); + desc = ext4_get_group_desc (sb, group, NULL); if (!desc || !desc->bg_free_inodes_count) continue; if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei) @@ -269,7 +329,6 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) ext4_grpblk_t min_blocks; int group = -1, i; struct ext4_group_desc *desc; - struct buffer_head *bh; freei = percpu_counter_read_positive(&sbi->s_freeinodes_counter); avefreei = freei / ngroups; @@ -287,7 +346,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) parent_group = (unsigned)group % ngroups; for (i = 0; i < ngroups; i++) { group = (parent_group + i) % ngroups; - desc = ext4_get_group_desc (sb, group, &bh); + desc = ext4_get_group_desc (sb, group, NULL); if (!desc || !desc->bg_free_inodes_count) continue; if (le16_to_cpu(desc->bg_used_dirs_count) >= best_ndir) @@ -322,7 +381,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) for (i = 0; i < ngroups; i++) { group = (parent_group + i) % ngroups; - desc = ext4_get_group_desc (sb, group, &bh); + desc = ext4_get_group_desc (sb, group, NULL); if (!desc || !desc->bg_free_inodes_count) continue; if (le16_to_cpu(desc->bg_used_dirs_count) >= max_dirs) @@ -337,7 +396,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) fallback: for (i = 0; i < ngroups; i++) { group = (parent_group + i) % ngroups; - desc = ext4_get_group_desc (sb, group, &bh); + desc = ext4_get_group_desc (sb, group, NULL); if (!desc || !desc->bg_free_inodes_count) continue; if (le16_to_cpu(desc->bg_free_inodes_count) >= avefreei) @@ -361,14 +420,13 @@ static int find_group_other(struct super_block *sb, struct inode *parent) int parent_group = EXT4_I(parent)->i_block_group; int ngroups = EXT4_SB(sb)->s_groups_count; struct ext4_group_desc *desc; - struct buffer_head *bh; int group, i; /* * Try to place the inode in its parent directory */ group = parent_group; - desc = ext4_get_group_desc (sb, group, &bh); + desc = ext4_get_group_desc (sb, group, NULL); if (desc && le16_to_cpu(desc->bg_free_inodes_count) && le16_to_cpu(desc->bg_free_blocks_count)) return group; @@ -392,7 +450,7 @@ static int find_group_other(struct super_block *sb, struct inode *parent) group += i; if (group >= ngroups) group -= ngroups; - desc = ext4_get_group_desc (sb, group, &bh); + desc = ext4_get_group_desc (sb, group, NULL); if (desc && le16_to_cpu(desc->bg_free_inodes_count) && le16_to_cpu(desc->bg_free_blocks_count)) return group; @@ -406,7 +464,7 @@ static int find_group_other(struct super_block *sb, struct inode *parent) for (i = 0; i < ngroups; i++) { if (++group >= ngroups) group = 0; - desc = ext4_get_group_desc (sb, group, &bh); + desc = ext4_get_group_desc (sb, group, NULL); if (desc && le16_to_cpu(desc->bg_free_inodes_count)) return group; } @@ -438,7 +496,7 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode * dir, int mode) struct ext4_sb_info *sbi; int err = 0; struct inode *ret; - int i; + int i, free = 0; /* Cannot create files in a deleted directory */ if (!dir || !dir->i_nlink) @@ -520,11 +578,13 @@ repeat_in_this_group: goto out; got: - ino += group * EXT4_INODES_PER_GROUP(sb) + 1; - if (ino < EXT4_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { - ext4_error (sb, "ext4_new_inode", - "reserved inode or inode > inodes count - " - "block_group = %d, inode=%lu", group, ino); + ino++; + if ((group == 0 && ino < EXT4_FIRST_INO(sb)) || + ino > EXT4_INODES_PER_GROUP(sb)) { + ext4_error(sb, __FUNCTION__, + "reserved inode or inode > inodes count - " + "block_group = %d, inode=%lu", group, + ino + group * EXT4_INODES_PER_GROUP(sb)); err = -EIO; goto fail; } @@ -532,13 +592,78 @@ got: BUFFER_TRACE(bh2, "get_write_access"); err = ext4_journal_get_write_access(handle, bh2); if (err) goto fail; + + /* We may have to initialize the block bitmap if it isn't already */ + if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM) && + gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { + struct buffer_head *block_bh = read_block_bitmap(sb, group); + + BUFFER_TRACE(block_bh, "get block bitmap access"); + err = ext4_journal_get_write_access(handle, block_bh); + if (err) { + brelse(block_bh); + goto fail; + } + + free = 0; + spin_lock(sb_bgl_lock(sbi, group)); + /* recheck and clear flag under lock if we still need to */ + if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { + gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); + free = ext4_free_blocks_after_init(sb, group, gdp); + gdp->bg_free_blocks_count = cpu_to_le16(free); + } + spin_unlock(sb_bgl_lock(sbi, group)); + + /* Don't need to dirty bitmap block if we didn't change it */ + if (free) { + BUFFER_TRACE(block_bh, "dirty block bitmap"); + err = ext4_journal_dirty_metadata(handle, block_bh); + } + + brelse(block_bh); + if (err) + goto fail; + } + spin_lock(sb_bgl_lock(sbi, group)); + /* If we didn't allocate from within the initialized part of the inode + * table then we need to initialize up to this inode. */ + if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) { + if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) { + gdp->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT); + + /* When marking the block group with + * ~EXT4_BG_INODE_UNINIT we don't want to depend + * on the value of bg_itable_unsed even though + * mke2fs could have initialized the same for us. + * Instead we calculated the value below + */ + + free = 0; + } else { + free = EXT4_INODES_PER_GROUP(sb) - + le16_to_cpu(gdp->bg_itable_unused); + } + + /* + * Check the relative inode number against the last used + * relative inode number in this group. if it is greater + * we need to update the bg_itable_unused count + * + */ + if (ino > free) + gdp->bg_itable_unused = + cpu_to_le16(EXT4_INODES_PER_GROUP(sb) - ino); + } + gdp->bg_free_inodes_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1); if (S_ISDIR(mode)) { gdp->bg_used_dirs_count = cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1); } + gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp); spin_unlock(sb_bgl_lock(sbi, group)); BUFFER_TRACE(bh2, "call ext4_journal_dirty_metadata"); err = ext4_journal_dirty_metadata(handle, bh2); @@ -560,7 +685,7 @@ got: inode->i_gid = current->fsgid; inode->i_mode = mode; - inode->i_ino = ino; + inode->i_ino = ino + group * EXT4_INODES_PER_GROUP(sb); /* This is the optimal IO size (for stat), not the fs block size */ inode->i_blocks = 0; inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime = @@ -576,11 +701,6 @@ got: /* dirsync only applies to directories */ if (!S_ISDIR(mode)) ei->i_flags &= ~EXT4_DIRSYNC_FL; -#ifdef EXT4_FRAGMENTS - ei->i_faddr = 0; - ei->i_frag_no = 0; - ei->i_frag_size = 0; -#endif ei->i_file_acl = 0; ei->i_dir_acl = 0; ei->i_dtime = 0; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index a4848e04a5ed..5489703d9573 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1027,7 +1027,7 @@ struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode, } if (buffer_new(&dummy)) { J_ASSERT(create != 0); - J_ASSERT(handle != 0); + J_ASSERT(handle != NULL); /* * Now that we do not always journal data, we should @@ -1146,34 +1146,50 @@ static int do_journal_get_write_access(handle_t *handle, return ext4_journal_get_write_access(handle, bh); } -static int ext4_prepare_write(struct file *file, struct page *page, - unsigned from, unsigned to) +static int ext4_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - struct inode *inode = page->mapping->host; + struct inode *inode = mapping->host; int ret, needed_blocks = ext4_writepage_trans_blocks(inode); handle_t *handle; int retries = 0; + struct page *page; + pgoff_t index; + unsigned from, to; + + index = pos >> PAGE_CACHE_SHIFT; + from = pos & (PAGE_CACHE_SIZE - 1); + to = from + len; retry: - handle = ext4_journal_start(inode, needed_blocks); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - goto out; + page = __grab_cache_page(mapping, index); + if (!page) + return -ENOMEM; + *pagep = page; + + handle = ext4_journal_start(inode, needed_blocks); + if (IS_ERR(handle)) { + unlock_page(page); + page_cache_release(page); + ret = PTR_ERR(handle); + goto out; } - if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode)) - ret = nobh_prepare_write(page, from, to, ext4_get_block); - else - ret = block_prepare_write(page, from, to, ext4_get_block); - if (ret) - goto prepare_write_failed; - if (ext4_should_journal_data(inode)) { + ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + ext4_get_block); + + if (!ret && ext4_should_journal_data(inode)) { ret = walk_page_buffers(handle, page_buffers(page), from, to, NULL, do_journal_get_write_access); } -prepare_write_failed: - if (ret) + + if (ret) { ext4_journal_stop(handle); + unlock_page(page); + page_cache_release(page); + } + if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) goto retry; out: @@ -1185,12 +1201,12 @@ int ext4_journal_dirty_data(handle_t *handle, struct buffer_head *bh) int err = jbd2_journal_dirty_data(handle, bh); if (err) ext4_journal_abort_handle(__FUNCTION__, __FUNCTION__, - bh, handle,err); + bh, handle, err); return err; } -/* For commit_write() in data=journal mode */ -static int commit_write_fn(handle_t *handle, struct buffer_head *bh) +/* For write_end() in data=journal mode */ +static int write_end_fn(handle_t *handle, struct buffer_head *bh) { if (!buffer_mapped(bh) || buffer_freed(bh)) return 0; @@ -1199,84 +1215,130 @@ static int commit_write_fn(handle_t *handle, struct buffer_head *bh) } /* + * Generic write_end handler for ordered and writeback ext4 journal modes. + * We can't use generic_write_end, because that unlocks the page and we need to + * unlock the page after ext4_journal_stop, but ext4_journal_stop must run + * after block_write_end. + */ +static int ext4_generic_write_end(struct file *file, + struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) +{ + struct inode *inode = file->f_mapping->host; + + copied = block_write_end(file, mapping, pos, len, copied, page, fsdata); + + if (pos+copied > inode->i_size) { + i_size_write(inode, pos+copied); + mark_inode_dirty(inode); + } + + return copied; +} + +/* * We need to pick up the new inode size which generic_commit_write gave us * `file' can be NULL - eg, when called from page_symlink(). * * ext4 never places buffers on inode->i_mapping->private_list. metadata * buffers are managed internally. */ -static int ext4_ordered_commit_write(struct file *file, struct page *page, - unsigned from, unsigned to) +static int ext4_ordered_write_end(struct file *file, + struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) { handle_t *handle = ext4_journal_current_handle(); - struct inode *inode = page->mapping->host; + struct inode *inode = file->f_mapping->host; + unsigned from, to; int ret = 0, ret2; + from = pos & (PAGE_CACHE_SIZE - 1); + to = from + len; + ret = walk_page_buffers(handle, page_buffers(page), from, to, NULL, ext4_journal_dirty_data); if (ret == 0) { /* - * generic_commit_write() will run mark_inode_dirty() if i_size + * generic_write_end() will run mark_inode_dirty() if i_size * changes. So let's piggyback the i_disksize mark_inode_dirty * into that. */ loff_t new_i_size; - new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + new_i_size = pos + copied; if (new_i_size > EXT4_I(inode)->i_disksize) EXT4_I(inode)->i_disksize = new_i_size; - ret = generic_commit_write(file, page, from, to); + copied = ext4_generic_write_end(file, mapping, pos, len, copied, + page, fsdata); + if (copied < 0) + ret = copied; } ret2 = ext4_journal_stop(handle); if (!ret) ret = ret2; - return ret; + unlock_page(page); + page_cache_release(page); + + return ret ? ret : copied; } -static int ext4_writeback_commit_write(struct file *file, struct page *page, - unsigned from, unsigned to) +static int ext4_writeback_write_end(struct file *file, + struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) { handle_t *handle = ext4_journal_current_handle(); - struct inode *inode = page->mapping->host; + struct inode *inode = file->f_mapping->host; int ret = 0, ret2; loff_t new_i_size; - new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + new_i_size = pos + copied; if (new_i_size > EXT4_I(inode)->i_disksize) EXT4_I(inode)->i_disksize = new_i_size; - if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode)) - ret = nobh_commit_write(file, page, from, to); - else - ret = generic_commit_write(file, page, from, to); + copied = ext4_generic_write_end(file, mapping, pos, len, copied, + page, fsdata); + if (copied < 0) + ret = copied; ret2 = ext4_journal_stop(handle); if (!ret) ret = ret2; - return ret; + unlock_page(page); + page_cache_release(page); + + return ret ? ret : copied; } -static int ext4_journalled_commit_write(struct file *file, - struct page *page, unsigned from, unsigned to) +static int ext4_journalled_write_end(struct file *file, + struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) { handle_t *handle = ext4_journal_current_handle(); - struct inode *inode = page->mapping->host; + struct inode *inode = mapping->host; int ret = 0, ret2; int partial = 0; - loff_t pos; + unsigned from, to; - /* - * Here we duplicate the generic_commit_write() functionality - */ - pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + from = pos & (PAGE_CACHE_SIZE - 1); + to = from + len; + + if (copied < len) { + if (!PageUptodate(page)) + copied = 0; + page_zero_new_buffers(page, from+copied, to); + } ret = walk_page_buffers(handle, page_buffers(page), from, - to, &partial, commit_write_fn); + to, &partial, write_end_fn); if (!partial) SetPageUptodate(page); - if (pos > inode->i_size) - i_size_write(inode, pos); + if (pos+copied > inode->i_size) + i_size_write(inode, pos+copied); EXT4_I(inode)->i_state |= EXT4_STATE_JDATA; if (inode->i_size > EXT4_I(inode)->i_disksize) { EXT4_I(inode)->i_disksize = inode->i_size; @@ -1284,10 +1346,14 @@ static int ext4_journalled_commit_write(struct file *file, if (!ret) ret = ret2; } + ret2 = ext4_journal_stop(handle); if (!ret) ret = ret2; - return ret; + unlock_page(page); + page_cache_release(page); + + return ret ? ret : copied; } /* @@ -1545,7 +1611,7 @@ static int ext4_journalled_writepage(struct page *page, PAGE_CACHE_SIZE, NULL, do_journal_get_write_access); err = walk_page_buffers(handle, page_buffers(page), 0, - PAGE_CACHE_SIZE, NULL, commit_write_fn); + PAGE_CACHE_SIZE, NULL, write_end_fn); if (ret == 0) ret = err; EXT4_I(inode)->i_state |= EXT4_STATE_JDATA; @@ -1705,8 +1771,8 @@ static const struct address_space_operations ext4_ordered_aops = { .readpages = ext4_readpages, .writepage = ext4_ordered_writepage, .sync_page = block_sync_page, - .prepare_write = ext4_prepare_write, - .commit_write = ext4_ordered_commit_write, + .write_begin = ext4_write_begin, + .write_end = ext4_ordered_write_end, .bmap = ext4_bmap, .invalidatepage = ext4_invalidatepage, .releasepage = ext4_releasepage, @@ -1719,8 +1785,8 @@ static const struct address_space_operations ext4_writeback_aops = { .readpages = ext4_readpages, .writepage = ext4_writeback_writepage, .sync_page = block_sync_page, - .prepare_write = ext4_prepare_write, - .commit_write = ext4_writeback_commit_write, + .write_begin = ext4_write_begin, + .write_end = ext4_writeback_write_end, .bmap = ext4_bmap, .invalidatepage = ext4_invalidatepage, .releasepage = ext4_releasepage, @@ -1733,8 +1799,8 @@ static const struct address_space_operations ext4_journalled_aops = { .readpages = ext4_readpages, .writepage = ext4_journalled_writepage, .sync_page = block_sync_page, - .prepare_write = ext4_prepare_write, - .commit_write = ext4_journalled_commit_write, + .write_begin = ext4_write_begin, + .write_end = ext4_journalled_write_end, .set_page_dirty = ext4_journalled_set_page_dirty, .bmap = ext4_bmap, .invalidatepage = ext4_invalidatepage, @@ -2645,11 +2711,6 @@ void ext4_read_inode(struct inode * inode) } inode->i_blocks = le32_to_cpu(raw_inode->i_blocks); ei->i_flags = le32_to_cpu(raw_inode->i_flags); -#ifdef EXT4_FRAGMENTS - ei->i_faddr = le32_to_cpu(raw_inode->i_faddr); - ei->i_frag_no = raw_inode->i_frag; - ei->i_frag_size = raw_inode->i_fsize; -#endif ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl); if (EXT4_SB(inode->i_sb)->s_es->s_creator_os != cpu_to_le32(EXT4_OS_HURD)) @@ -2794,11 +2855,6 @@ static int ext4_do_update_inode(handle_t *handle, raw_inode->i_blocks = cpu_to_le32(inode->i_blocks); raw_inode->i_dtime = cpu_to_le32(ei->i_dtime); raw_inode->i_flags = cpu_to_le32(ei->i_flags); -#ifdef EXT4_FRAGMENTS - raw_inode->i_faddr = cpu_to_le32(ei->i_faddr); - raw_inode->i_frag = ei->i_frag_no; - raw_inode->i_fsize = ei->i_frag_size; -#endif if (EXT4_SB(inode->i_sb)->s_es->s_creator_os != cpu_to_le32(EXT4_OS_HURD)) raw_inode->i_file_acl_high = @@ -3177,12 +3233,14 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode) iloc, handle); if (ret) { EXT4_I(inode)->i_state |= EXT4_STATE_NO_EXPAND; - if (mnt_count != sbi->s_es->s_mnt_count) { + if (mnt_count != + le16_to_cpu(sbi->s_es->s_mnt_count)) { ext4_warning(inode->i_sb, __FUNCTION__, "Unable to expand inode %lu. Delete" " some EAs or run e2fsck.", inode->i_ino); - mnt_count = sbi->s_es->s_mnt_count; + mnt_count = + le16_to_cpu(sbi->s_es->s_mnt_count); } } } diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 5fdb862e71c4..94ee6f315dc1 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -144,7 +144,6 @@ struct dx_map_entry u16 size; }; -#ifdef CONFIG_EXT4_INDEX static inline unsigned dx_get_block (struct dx_entry *entry); static void dx_set_block (struct dx_entry *entry, unsigned value); static inline unsigned dx_get_hash (struct dx_entry *entry); @@ -766,8 +765,6 @@ static void dx_insert_block(struct dx_frame *frame, u32 hash, u32 block) dx_set_block(new, block); dx_set_count(entries, count + 1); } -#endif - static void ext4_update_dx_flag(struct inode *inode) { @@ -869,7 +866,6 @@ static struct buffer_head * ext4_find_entry (struct dentry *dentry, name = dentry->d_name.name; if (namelen > EXT4_NAME_LEN) return NULL; -#ifdef CONFIG_EXT4_INDEX if (is_dx(dir)) { bh = ext4_dx_find_entry(dentry, res_dir, &err); /* @@ -881,7 +877,6 @@ static struct buffer_head * ext4_find_entry (struct dentry *dentry, return bh; dxtrace(printk("ext4_find_entry: dx failed, falling back\n")); } -#endif nblocks = dir->i_size >> EXT4_BLOCK_SIZE_BITS(sb); start = EXT4_I(dir)->i_dir_start_lookup; if (start >= nblocks) @@ -957,7 +952,6 @@ cleanup_and_exit: return ret; } -#ifdef CONFIG_EXT4_INDEX static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry, struct ext4_dir_entry_2 **res_dir, int *err) { @@ -1025,7 +1019,6 @@ errout: dx_release (frames); return NULL; } -#endif static struct dentry *ext4_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) { @@ -1121,7 +1114,6 @@ static inline void ext4_set_de_type(struct super_block *sb, de->file_type = ext4_type_by_mode[(mode & S_IFMT)>>S_SHIFT]; } -#ifdef CONFIG_EXT4_INDEX /* * Move count entries from end of map between two memory locations. * Returns pointer to last entry moved. @@ -1266,8 +1258,6 @@ errout: *error = err; return NULL; } -#endif - /* * Add a new entry into a directory (leaf) block. If de is non-NULL, @@ -1364,7 +1354,6 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, return 0; } -#ifdef CONFIG_EXT4_INDEX /* * This converts a one block unindexed directory to a 3 block indexed * directory, and adds the dentry to the indexed directory. @@ -1443,7 +1432,6 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, return add_dirent_to_buf(handle, dentry, inode, de, bh); } -#endif /* * ext4_add_entry() @@ -1464,9 +1452,7 @@ static int ext4_add_entry (handle_t *handle, struct dentry *dentry, struct ext4_dir_entry_2 *de; struct super_block * sb; int retval; -#ifdef CONFIG_EXT4_INDEX int dx_fallback=0; -#endif unsigned blocksize; u32 block, blocks; @@ -1474,7 +1460,6 @@ static int ext4_add_entry (handle_t *handle, struct dentry *dentry, blocksize = sb->s_blocksize; if (!dentry->d_name.len) return -EINVAL; -#ifdef CONFIG_EXT4_INDEX if (is_dx(dir)) { retval = ext4_dx_add_entry(handle, dentry, inode); if (!retval || (retval != ERR_BAD_DX_DIR)) @@ -1483,7 +1468,6 @@ static int ext4_add_entry (handle_t *handle, struct dentry *dentry, dx_fallback++; ext4_mark_inode_dirty(handle, dir); } -#endif blocks = dir->i_size >> sb->s_blocksize_bits; for (block = 0, offset = 0; block < blocks; block++) { bh = ext4_bread(handle, dir, block, 0, &retval); @@ -1493,11 +1477,9 @@ static int ext4_add_entry (handle_t *handle, struct dentry *dentry, if (retval != -ENOSPC) return retval; -#ifdef CONFIG_EXT4_INDEX if (blocks == 1 && !dx_fallback && EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) return make_indexed_dir(handle, dentry, inode, bh); -#endif brelse(bh); } bh = ext4_append(handle, dir, &block, &retval); @@ -1509,7 +1491,6 @@ static int ext4_add_entry (handle_t *handle, struct dentry *dentry, return add_dirent_to_buf(handle, dentry, inode, de, bh); } -#ifdef CONFIG_EXT4_INDEX /* * Returns 0 for success, or a negative error value */ @@ -1644,7 +1625,6 @@ cleanup: dx_release(frames); return err; } -#endif /* * ext4_delete_entry deletes a directory entry by merging it with the diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index aa11d7dbe970..bd8a52bb3999 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -16,6 +16,7 @@ #include <linux/errno.h> #include <linux/slab.h> +#include "group.h" #define outside(b, first, last) ((b) < (first) || (b) >= (last)) #define inside(b, first, last) ((b) >= (first) && (b) < (last)) @@ -140,22 +141,29 @@ static struct buffer_head *bclean(handle_t *handle, struct super_block *sb, } /* - * To avoid calling the atomic setbit hundreds or thousands of times, we only - * need to use it within a single byte (to ensure we get endianness right). - * We can use memset for the rest of the bitmap as there are no other users. + * If we have fewer than thresh credits, extend by EXT4_MAX_TRANS_DATA. + * If that fails, restart the transaction & regain write access for the + * buffer head which is used for block_bitmap modifications. */ -static void mark_bitmap_end(int start_bit, int end_bit, char *bitmap) +static int extend_or_restart_transaction(handle_t *handle, int thresh, + struct buffer_head *bh) { - int i; + int err; + + if (handle->h_buffer_credits >= thresh) + return 0; - if (start_bit >= end_bit) - return; + err = ext4_journal_extend(handle, EXT4_MAX_TRANS_DATA); + if (err < 0) + return err; + if (err) { + if ((err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA))) + return err; + if ((err = ext4_journal_get_write_access(handle, bh))) + return err; + } - ext4_debug("mark end bits +%d through +%d used\n", start_bit, end_bit); - for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++) - ext4_set_bit(i, bitmap); - if (i < end_bit) - memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3); + return 0; } /* @@ -180,8 +188,9 @@ static int setup_new_group_blocks(struct super_block *sb, int i; int err = 0, err2; - handle = ext4_journal_start_sb(sb, reserved_gdb + gdblocks + - 2 + sbi->s_itb_per_group); + /* This transaction may be extended/restarted along the way */ + handle = ext4_journal_start_sb(sb, EXT4_MAX_TRANS_DATA); + if (IS_ERR(handle)) return PTR_ERR(handle); @@ -208,6 +217,9 @@ static int setup_new_group_blocks(struct super_block *sb, ext4_debug("update backup group %#04lx (+%d)\n", block, bit); + if ((err = extend_or_restart_transaction(handle, 1, bh))) + goto exit_bh; + gdb = sb_getblk(sb, block); if (!gdb) { err = -EIO; @@ -217,10 +229,10 @@ static int setup_new_group_blocks(struct super_block *sb, brelse(gdb); goto exit_bh; } - lock_buffer(bh); - memcpy(gdb->b_data, sbi->s_group_desc[i]->b_data, bh->b_size); + lock_buffer(gdb); + memcpy(gdb->b_data, sbi->s_group_desc[i]->b_data, gdb->b_size); set_buffer_uptodate(gdb); - unlock_buffer(bh); + unlock_buffer(gdb); ext4_journal_dirty_metadata(handle, gdb); ext4_set_bit(bit, bh->b_data); brelse(gdb); @@ -233,6 +245,9 @@ static int setup_new_group_blocks(struct super_block *sb, ext4_debug("clear reserved block %#04lx (+%d)\n", block, bit); + if ((err = extend_or_restart_transaction(handle, 1, bh))) + goto exit_bh; + if (IS_ERR(gdb = bclean(handle, sb, block))) { err = PTR_ERR(bh); goto exit_bh; @@ -254,6 +269,10 @@ static int setup_new_group_blocks(struct super_block *sb, struct buffer_head *it; ext4_debug("clear inode block %#04lx (+%d)\n", block, bit); + + if ((err = extend_or_restart_transaction(handle, 1, bh))) + goto exit_bh; + if (IS_ERR(it = bclean(handle, sb, block))) { err = PTR_ERR(it); goto exit_bh; @@ -262,6 +281,10 @@ static int setup_new_group_blocks(struct super_block *sb, brelse(it); ext4_set_bit(bit, bh->b_data); } + + if ((err = extend_or_restart_transaction(handle, 2, bh))) + goto exit_bh; + mark_bitmap_end(input->blocks_count, EXT4_BLOCKS_PER_GROUP(sb), bh->b_data); ext4_journal_dirty_metadata(handle, bh); @@ -289,7 +312,6 @@ exit_journal: return err; } - /* * Iterate through the groups which hold BACKUP superblock/GDT copies in an * ext4 filesystem. The counters should be initialized to 1, 5, and 7 before @@ -842,6 +864,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) ext4_inode_table_set(sb, gdp, input->inode_table); /* LV FIXME */ gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count); gdp->bg_free_inodes_count = cpu_to_le16(EXT4_INODES_PER_GROUP(sb)); + gdp->bg_checksum = ext4_group_desc_csum(sbi, input->group, gdp); /* * Make the new blocks and inodes valid next. We do this before @@ -893,9 +916,9 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) input->reserved_blocks); /* Update the free space counts */ - percpu_counter_mod(&sbi->s_freeblocks_counter, + percpu_counter_add(&sbi->s_freeblocks_counter, input->free_blocks_count); - percpu_counter_mod(&sbi->s_freeinodes_counter, + percpu_counter_add(&sbi->s_freeinodes_counter, EXT4_INODES_PER_GROUP(sb)); ext4_journal_dirty_metadata(handle, sbi->s_sbh); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 3c1397fa83df..b11e9e2bcd01 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -37,12 +37,14 @@ #include <linux/quotaops.h> #include <linux/seq_file.h> #include <linux/log2.h> +#include <linux/crc16.h> #include <asm/uaccess.h> #include "xattr.h" #include "acl.h" #include "namei.h" +#include "group.h" static int ext4_load_journal(struct super_block *, struct ext4_super_block *, unsigned long journal_devnum); @@ -68,31 +70,31 @@ static void ext4_write_super_lockfs(struct super_block *sb); ext4_fsblk_t ext4_block_bitmap(struct super_block *sb, struct ext4_group_desc *bg) { - return le32_to_cpu(bg->bg_block_bitmap) | + return le32_to_cpu(bg->bg_block_bitmap_lo) | (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? - (ext4_fsblk_t)le32_to_cpu(bg->bg_block_bitmap_hi) << 32 : 0); + (ext4_fsblk_t)le32_to_cpu(bg->bg_block_bitmap_hi) << 32 : 0); } ext4_fsblk_t ext4_inode_bitmap(struct super_block *sb, struct ext4_group_desc *bg) { - return le32_to_cpu(bg->bg_inode_bitmap) | + return le32_to_cpu(bg->bg_inode_bitmap_lo) | (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? - (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_bitmap_hi) << 32 : 0); + (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_bitmap_hi) << 32 : 0); } ext4_fsblk_t ext4_inode_table(struct super_block *sb, struct ext4_group_desc *bg) { - return le32_to_cpu(bg->bg_inode_table) | + return le32_to_cpu(bg->bg_inode_table_lo) | (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? - (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_table_hi) << 32 : 0); + (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_table_hi) << 32 : 0); } void ext4_block_bitmap_set(struct super_block *sb, struct ext4_group_desc *bg, ext4_fsblk_t blk) { - bg->bg_block_bitmap = cpu_to_le32((u32)blk); + bg->bg_block_bitmap_lo = cpu_to_le32((u32)blk); if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) bg->bg_block_bitmap_hi = cpu_to_le32(blk >> 32); } @@ -100,7 +102,7 @@ void ext4_block_bitmap_set(struct super_block *sb, void ext4_inode_bitmap_set(struct super_block *sb, struct ext4_group_desc *bg, ext4_fsblk_t blk) { - bg->bg_inode_bitmap = cpu_to_le32((u32)blk); + bg->bg_inode_bitmap_lo = cpu_to_le32((u32)blk); if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) bg->bg_inode_bitmap_hi = cpu_to_le32(blk >> 32); } @@ -108,7 +110,7 @@ void ext4_inode_bitmap_set(struct super_block *sb, void ext4_inode_table_set(struct super_block *sb, struct ext4_group_desc *bg, ext4_fsblk_t blk) { - bg->bg_inode_table = cpu_to_le32((u32)blk); + bg->bg_inode_table_lo = cpu_to_le32((u32)blk); if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) bg->bg_inode_table_hi = cpu_to_le32(blk >> 32); } @@ -523,7 +525,7 @@ static void ext4_destroy_inode(struct inode *inode) kmem_cache_free(ext4_inode_cachep, EXT4_I(inode)); } -static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(struct kmem_cache *cachep, void *foo) { struct ext4_inode_info *ei = (struct ext4_inode_info *) foo; @@ -596,9 +598,80 @@ static inline void ext4_show_quota_options(struct seq_file *seq, struct super_bl #endif } +/* + * Show an option if + * - it's set to a non-default value OR + * - if the per-sb default is different from the global default + */ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs) { struct super_block *sb = vfs->mnt_sb; + struct ext4_sb_info *sbi = EXT4_SB(sb); + struct ext4_super_block *es = sbi->s_es; + unsigned long def_mount_opts; + + def_mount_opts = le32_to_cpu(es->s_default_mount_opts); + + if (sbi->s_sb_block != 1) + seq_printf(seq, ",sb=%llu", sbi->s_sb_block); + if (test_opt(sb, MINIX_DF)) + seq_puts(seq, ",minixdf"); + if (test_opt(sb, GRPID)) + seq_puts(seq, ",grpid"); + if (!test_opt(sb, GRPID) && (def_mount_opts & EXT4_DEFM_BSDGROUPS)) + seq_puts(seq, ",nogrpid"); + if (sbi->s_resuid != EXT4_DEF_RESUID || + le16_to_cpu(es->s_def_resuid) != EXT4_DEF_RESUID) { + seq_printf(seq, ",resuid=%u", sbi->s_resuid); + } + if (sbi->s_resgid != EXT4_DEF_RESGID || + le16_to_cpu(es->s_def_resgid) != EXT4_DEF_RESGID) { + seq_printf(seq, ",resgid=%u", sbi->s_resgid); + } + if (test_opt(sb, ERRORS_CONT)) { + int def_errors = le16_to_cpu(es->s_errors); + + if (def_errors == EXT4_ERRORS_PANIC || + def_errors == EXT4_ERRORS_RO) { + seq_puts(seq, ",errors=continue"); + } + } + if (test_opt(sb, ERRORS_RO)) + seq_puts(seq, ",errors=remount-ro"); + if (test_opt(sb, ERRORS_PANIC)) + seq_puts(seq, ",errors=panic"); + if (test_opt(sb, NO_UID32)) + seq_puts(seq, ",nouid32"); + if (test_opt(sb, DEBUG)) + seq_puts(seq, ",debug"); + if (test_opt(sb, OLDALLOC)) + seq_puts(seq, ",oldalloc"); +#ifdef CONFIG_EXT4_FS_XATTR + if (test_opt(sb, XATTR_USER)) + seq_puts(seq, ",user_xattr"); + if (!test_opt(sb, XATTR_USER) && + (def_mount_opts & EXT4_DEFM_XATTR_USER)) { + seq_puts(seq, ",nouser_xattr"); + } +#endif +#ifdef CONFIG_EXT4_FS_POSIX_ACL + if (test_opt(sb, POSIX_ACL)) + seq_puts(seq, ",acl"); + if (!test_opt(sb, POSIX_ACL) && (def_mount_opts & EXT4_DEFM_ACL)) + seq_puts(seq, ",noacl"); +#endif + if (!test_opt(sb, RESERVATION)) + seq_puts(seq, ",noreservation"); + if (sbi->s_commit_interval) { + seq_printf(seq, ",commit=%u", + (unsigned) (sbi->s_commit_interval / HZ)); + } + if (test_opt(sb, BARRIER)) + seq_puts(seq, ",barrier=1"); + if (test_opt(sb, NOBH)) + seq_puts(seq, ",nobh"); + if (!test_opt(sb, EXTENTS)) + seq_puts(seq, ",noextents"); if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) seq_puts(seq, ",data=journal"); @@ -966,7 +1039,7 @@ static int parse_options (char *options, struct super_block *sb, if (option < 0) return 0; if (option == 0) - option = JBD_DEFAULT_MAX_COMMIT_AGE; + option = JBD2_DEFAULT_MAX_COMMIT_AGE; sbi->s_commit_interval = HZ * option; break; case Opt_data_journal: @@ -1237,6 +1310,43 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es, return res; } +__le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group, + struct ext4_group_desc *gdp) +{ + __u16 crc = 0; + + if (sbi->s_es->s_feature_ro_compat & + cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) { + int offset = offsetof(struct ext4_group_desc, bg_checksum); + __le32 le_group = cpu_to_le32(block_group); + + crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid)); + crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group)); + crc = crc16(crc, (__u8 *)gdp, offset); + offset += sizeof(gdp->bg_checksum); /* skip checksum */ + /* for checksum of struct ext4_group_desc do the rest...*/ + if ((sbi->s_es->s_feature_incompat & + cpu_to_le32(EXT4_FEATURE_INCOMPAT_64BIT)) && + offset < le16_to_cpu(sbi->s_es->s_desc_size)) + crc = crc16(crc, (__u8 *)gdp + offset, + le16_to_cpu(sbi->s_es->s_desc_size) - + offset); + } + + return cpu_to_le16(crc); +} + +int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 block_group, + struct ext4_group_desc *gdp) +{ + if ((sbi->s_es->s_feature_ro_compat & + cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) && + (gdp->bg_checksum != ext4_group_desc_csum(sbi, block_group, gdp))) + return 0; + + return 1; +} + /* Called at mount-time, super-block is locked */ static int ext4_check_descriptors (struct super_block * sb) { @@ -1248,13 +1358,17 @@ static int ext4_check_descriptors (struct super_block * sb) ext4_fsblk_t inode_table; struct ext4_group_desc * gdp = NULL; int desc_block = 0; + int flexbg_flag = 0; int i; + if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) + flexbg_flag = 1; + ext4_debug ("Checking group descriptors"); for (i = 0; i < sbi->s_groups_count; i++) { - if (i == sbi->s_groups_count - 1) + if (i == sbi->s_groups_count - 1 || flexbg_flag) last_block = ext4_blocks_count(sbi->s_es) - 1; else last_block = first_block + @@ -1291,7 +1405,16 @@ static int ext4_check_descriptors (struct super_block * sb) i, inode_table); return 0; } - first_block += EXT4_BLOCKS_PER_GROUP(sb); + if (!ext4_group_desc_csum_verify(sbi, i, gdp)) { + ext4_error(sb, __FUNCTION__, + "Checksum for group %d failed (%u!=%u)\n", i, + le16_to_cpu(ext4_group_desc_csum(sbi, i, + gdp)), + le16_to_cpu(gdp->bg_checksum)); + return 0; + } + if (!flexbg_flag) + first_block += EXT4_BLOCKS_PER_GROUP(sb); gdp = (struct ext4_group_desc *) ((__u8 *)gdp + EXT4_DESC_SIZE(sb)); } @@ -1415,8 +1538,6 @@ static void ext4_orphan_cleanup (struct super_block * sb, sb->s_flags = s_flags; /* Restore MS_RDONLY status */ } -#define log2(n) ffz(~(n)) - /* * Maximal file size. There is a direct, and {,double-,triple-}indirect * block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks. @@ -1479,6 +1600,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) int needs_recovery; __le32 features; __u64 blocks_count; + int err; sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); if (!sbi) @@ -1487,6 +1609,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) sbi->s_mount_opt = 0; sbi->s_resuid = EXT4_DEF_RESUID; sbi->s_resgid = EXT4_DEF_RESGID; + sbi->s_sb_block = sb_block; unlock_kernel(); @@ -1655,19 +1778,11 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) sb->s_time_gran = 1 << (EXT4_EPOCH_BITS - 2); } - sbi->s_frag_size = EXT4_MIN_FRAG_SIZE << - le32_to_cpu(es->s_log_frag_size); - if (blocksize != sbi->s_frag_size) { - printk(KERN_ERR - "EXT4-fs: fragsize %lu != blocksize %u (unsupported)\n", - sbi->s_frag_size, blocksize); - goto failed_mount; - } sbi->s_desc_size = le16_to_cpu(es->s_desc_size); if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_64BIT)) { if (sbi->s_desc_size < EXT4_MIN_DESC_SIZE_64BIT || sbi->s_desc_size > EXT4_MAX_DESC_SIZE || - sbi->s_desc_size & (sbi->s_desc_size - 1)) { + !is_power_of_2(sbi->s_desc_size)) { printk(KERN_ERR "EXT4-fs: unsupported descriptor size %lu\n", sbi->s_desc_size); @@ -1676,7 +1791,6 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) } else sbi->s_desc_size = EXT4_MIN_DESC_SIZE; sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group); - sbi->s_frags_per_group = le32_to_cpu(es->s_frags_per_group); sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group); if (EXT4_INODE_SIZE(sb) == 0) goto cantfind_ext4; @@ -1688,8 +1802,8 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) sbi->s_desc_per_block = blocksize / EXT4_DESC_SIZE(sb); sbi->s_sbh = bh; sbi->s_mount_state = le16_to_cpu(es->s_state); - sbi->s_addr_per_block_bits = log2(EXT4_ADDR_PER_BLOCK(sb)); - sbi->s_desc_per_block_bits = log2(EXT4_DESC_PER_BLOCK(sb)); + sbi->s_addr_per_block_bits = ilog2(EXT4_ADDR_PER_BLOCK(sb)); + sbi->s_desc_per_block_bits = ilog2(EXT4_DESC_PER_BLOCK(sb)); for (i=0; i < 4; i++) sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); sbi->s_def_hash_version = es->s_def_hash_version; @@ -1700,12 +1814,6 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) sbi->s_blocks_per_group); goto failed_mount; } - if (sbi->s_frags_per_group > blocksize * 8) { - printk (KERN_ERR - "EXT4-fs: #fragments per group too big: %lu\n", - sbi->s_frags_per_group); - goto failed_mount; - } if (sbi->s_inodes_per_group > blocksize * 8) { printk (KERN_ERR "EXT4-fs: #inodes per group too big: %lu\n", @@ -1759,12 +1867,20 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) get_random_bytes(&sbi->s_next_generation, sizeof(u32)); spin_lock_init(&sbi->s_next_gen_lock); - percpu_counter_init(&sbi->s_freeblocks_counter, - ext4_count_free_blocks(sb)); - percpu_counter_init(&sbi->s_freeinodes_counter, - ext4_count_free_inodes(sb)); - percpu_counter_init(&sbi->s_dirs_counter, - ext4_count_dirs(sb)); + err = percpu_counter_init(&sbi->s_freeblocks_counter, + ext4_count_free_blocks(sb)); + if (!err) { + err = percpu_counter_init(&sbi->s_freeinodes_counter, + ext4_count_free_inodes(sb)); + } + if (!err) { + err = percpu_counter_init(&sbi->s_dirs_counter, + ext4_count_dirs(sb)); + } + if (err) { + printk(KERN_ERR "EXT4-fs: insufficient memory\n"); + goto failed_mount3; + } /* per fileystem reservation list head & lock */ spin_lock_init(&sbi->s_rsv_window_lock); @@ -2551,7 +2667,7 @@ static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf) if (test_opt(sb, MINIX_DF)) { sbi->s_overhead_last = 0; - } else if (sbi->s_blocks_last != le32_to_cpu(es->s_blocks_count)) { + } else if (sbi->s_blocks_last != ext4_blocks_count(es)) { unsigned long ngroups = sbi->s_groups_count, i; ext4_fsblk_t overhead = 0; smp_rmb(); @@ -2586,19 +2702,19 @@ static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf) overhead += ngroups * (2 + sbi->s_itb_per_group); sbi->s_overhead_last = overhead; smp_wmb(); - sbi->s_blocks_last = le32_to_cpu(es->s_blocks_count); + sbi->s_blocks_last = ext4_blocks_count(es); } buf->f_type = EXT4_SUPER_MAGIC; buf->f_bsize = sb->s_blocksize; buf->f_blocks = ext4_blocks_count(es) - sbi->s_overhead_last; - buf->f_bfree = percpu_counter_sum(&sbi->s_freeblocks_counter); - es->s_free_blocks_count = cpu_to_le32(buf->f_bfree); + buf->f_bfree = percpu_counter_sum_positive(&sbi->s_freeblocks_counter); + ext4_free_blocks_count_set(es, buf->f_bfree); buf->f_bavail = buf->f_bfree - ext4_r_blocks_count(es); if (buf->f_bfree < ext4_r_blocks_count(es)) buf->f_bavail = 0; buf->f_files = le32_to_cpu(es->s_inodes_count); - buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter); + buf->f_ffree = percpu_counter_sum_positive(&sbi->s_freeinodes_counter); es->s_free_inodes_count = cpu_to_le32(buf->f_ffree); buf->f_namelen = EXT4_NAME_LEN; fsid = le64_to_cpup((void *)es->s_uuid) ^ diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index b10d68fffb55..86387302c2a9 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -750,12 +750,11 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, } } else { /* Allocate a buffer where we construct the new block. */ - s->base = kmalloc(sb->s_blocksize, GFP_KERNEL); + s->base = kzalloc(sb->s_blocksize, GFP_KERNEL); /* assert(header == s->base) */ error = -ENOMEM; if (s->base == NULL) goto cleanup; - memset(s->base, 0, sb->s_blocksize); header(s->base)->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC); header(s->base)->h_blocks = cpu_to_le32(1); header(s->base)->h_refcount = cpu_to_le32(1); @@ -1121,7 +1120,7 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize, int total_ino, total_blk; void *base, *start, *end; int extra_isize = 0, error = 0, tried_min_extra_isize = 0; - int s_min_extra_isize = EXT4_SB(inode->i_sb)->s_es->s_min_extra_isize; + int s_min_extra_isize = le16_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_min_extra_isize); down_write(&EXT4_I(inode)->xattr_sem); retry: @@ -1293,7 +1292,7 @@ retry: i.name = b_entry_name; i.value = buffer; - i.value_len = cpu_to_le32(size); + i.value_len = size; error = ext4_xattr_block_find(inode, &i, bs); if (error) goto cleanup; diff --git a/fs/fat/cache.c b/fs/fat/cache.c index be6f89b152ca..639b3b4f86d1 100644 --- a/fs/fat/cache.c +++ b/fs/fat/cache.c @@ -36,7 +36,7 @@ static inline int fat_max_cache(struct inode *inode) static struct kmem_cache *fat_cache_cachep; -static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags) +static void init_once(struct kmem_cache *cachep, void *foo) { struct fat_cache *cache = (struct fat_cache *)foo; diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 4baa5f205368..c0c5e9c55b58 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -141,19 +141,24 @@ static int fat_readpages(struct file *file, struct address_space *mapping, return mpage_readpages(mapping, pages, nr_pages, fat_get_block); } -static int fat_prepare_write(struct file *file, struct page *page, - unsigned from, unsigned to) +static int fat_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - return cont_prepare_write(page, from, to, fat_get_block, - &MSDOS_I(page->mapping->host)->mmu_private); + *pagep = NULL; + return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + fat_get_block, + &MSDOS_I(mapping->host)->mmu_private); } -static int fat_commit_write(struct file *file, struct page *page, - unsigned from, unsigned to) +static int fat_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *pagep, void *fsdata) { - struct inode *inode = page->mapping->host; - int err = generic_commit_write(file, page, from, to); - if (!err && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) { + struct inode *inode = mapping->host; + int err; + err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata); + if (!(err < 0) && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) { inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; MSDOS_I(inode)->i_attrs |= ATTR_ARCH; mark_inode_dirty(inode); @@ -202,8 +207,8 @@ static const struct address_space_operations fat_aops = { .writepage = fat_writepage, .writepages = fat_writepages, .sync_page = block_sync_page, - .prepare_write = fat_prepare_write, - .commit_write = fat_commit_write, + .write_begin = fat_write_begin, + .write_end = fat_write_end, .direct_IO = fat_direct_IO, .bmap = _fat_bmap }; @@ -496,7 +501,7 @@ static void fat_destroy_inode(struct inode *inode) kmem_cache_free(fat_inode_cachep, MSDOS_I(inode)); } -static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(struct kmem_cache *cachep, void *foo) { struct msdos_inode_info *ei = (struct msdos_inode_info *)foo; diff --git a/fs/fcntl.c b/fs/fcntl.c index 78b2ff044054..8685263ccc4a 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -18,6 +18,7 @@ #include <linux/ptrace.h> #include <linux/signal.h> #include <linux/rcupdate.h> +#include <linux/pid_namespace.h> #include <asm/poll.h> #include <asm/siginfo.h> @@ -110,7 +111,7 @@ out: return error; } -static int dupfd(struct file *file, unsigned int start) +static int dupfd(struct file *file, unsigned int start, int cloexec) { struct files_struct * files = current->files; struct fdtable *fdt; @@ -122,7 +123,10 @@ static int dupfd(struct file *file, unsigned int start) /* locate_fd() may have expanded fdtable, load the ptr */ fdt = files_fdtable(files); FD_SET(fd, fdt->open_fds); - FD_CLR(fd, fdt->close_on_exec); + if (cloexec) + FD_SET(fd, fdt->close_on_exec); + else + FD_CLR(fd, fdt->close_on_exec); spin_unlock(&files->file_lock); fd_install(fd, file); } else { @@ -195,7 +199,7 @@ asmlinkage long sys_dup(unsigned int fildes) struct file * file = fget(fildes); if (file) - ret = dupfd(file, 0); + ret = dupfd(file, 0, 0); return ret; } @@ -289,7 +293,7 @@ int f_setown(struct file *filp, unsigned long arg, int force) who = -who; } rcu_read_lock(); - pid = find_pid(who); + pid = find_vpid(who); result = __f_setown(filp, pid, type, force); rcu_read_unlock(); return result; @@ -305,7 +309,7 @@ pid_t f_getown(struct file *filp) { pid_t pid; read_lock(&filp->f_owner.lock); - pid = pid_nr(filp->f_owner.pid); + pid = pid_nr_ns(filp->f_owner.pid, current->nsproxy->pid_ns); if (filp->f_owner.pid_type == PIDTYPE_PGID) pid = -pid; read_unlock(&filp->f_owner.lock); @@ -319,8 +323,9 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, switch (cmd) { case F_DUPFD: + case F_DUPFD_CLOEXEC: get_file(filp); - err = dupfd(filp, arg); + err = dupfd(filp, arg, cmd == F_DUPFD_CLOEXEC); break; case F_GETFD: err = get_close_on_exec(fd) ? FD_CLOEXEC : 0; diff --git a/fs/file_table.c b/fs/file_table.c index d17fd691b832..664e3f2309b8 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -98,16 +98,15 @@ struct file *get_empty_filp(void) * percpu_counters are inaccurate. Do an expensive check before * we go and fail. */ - if (percpu_counter_sum(&nr_files) >= files_stat.max_files) + if (percpu_counter_sum_positive(&nr_files) >= files_stat.max_files) goto over; } - f = kmem_cache_alloc(filp_cachep, GFP_KERNEL); + f = kmem_cache_zalloc(filp_cachep, GFP_KERNEL); if (f == NULL) goto fail; percpu_counter_inc(&nr_files); - memset(f, 0, sizeof(*f)); if (security_file_alloc(f)) goto fail_sec; @@ -138,6 +137,66 @@ fail: EXPORT_SYMBOL(get_empty_filp); +/** + * alloc_file - allocate and initialize a 'struct file' + * @mnt: the vfsmount on which the file will reside + * @dentry: the dentry representing the new file + * @mode: the mode with which the new file will be opened + * @fop: the 'struct file_operations' for the new file + * + * Use this instead of get_empty_filp() to get a new + * 'struct file'. Do so because of the same initialization + * pitfalls reasons listed for init_file(). This is a + * preferred interface to using init_file(). + * + * If all the callers of init_file() are eliminated, its + * code should be moved into this function. + */ +struct file *alloc_file(struct vfsmount *mnt, struct dentry *dentry, + mode_t mode, const struct file_operations *fop) +{ + struct file *file; + struct path; + + file = get_empty_filp(); + if (!file) + return NULL; + + init_file(file, mnt, dentry, mode, fop); + return file; +} +EXPORT_SYMBOL(alloc_file); + +/** + * init_file - initialize a 'struct file' + * @file: the already allocated 'struct file' to initialized + * @mnt: the vfsmount on which the file resides + * @dentry: the dentry representing this file + * @mode: the mode the file is opened with + * @fop: the 'struct file_operations' for this file + * + * Use this instead of setting the members directly. Doing so + * avoids making mistakes like forgetting the mntget() or + * forgetting to take a write on the mnt. + * + * Note: This is a crappy interface. It is here to make + * merging with the existing users of get_empty_filp() + * who have complex failure logic easier. All users + * of this should be moving to alloc_file(). + */ +int init_file(struct file *file, struct vfsmount *mnt, struct dentry *dentry, + mode_t mode, const struct file_operations *fop) +{ + int error = 0; + file->f_path.dentry = dentry; + file->f_path.mnt = mntget(mnt); + file->f_mapping = dentry->d_inode->i_mapping; + file->f_mode = mode; + file->f_op = fop; + return error; +} +EXPORT_SYMBOL(init_file); + void fastcall fput(struct file *file) { if (atomic_dec_and_test(&file->f_count)) @@ -264,12 +323,11 @@ void file_kill(struct file *file) int fs_may_remount_ro(struct super_block *sb) { - struct list_head *p; + struct file *file; /* Check that no files are currently opened for writing. */ file_list_lock(); - list_for_each(p, &sb->s_files) { - struct file *file = list_entry(p, struct file, f_u.fu_list); + list_for_each_entry(file, &sb->s_files, f_u.fu_list) { struct inode *inode = file->f_path.dentry->d_inode; /* File with pending delete? */ diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index a4b142a6a2c7..0fca82021d76 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -14,6 +14,7 @@ */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/spinlock.h> #include <linux/sched.h> #include <linux/fs.h> @@ -88,7 +89,7 @@ void __mark_inode_dirty(struct inode *inode, int flags) if (inode->i_ino || strcmp(inode->i_sb->s_id, "bdev")) printk(KERN_DEBUG "%s(%d): dirtied inode %lu (%s) on %s\n", - current->comm, current->pid, inode->i_ino, + current->comm, task_pid_nr(current), inode->i_ino, name, inode->i_sb->s_id); } @@ -99,11 +100,11 @@ void __mark_inode_dirty(struct inode *inode, int flags) inode->i_state |= flags; /* - * If the inode is locked, just update its dirty state. + * If the inode is being synced, just update its dirty state. * The unlocker will place the inode on the appropriate * superblock list, based upon its state. */ - if (inode->i_state & I_LOCK) + if (inode->i_state & I_SYNC) goto out; /* @@ -118,7 +119,7 @@ void __mark_inode_dirty(struct inode *inode, int flags) goto out; /* - * If the inode was already on s_dirty or s_io, don't + * If the inode was already on s_dirty/s_io/s_more_io, don't * reposition it (that would break s_dirty time-ordering). */ if (!was_dirty) { @@ -140,6 +141,82 @@ static int write_inode(struct inode *inode, int sync) } /* + * Redirty an inode: set its when-it-was dirtied timestamp and move it to the + * furthest end of its superblock's dirty-inode list. + * + * Before stamping the inode's ->dirtied_when, we check to see whether it is + * already the most-recently-dirtied inode on the s_dirty list. If that is + * the case then the inode must have been redirtied while it was being written + * out and we don't reset its dirtied_when. + */ +static void redirty_tail(struct inode *inode) +{ + struct super_block *sb = inode->i_sb; + + if (!list_empty(&sb->s_dirty)) { + struct inode *tail_inode; + + tail_inode = list_entry(sb->s_dirty.next, struct inode, i_list); + if (!time_after_eq(inode->dirtied_when, + tail_inode->dirtied_when)) + inode->dirtied_when = jiffies; + } + list_move(&inode->i_list, &sb->s_dirty); +} + +/* + * requeue inode for re-scanning after sb->s_io list is exhausted. + */ +static void requeue_io(struct inode *inode) +{ + list_move(&inode->i_list, &inode->i_sb->s_more_io); +} + +static void inode_sync_complete(struct inode *inode) +{ + /* + * Prevent speculative execution through spin_unlock(&inode_lock); + */ + smp_mb(); + wake_up_bit(&inode->i_state, __I_SYNC); +} + +/* + * Move expired dirty inodes from @delaying_queue to @dispatch_queue. + */ +static void move_expired_inodes(struct list_head *delaying_queue, + struct list_head *dispatch_queue, + unsigned long *older_than_this) +{ + while (!list_empty(delaying_queue)) { + struct inode *inode = list_entry(delaying_queue->prev, + struct inode, i_list); + if (older_than_this && + time_after(inode->dirtied_when, *older_than_this)) + break; + list_move(&inode->i_list, dispatch_queue); + } +} + +/* + * Queue all expired dirty inodes for io, eldest first. + */ +static void queue_io(struct super_block *sb, + unsigned long *older_than_this) +{ + list_splice_init(&sb->s_more_io, sb->s_io.prev); + move_expired_inodes(&sb->s_dirty, &sb->s_io, older_than_this); +} + +int sb_has_dirty_inodes(struct super_block *sb) +{ + return !list_empty(&sb->s_dirty) || + !list_empty(&sb->s_io) || + !list_empty(&sb->s_more_io); +} +EXPORT_SYMBOL(sb_has_dirty_inodes); + +/* * Write a single inode's dirty pages and inode data out to disk. * If `wait' is set, wait on the writeout. * @@ -154,15 +231,14 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc) { unsigned dirty; struct address_space *mapping = inode->i_mapping; - struct super_block *sb = inode->i_sb; int wait = wbc->sync_mode == WB_SYNC_ALL; int ret; - BUG_ON(inode->i_state & I_LOCK); + BUG_ON(inode->i_state & I_SYNC); - /* Set I_LOCK, reset I_DIRTY */ + /* Set I_SYNC, reset I_DIRTY */ dirty = inode->i_state & I_DIRTY; - inode->i_state |= I_LOCK; + inode->i_state |= I_SYNC; inode->i_state &= ~I_DIRTY; spin_unlock(&inode_lock); @@ -183,24 +259,32 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc) } spin_lock(&inode_lock); - inode->i_state &= ~I_LOCK; + inode->i_state &= ~I_SYNC; if (!(inode->i_state & I_FREEING)) { if (!(inode->i_state & I_DIRTY) && mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { /* * We didn't write back all the pages. nfs_writepages() * sometimes bales out without doing anything. Redirty - * the inode. It is still on sb->s_io. + * the inode; Move it from s_io onto s_more_io/s_dirty. + */ + /* + * akpm: if the caller was the kupdate function we put + * this inode at the head of s_dirty so it gets first + * consideration. Otherwise, move it to the tail, for + * the reasons described there. I'm not really sure + * how much sense this makes. Presumably I had a good + * reasons for doing it this way, and I'd rather not + * muck with it at present. */ if (wbc->for_kupdate) { /* - * For the kupdate function we leave the inode - * at the head of sb_dirty so it will get more - * writeout as soon as the queue becomes - * uncongested. + * For the kupdate function we move the inode + * to s_more_io so it will get more writeout as + * soon as the queue becomes uncongested. */ inode->i_state |= I_DIRTY_PAGES; - list_move_tail(&inode->i_list, &sb->s_dirty); + requeue_io(inode); } else { /* * Otherwise fully redirty the inode so that @@ -210,15 +294,14 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc) * all the other files. */ inode->i_state |= I_DIRTY_PAGES; - inode->dirtied_when = jiffies; - list_move(&inode->i_list, &sb->s_dirty); + redirty_tail(inode); } } else if (inode->i_state & I_DIRTY) { /* * Someone redirtied the inode while were writing back * the pages. */ - list_move(&inode->i_list, &sb->s_dirty); + redirty_tail(inode); } else if (atomic_read(&inode->i_count)) { /* * The inode is clean, inuse @@ -231,7 +314,7 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc) list_move(&inode->i_list, &inode_unused); } } - wake_up_inode(inode); + inode_sync_complete(inode); return ret; } @@ -250,11 +333,18 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc) else WARN_ON(inode->i_state & I_WILL_FREE); - if ((wbc->sync_mode != WB_SYNC_ALL) && (inode->i_state & I_LOCK)) { + if ((wbc->sync_mode != WB_SYNC_ALL) && (inode->i_state & I_SYNC)) { struct address_space *mapping = inode->i_mapping; int ret; - list_move(&inode->i_list, &inode->i_sb->s_dirty); + /* + * We're skipping this inode because it's locked, and we're not + * doing writeback-for-data-integrity. Move it to s_more_io so + * that writeback can proceed with the other inodes on s_io. + * We'll have another go at writing back this inode when we + * completed a full scan of s_io. + */ + requeue_io(inode); /* * Even if we don't actually write the inode itself here, @@ -269,16 +359,16 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc) /* * It's a data-integrity sync. We must wait. */ - if (inode->i_state & I_LOCK) { - DEFINE_WAIT_BIT(wq, &inode->i_state, __I_LOCK); + if (inode->i_state & I_SYNC) { + DEFINE_WAIT_BIT(wq, &inode->i_state, __I_SYNC); - wqh = bit_waitqueue(&inode->i_state, __I_LOCK); + wqh = bit_waitqueue(&inode->i_state, __I_SYNC); do { spin_unlock(&inode_lock); __wait_on_bit(wqh, &wq, inode_wait, TASK_UNINTERRUPTIBLE); spin_lock(&inode_lock); - } while (inode->i_state & I_LOCK); + } while (inode->i_state & I_SYNC); } return __sync_single_inode(inode, wbc); } @@ -311,7 +401,7 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc) * The inodes to be written are parked on sb->s_io. They are moved back onto * sb->s_dirty as they are selected for writing. This way, none can be missed * on the writer throttling path, and we get decent balancing between many - * throttled threads: we don't want them all piling up on __wait_on_inode. + * throttled threads: we don't want them all piling up on inode_sync_wait. */ static void sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc) @@ -319,7 +409,7 @@ sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc) const unsigned long start = jiffies; /* livelock avoidance */ if (!wbc->for_kupdate || list_empty(&sb->s_io)) - list_splice_init(&sb->s_dirty, &sb->s_io); + queue_io(sb, wbc->older_than_this); while (!list_empty(&sb->s_io)) { struct inode *inode = list_entry(sb->s_io.prev, @@ -329,7 +419,7 @@ sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc) long pages_skipped; if (!bdi_cap_writeback_dirty(bdi)) { - list_move(&inode->i_list, &sb->s_dirty); + redirty_tail(inode); if (sb_is_blkdev_sb(sb)) { /* * Dirty memory-backed blockdev: the ramdisk @@ -349,14 +439,14 @@ sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc) wbc->encountered_congestion = 1; if (!sb_is_blkdev_sb(sb)) break; /* Skip a congested fs */ - list_move(&inode->i_list, &sb->s_dirty); + requeue_io(inode); continue; /* Skip a congested blockdev */ } if (wbc->bdi && bdi != wbc->bdi) { if (!sb_is_blkdev_sb(sb)) break; /* fs has the wrong queue */ - list_move(&inode->i_list, &sb->s_dirty); + requeue_io(inode); continue; /* blockdev has wrong queue */ } @@ -364,11 +454,6 @@ sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc) if (time_after(inode->dirtied_when, start)) break; - /* Was this inode dirtied too recently? */ - if (wbc->older_than_this && time_after(inode->dirtied_when, - *wbc->older_than_this)) - break; - /* Is another pdflush already flushing this queue? */ if (current_is_pdflush() && !writeback_acquire(bdi)) break; @@ -388,7 +473,7 @@ sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc) * writeback is not making progress due to locked * buffers. Skip this inode for now. */ - list_move(&inode->i_list, &sb->s_dirty); + redirty_tail(inode); } spin_unlock(&inode_lock); iput(inode); @@ -397,6 +482,8 @@ sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc) if (wbc->nr_to_write <= 0) break; } + if (!list_empty(&sb->s_more_io)) + wbc->more_io = 1; return; /* Leave any unwritten inodes on s_io */ } @@ -406,7 +493,7 @@ sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc) * Note: * We don't need to grab a reference to superblock here. If it has non-empty * ->s_dirty it's hadn't been killed yet and kill_super() won't proceed - * past sync_inodes_sb() until both the ->s_dirty and ->s_io lists are + * past sync_inodes_sb() until the ->s_dirty/s_io/s_more_io lists are all * empty. Since __sync_single_inode() regains inode_lock before it finally moves * inode from superblock lists we are OK. * @@ -429,7 +516,7 @@ writeback_inodes(struct writeback_control *wbc) restart: sb = sb_entry(super_blocks.prev); for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.prev)) { - if (!list_empty(&sb->s_dirty) || !list_empty(&sb->s_io)) { + if (sb_has_dirty_inodes(sb)) { /* we're making our own get_super here */ sb->s_count++; spin_unlock(&sb_lock); @@ -583,7 +670,7 @@ int write_inode_now(struct inode *inode, int sync) ret = __writeback_single_inode(inode, &wbc); spin_unlock(&inode_lock); if (sync) - wait_on_inode(inode); + inode_sync_wait(inode); return ret; } EXPORT_SYMBOL(write_inode_now); @@ -658,7 +745,7 @@ int generic_osync_inode(struct inode *inode, struct address_space *mapping, int err = err2; } else - wait_on_inode(inode); + inode_sync_wait(inode); return err; } diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 3ad22beb24c2..db534bcde45f 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -129,7 +129,7 @@ static struct fuse_req *get_reserved_req(struct fuse_conn *fc, struct fuse_file *ff = file->private_data; do { - wait_event(fc->blocked_waitq, ff->reserved_req); + wait_event(fc->reserved_req_waitq, ff->reserved_req); spin_lock(&fc->lock); if (ff->reserved_req) { req = ff->reserved_req; @@ -155,7 +155,7 @@ static void put_reserved_req(struct fuse_conn *fc, struct fuse_req *req) fuse_request_init(req); BUG_ON(ff->reserved_req); ff->reserved_req = req; - wake_up(&fc->blocked_waitq); + wake_up_all(&fc->reserved_req_waitq); spin_unlock(&fc->lock); fput(file); } @@ -224,13 +224,13 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) fc->blocked = 0; wake_up_all(&fc->blocked_waitq); } + if (fc->num_background == FUSE_CONGESTION_THRESHOLD) { + clear_bdi_congested(&fc->bdi, READ); + clear_bdi_congested(&fc->bdi, WRITE); + } fc->num_background--; } spin_unlock(&fc->lock); - dput(req->dentry); - mntput(req->vfsmount); - if (req->file) - fput(req->file); wake_up(&req->waitq); if (end) end(fc, req); @@ -273,28 +273,41 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req) queue_interrupt(fc, req); } - if (req->force) { - spin_unlock(&fc->lock); - wait_event(req->waitq, req->state == FUSE_REQ_FINISHED); - spin_lock(&fc->lock); - } else { + if (!req->force) { sigset_t oldset; /* Only fatal signals may interrupt this */ block_sigs(&oldset); wait_answer_interruptible(fc, req); restore_sigs(&oldset); + + if (req->aborted) + goto aborted; + if (req->state == FUSE_REQ_FINISHED) + return; + + /* Request is not yet in userspace, bail out */ + if (req->state == FUSE_REQ_PENDING) { + list_del(&req->list); + __fuse_put_request(req); + req->out.h.error = -EINTR; + return; + } } - if (req->aborted) - goto aborted; - if (req->state == FUSE_REQ_FINISHED) - return; + /* + * Either request is already in userspace, or it was forced. + * Wait it out. + */ + spin_unlock(&fc->lock); + wait_event(req->waitq, req->state == FUSE_REQ_FINISHED); + spin_lock(&fc->lock); - req->out.h.error = -EINTR; - req->aborted = 1; + if (!req->aborted) + return; aborted: + BUG_ON(req->state != FUSE_REQ_FINISHED); if (req->locked) { /* This is uninterruptible sleep, because data is being copied to/from the buffers of req. During @@ -305,14 +318,6 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req) wait_event(req->waitq, !req->locked); spin_lock(&fc->lock); } - if (req->state == FUSE_REQ_PENDING) { - list_del(&req->list); - __fuse_put_request(req); - } else if (req->state == FUSE_REQ_SENT) { - spin_unlock(&fc->lock); - wait_event(req->waitq, req->state == FUSE_REQ_FINISHED); - spin_lock(&fc->lock); - } } static unsigned len_args(unsigned numargs, struct fuse_arg *args) @@ -378,6 +383,10 @@ static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req) fc->num_background++; if (fc->num_background == FUSE_MAX_BACKGROUND) fc->blocked = 1; + if (fc->num_background == FUSE_CONGESTION_THRESHOLD) { + set_bdi_congested(&fc->bdi, READ); + set_bdi_congested(&fc->bdi, WRITE); + } queue_request(fc, req); spin_unlock(&fc->lock); @@ -738,11 +747,12 @@ static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov, fuse_copy_finish(&cs); spin_lock(&fc->lock); req->locked = 0; - if (!err && req->aborted) - err = -ENOENT; + if (req->aborted) { + request_end(fc, req); + return -ENODEV; + } if (err) { - if (!req->aborted) - req->out.h.error = -EIO; + req->out.h.error = -EIO; request_end(fc, req); return err; } diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index bd5a772d8ccf..3763757f9fe7 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -63,13 +63,21 @@ static u64 time_to_jiffies(unsigned long sec, unsigned long nsec) * Set dentry and possibly attribute timeouts from the lookup/mk* * replies */ -static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o) +static void fuse_change_entry_timeout(struct dentry *entry, + struct fuse_entry_out *o) { fuse_dentry_settime(entry, time_to_jiffies(o->entry_valid, o->entry_valid_nsec)); - if (entry->d_inode) - get_fuse_inode(entry->d_inode)->i_time = - time_to_jiffies(o->attr_valid, o->attr_valid_nsec); +} + +static u64 attr_timeout(struct fuse_attr_out *o) +{ + return time_to_jiffies(o->attr_valid, o->attr_valid_nsec); +} + +static u64 entry_attr_timeout(struct fuse_entry_out *o) +{ + return time_to_jiffies(o->attr_valid, o->attr_valid_nsec); } /* @@ -108,13 +116,19 @@ static void fuse_lookup_init(struct fuse_req *req, struct inode *dir, struct dentry *entry, struct fuse_entry_out *outarg) { + struct fuse_conn *fc = get_fuse_conn(dir); + + memset(outarg, 0, sizeof(struct fuse_entry_out)); req->in.h.opcode = FUSE_LOOKUP; req->in.h.nodeid = get_node_id(dir); req->in.numargs = 1; req->in.args[0].size = entry->d_name.len + 1; req->in.args[0].value = entry->d_name.name; req->out.numargs = 1; - req->out.args[0].size = sizeof(struct fuse_entry_out); + if (fc->minor < 9) + req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; + else + req->out.args[0].size = sizeof(struct fuse_entry_out); req->out.args[0].value = outarg; } @@ -140,6 +154,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) struct fuse_req *req; struct fuse_req *forget_req; struct dentry *parent; + u64 attr_version; /* For negative dentries, always do a fresh lookup */ if (!inode) @@ -156,6 +171,10 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) return 0; } + spin_lock(&fc->lock); + attr_version = fc->attr_version; + spin_unlock(&fc->lock); + parent = dget_parent(entry); fuse_lookup_init(req, parent->d_inode, entry, &outarg); request_send(fc, req); @@ -180,8 +199,10 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) return 0; - fuse_change_attributes(inode, &outarg.attr); - fuse_change_timeout(entry, &outarg); + fuse_change_attributes(inode, &outarg.attr, + entry_attr_timeout(&outarg), + attr_version); + fuse_change_entry_timeout(entry, &outarg); } return 1; } @@ -228,6 +249,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, struct fuse_conn *fc = get_fuse_conn(dir); struct fuse_req *req; struct fuse_req *forget_req; + u64 attr_version; if (entry->d_name.len > FUSE_NAME_MAX) return ERR_PTR(-ENAMETOOLONG); @@ -242,6 +264,10 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, return ERR_PTR(PTR_ERR(forget_req)); } + spin_lock(&fc->lock); + attr_version = fc->attr_version; + spin_unlock(&fc->lock); + fuse_lookup_init(req, dir, entry, &outarg); request_send(fc, req); err = req->out.h.error; @@ -253,7 +279,8 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, err = -EIO; if (!err && outarg.nodeid) { inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, - &outarg.attr); + &outarg.attr, entry_attr_timeout(&outarg), + attr_version); if (!inode) { fuse_send_forget(fc, forget_req, outarg.nodeid, 1); return ERR_PTR(-ENOMEM); @@ -276,7 +303,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, entry->d_op = &fuse_dentry_operations; if (!err) - fuse_change_timeout(entry, &outarg); + fuse_change_entry_timeout(entry, &outarg); else fuse_invalidate_entry_cache(entry); return NULL; @@ -288,12 +315,11 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, static void fuse_sync_release(struct fuse_conn *fc, struct fuse_file *ff, u64 nodeid, int flags) { - struct fuse_req *req; - - req = fuse_release_fill(ff, nodeid, flags, FUSE_RELEASE); - req->force = 1; - request_send(fc, req); - fuse_put_request(fc, req); + fuse_release_fill(ff, nodeid, flags, FUSE_RELEASE); + ff->reserved_req->force = 1; + request_send(fc, ff->reserved_req); + fuse_put_request(fc, ff->reserved_req); + kfree(ff); } /* @@ -336,6 +362,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, flags &= ~O_NOCTTY; memset(&inarg, 0, sizeof(inarg)); + memset(&outentry, 0, sizeof(outentry)); inarg.flags = flags; inarg.mode = mode; req->in.h.opcode = FUSE_CREATE; @@ -346,7 +373,10 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, req->in.args[1].size = entry->d_name.len + 1; req->in.args[1].value = entry->d_name.name; req->out.numargs = 2; - req->out.args[0].size = sizeof(outentry); + if (fc->minor < 9) + req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; + else + req->out.args[0].size = sizeof(outentry); req->out.args[0].value = &outentry; req->out.args[1].size = sizeof(outopen); req->out.args[1].value = &outopen; @@ -364,7 +394,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, fuse_put_request(fc, req); inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, - &outentry.attr); + &outentry.attr, entry_attr_timeout(&outentry), 0); if (!inode) { flags &= ~(O_CREAT | O_EXCL | O_TRUNC); ff->fh = outopen.fh; @@ -374,7 +404,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, } fuse_put_request(fc, forget_req); d_instantiate(entry, inode); - fuse_change_timeout(entry, &outentry); + fuse_change_entry_timeout(entry, &outentry); file = lookup_instantiate_filp(nd, entry, generic_file_open); if (IS_ERR(file)) { ff->fh = outopen.fh; @@ -411,9 +441,13 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, return PTR_ERR(forget_req); } + memset(&outarg, 0, sizeof(outarg)); req->in.h.nodeid = get_node_id(dir); req->out.numargs = 1; - req->out.args[0].size = sizeof(outarg); + if (fc->minor < 9) + req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; + else + req->out.args[0].size = sizeof(outarg); req->out.args[0].value = &outarg; request_send(fc, req); err = req->out.h.error; @@ -429,7 +463,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, goto out_put_forget_req; inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, - &outarg.attr); + &outarg.attr, entry_attr_timeout(&outarg), 0); if (!inode) { fuse_send_forget(fc, forget_req, outarg.nodeid, 1); return -ENOMEM; @@ -452,7 +486,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, } else d_instantiate(entry, inode); - fuse_change_timeout(entry, &outarg); + fuse_change_entry_timeout(entry, &outarg); fuse_invalidate_attr(dir); return 0; @@ -664,32 +698,78 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, return err; } -int fuse_do_getattr(struct inode *inode) +static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr, + struct kstat *stat) +{ + stat->dev = inode->i_sb->s_dev; + stat->ino = attr->ino; + stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); + stat->nlink = attr->nlink; + stat->uid = attr->uid; + stat->gid = attr->gid; + stat->rdev = inode->i_rdev; + stat->atime.tv_sec = attr->atime; + stat->atime.tv_nsec = attr->atimensec; + stat->mtime.tv_sec = attr->mtime; + stat->mtime.tv_nsec = attr->mtimensec; + stat->ctime.tv_sec = attr->ctime; + stat->ctime.tv_nsec = attr->ctimensec; + stat->size = attr->size; + stat->blocks = attr->blocks; + stat->blksize = (1 << inode->i_blkbits); +} + +static int fuse_do_getattr(struct inode *inode, struct kstat *stat, + struct file *file) { int err; - struct fuse_attr_out arg; + struct fuse_getattr_in inarg; + struct fuse_attr_out outarg; struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_req *req = fuse_get_req(fc); + struct fuse_req *req; + u64 attr_version; + + req = fuse_get_req(fc); if (IS_ERR(req)) return PTR_ERR(req); + spin_lock(&fc->lock); + attr_version = fc->attr_version; + spin_unlock(&fc->lock); + + memset(&inarg, 0, sizeof(inarg)); + memset(&outarg, 0, sizeof(outarg)); + /* Directories have separate file-handle space */ + if (file && S_ISREG(inode->i_mode)) { + struct fuse_file *ff = file->private_data; + + inarg.getattr_flags |= FUSE_GETATTR_FH; + inarg.fh = ff->fh; + } req->in.h.opcode = FUSE_GETATTR; req->in.h.nodeid = get_node_id(inode); + req->in.numargs = 1; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; req->out.numargs = 1; - req->out.args[0].size = sizeof(arg); - req->out.args[0].value = &arg; + if (fc->minor < 9) + req->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE; + else + req->out.args[0].size = sizeof(outarg); + req->out.args[0].value = &outarg; request_send(fc, req); err = req->out.h.error; fuse_put_request(fc, req); if (!err) { - if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) { + if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { make_bad_inode(inode); err = -EIO; } else { - struct fuse_inode *fi = get_fuse_inode(inode); - fuse_change_attributes(inode, &arg.attr); - fi->i_time = time_to_jiffies(arg.attr_valid, - arg.attr_valid_nsec); + fuse_change_attributes(inode, &outarg.attr, + attr_timeout(&outarg), + attr_version); + if (stat) + fuse_fillattr(inode, &outarg.attr, stat); } } return err; @@ -708,7 +788,7 @@ int fuse_do_getattr(struct inode *inode) * for which the owner of the mount has ptrace privilege. This * excludes processes started by other users, suid or sgid processes. */ -static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task) +int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task) { if (fc->flags & FUSE_ALLOW_OTHER) return 1; @@ -724,30 +804,6 @@ static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task) return 0; } -/* - * Check whether the inode attributes are still valid - * - * If the attribute validity timeout has expired, then fetch the fresh - * attributes with a 'getattr' request - * - * I'm not sure why cached attributes are never returned for the root - * inode, this is probably being too cautious. - */ -static int fuse_revalidate(struct dentry *entry) -{ - struct inode *inode = entry->d_inode; - struct fuse_inode *fi = get_fuse_inode(inode); - struct fuse_conn *fc = get_fuse_conn(inode); - - if (!fuse_allow_task(fc, current)) - return -EACCES; - if (get_node_id(inode) != FUSE_ROOT_ID && - fi->i_time >= get_jiffies_64()) - return 0; - - return fuse_do_getattr(inode); -} - static int fuse_access(struct inode *inode, int mask) { struct fuse_conn *fc = get_fuse_conn(inode); @@ -795,17 +851,35 @@ static int fuse_access(struct inode *inode, int mask) static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) { struct fuse_conn *fc = get_fuse_conn(inode); + bool refreshed = false; + int err = 0; if (!fuse_allow_task(fc, current)) return -EACCES; - else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { + + /* + * If attributes are needed, refresh them before proceeding + */ + if ((fc->flags & FUSE_DEFAULT_PERMISSIONS) || + ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { + struct fuse_inode *fi = get_fuse_inode(inode); + if (fi->i_time < get_jiffies_64()) { + err = fuse_do_getattr(inode, NULL, NULL); + if (err) + return err; + + refreshed = true; + } + } + + if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { int err = generic_permission(inode, mask, NULL); /* If permission is denied, try to refresh file attributes. This is also needed, because the root node will at first have no permissions */ - if (err == -EACCES) { - err = fuse_do_getattr(inode); + if (err == -EACCES && !refreshed) { + err = fuse_do_getattr(inode, NULL, NULL); if (!err) err = generic_permission(inode, mask, NULL); } @@ -814,17 +888,19 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) exist. So if permissions are revoked this won't be noticed immediately, only after the attribute timeout has expired */ - - return err; - } else { - int mode = inode->i_mode; - if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO)) - return -EACCES; - - if (nd && (nd->flags & (LOOKUP_ACCESS | LOOKUP_CHDIR))) - return fuse_access(inode, mask); - return 0; + } else if (nd && (nd->flags & (LOOKUP_ACCESS | LOOKUP_CHDIR))) { + err = fuse_access(inode, mask); + } else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) { + if (!(inode->i_mode & S_IXUGO)) { + if (refreshed) + return -EACCES; + + err = fuse_do_getattr(inode, NULL, NULL); + if (!err && !(inode->i_mode & S_IXUGO)) + return -EACCES; + } } + return err; } static int parse_dirfile(char *buf, size_t nbytes, struct file *file, @@ -859,6 +935,7 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) struct page *page; struct inode *inode = file->f_path.dentry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_file *ff = file->private_data; struct fuse_req *req; if (is_bad_inode(inode)) @@ -875,7 +952,7 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) } req->num_pages = 1; req->pages[0] = page; - fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR); + fuse_read_fill(req, ff, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR); request_send(fc, req); nbytes = req->out.args[0].size; err = req->out.h.error; @@ -955,6 +1032,20 @@ static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync) return file ? fuse_fsync_common(file, de, datasync, 1) : 0; } +static bool update_mtime(unsigned ivalid) +{ + /* Always update if mtime is explicitly set */ + if (ivalid & ATTR_MTIME_SET) + return true; + + /* If it's an open(O_TRUNC) or an ftruncate(), don't update */ + if ((ivalid & ATTR_SIZE) && (ivalid & (ATTR_OPEN | ATTR_FILE))) + return false; + + /* In all other cases update */ + return true; +} + static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg) { unsigned ivalid = iattr->ia_valid; @@ -967,33 +1058,19 @@ static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg) arg->valid |= FATTR_GID, arg->gid = iattr->ia_gid; if (ivalid & ATTR_SIZE) arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size; - /* You can only _set_ these together (they may change by themselves) */ - if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) { - arg->valid |= FATTR_ATIME | FATTR_MTIME; + if (ivalid & ATTR_ATIME) { + arg->valid |= FATTR_ATIME; arg->atime = iattr->ia_atime.tv_sec; - arg->mtime = iattr->ia_mtime.tv_sec; + arg->atimensec = iattr->ia_atime.tv_nsec; + if (!(ivalid & ATTR_ATIME_SET)) + arg->valid |= FATTR_ATIME_NOW; } - if (ivalid & ATTR_FILE) { - struct fuse_file *ff = iattr->ia_file->private_data; - arg->valid |= FATTR_FH; - arg->fh = ff->fh; - } -} - -static void fuse_vmtruncate(struct inode *inode, loff_t offset) -{ - struct fuse_conn *fc = get_fuse_conn(inode); - int need_trunc; - - spin_lock(&fc->lock); - need_trunc = inode->i_size > offset; - i_size_write(inode, offset); - spin_unlock(&fc->lock); - - if (need_trunc) { - struct address_space *mapping = inode->i_mapping; - unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); - truncate_inode_pages(mapping, offset); + if ((ivalid & ATTR_MTIME) && update_mtime(ivalid)) { + arg->valid |= FATTR_MTIME; + arg->mtime = iattr->ia_mtime.tv_sec; + arg->mtimensec = iattr->ia_mtime.tv_nsec; + if (!(ivalid & ATTR_MTIME_SET)) + arg->valid |= FATTR_MTIME_NOW; } } @@ -1005,16 +1082,18 @@ static void fuse_vmtruncate(struct inode *inode, loff_t offset) * vmtruncate() doesn't allow for this case, so do the rlimit checking * and the actual truncation by hand. */ -static int fuse_setattr(struct dentry *entry, struct iattr *attr) +static int fuse_do_setattr(struct dentry *entry, struct iattr *attr, + struct file *file) { struct inode *inode = entry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_inode *fi = get_fuse_inode(inode); struct fuse_req *req; struct fuse_setattr_in inarg; struct fuse_attr_out outarg; int err; - int is_truncate = 0; + + if (!fuse_allow_task(fc, current)) + return -EACCES; if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { err = inode_change_ok(inode, attr); @@ -1022,9 +1101,11 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr) return err; } + if ((attr->ia_valid & ATTR_OPEN) && fc->atomic_o_trunc) + return 0; + if (attr->ia_valid & ATTR_SIZE) { unsigned long limit; - is_truncate = 1; if (IS_SWAPFILE(inode)) return -ETXTBSY; limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; @@ -1039,42 +1120,73 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr) return PTR_ERR(req); memset(&inarg, 0, sizeof(inarg)); + memset(&outarg, 0, sizeof(outarg)); iattr_to_fattr(attr, &inarg); + if (file) { + struct fuse_file *ff = file->private_data; + inarg.valid |= FATTR_FH; + inarg.fh = ff->fh; + } + if (attr->ia_valid & ATTR_SIZE) { + /* For mandatory locking in truncate */ + inarg.valid |= FATTR_LOCKOWNER; + inarg.lock_owner = fuse_lock_owner_id(fc, current->files); + } req->in.h.opcode = FUSE_SETATTR; req->in.h.nodeid = get_node_id(inode); req->in.numargs = 1; req->in.args[0].size = sizeof(inarg); req->in.args[0].value = &inarg; req->out.numargs = 1; - req->out.args[0].size = sizeof(outarg); + if (fc->minor < 9) + req->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE; + else + req->out.args[0].size = sizeof(outarg); req->out.args[0].value = &outarg; request_send(fc, req); err = req->out.h.error; fuse_put_request(fc, req); - if (!err) { - if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { - make_bad_inode(inode); - err = -EIO; - } else { - if (is_truncate) - fuse_vmtruncate(inode, outarg.attr.size); - fuse_change_attributes(inode, &outarg.attr); - fi->i_time = time_to_jiffies(outarg.attr_valid, - outarg.attr_valid_nsec); - } - } else if (err == -EINTR) - fuse_invalidate_attr(inode); + if (err) { + if (err == -EINTR) + fuse_invalidate_attr(inode); + return err; + } - return err; + if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { + make_bad_inode(inode); + return -EIO; + } + + fuse_change_attributes(inode, &outarg.attr, attr_timeout(&outarg), 0); + return 0; +} + +static int fuse_setattr(struct dentry *entry, struct iattr *attr) +{ + if (attr->ia_valid & ATTR_FILE) + return fuse_do_setattr(entry, attr, attr->ia_file); + else + return fuse_do_setattr(entry, attr, NULL); } static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, struct kstat *stat) { struct inode *inode = entry->d_inode; - int err = fuse_revalidate(entry); - if (!err) + struct fuse_inode *fi = get_fuse_inode(inode); + struct fuse_conn *fc = get_fuse_conn(inode); + int err; + + if (!fuse_allow_task(fc, current)) + return -EACCES; + + if (fi->i_time < get_jiffies_64()) + err = fuse_do_getattr(inode, stat, NULL); + else { + err = 0; generic_fillattr(inode, stat); + stat->mode = fi->orig_i_mode; + } return err; } @@ -1176,6 +1288,9 @@ static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) struct fuse_getxattr_out outarg; ssize_t ret; + if (!fuse_allow_task(fc, current)) + return -EACCES; + if (fc->no_listxattr) return -EOPNOTSUPP; diff --git a/fs/fuse/file.c b/fs/fuse/file.c index f79de7c8cdfa..0fcdba9d47c0 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -28,7 +28,9 @@ static int fuse_send_open(struct inode *inode, struct file *file, int isdir, return PTR_ERR(req); memset(&inarg, 0, sizeof(inarg)); - inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); + inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY); + if (!fc->atomic_o_trunc) + inarg.flags &= ~O_TRUNC; req->in.h.opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN; req->in.h.nodeid = get_node_id(inode); req->in.numargs = 1; @@ -54,6 +56,8 @@ struct fuse_file *fuse_file_alloc(void) kfree(ff); ff = NULL; } + INIT_LIST_HEAD(&ff->write_entry); + atomic_set(&ff->count, 0); } return ff; } @@ -64,15 +68,39 @@ void fuse_file_free(struct fuse_file *ff) kfree(ff); } +static struct fuse_file *fuse_file_get(struct fuse_file *ff) +{ + atomic_inc(&ff->count); + return ff; +} + +static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req) +{ + dput(req->dentry); + mntput(req->vfsmount); + fuse_put_request(fc, req); +} + +static void fuse_file_put(struct fuse_file *ff) +{ + if (atomic_dec_and_test(&ff->count)) { + struct fuse_req *req = ff->reserved_req; + struct fuse_conn *fc = get_fuse_conn(req->dentry->d_inode); + req->end = fuse_release_end; + request_send_background(fc, req); + kfree(ff); + } +} + void fuse_finish_open(struct inode *inode, struct file *file, struct fuse_file *ff, struct fuse_open_out *outarg) { if (outarg->open_flags & FOPEN_DIRECT_IO) file->f_op = &fuse_direct_io_file_operations; if (!(outarg->open_flags & FOPEN_KEEP_CACHE)) - invalidate_mapping_pages(inode->i_mapping, 0, -1); + invalidate_inode_pages2(inode->i_mapping); ff->fh = outarg->fh; - file->private_data = ff; + file->private_data = fuse_file_get(ff); } int fuse_open_common(struct inode *inode, struct file *file, int isdir) @@ -89,14 +117,6 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir) if (err) return err; - /* If opening the root node, no lookup has been performed on - it, so the attributes must be refreshed */ - if (get_node_id(inode) == FUSE_ROOT_ID) { - err = fuse_do_getattr(inode); - if (err) - return err; - } - ff = fuse_file_alloc(); if (!ff) return -ENOMEM; @@ -113,8 +133,7 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir) return err; } -struct fuse_req *fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags, - int opcode) +void fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags, int opcode) { struct fuse_req *req = ff->reserved_req; struct fuse_release_in *inarg = &req->misc.release_in; @@ -126,9 +145,6 @@ struct fuse_req *fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags, req->in.numargs = 1; req->in.args[0].size = sizeof(struct fuse_release_in); req->in.args[0].value = inarg; - kfree(ff); - - return req; } int fuse_release_common(struct inode *inode, struct file *file, int isdir) @@ -136,15 +152,23 @@ int fuse_release_common(struct inode *inode, struct file *file, int isdir) struct fuse_file *ff = file->private_data; if (ff) { struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_req *req; - req = fuse_release_fill(ff, get_node_id(inode), file->f_flags, - isdir ? FUSE_RELEASEDIR : FUSE_RELEASE); + fuse_release_fill(ff, get_node_id(inode), file->f_flags, + isdir ? FUSE_RELEASEDIR : FUSE_RELEASE); /* Hold vfsmount and dentry until release is finished */ - req->vfsmount = mntget(file->f_path.mnt); - req->dentry = dget(file->f_path.dentry); - request_send_background(fc, req); + ff->reserved_req->vfsmount = mntget(file->f_path.mnt); + ff->reserved_req->dentry = dget(file->f_path.dentry); + + spin_lock(&fc->lock); + list_del(&ff->write_entry); + spin_unlock(&fc->lock); + /* + * Normally this will send the RELEASE request, + * however if some asynchronous READ or WRITE requests + * are outstanding, the sending will be delayed + */ + fuse_file_put(ff); } /* Return value is ignored by VFS */ @@ -165,7 +189,7 @@ static int fuse_release(struct inode *inode, struct file *file) * Scramble the ID space with XTEA, so that the value of the files_struct * pointer is not exposed to userspace. */ -static u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id) +u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id) { u32 *k = fc->scramble_key; u64 v = (unsigned long) id; @@ -264,10 +288,9 @@ static int fuse_fsync(struct file *file, struct dentry *de, int datasync) return fuse_fsync_common(file, de, datasync, 0); } -void fuse_read_fill(struct fuse_req *req, struct file *file, +void fuse_read_fill(struct fuse_req *req, struct fuse_file *ff, struct inode *inode, loff_t pos, size_t count, int opcode) { - struct fuse_file *ff = file->private_data; struct fuse_read_in *inarg = &req->misc.read_in; inarg->fh = ff->fh; @@ -285,10 +308,19 @@ void fuse_read_fill(struct fuse_req *req, struct file *file, } static size_t fuse_send_read(struct fuse_req *req, struct file *file, - struct inode *inode, loff_t pos, size_t count) + struct inode *inode, loff_t pos, size_t count, + fl_owner_t owner) { struct fuse_conn *fc = get_fuse_conn(inode); - fuse_read_fill(req, file, inode, pos, count, FUSE_READ); + struct fuse_file *ff = file->private_data; + + fuse_read_fill(req, ff, inode, pos, count, FUSE_READ); + if (owner != NULL) { + struct fuse_read_in *inarg = &req->misc.read_in; + + inarg->read_flags |= FUSE_READ_LOCKOWNER; + inarg->lock_owner = fuse_lock_owner_id(fc, owner); + } request_send(fc, req); return req->out.args[0].size; } @@ -312,7 +344,8 @@ static int fuse_readpage(struct file *file, struct page *page) req->out.page_zeroing = 1; req->num_pages = 1; req->pages[0] = page; - fuse_send_read(req, file, inode, page_offset(page), PAGE_CACHE_SIZE); + fuse_send_read(req, file, inode, page_offset(page), PAGE_CACHE_SIZE, + NULL); err = req->out.h.error; fuse_put_request(fc, req); if (!err) @@ -337,20 +370,21 @@ static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req) SetPageError(page); unlock_page(page); } + if (req->ff) + fuse_file_put(req->ff); fuse_put_request(fc, req); } -static void fuse_send_readpages(struct fuse_req *req, struct file *file, +static void fuse_send_readpages(struct fuse_req *req, struct fuse_file *ff, struct inode *inode) { struct fuse_conn *fc = get_fuse_conn(inode); loff_t pos = page_offset(req->pages[0]); size_t count = req->num_pages << PAGE_CACHE_SHIFT; req->out.page_zeroing = 1; - fuse_read_fill(req, file, inode, pos, count, FUSE_READ); + fuse_read_fill(req, ff, inode, pos, count, FUSE_READ); if (fc->async_read) { - get_file(file); - req->file = file; + req->ff = fuse_file_get(ff); req->end = fuse_readpages_end; request_send_background(fc, req); } else { @@ -359,15 +393,15 @@ static void fuse_send_readpages(struct fuse_req *req, struct file *file, } } -struct fuse_readpages_data { +struct fuse_fill_data { struct fuse_req *req; - struct file *file; + struct fuse_file *ff; struct inode *inode; }; static int fuse_readpages_fill(void *_data, struct page *page) { - struct fuse_readpages_data *data = _data; + struct fuse_fill_data *data = _data; struct fuse_req *req = data->req; struct inode *inode = data->inode; struct fuse_conn *fc = get_fuse_conn(inode); @@ -376,7 +410,7 @@ static int fuse_readpages_fill(void *_data, struct page *page) (req->num_pages == FUSE_MAX_PAGES_PER_REQ || (req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_read || req->pages[req->num_pages - 1]->index + 1 != page->index)) { - fuse_send_readpages(req, data->file, inode); + fuse_send_readpages(req, data->ff, inode); data->req = req = fuse_get_req(fc); if (IS_ERR(req)) { unlock_page(page); @@ -393,14 +427,14 @@ static int fuse_readpages(struct file *file, struct address_space *mapping, { struct inode *inode = mapping->host; struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_readpages_data data; + struct fuse_fill_data data; int err; err = -EIO; if (is_bad_inode(inode)) goto out; - data.file = file; + data.ff = file->private_data; data.inode = inode; data.req = fuse_get_req(fc); err = PTR_ERR(data.req); @@ -410,7 +444,7 @@ static int fuse_readpages(struct file *file, struct address_space *mapping, err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data); if (!err) { if (data.req->num_pages) - fuse_send_readpages(data.req, file, inode); + fuse_send_readpages(data.req, data.ff, inode); else fuse_put_request(fc, data.req); } @@ -418,48 +452,69 @@ out: return err; } -static size_t fuse_send_write(struct fuse_req *req, struct file *file, - struct inode *inode, loff_t pos, size_t count) +static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff, + struct inode *inode, loff_t pos, size_t count, + int writepage) { struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_file *ff = file->private_data; - struct fuse_write_in inarg; - struct fuse_write_out outarg; + struct fuse_write_in *inarg = &req->misc.write.in; + struct fuse_write_out *outarg = &req->misc.write.out; - memset(&inarg, 0, sizeof(struct fuse_write_in)); - inarg.fh = ff->fh; - inarg.offset = pos; - inarg.size = count; + memset(inarg, 0, sizeof(struct fuse_write_in)); + inarg->fh = ff->fh; + inarg->offset = pos; + inarg->size = count; + inarg->write_flags = writepage ? FUSE_WRITE_CACHE : 0; req->in.h.opcode = FUSE_WRITE; req->in.h.nodeid = get_node_id(inode); req->in.argpages = 1; req->in.numargs = 2; - req->in.args[0].size = sizeof(struct fuse_write_in); - req->in.args[0].value = &inarg; + if (fc->minor < 9) + req->in.args[0].size = FUSE_COMPAT_WRITE_IN_SIZE; + else + req->in.args[0].size = sizeof(struct fuse_write_in); + req->in.args[0].value = inarg; req->in.args[1].size = count; req->out.numargs = 1; req->out.args[0].size = sizeof(struct fuse_write_out); - req->out.args[0].value = &outarg; + req->out.args[0].value = outarg; +} + +static size_t fuse_send_write(struct fuse_req *req, struct file *file, + struct inode *inode, loff_t pos, size_t count, + fl_owner_t owner) +{ + struct fuse_conn *fc = get_fuse_conn(inode); + fuse_write_fill(req, file->private_data, inode, pos, count, 0); + if (owner != NULL) { + struct fuse_write_in *inarg = &req->misc.write.in; + inarg->write_flags |= FUSE_WRITE_LOCKOWNER; + inarg->lock_owner = fuse_lock_owner_id(fc, owner); + } request_send(fc, req); - return outarg.size; + return req->misc.write.out.size; } -static int fuse_prepare_write(struct file *file, struct page *page, - unsigned offset, unsigned to) +static int fuse_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - /* No op */ + pgoff_t index = pos >> PAGE_CACHE_SHIFT; + + *pagep = __grab_cache_page(mapping, index); + if (!*pagep) + return -ENOMEM; return 0; } -static int fuse_commit_write(struct file *file, struct page *page, - unsigned offset, unsigned to) +static int fuse_buffered_write(struct file *file, struct inode *inode, + loff_t pos, unsigned count, struct page *page) { int err; size_t nres; - unsigned count = to - offset; - struct inode *inode = page->mapping->host; struct fuse_conn *fc = get_fuse_conn(inode); - loff_t pos = page_offset(page) + offset; + struct fuse_inode *fi = get_fuse_inode(inode); + unsigned offset = pos & (PAGE_CACHE_SIZE - 1); struct fuse_req *req; if (is_bad_inode(inode)) @@ -472,23 +527,39 @@ static int fuse_commit_write(struct file *file, struct page *page, req->num_pages = 1; req->pages[0] = page; req->page_offset = offset; - nres = fuse_send_write(req, file, inode, pos, count); + nres = fuse_send_write(req, file, inode, pos, count, NULL); err = req->out.h.error; fuse_put_request(fc, req); - if (!err && nres != count) + if (!err && !nres) err = -EIO; if (!err) { - pos += count; + pos += nres; spin_lock(&fc->lock); + fi->attr_version = ++fc->attr_version; if (pos > inode->i_size) i_size_write(inode, pos); spin_unlock(&fc->lock); - if (offset == 0 && to == PAGE_CACHE_SIZE) + if (count == PAGE_CACHE_SIZE) SetPageUptodate(page); } fuse_invalidate_attr(inode); - return err; + return err ? err : nres; +} + +static int fuse_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) +{ + struct inode *inode = mapping->host; + int res = 0; + + if (copied) + res = fuse_buffered_write(file, inode, pos, copied, page); + + unlock_page(page); + page_cache_release(page); + return res; } static void fuse_release_user_pages(struct fuse_req *req, int write) @@ -557,9 +628,11 @@ static ssize_t fuse_direct_io(struct file *file, const char __user *buf, nbytes = (req->num_pages << PAGE_SHIFT) - req->page_offset; nbytes = min(count, nbytes); if (write) - nres = fuse_send_write(req, file, inode, pos, nbytes); + nres = fuse_send_write(req, file, inode, pos, nbytes, + current->files); else - nres = fuse_send_read(req, file, inode, pos, nbytes); + nres = fuse_send_read(req, file, inode, pos, nbytes, + current->files); fuse_release_user_pages(req, !write); if (req->out.h.error) { if (!res) @@ -661,7 +734,8 @@ static int convert_fuse_file_lock(const struct fuse_file_lock *ffl, } static void fuse_lk_fill(struct fuse_req *req, struct file *file, - const struct file_lock *fl, int opcode, pid_t pid) + const struct file_lock *fl, int opcode, pid_t pid, + int flock) { struct inode *inode = file->f_path.dentry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); @@ -674,6 +748,8 @@ static void fuse_lk_fill(struct fuse_req *req, struct file *file, arg->lk.end = fl->fl_end; arg->lk.type = fl->fl_type; arg->lk.pid = pid; + if (flock) + arg->lk_flags |= FUSE_LK_FLOCK; req->in.h.opcode = opcode; req->in.h.nodeid = get_node_id(inode); req->in.numargs = 1; @@ -693,7 +769,7 @@ static int fuse_getlk(struct file *file, struct file_lock *fl) if (IS_ERR(req)) return PTR_ERR(req); - fuse_lk_fill(req, file, fl, FUSE_GETLK, 0); + fuse_lk_fill(req, file, fl, FUSE_GETLK, 0, 0); req->out.numargs = 1; req->out.args[0].size = sizeof(outarg); req->out.args[0].value = &outarg; @@ -706,7 +782,7 @@ static int fuse_getlk(struct file *file, struct file_lock *fl) return err; } -static int fuse_setlk(struct file *file, struct file_lock *fl) +static int fuse_setlk(struct file *file, struct file_lock *fl, int flock) { struct inode *inode = file->f_path.dentry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); @@ -723,7 +799,7 @@ static int fuse_setlk(struct file *file, struct file_lock *fl) if (IS_ERR(req)) return PTR_ERR(req); - fuse_lk_fill(req, file, fl, opcode, pid); + fuse_lk_fill(req, file, fl, opcode, pid, flock); request_send(fc, req); err = req->out.h.error; /* locking is restartable */ @@ -749,8 +825,25 @@ static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl) if (fc->no_lock) err = posix_lock_file_wait(file, fl); else - err = fuse_setlk(file, fl); + err = fuse_setlk(file, fl, 0); + } + return err; +} + +static int fuse_file_flock(struct file *file, int cmd, struct file_lock *fl) +{ + struct inode *inode = file->f_path.dentry->d_inode; + struct fuse_conn *fc = get_fuse_conn(inode); + int err; + + if (fc->no_lock) { + err = flock_lock_file_wait(file, fl); + } else { + /* emulate flock with POSIX locks */ + fl->fl_owner = (fl_owner_t) file; + err = fuse_setlk(file, fl, 1); } + return err; } @@ -802,6 +895,7 @@ static const struct file_operations fuse_file_operations = { .release = fuse_release, .fsync = fuse_fsync, .lock = fuse_file_lock, + .flock = fuse_file_flock, .splice_read = generic_file_splice_read, }; @@ -814,13 +908,14 @@ static const struct file_operations fuse_direct_io_file_operations = { .release = fuse_release, .fsync = fuse_fsync, .lock = fuse_file_lock, + .flock = fuse_file_flock, /* no mmap and splice_read */ }; static const struct address_space_operations fuse_file_aops = { .readpage = fuse_readpage, - .prepare_write = fuse_prepare_write, - .commit_write = fuse_commit_write, + .write_begin = fuse_write_begin, + .write_end = fuse_write_end, .readpages = fuse_readpages, .set_page_dirty = fuse_set_page_dirty, .bmap = fuse_bmap, diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 68ae87cbafab..6c5461de1a5f 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -20,7 +20,10 @@ #define FUSE_MAX_PAGES_PER_REQ 32 /** Maximum number of outstanding background requests */ -#define FUSE_MAX_BACKGROUND 10 +#define FUSE_MAX_BACKGROUND 12 + +/** Congestion starts at 75% of maximum */ +#define FUSE_CONGESTION_THRESHOLD (FUSE_MAX_BACKGROUND * 75 / 100) /** It could be as large as PATH_MAX, but would that have any uses? */ #define FUSE_NAME_MAX 1024 @@ -60,6 +63,16 @@ struct fuse_inode { /** Time in jiffies until the file attributes are valid */ u64 i_time; + + /** The sticky bit in inode->i_mode may have been removed, so + preserve the original mode */ + mode_t orig_i_mode; + + /** Version of last attribute change */ + u64 attr_version; + + /** Files usable in writepage. Protected by fc->lock */ + struct list_head write_files; }; /** FUSE specific file data */ @@ -69,6 +82,12 @@ struct fuse_file { /** File handle used by userspace */ u64 fh; + + /** Refcount */ + atomic_t count; + + /** Entry on inode's write_files list */ + struct list_head write_entry; }; /** One input argument of a request */ @@ -200,6 +219,10 @@ struct fuse_req { struct fuse_init_in init_in; struct fuse_init_out init_out; struct fuse_read_in read_in; + struct { + struct fuse_write_in in; + struct fuse_write_out out; + } write; struct fuse_lk_in lk_in; } misc; @@ -213,7 +236,7 @@ struct fuse_req { unsigned page_offset; /** File used in the request (or NULL) */ - struct file *file; + struct fuse_file *ff; /** vfsmount used in release */ struct vfsmount *vfsmount; @@ -286,6 +309,9 @@ struct fuse_conn { /** waitq for blocked connection */ wait_queue_head_t blocked_waitq; + /** waitq for reserved requests */ + wait_queue_head_t reserved_req_waitq; + /** The next unique request id */ u64 reqctr; @@ -304,6 +330,9 @@ struct fuse_conn { /** Do readpages asynchronously? Only set in INIT */ unsigned async_read : 1; + /** Do not send separate SETATTR request before open(O_TRUNC) */ + unsigned atomic_o_trunc : 1; + /* * The following bitfields are only for optimization purposes * and hence races in setting them will not cause malfunction @@ -374,6 +403,9 @@ struct fuse_conn { /** Reserved request for the DESTROY message */ struct fuse_req *destroy_req; + + /** Version counter for attribute changes */ + u64 attr_version; }; static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb) @@ -403,7 +435,8 @@ extern const struct file_operations fuse_dev_operations; * Get a filled in inode */ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, - int generation, struct fuse_attr *attr); + int generation, struct fuse_attr *attr, + u64 attr_valid, u64 attr_version); /** * Send FORGET command @@ -414,7 +447,7 @@ void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, /** * Initialize READ or READDIR request */ -void fuse_read_fill(struct fuse_req *req, struct file *file, +void fuse_read_fill(struct fuse_req *req, struct fuse_file *ff, struct inode *inode, loff_t pos, size_t count, int opcode); /** @@ -427,9 +460,9 @@ void fuse_file_free(struct fuse_file *ff); void fuse_finish_open(struct inode *inode, struct file *file, struct fuse_file *ff, struct fuse_open_out *outarg); -/** */ -struct fuse_req *fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags, - int opcode); +/** Fill in ff->reserved_req with a RELEASE request */ +void fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags, int opcode); + /** * Send RELEASE or RELEASEDIR request */ @@ -464,7 +497,8 @@ void fuse_init_symlink(struct inode *inode); /** * Change attributes of an inode */ -void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr); +void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, + u64 attr_valid, u64 attr_version); /** * Initialize the client device @@ -524,11 +558,6 @@ void request_send_background(struct fuse_conn *fc, struct fuse_req *req); void fuse_abort_conn(struct fuse_conn *fc); /** - * Get the attributes of a file - */ -int fuse_do_getattr(struct inode *inode); - -/** * Invalidate inode attributes */ void fuse_invalidate_attr(struct inode *inode); @@ -557,3 +586,10 @@ void fuse_ctl_remove_conn(struct fuse_conn *fc); * Is file type valid? */ int fuse_valid_type(int m); + +/** + * Is task allowed to perform filesystem operation? + */ +int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task); + +u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id); diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 5448f625ab56..9a68d6970845 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -56,6 +56,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) fi->i_time = 0; fi->nodeid = 0; fi->nlookup = 0; + INIT_LIST_HEAD(&fi->write_files); fi->forget_req = fuse_request_alloc(); if (!fi->forget_req) { kmem_cache_free(fuse_inode_cachep, inode); @@ -68,6 +69,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) static void fuse_destroy_inode(struct inode *inode) { struct fuse_inode *fi = get_fuse_inode(inode); + BUG_ON(!list_empty(&fi->write_files)); if (fi->forget_req) fuse_request_free(fi->forget_req); kmem_cache_free(fuse_inode_cachep, inode); @@ -109,20 +111,35 @@ static int fuse_remount_fs(struct super_block *sb, int *flags, char *data) return 0; } -void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) +static void fuse_truncate(struct address_space *mapping, loff_t offset) +{ + /* See vmtruncate() */ + unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); + truncate_inode_pages(mapping, offset); + unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); +} + + +void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, + u64 attr_valid, u64 attr_version) { struct fuse_conn *fc = get_fuse_conn(inode); - if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size) - invalidate_mapping_pages(inode->i_mapping, 0, -1); + struct fuse_inode *fi = get_fuse_inode(inode); + loff_t oldsize; + + spin_lock(&fc->lock); + if (attr_version != 0 && fi->attr_version > attr_version) { + spin_unlock(&fc->lock); + return; + } + fi->attr_version = ++fc->attr_version; + fi->i_time = attr_valid; inode->i_ino = attr->ino; - inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777); + inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); inode->i_nlink = attr->nlink; inode->i_uid = attr->uid; inode->i_gid = attr->gid; - spin_lock(&fc->lock); - i_size_write(inode, attr->size); - spin_unlock(&fc->lock); inode->i_blocks = attr->blocks; inode->i_atime.tv_sec = attr->atime; inode->i_atime.tv_nsec = attr->atimensec; @@ -130,6 +147,30 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) inode->i_mtime.tv_nsec = attr->mtimensec; inode->i_ctime.tv_sec = attr->ctime; inode->i_ctime.tv_nsec = attr->ctimensec; + + if (attr->blksize != 0) + inode->i_blkbits = ilog2(attr->blksize); + else + inode->i_blkbits = inode->i_sb->s_blocksize_bits; + + /* + * Don't set the sticky bit in i_mode, unless we want the VFS + * to check permissions. This prevents failures due to the + * check in may_delete(). + */ + fi->orig_i_mode = inode->i_mode; + if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) + inode->i_mode &= ~S_ISVTX; + + oldsize = inode->i_size; + i_size_write(inode, attr->size); + spin_unlock(&fc->lock); + + if (S_ISREG(inode->i_mode) && oldsize != attr->size) { + if (attr->size < oldsize) + fuse_truncate(inode->i_mapping, attr->size); + invalidate_inode_pages2(inode->i_mapping); + } } static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) @@ -169,7 +210,8 @@ static int fuse_inode_set(struct inode *inode, void *_nodeidp) } struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, - int generation, struct fuse_attr *attr) + int generation, struct fuse_attr *attr, + u64 attr_valid, u64 attr_version) { struct inode *inode; struct fuse_inode *fi; @@ -197,7 +239,8 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, spin_lock(&fc->lock); fi->nlookup ++; spin_unlock(&fc->lock); - fuse_change_attributes(inode, attr); + fuse_change_attributes(inode, attr, attr_valid, attr_version); + return inode; } @@ -232,6 +275,7 @@ static void fuse_put_super(struct super_block *sb) kill_fasync(&fc->fasync, SIGIO, POLL_IN); wake_up_all(&fc->waitq); wake_up_all(&fc->blocked_waitq); + wake_up_all(&fc->reserved_req_waitq); mutex_lock(&fuse_mutex); list_del(&fc->entry); fuse_ctl_remove_conn(fc); @@ -261,6 +305,11 @@ static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf) struct fuse_statfs_out outarg; int err; + if (!fuse_allow_task(fc, current)) { + buf->f_type = FUSE_SUPER_MAGIC; + return 0; + } + req = fuse_get_req(fc); if (IS_ERR(req)) return PTR_ERR(req); @@ -401,6 +450,7 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) static struct fuse_conn *new_conn(void) { struct fuse_conn *fc; + int err; fc = kzalloc(sizeof(*fc), GFP_KERNEL); if (fc) { @@ -409,6 +459,7 @@ static struct fuse_conn *new_conn(void) atomic_set(&fc->count, 1); init_waitqueue_head(&fc->waitq); init_waitqueue_head(&fc->blocked_waitq); + init_waitqueue_head(&fc->reserved_req_waitq); INIT_LIST_HEAD(&fc->pending); INIT_LIST_HEAD(&fc->processing); INIT_LIST_HEAD(&fc->io); @@ -416,10 +467,18 @@ static struct fuse_conn *new_conn(void) atomic_set(&fc->num_waiting, 0); fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; fc->bdi.unplug_io_fn = default_unplug_io_fn; + err = bdi_init(&fc->bdi); + if (err) { + kfree(fc); + fc = NULL; + goto out; + } fc->reqctr = 0; fc->blocked = 1; + fc->attr_version = 1; get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key)); } +out: return fc; } @@ -429,6 +488,7 @@ void fuse_conn_put(struct fuse_conn *fc) if (fc->destroy_req) fuse_request_free(fc->destroy_req); mutex_destroy(&fc->inst_mutex); + bdi_destroy(&fc->bdi); kfree(fc); } } @@ -446,7 +506,8 @@ static struct inode *get_root_inode(struct super_block *sb, unsigned mode) attr.mode = mode; attr.ino = FUSE_ROOT_ID; - return fuse_iget(sb, 1, 0, &attr); + attr.nlink = 1; + return fuse_iget(sb, 1, 0, &attr, 0, 0); } static const struct super_operations fuse_super_operations = { @@ -477,6 +538,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) fc->async_read = 1; if (!(arg->flags & FUSE_POSIX_LOCKS)) fc->no_lock = 1; + if (arg->flags & FUSE_ATOMIC_O_TRUNC) + fc->atomic_o_trunc = 1; } else { ra_pages = fc->max_read / PAGE_CACHE_SIZE; fc->no_lock = 1; @@ -499,7 +562,8 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) arg->major = FUSE_KERNEL_VERSION; arg->minor = FUSE_KERNEL_MINOR_VERSION; arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; - arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS; + arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_FILE_OPS | + FUSE_ATOMIC_O_TRUNC; req->in.h.opcode = FUSE_INIT; req->in.numargs = 1; req->in.args[0].size = sizeof(*arg); @@ -683,8 +747,7 @@ static inline void unregister_fuseblk(void) static decl_subsys(fuse, NULL, NULL); static decl_subsys(connections, NULL, NULL); -static void fuse_inode_init_once(void *foo, struct kmem_cache *cachep, - unsigned long flags) +static void fuse_inode_init_once(struct kmem_cache *cachep, void *foo) { struct inode * inode = foo; diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index cd805a66880d..93fa427bb5f5 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -93,9 +93,10 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, map_bh(bh, inode->i_sb, block); set_buffer_uptodate(bh); + if (!gfs2_is_jdata(ip)) + mark_buffer_dirty(bh); if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) gfs2_trans_add_bh(ip->i_gl, bh, 0); - mark_buffer_dirty(bh); if (release) { unlock_page(page); @@ -1085,6 +1086,33 @@ static int do_shrink(struct gfs2_inode *ip, u64 size) return error; } +static int do_touch(struct gfs2_inode *ip, u64 size) +{ + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); + struct buffer_head *dibh; + int error; + + error = gfs2_trans_begin(sdp, RES_DINODE, 0); + if (error) + return error; + + down_write(&ip->i_rw_mutex); + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto do_touch_out; + + ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; + gfs2_trans_add_bh(ip->i_gl, dibh, 1); + gfs2_dinode_out(ip, dibh->b_data); + brelse(dibh); + +do_touch_out: + up_write(&ip->i_rw_mutex); + gfs2_trans_end(sdp); + return error; +} + /** * gfs2_truncatei - make a file a given size * @ip: the inode @@ -1105,8 +1133,11 @@ int gfs2_truncatei(struct gfs2_inode *ip, u64 size) if (size > ip->i_di.di_size) error = do_grow(ip, size); - else + else if (size < ip->i_di.di_size) error = do_shrink(ip, size); + else + /* update time stamps */ + error = do_touch(ip, size); return error; } diff --git a/fs/gfs2/daemon.c b/fs/gfs2/daemon.c index 3548d9f31e0d..3731ab0771d5 100644 --- a/fs/gfs2/daemon.c +++ b/fs/gfs2/daemon.c @@ -35,30 +35,6 @@ The kthread functions used to start these daemons block and flush signals. */ /** - * gfs2_scand - Look for cached glocks and inodes to toss from memory - * @sdp: Pointer to GFS2 superblock - * - * One of these daemons runs, finding candidates to add to sd_reclaim_list. - * See gfs2_glockd() - */ - -int gfs2_scand(void *data) -{ - struct gfs2_sbd *sdp = data; - unsigned long t; - - while (!kthread_should_stop()) { - gfs2_scand_internal(sdp); - t = gfs2_tune_get(sdp, gt_scand_secs) * HZ; - if (freezing(current)) - refrigerator(); - schedule_timeout_interruptible(t); - } - - return 0; -} - -/** * gfs2_glockd - Reclaim unused glock structures * @sdp: Pointer to GFS2 superblock * diff --git a/fs/gfs2/daemon.h b/fs/gfs2/daemon.h index 801007120fb2..0de9b3557955 100644 --- a/fs/gfs2/daemon.h +++ b/fs/gfs2/daemon.h @@ -10,7 +10,6 @@ #ifndef __DAEMON_DOT_H__ #define __DAEMON_DOT_H__ -int gfs2_scand(void *data); int gfs2_glockd(void *data); int gfs2_recoverd(void *data); int gfs2_logd(void *data); diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 2beb2f401aa2..9949bb746a52 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -1043,6 +1043,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) error = gfs2_meta_inode_buffer(dip, &dibh); if (!gfs2_assert_withdraw(GFS2_SB(&dip->i_inode), !error)) { + gfs2_trans_add_bh(dip->i_gl, dibh, 1); dip->i_di.di_blocks++; gfs2_set_inode_blocks(&dip->i_inode); gfs2_dinode_out(dip, dibh->b_data); @@ -1501,7 +1502,7 @@ struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *name) inode = gfs2_inode_lookup(dir->i_sb, be16_to_cpu(dent->de_type), be64_to_cpu(dent->de_inum.no_addr), - be64_to_cpu(dent->de_inum.no_formal_ino)); + be64_to_cpu(dent->de_inum.no_formal_ino), 0); brelse(bh); return inode; } diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c index 1ab3e9d73886..aa8dbf303f6d 100644 --- a/fs/gfs2/eaops.c +++ b/fs/gfs2/eaops.c @@ -200,28 +200,28 @@ static int security_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er) return gfs2_ea_remove_i(ip, er); } -static struct gfs2_eattr_operations gfs2_user_eaops = { +static const struct gfs2_eattr_operations gfs2_user_eaops = { .eo_get = user_eo_get, .eo_set = user_eo_set, .eo_remove = user_eo_remove, .eo_name = "user", }; -struct gfs2_eattr_operations gfs2_system_eaops = { +const struct gfs2_eattr_operations gfs2_system_eaops = { .eo_get = system_eo_get, .eo_set = system_eo_set, .eo_remove = system_eo_remove, .eo_name = "system", }; -static struct gfs2_eattr_operations gfs2_security_eaops = { +static const struct gfs2_eattr_operations gfs2_security_eaops = { .eo_get = security_eo_get, .eo_set = security_eo_set, .eo_remove = security_eo_remove, .eo_name = "security", }; -struct gfs2_eattr_operations *gfs2_ea_ops[] = { +const struct gfs2_eattr_operations *gfs2_ea_ops[] = { NULL, &gfs2_user_eaops, &gfs2_system_eaops, diff --git a/fs/gfs2/eaops.h b/fs/gfs2/eaops.h index 508b4f7a2449..da2f7fbbb40d 100644 --- a/fs/gfs2/eaops.h +++ b/fs/gfs2/eaops.h @@ -22,9 +22,9 @@ struct gfs2_eattr_operations { unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name); -extern struct gfs2_eattr_operations gfs2_system_eaops; +extern const struct gfs2_eattr_operations gfs2_system_eaops; -extern struct gfs2_eattr_operations *gfs2_ea_ops[]; +extern const struct gfs2_eattr_operations *gfs2_ea_ops[]; #endif /* __EAOPS_DOT_H__ */ diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 3f0974e1afef..a37efe4aae6f 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -25,8 +25,10 @@ #include <asm/uaccess.h> #include <linux/seq_file.h> #include <linux/debugfs.h> -#include <linux/module.h> -#include <linux/kallsyms.h> +#include <linux/kthread.h> +#include <linux/freezer.h> +#include <linux/workqueue.h> +#include <linux/jiffies.h> #include "gfs2.h" #include "incore.h" @@ -48,7 +50,6 @@ struct glock_iter { int hash; /* hash bucket index */ struct gfs2_sbd *sdp; /* incore superblock */ struct gfs2_glock *gl; /* current glock struct */ - struct hlist_head *hb_list; /* current hash bucket ptr */ struct seq_file *seq; /* sequence file for debugfs */ char string[512]; /* scratch space */ }; @@ -59,8 +60,13 @@ static int gfs2_dump_lockstate(struct gfs2_sbd *sdp); static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl); static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh); static void gfs2_glock_drop_th(struct gfs2_glock *gl); +static void run_queue(struct gfs2_glock *gl); + static DECLARE_RWSEM(gfs2_umount_flush_sem); static struct dentry *gfs2_root; +static struct task_struct *scand_process; +static unsigned int scand_secs = 5; +static struct workqueue_struct *glock_workqueue; #define GFS2_GL_HASH_SHIFT 15 #define GFS2_GL_HASH_SIZE (1 << GFS2_GL_HASH_SHIFT) @@ -276,6 +282,18 @@ static struct gfs2_glock *gfs2_glock_find(const struct gfs2_sbd *sdp, return gl; } +static void glock_work_func(struct work_struct *work) +{ + struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_work.work); + + spin_lock(&gl->gl_spin); + if (test_and_clear_bit(GLF_PENDING_DEMOTE, &gl->gl_flags)) + set_bit(GLF_DEMOTE, &gl->gl_flags); + run_queue(gl); + spin_unlock(&gl->gl_spin); + gfs2_glock_put(gl); +} + /** * gfs2_glock_get() - Get a glock, or create one if one doesn't exist * @sdp: The GFS2 superblock @@ -315,6 +333,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, gl->gl_name = name; atomic_set(&gl->gl_ref, 1); gl->gl_state = LM_ST_UNLOCKED; + gl->gl_demote_state = LM_ST_EXCLUSIVE; gl->gl_hash = hash; gl->gl_owner_pid = 0; gl->gl_ip = 0; @@ -323,10 +342,12 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, gl->gl_req_bh = NULL; gl->gl_vn = 0; gl->gl_stamp = jiffies; + gl->gl_tchange = jiffies; gl->gl_object = NULL; gl->gl_sbd = sdp; gl->gl_aspace = NULL; lops_init_le(&gl->gl_le, &gfs2_glock_lops); + INIT_DELAYED_WORK(&gl->gl_work, glock_work_func); /* If this glock protects actual on-disk data or metadata blocks, create a VFS inode to manage the pages/buffers holding them. */ @@ -440,6 +461,8 @@ static void wait_on_holder(struct gfs2_holder *gh) static void gfs2_demote_wake(struct gfs2_glock *gl) { + BUG_ON(!spin_is_locked(&gl->gl_spin)); + gl->gl_demote_state = LM_ST_EXCLUSIVE; clear_bit(GLF_DEMOTE, &gl->gl_flags); smp_mb__after_clear_bit(); wake_up_bit(&gl->gl_flags, GLF_DEMOTE); @@ -545,12 +568,14 @@ static int rq_demote(struct gfs2_glock *gl) return 0; } set_bit(GLF_LOCK, &gl->gl_flags); - spin_unlock(&gl->gl_spin); if (gl->gl_demote_state == LM_ST_UNLOCKED || - gl->gl_state != LM_ST_EXCLUSIVE) + gl->gl_state != LM_ST_EXCLUSIVE) { + spin_unlock(&gl->gl_spin); gfs2_glock_drop_th(gl); - else + } else { + spin_unlock(&gl->gl_spin); gfs2_glock_xmote_th(gl, NULL); + } spin_lock(&gl->gl_spin); return 0; @@ -679,24 +704,25 @@ static void gfs2_glmutex_unlock(struct gfs2_glock *gl) * practise: LM_ST_SHARED and LM_ST_UNLOCKED */ -static void handle_callback(struct gfs2_glock *gl, unsigned int state, int remote) +static void handle_callback(struct gfs2_glock *gl, unsigned int state, + int remote, unsigned long delay) { + int bit = delay ? GLF_PENDING_DEMOTE : GLF_DEMOTE; + spin_lock(&gl->gl_spin); - if (test_and_set_bit(GLF_DEMOTE, &gl->gl_flags) == 0) { + set_bit(bit, &gl->gl_flags); + if (gl->gl_demote_state == LM_ST_EXCLUSIVE) { gl->gl_demote_state = state; gl->gl_demote_time = jiffies; if (remote && gl->gl_ops->go_type == LM_TYPE_IOPEN && gl->gl_object) { - struct inode *inode = igrab(gl->gl_object); + gfs2_glock_schedule_for_reclaim(gl); spin_unlock(&gl->gl_spin); - if (inode) { - d_prune_aliases(inode); - iput(inode); - } return; } - } else if (gl->gl_demote_state != LM_ST_UNLOCKED) { - gl->gl_demote_state = state; + } else if (gl->gl_demote_state != LM_ST_UNLOCKED && + gl->gl_demote_state != state) { + gl->gl_demote_state = LM_ST_UNLOCKED; } spin_unlock(&gl->gl_spin); } @@ -723,6 +749,7 @@ static void state_change(struct gfs2_glock *gl, unsigned int new_state) } gl->gl_state = new_state; + gl->gl_tchange = jiffies; } /** @@ -760,10 +787,20 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) if (!gh) { gl->gl_stamp = jiffies; - if (ret & LM_OUT_CANCELED) + if (ret & LM_OUT_CANCELED) { op_done = 0; - else + } else { + spin_lock(&gl->gl_spin); + if (gl->gl_state != gl->gl_demote_state) { + gl->gl_req_bh = NULL; + spin_unlock(&gl->gl_spin); + gfs2_glock_drop_th(gl); + gfs2_glock_put(gl); + return; + } gfs2_demote_wake(gl); + spin_unlock(&gl->gl_spin); + } } else { spin_lock(&gl->gl_spin); list_del_init(&gh->gh_list); @@ -799,7 +836,6 @@ out: gl->gl_req_gh = NULL; gl->gl_req_bh = NULL; clear_bit(GLF_LOCK, &gl->gl_flags); - run_queue(gl); spin_unlock(&gl->gl_spin); } @@ -817,7 +853,7 @@ out: * */ -void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh) +static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh) { struct gfs2_sbd *sdp = gl->gl_sbd; int flags = gh ? gh->gh_flags : 0; @@ -871,7 +907,6 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret) gfs2_assert_warn(sdp, !ret); state_change(gl, LM_ST_UNLOCKED); - gfs2_demote_wake(gl); if (glops->go_inval) glops->go_inval(gl, DIO_METADATA); @@ -884,10 +919,10 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret) } spin_lock(&gl->gl_spin); + gfs2_demote_wake(gl); gl->gl_req_gh = NULL; gl->gl_req_bh = NULL; clear_bit(GLF_LOCK, &gl->gl_flags); - run_queue(gl); spin_unlock(&gl->gl_spin); gfs2_glock_put(gl); @@ -1067,24 +1102,31 @@ static void add_to_queue(struct gfs2_holder *gh) if (test_and_set_bit(HIF_WAIT, &gh->gh_iflags)) BUG(); - existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner_pid); - if (existing) { - print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip); - printk(KERN_INFO "pid : %d\n", existing->gh_owner_pid); - printk(KERN_INFO "lock type : %d lock state : %d\n", - existing->gh_gl->gl_name.ln_type, existing->gh_gl->gl_state); - print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip); - printk(KERN_INFO "pid : %d\n", gh->gh_owner_pid); - printk(KERN_INFO "lock type : %d lock state : %d\n", - gl->gl_name.ln_type, gl->gl_state); - BUG(); - } - - existing = find_holder_by_owner(&gl->gl_waiters3, gh->gh_owner_pid); - if (existing) { - print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip); - print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip); - BUG(); + if (!(gh->gh_flags & GL_FLOCK)) { + existing = find_holder_by_owner(&gl->gl_holders, + gh->gh_owner_pid); + if (existing) { + print_symbol(KERN_WARNING "original: %s\n", + existing->gh_ip); + printk(KERN_INFO "pid : %d\n", existing->gh_owner_pid); + printk(KERN_INFO "lock type : %d lock state : %d\n", + existing->gh_gl->gl_name.ln_type, + existing->gh_gl->gl_state); + print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip); + printk(KERN_INFO "pid : %d\n", gh->gh_owner_pid); + printk(KERN_INFO "lock type : %d lock state : %d\n", + gl->gl_name.ln_type, gl->gl_state); + BUG(); + } + + existing = find_holder_by_owner(&gl->gl_waiters3, + gh->gh_owner_pid); + if (existing) { + print_symbol(KERN_WARNING "original: %s\n", + existing->gh_ip); + print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip); + BUG(); + } } if (gh->gh_flags & LM_FLAG_PRIORITY) @@ -1195,9 +1237,10 @@ void gfs2_glock_dq(struct gfs2_holder *gh) { struct gfs2_glock *gl = gh->gh_gl; const struct gfs2_glock_operations *glops = gl->gl_ops; + unsigned delay = 0; if (gh->gh_flags & GL_NOCACHE) - handle_callback(gl, LM_ST_UNLOCKED, 0); + handle_callback(gl, LM_ST_UNLOCKED, 0, 0); gfs2_glmutex_lock(gl); @@ -1215,8 +1258,14 @@ void gfs2_glock_dq(struct gfs2_holder *gh) } clear_bit(GLF_LOCK, &gl->gl_flags); - run_queue(gl); spin_unlock(&gl->gl_spin); + + gfs2_glock_hold(gl); + if (test_bit(GLF_PENDING_DEMOTE, &gl->gl_flags) && + !test_bit(GLF_DEMOTE, &gl->gl_flags)) + delay = gl->gl_ops->go_min_hold_time; + if (queue_delayed_work(glock_workqueue, &gl->gl_work, delay) == 0) + gfs2_glock_put(gl); } void gfs2_glock_dq_wait(struct gfs2_holder *gh) @@ -1443,18 +1492,21 @@ static void blocking_cb(struct gfs2_sbd *sdp, struct lm_lockname *name, unsigned int state) { struct gfs2_glock *gl; + unsigned long delay = 0; + unsigned long holdtime; + unsigned long now = jiffies; gl = gfs2_glock_find(sdp, name); if (!gl) return; - handle_callback(gl, state, 1); - - spin_lock(&gl->gl_spin); - run_queue(gl); - spin_unlock(&gl->gl_spin); + holdtime = gl->gl_tchange + gl->gl_ops->go_min_hold_time; + if (time_before(now, holdtime)) + delay = holdtime - now; - gfs2_glock_put(gl); + handle_callback(gl, state, 1, delay); + if (queue_delayed_work(glock_workqueue, &gl->gl_work, delay) == 0) + gfs2_glock_put(gl); } /** @@ -1495,7 +1547,8 @@ void gfs2_glock_cb(void *cb_data, unsigned int type, void *data) return; if (!gfs2_assert_warn(sdp, gl->gl_req_bh)) gl->gl_req_bh(gl, async->lc_ret); - gfs2_glock_put(gl); + if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) + gfs2_glock_put(gl); up_read(&gfs2_umount_flush_sem); return; } @@ -1588,7 +1641,7 @@ void gfs2_reclaim_glock(struct gfs2_sbd *sdp) if (gfs2_glmutex_trylock(gl)) { if (list_empty(&gl->gl_holders) && gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl)) - handle_callback(gl, LM_ST_UNLOCKED, 0); + handle_callback(gl, LM_ST_UNLOCKED, 0, 0); gfs2_glmutex_unlock(gl); } @@ -1617,7 +1670,7 @@ static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp, goto out; gl = list_entry(head->first, struct gfs2_glock, gl_list); while(1) { - if (gl->gl_sbd == sdp) { + if (!sdp || gl->gl_sbd == sdp) { gfs2_glock_hold(gl); read_unlock(gl_lock_addr(hash)); if (prev) @@ -1635,6 +1688,7 @@ out: read_unlock(gl_lock_addr(hash)); if (prev) gfs2_glock_put(prev); + cond_resched(); return has_entries; } @@ -1663,20 +1717,6 @@ out_schedule: } /** - * gfs2_scand_internal - Look for glocks and inodes to toss from memory - * @sdp: the filesystem - * - */ - -void gfs2_scand_internal(struct gfs2_sbd *sdp) -{ - unsigned int x; - - for (x = 0; x < GFS2_GL_HASH_SIZE; x++) - examine_bucket(scan_glock, sdp, x); -} - -/** * clear_glock - look at a glock and see if we can free it from glock cache * @gl: the glock to look at * @@ -1701,7 +1741,7 @@ static void clear_glock(struct gfs2_glock *gl) if (gfs2_glmutex_trylock(gl)) { if (list_empty(&gl->gl_holders) && gl->gl_state != LM_ST_UNLOCKED) - handle_callback(gl, LM_ST_UNLOCKED, 0); + handle_callback(gl, LM_ST_UNLOCKED, 0, 0); gfs2_glmutex_unlock(gl); } } @@ -1843,7 +1883,7 @@ static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl) spin_lock(&gl->gl_spin); - print_dbg(gi, "Glock 0x%p (%u, %llu)\n", gl, gl->gl_name.ln_type, + print_dbg(gi, "Glock 0x%p (%u, 0x%llx)\n", gl, gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number); print_dbg(gi, " gl_flags ="); for (x = 0; x < 32; x++) { @@ -1963,6 +2003,35 @@ static int gfs2_dump_lockstate(struct gfs2_sbd *sdp) return error; } +/** + * gfs2_scand - Look for cached glocks and inodes to toss from memory + * @sdp: Pointer to GFS2 superblock + * + * One of these daemons runs, finding candidates to add to sd_reclaim_list. + * See gfs2_glockd() + */ + +static int gfs2_scand(void *data) +{ + unsigned x; + unsigned delay; + + while (!kthread_should_stop()) { + for (x = 0; x < GFS2_GL_HASH_SIZE; x++) + examine_bucket(scan_glock, NULL, x); + if (freezing(current)) + refrigerator(); + delay = scand_secs; + if (delay < 1) + delay = 1; + schedule_timeout_interruptible(delay * HZ); + } + + return 0; +} + + + int __init gfs2_glock_init(void) { unsigned i; @@ -1974,52 +2043,69 @@ int __init gfs2_glock_init(void) rwlock_init(&gl_hash_locks[i]); } #endif + + scand_process = kthread_run(gfs2_scand, NULL, "gfs2_scand"); + if (IS_ERR(scand_process)) + return PTR_ERR(scand_process); + + glock_workqueue = create_workqueue("glock_workqueue"); + if (IS_ERR(glock_workqueue)) { + kthread_stop(scand_process); + return PTR_ERR(glock_workqueue); + } + return 0; } +void gfs2_glock_exit(void) +{ + destroy_workqueue(glock_workqueue); + kthread_stop(scand_process); +} + +module_param(scand_secs, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(scand_secs, "The number of seconds between scand runs"); + static int gfs2_glock_iter_next(struct glock_iter *gi) { + struct gfs2_glock *gl; + +restart: read_lock(gl_lock_addr(gi->hash)); - while (1) { - if (!gi->hb_list) { /* If we don't have a hash bucket yet */ - gi->hb_list = &gl_hash_table[gi->hash].hb_list; - if (hlist_empty(gi->hb_list)) { - read_unlock(gl_lock_addr(gi->hash)); - gi->hash++; - read_lock(gl_lock_addr(gi->hash)); - gi->hb_list = NULL; - if (gi->hash >= GFS2_GL_HASH_SIZE) { - read_unlock(gl_lock_addr(gi->hash)); - return 1; - } - else - continue; - } - if (!hlist_empty(gi->hb_list)) { - gi->gl = list_entry(gi->hb_list->first, - struct gfs2_glock, - gl_list); - } - } else { - if (gi->gl->gl_list.next == NULL) { - read_unlock(gl_lock_addr(gi->hash)); - gi->hash++; - read_lock(gl_lock_addr(gi->hash)); - gi->hb_list = NULL; - continue; - } - gi->gl = list_entry(gi->gl->gl_list.next, - struct gfs2_glock, gl_list); - } + gl = gi->gl; + if (gl) { + gi->gl = hlist_entry(gl->gl_list.next, + struct gfs2_glock, gl_list); if (gi->gl) - break; + gfs2_glock_hold(gi->gl); } read_unlock(gl_lock_addr(gi->hash)); + if (gl) + gfs2_glock_put(gl); + if (gl && gi->gl == NULL) + gi->hash++; + while(gi->gl == NULL) { + if (gi->hash >= GFS2_GL_HASH_SIZE) + return 1; + read_lock(gl_lock_addr(gi->hash)); + gi->gl = hlist_entry(gl_hash_table[gi->hash].hb_list.first, + struct gfs2_glock, gl_list); + if (gi->gl) + gfs2_glock_hold(gi->gl); + read_unlock(gl_lock_addr(gi->hash)); + gi->hash++; + } + + if (gi->sdp != gi->gl->gl_sbd) + goto restart; + return 0; } static void gfs2_glock_iter_free(struct glock_iter *gi) { + if (gi->gl) + gfs2_glock_put(gi->gl); kfree(gi); } @@ -2033,9 +2119,8 @@ static struct glock_iter *gfs2_glock_iter_init(struct gfs2_sbd *sdp) gi->sdp = sdp; gi->hash = 0; - gi->gl = NULL; - gi->hb_list = NULL; gi->seq = NULL; + gi->gl = NULL; memset(gi->string, 0, sizeof(gi->string)); if (gfs2_glock_iter_next(gi)) { @@ -2055,7 +2140,7 @@ static void *gfs2_glock_seq_start(struct seq_file *file, loff_t *pos) if (!gi) return NULL; - while (n--) { + while(n--) { if (gfs2_glock_iter_next(gi)) { gfs2_glock_iter_free(gi); return NULL; @@ -2082,7 +2167,9 @@ static void *gfs2_glock_seq_next(struct seq_file *file, void *iter_ptr, static void gfs2_glock_seq_stop(struct seq_file *file, void *iter_ptr) { - /* nothing for now */ + struct glock_iter *gi = iter_ptr; + if (gi) + gfs2_glock_iter_free(gi); } static int gfs2_glock_seq_show(struct seq_file *file, void *iter_ptr) @@ -2095,7 +2182,7 @@ static int gfs2_glock_seq_show(struct seq_file *file, void *iter_ptr) return 0; } -static struct seq_operations gfs2_glock_seq_ops = { +static const struct seq_operations gfs2_glock_seq_ops = { .start = gfs2_glock_seq_start, .next = gfs2_glock_seq_next, .stop = gfs2_glock_seq_stop, diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 7721ca3fff9e..b16f604eea9f 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -26,6 +26,7 @@ #define GL_SKIP 0x00000100 #define GL_ATIME 0x00000200 #define GL_NOCACHE 0x00000400 +#define GL_FLOCK 0x00000800 #define GL_NOCANCEL 0x00001000 #define GLR_TRYFAILED 13 @@ -132,11 +133,11 @@ void gfs2_glock_cb(void *cb_data, unsigned int type, void *data); void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl); void gfs2_reclaim_glock(struct gfs2_sbd *sdp); - -void gfs2_scand_internal(struct gfs2_sbd *sdp); void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait); int __init gfs2_glock_init(void); +void gfs2_glock_exit(void); + int gfs2_create_debugfs_file(struct gfs2_sbd *sdp); void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp); int gfs2_register_debugfs(void); diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 777ca46010e8..4670dcb2a877 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -41,7 +41,6 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl) struct list_head *head = &gl->gl_ail_list; struct gfs2_bufdata *bd; struct buffer_head *bh; - u64 blkno; int error; blocks = atomic_read(&gl->gl_ail_count); @@ -57,19 +56,12 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl) bd = list_entry(head->next, struct gfs2_bufdata, bd_ail_gl_list); bh = bd->bd_bh; - blkno = bh->b_blocknr; + gfs2_remove_from_ail(NULL, bd); + bd->bd_bh = NULL; + bh->b_private = NULL; + bd->bd_blkno = bh->b_blocknr; gfs2_assert_withdraw(sdp, !buffer_busy(bh)); - - bd->bd_ail = NULL; - list_del(&bd->bd_ail_st_list); - list_del(&bd->bd_ail_gl_list); - atomic_dec(&gl->gl_ail_count); - brelse(bh); - gfs2_log_unlock(sdp); - - gfs2_trans_add_revoke(sdp, blkno); - - gfs2_log_lock(sdp); + gfs2_trans_add_revoke(sdp, bd); } gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count)); gfs2_log_unlock(sdp); @@ -156,9 +148,11 @@ static void inode_go_sync(struct gfs2_glock *gl) ip = NULL; if (test_bit(GLF_DIRTY, &gl->gl_flags)) { - if (ip) + if (ip && !gfs2_is_jdata(ip)) filemap_fdatawrite(ip->i_inode.i_mapping); gfs2_log_flush(gl->gl_sbd, gl); + if (ip && gfs2_is_jdata(ip)) + filemap_fdatawrite(ip->i_inode.i_mapping); gfs2_meta_sync(gl); if (ip) { struct address_space *mapping = ip->i_inode.i_mapping; @@ -452,6 +446,7 @@ const struct gfs2_glock_operations gfs2_inode_glops = { .go_lock = inode_go_lock, .go_unlock = inode_go_unlock, .go_type = LM_TYPE_INODE, + .go_min_hold_time = HZ / 10, }; const struct gfs2_glock_operations gfs2_rgrp_glops = { @@ -462,6 +457,7 @@ const struct gfs2_glock_operations gfs2_rgrp_glops = { .go_lock = rgrp_go_lock, .go_unlock = rgrp_go_unlock, .go_type = LM_TYPE_RGRP, + .go_min_hold_time = HZ / 10, }; const struct gfs2_glock_operations gfs2_trans_glops = { diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 170ba93829c0..eaddfb5a8e6f 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -11,6 +11,7 @@ #define __INCORE_DOT_H__ #include <linux/fs.h> +#include <linux/workqueue.h> #define DIO_WAIT 0x00000010 #define DIO_METADATA 0x00000020 @@ -113,7 +114,13 @@ struct gfs2_bufdata { struct buffer_head *bd_bh; struct gfs2_glock *bd_gl; - struct list_head bd_list_tr; + union { + struct list_head list_tr; + u64 blkno; + } u; +#define bd_list_tr u.list_tr +#define bd_blkno u.blkno + struct gfs2_log_element bd_le; struct gfs2_ail *bd_ail; @@ -130,6 +137,7 @@ struct gfs2_glock_operations { int (*go_lock) (struct gfs2_holder *gh); void (*go_unlock) (struct gfs2_holder *gh); const int go_type; + const unsigned long go_min_hold_time; }; enum { @@ -161,6 +169,7 @@ enum { GLF_LOCK = 1, GLF_STICKY = 2, GLF_DEMOTE = 3, + GLF_PENDING_DEMOTE = 4, GLF_DIRTY = 5, }; @@ -193,6 +202,7 @@ struct gfs2_glock { u64 gl_vn; unsigned long gl_stamp; + unsigned long gl_tchange; void *gl_object; struct list_head gl_reclaim; @@ -203,6 +213,7 @@ struct gfs2_glock { struct gfs2_log_element gl_le; struct list_head gl_ail_list; atomic_t gl_ail_count; + struct delayed_work gl_work; }; struct gfs2_alloc { @@ -293,11 +304,6 @@ struct gfs2_file { struct gfs2_holder f_fl_gh; }; -struct gfs2_revoke { - struct gfs2_log_element rv_le; - u64 rv_blkno; -}; - struct gfs2_revoke_replay { struct list_head rr_list; u64 rr_blkno; @@ -335,12 +341,6 @@ struct gfs2_quota_data { unsigned long qd_last_touched; }; -struct gfs2_log_buf { - struct list_head lb_list; - struct buffer_head *lb_bh; - struct buffer_head *lb_real; -}; - struct gfs2_trans { unsigned long tr_ip; @@ -429,7 +429,6 @@ struct gfs2_tune { unsigned int gt_log_flush_secs; unsigned int gt_jindex_refresh_secs; /* Check for new journal index */ - unsigned int gt_scand_secs; unsigned int gt_recoverd_secs; unsigned int gt_logd_secs; unsigned int gt_quotad_secs; @@ -574,7 +573,6 @@ struct gfs2_sbd { /* Daemon stuff */ - struct task_struct *sd_scand_process; struct task_struct *sd_recoverd_process; struct task_struct *sd_logd_process; struct task_struct *sd_quotad_process; @@ -609,13 +607,13 @@ struct gfs2_sbd { unsigned int sd_log_num_revoke; unsigned int sd_log_num_rg; unsigned int sd_log_num_databuf; - unsigned int sd_log_num_jdata; struct list_head sd_log_le_gl; struct list_head sd_log_le_buf; struct list_head sd_log_le_revoke; struct list_head sd_log_le_rg; struct list_head sd_log_le_databuf; + struct list_head sd_log_le_ordered; unsigned int sd_log_blks_free; struct mutex sd_log_reserve_mutex; @@ -627,7 +625,8 @@ struct gfs2_sbd { unsigned long sd_log_flush_time; struct rw_semaphore sd_log_flush_lock; - struct list_head sd_log_flush_list; + atomic_t sd_log_in_flight; + wait_queue_head_t sd_log_flush_wait; unsigned int sd_log_flush_head; u64 sd_log_flush_wrapped; diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 34f7bcdea1e9..5f6dc32946cd 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -77,6 +77,49 @@ static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr) return iget5_locked(sb, hash, iget_test, iget_set, &no_addr); } +struct gfs2_skip_data { + u64 no_addr; + int skipped; +}; + +static int iget_skip_test(struct inode *inode, void *opaque) +{ + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_skip_data *data = opaque; + + if (ip->i_no_addr == data->no_addr && inode->i_private != NULL){ + if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)){ + data->skipped = 1; + return 0; + } + return 1; + } + return 0; +} + +static int iget_skip_set(struct inode *inode, void *opaque) +{ + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_skip_data *data = opaque; + + if (data->skipped) + return 1; + inode->i_ino = (unsigned long)(data->no_addr); + ip->i_no_addr = data->no_addr; + return 0; +} + +static struct inode *gfs2_iget_skip(struct super_block *sb, + u64 no_addr) +{ + struct gfs2_skip_data data; + unsigned long hash = (unsigned long)no_addr; + + data.no_addr = no_addr; + data.skipped = 0; + return iget5_locked(sb, hash, iget_skip_test, iget_skip_set, &data); +} + /** * GFS2 lookup code fills in vfs inode contents based on info obtained * from directory entry inside gfs2_inode_lookup(). This has caused issues @@ -112,6 +155,7 @@ void gfs2_set_iop(struct inode *inode) * @sb: The super block * @no_addr: The inode number * @type: The type of the inode + * @skip_freeing: set this not return an inode if it is currently being freed. * * Returns: A VFS inode, or an error */ @@ -119,13 +163,19 @@ void gfs2_set_iop(struct inode *inode) struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, u64 no_addr, - u64 no_formal_ino) + u64 no_formal_ino, int skip_freeing) { - struct inode *inode = gfs2_iget(sb, no_addr); - struct gfs2_inode *ip = GFS2_I(inode); + struct inode *inode; + struct gfs2_inode *ip; struct gfs2_glock *io_gl; int error; + if (skip_freeing) + inode = gfs2_iget_skip(sb, no_addr); + else + inode = gfs2_iget(sb, no_addr); + ip = GFS2_I(inode); + if (!inode) return ERR_PTR(-ENOBUFS); @@ -244,6 +294,11 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) return 0; } +static void gfs2_inode_bh(struct gfs2_inode *ip, struct buffer_head *bh) +{ + ip->i_cache[0] = bh; +} + /** * gfs2_inode_refresh - Refresh the incore copy of the dinode * @ip: The GFS2 inode @@ -688,7 +743,7 @@ out: static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, const struct gfs2_inum_host *inum, unsigned int mode, unsigned int uid, unsigned int gid, - const u64 *generation, dev_t dev) + const u64 *generation, dev_t dev, struct buffer_head **bhp) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_dinode *di; @@ -743,13 +798,15 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, di->di_mtime_nsec = cpu_to_be32(tv.tv_nsec); di->di_ctime_nsec = cpu_to_be32(tv.tv_nsec); memset(&di->di_reserved, 0, sizeof(di->di_reserved)); + + set_buffer_uptodate(dibh); - brelse(dibh); + *bhp = dibh; } static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, unsigned int mode, const struct gfs2_inum_host *inum, - const u64 *generation, dev_t dev) + const u64 *generation, dev_t dev, struct buffer_head **bhp) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); unsigned int uid, gid; @@ -770,7 +827,7 @@ static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, if (error) goto out_quota; - init_dinode(dip, gl, inum, mode, uid, gid, generation, dev); + init_dinode(dip, gl, inum, mode, uid, gid, generation, dev, bhp); gfs2_quota_change(dip, +1, uid, gid); gfs2_trans_end(sdp); @@ -909,6 +966,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 }; int error; u64 generation; + struct buffer_head *bh=NULL; if (!name->len || name->len > GFS2_FNAMESIZE) return ERR_PTR(-ENAMETOOLONG); @@ -935,16 +993,18 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, if (error) goto fail_gunlock; - error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev); + error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev, &bh); if (error) goto fail_gunlock2; inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), inum.no_addr, - inum.no_formal_ino); + inum.no_formal_ino, 0); if (IS_ERR(inode)) goto fail_gunlock2; + gfs2_inode_bh(GFS2_I(inode), bh); + error = gfs2_inode_refresh(GFS2_I(inode)); if (error) goto fail_gunlock2; diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 4517ac82c01c..351ac87ab384 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -49,7 +49,8 @@ static inline void gfs2_inum_out(const struct gfs2_inode *ip, void gfs2_inode_attr_in(struct gfs2_inode *ip); void gfs2_set_iop(struct inode *inode); struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, - u64 no_addr, u64 no_formal_ino); + u64 no_addr, u64 no_formal_ino, + int skip_freeing); struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr); int gfs2_inode_refresh(struct gfs2_inode *ip); diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h index 24d70f73b651..9e8265d28377 100644 --- a/fs/gfs2/locking/dlm/lock_dlm.h +++ b/fs/gfs2/locking/dlm/lock_dlm.h @@ -13,7 +13,6 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/spinlock.h> -#include <linux/module.h> #include <linux/types.h> #include <linux/string.h> #include <linux/list.h> diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c index fba1f1d87e4f..1f7b038530b4 100644 --- a/fs/gfs2/locking/dlm/plock.c +++ b/fs/gfs2/locking/dlm/plock.c @@ -346,15 +346,16 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count, static unsigned int dev_poll(struct file *file, poll_table *wait) { + unsigned int mask = 0; + poll_wait(file, &send_wq, wait); spin_lock(&ops_lock); - if (!list_empty(&send_list)) { - spin_unlock(&ops_lock); - return POLLIN | POLLRDNORM; - } + if (!list_empty(&send_list)) + mask = POLLIN | POLLRDNORM; spin_unlock(&ops_lock); - return 0; + + return mask; } static const struct file_operations dev_fops = { diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c index d9fe3ca40e18..ae9e6a25fe2b 100644 --- a/fs/gfs2/locking/dlm/sysfs.c +++ b/fs/gfs2/locking/dlm/sysfs.c @@ -190,7 +190,6 @@ static struct kobj_type gdlm_ktype = { }; static struct kset gdlm_kset = { - .kobj = {.name = "lock_dlm",}, .ktype = &gdlm_ktype, }; @@ -224,6 +223,7 @@ int gdlm_sysfs_init(void) { int error; + kobject_set_name(&gdlm_kset.kobj, "lock_dlm"); kobj_set_kset_s(&gdlm_kset, kernel_subsys); error = kset_register(&gdlm_kset); if (error) diff --git a/fs/gfs2/locking/dlm/thread.c b/fs/gfs2/locking/dlm/thread.c index 1aca51e45092..bd938f06481d 100644 --- a/fs/gfs2/locking/dlm/thread.c +++ b/fs/gfs2/locking/dlm/thread.c @@ -268,20 +268,16 @@ static inline int check_drop(struct gdlm_ls *ls) return 0; } -static int gdlm_thread(void *data) +static int gdlm_thread(void *data, int blist) { struct gdlm_ls *ls = (struct gdlm_ls *) data; struct gdlm_lock *lp = NULL; - int blist = 0; uint8_t complete, blocking, submit, drop; DECLARE_WAITQUEUE(wait, current); /* Only thread1 is allowed to do blocking callbacks since gfs may wait for a completion callback within a blocking cb. */ - if (current == ls->thread1) - blist = 1; - while (!kthread_should_stop()) { set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&ls->thread_wait, &wait); @@ -333,12 +329,22 @@ static int gdlm_thread(void *data) return 0; } +static int gdlm_thread1(void *data) +{ + return gdlm_thread(data, 1); +} + +static int gdlm_thread2(void *data) +{ + return gdlm_thread(data, 0); +} + int gdlm_init_threads(struct gdlm_ls *ls) { struct task_struct *p; int error; - p = kthread_run(gdlm_thread, ls, "lock_dlm1"); + p = kthread_run(gdlm_thread1, ls, "lock_dlm1"); error = IS_ERR(p); if (error) { log_error("can't start lock_dlm1 thread %d", error); @@ -346,7 +352,7 @@ int gdlm_init_threads(struct gdlm_ls *ls) } ls->thread1 = p; - p = kthread_run(gdlm_thread, ls, "lock_dlm2"); + p = kthread_run(gdlm_thread2, ls, "lock_dlm2"); error = IS_ERR(p); if (error) { log_error("can't start lock_dlm2 thread %d", error); diff --git a/fs/gfs2/locking/nolock/main.c b/fs/gfs2/locking/nolock/main.c index 0d149c8c493a..d3b8ce6fbbe3 100644 --- a/fs/gfs2/locking/nolock/main.c +++ b/fs/gfs2/locking/nolock/main.c @@ -9,7 +9,6 @@ #include <linux/module.h> #include <linux/slab.h> -#include <linux/module.h> #include <linux/init.h> #include <linux/types.h> #include <linux/fs.h> diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index f49a12e24086..7df702473252 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -60,6 +60,26 @@ unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, } /** + * gfs2_remove_from_ail - Remove an entry from the ail lists, updating counters + * @mapping: The associated mapping (maybe NULL) + * @bd: The gfs2_bufdata to remove + * + * The log lock _must_ be held when calling this function + * + */ + +void gfs2_remove_from_ail(struct address_space *mapping, struct gfs2_bufdata *bd) +{ + bd->bd_ail = NULL; + list_del_init(&bd->bd_ail_st_list); + list_del_init(&bd->bd_ail_gl_list); + atomic_dec(&bd->bd_gl->gl_ail_count); + if (mapping) + gfs2_meta_cache_flush(GFS2_I(mapping->host)); + brelse(bd->bd_bh); +} + +/** * gfs2_ail1_start_one - Start I/O on a part of the AIL * @sdp: the filesystem * @tr: the part of the AIL @@ -83,17 +103,9 @@ static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) gfs2_assert(sdp, bd->bd_ail == ai); - if (!bh){ - list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); - continue; - } - if (!buffer_busy(bh)) { - if (!buffer_uptodate(bh)) { - gfs2_log_unlock(sdp); + if (!buffer_uptodate(bh)) gfs2_io_error_bh(sdp, bh); - gfs2_log_lock(sdp); - } list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); continue; } @@ -103,9 +115,16 @@ static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list); + get_bh(bh); gfs2_log_unlock(sdp); - wait_on_buffer(bh); - ll_rw_block(WRITE, 1, &bh); + lock_buffer(bh); + if (test_clear_buffer_dirty(bh)) { + bh->b_end_io = end_buffer_write_sync; + submit_bh(WRITE, bh); + } else { + unlock_buffer(bh); + brelse(bh); + } gfs2_log_lock(sdp); retry = 1; @@ -130,11 +149,6 @@ static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int fl bd_ail_st_list) { bh = bd->bd_bh; - if (!bh){ - list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); - continue; - } - gfs2_assert(sdp, bd->bd_ail == ai); if (buffer_busy(bh)) { @@ -155,13 +169,14 @@ static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int fl static void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags) { - struct list_head *head = &sdp->sd_ail1_list; + struct list_head *head; u64 sync_gen; struct list_head *first; struct gfs2_ail *first_ai, *ai, *tmp; int done = 0; gfs2_log_lock(sdp); + head = &sdp->sd_ail1_list; if (list_empty(head)) { gfs2_log_unlock(sdp); return; @@ -233,11 +248,7 @@ static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) bd = list_entry(head->prev, struct gfs2_bufdata, bd_ail_st_list); gfs2_assert(sdp, bd->bd_ail == ai); - bd->bd_ail = NULL; - list_del(&bd->bd_ail_st_list); - list_del(&bd->bd_ail_gl_list); - atomic_dec(&bd->bd_gl->gl_ail_count); - brelse(bd->bd_bh); + gfs2_remove_from_ail(bd->bd_bh->b_page->mapping, bd); } } @@ -439,10 +450,10 @@ static unsigned int current_tail(struct gfs2_sbd *sdp) return tail; } -static inline void log_incr_head(struct gfs2_sbd *sdp) +void gfs2_log_incr_head(struct gfs2_sbd *sdp) { if (sdp->sd_log_flush_head == sdp->sd_log_tail) - gfs2_assert_withdraw(sdp, sdp->sd_log_flush_head == sdp->sd_log_head); + BUG_ON(sdp->sd_log_flush_head != sdp->sd_log_head); if (++sdp->sd_log_flush_head == sdp->sd_jdesc->jd_blocks) { sdp->sd_log_flush_head = 0; @@ -451,6 +462,23 @@ static inline void log_incr_head(struct gfs2_sbd *sdp) } /** + * gfs2_log_write_endio - End of I/O for a log buffer + * @bh: The buffer head + * @uptodate: I/O Status + * + */ + +static void gfs2_log_write_endio(struct buffer_head *bh, int uptodate) +{ + struct gfs2_sbd *sdp = bh->b_private; + bh->b_private = NULL; + + end_buffer_write_sync(bh, uptodate); + if (atomic_dec_and_test(&sdp->sd_log_in_flight)) + wake_up(&sdp->sd_log_flush_wait); +} + +/** * gfs2_log_get_buf - Get and initialize a buffer to use for log control data * @sdp: The GFS2 superblock * @@ -460,25 +488,43 @@ static inline void log_incr_head(struct gfs2_sbd *sdp) struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp) { u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head); - struct gfs2_log_buf *lb; struct buffer_head *bh; - lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_NOFS | __GFP_NOFAIL); - list_add(&lb->lb_list, &sdp->sd_log_flush_list); - - bh = lb->lb_bh = sb_getblk(sdp->sd_vfs, blkno); + bh = sb_getblk(sdp->sd_vfs, blkno); lock_buffer(bh); memset(bh->b_data, 0, bh->b_size); set_buffer_uptodate(bh); clear_buffer_dirty(bh); - unlock_buffer(bh); - - log_incr_head(sdp); + gfs2_log_incr_head(sdp); + atomic_inc(&sdp->sd_log_in_flight); + bh->b_private = sdp; + bh->b_end_io = gfs2_log_write_endio; return bh; } /** + * gfs2_fake_write_endio - + * @bh: The buffer head + * @uptodate: The I/O Status + * + */ + +static void gfs2_fake_write_endio(struct buffer_head *bh, int uptodate) +{ + struct buffer_head *real_bh = bh->b_private; + struct gfs2_bufdata *bd = real_bh->b_private; + struct gfs2_sbd *sdp = bd->bd_gl->gl_sbd; + + end_buffer_write_sync(bh, uptodate); + free_buffer_head(bh); + unlock_buffer(real_bh); + brelse(real_bh); + if (atomic_dec_and_test(&sdp->sd_log_in_flight)) + wake_up(&sdp->sd_log_flush_wait); +} + +/** * gfs2_log_fake_buf - Build a fake buffer head to write metadata buffer to log * @sdp: the filesystem * @data: the data the buffer_head should point to @@ -490,22 +536,20 @@ struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp, struct buffer_head *real) { u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head); - struct gfs2_log_buf *lb; struct buffer_head *bh; - lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_NOFS | __GFP_NOFAIL); - list_add(&lb->lb_list, &sdp->sd_log_flush_list); - lb->lb_real = real; - - bh = lb->lb_bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL); + bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL); atomic_set(&bh->b_count, 1); - bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate); + bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate) | (1 << BH_Lock); set_bh_page(bh, real->b_page, bh_offset(real)); bh->b_blocknr = blkno; bh->b_size = sdp->sd_sb.sb_bsize; bh->b_bdev = sdp->sd_vfs->s_bdev; + bh->b_private = real; + bh->b_end_io = gfs2_fake_write_endio; - log_incr_head(sdp); + gfs2_log_incr_head(sdp); + atomic_inc(&sdp->sd_log_in_flight); return bh; } @@ -572,45 +616,75 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull) gfs2_assert_withdraw(sdp, !pull); sdp->sd_log_idle = (tail == sdp->sd_log_flush_head); - log_incr_head(sdp); + gfs2_log_incr_head(sdp); } static void log_flush_commit(struct gfs2_sbd *sdp) { - struct list_head *head = &sdp->sd_log_flush_list; - struct gfs2_log_buf *lb; - struct buffer_head *bh; - int flushcount = 0; + DEFINE_WAIT(wait); + + if (atomic_read(&sdp->sd_log_in_flight)) { + do { + prepare_to_wait(&sdp->sd_log_flush_wait, &wait, + TASK_UNINTERRUPTIBLE); + if (atomic_read(&sdp->sd_log_in_flight)) + io_schedule(); + } while(atomic_read(&sdp->sd_log_in_flight)); + finish_wait(&sdp->sd_log_flush_wait, &wait); + } - while (!list_empty(head)) { - lb = list_entry(head->next, struct gfs2_log_buf, lb_list); - list_del(&lb->lb_list); - bh = lb->lb_bh; + log_write_header(sdp, 0, 0); +} - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) - gfs2_io_error_bh(sdp, bh); - if (lb->lb_real) { - while (atomic_read(&bh->b_count) != 1) /* Grrrr... */ - schedule(); - free_buffer_head(bh); - } else +static void gfs2_ordered_write(struct gfs2_sbd *sdp) +{ + struct gfs2_bufdata *bd; + struct buffer_head *bh; + LIST_HEAD(written); + + gfs2_log_lock(sdp); + while (!list_empty(&sdp->sd_log_le_ordered)) { + bd = list_entry(sdp->sd_log_le_ordered.next, struct gfs2_bufdata, bd_le.le_list); + list_move(&bd->bd_le.le_list, &written); + bh = bd->bd_bh; + if (!buffer_dirty(bh)) + continue; + get_bh(bh); + gfs2_log_unlock(sdp); + lock_buffer(bh); + if (test_clear_buffer_dirty(bh)) { + bh->b_end_io = end_buffer_write_sync; + submit_bh(WRITE, bh); + } else { + unlock_buffer(bh); brelse(bh); - kfree(lb); - flushcount++; + } + gfs2_log_lock(sdp); } + list_splice(&written, &sdp->sd_log_le_ordered); + gfs2_log_unlock(sdp); +} - /* If nothing was journaled, the header is unplanned and unwanted. */ - if (flushcount) { - log_write_header(sdp, 0, 0); - } else { - unsigned int tail; - tail = current_tail(sdp); +static void gfs2_ordered_wait(struct gfs2_sbd *sdp) +{ + struct gfs2_bufdata *bd; + struct buffer_head *bh; - gfs2_ail1_empty(sdp, 0); - if (sdp->sd_log_tail != tail) - log_pull_tail(sdp, tail); + gfs2_log_lock(sdp); + while (!list_empty(&sdp->sd_log_le_ordered)) { + bd = list_entry(sdp->sd_log_le_ordered.prev, struct gfs2_bufdata, bd_le.le_list); + bh = bd->bd_bh; + if (buffer_locked(bh)) { + get_bh(bh); + gfs2_log_unlock(sdp); + wait_on_buffer(bh); + brelse(bh); + gfs2_log_lock(sdp); + continue; + } + list_del_init(&bd->bd_le.le_list); } + gfs2_log_unlock(sdp); } /** @@ -640,10 +714,16 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) INIT_LIST_HEAD(&ai->ai_ail1_list); INIT_LIST_HEAD(&ai->ai_ail2_list); - gfs2_assert_withdraw(sdp, - sdp->sd_log_num_buf + sdp->sd_log_num_jdata == - sdp->sd_log_commited_buf + - sdp->sd_log_commited_databuf); + if (sdp->sd_log_num_buf != sdp->sd_log_commited_buf) { + printk(KERN_INFO "GFS2: log buf %u %u\n", sdp->sd_log_num_buf, + sdp->sd_log_commited_buf); + gfs2_assert_withdraw(sdp, 0); + } + if (sdp->sd_log_num_databuf != sdp->sd_log_commited_databuf) { + printk(KERN_INFO "GFS2: log databuf %u %u\n", + sdp->sd_log_num_databuf, sdp->sd_log_commited_databuf); + gfs2_assert_withdraw(sdp, 0); + } gfs2_assert_withdraw(sdp, sdp->sd_log_num_revoke == sdp->sd_log_commited_revoke); @@ -651,8 +731,11 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) sdp->sd_log_flush_wrapped = 0; ai->ai_first = sdp->sd_log_flush_head; + gfs2_ordered_write(sdp); lops_before_commit(sdp); - if (!list_empty(&sdp->sd_log_flush_list)) + gfs2_ordered_wait(sdp); + + if (sdp->sd_log_head != sdp->sd_log_flush_head) log_flush_commit(sdp); else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){ gfs2_log_lock(sdp); @@ -744,7 +827,6 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp) gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved); gfs2_assert_withdraw(sdp, !sdp->sd_log_num_gl); gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf); - gfs2_assert_withdraw(sdp, !sdp->sd_log_num_jdata); gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg); gfs2_assert_withdraw(sdp, !sdp->sd_log_num_databuf); diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h index 8e7aa0f29109..dae282400627 100644 --- a/fs/gfs2/log.h +++ b/fs/gfs2/log.h @@ -52,12 +52,14 @@ int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags); int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks); void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks); +void gfs2_log_incr_head(struct gfs2_sbd *sdp); struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp); struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp, struct buffer_head *real); void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl); void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans); +void gfs2_remove_from_ail(struct address_space *mapping, struct gfs2_bufdata *bd); void gfs2_log_shutdown(struct gfs2_sbd *sdp); void gfs2_meta_syncfs(struct gfs2_sbd *sdp); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 3b395c41b2f3..6c27cea761c6 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -27,7 +27,104 @@ #include "trans.h" #include "util.h" -static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) +/** + * gfs2_pin - Pin a buffer in memory + * @sdp: The superblock + * @bh: The buffer to be pinned + * + * The log lock must be held when calling this function + */ +static void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh) +{ + struct gfs2_bufdata *bd; + + gfs2_assert_withdraw(sdp, test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)); + + clear_buffer_dirty(bh); + if (test_set_buffer_pinned(bh)) + gfs2_assert_withdraw(sdp, 0); + if (!buffer_uptodate(bh)) + gfs2_io_error_bh(sdp, bh); + bd = bh->b_private; + /* If this buffer is in the AIL and it has already been written + * to in-place disk block, remove it from the AIL. + */ + if (bd->bd_ail) + list_move(&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list); + get_bh(bh); +} + +/** + * gfs2_unpin - Unpin a buffer + * @sdp: the filesystem the buffer belongs to + * @bh: The buffer to unpin + * @ai: + * + */ + +static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh, + struct gfs2_ail *ai) +{ + struct gfs2_bufdata *bd = bh->b_private; + + gfs2_assert_withdraw(sdp, buffer_uptodate(bh)); + + if (!buffer_pinned(bh)) + gfs2_assert_withdraw(sdp, 0); + + lock_buffer(bh); + mark_buffer_dirty(bh); + clear_buffer_pinned(bh); + + gfs2_log_lock(sdp); + if (bd->bd_ail) { + list_del(&bd->bd_ail_st_list); + brelse(bh); + } else { + struct gfs2_glock *gl = bd->bd_gl; + list_add(&bd->bd_ail_gl_list, &gl->gl_ail_list); + atomic_inc(&gl->gl_ail_count); + } + bd->bd_ail = ai; + list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list); + gfs2_log_unlock(sdp); + unlock_buffer(bh); +} + + +static inline struct gfs2_log_descriptor *bh_log_desc(struct buffer_head *bh) +{ + return (struct gfs2_log_descriptor *)bh->b_data; +} + +static inline __be64 *bh_log_ptr(struct buffer_head *bh) +{ + struct gfs2_log_descriptor *ld = bh_log_desc(bh); + return (__force __be64 *)(ld + 1); +} + +static inline __be64 *bh_ptr_end(struct buffer_head *bh) +{ + return (__force __be64 *)(bh->b_data + bh->b_size); +} + + +static struct buffer_head *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type) +{ + struct buffer_head *bh = gfs2_log_get_buf(sdp); + struct gfs2_log_descriptor *ld = bh_log_desc(bh); + ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC); + ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD); + ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD); + ld->ld_type = cpu_to_be32(ld_type); + ld->ld_length = 0; + ld->ld_data1 = 0; + ld->ld_data2 = 0; + memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved)); + return bh; +} + +static void __glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) { struct gfs2_glock *gl; struct gfs2_trans *tr = current->journal_info; @@ -38,15 +135,19 @@ static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl))) return; - gfs2_log_lock(sdp); - if (!list_empty(&le->le_list)){ - gfs2_log_unlock(sdp); + if (!list_empty(&le->le_list)) return; - } + gfs2_glock_hold(gl); set_bit(GLF_DIRTY, &gl->gl_flags); sdp->sd_log_num_gl++; list_add(&le->le_list, &sdp->sd_log_le_gl); +} + +static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) +{ + gfs2_log_lock(sdp); + __glock_lo_add(sdp, le); gfs2_log_unlock(sdp); } @@ -71,30 +172,25 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le); struct gfs2_trans *tr; + lock_buffer(bd->bd_bh); gfs2_log_lock(sdp); - if (!list_empty(&bd->bd_list_tr)) { - gfs2_log_unlock(sdp); - return; - } + if (!list_empty(&bd->bd_list_tr)) + goto out; tr = current->journal_info; tr->tr_touched = 1; tr->tr_num_buf++; list_add(&bd->bd_list_tr, &tr->tr_list_buf); - gfs2_log_unlock(sdp); - if (!list_empty(&le->le_list)) - return; - - gfs2_trans_add_gl(bd->bd_gl); - + goto out; + __glock_lo_add(sdp, &bd->bd_gl->gl_le); gfs2_meta_check(sdp, bd->bd_bh); gfs2_pin(sdp, bd->bd_bh); - gfs2_log_lock(sdp); sdp->sd_log_num_buf++; list_add(&le->le_list, &sdp->sd_log_le_buf); - gfs2_log_unlock(sdp); - tr->tr_num_buf_new++; +out: + gfs2_log_unlock(sdp); + unlock_buffer(bd->bd_bh); } static void buf_lo_incore_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) @@ -117,8 +213,7 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp) struct buffer_head *bh; struct gfs2_log_descriptor *ld; struct gfs2_bufdata *bd1 = NULL, *bd2; - unsigned int total = sdp->sd_log_num_buf; - unsigned int offset = BUF_OFFSET; + unsigned int total; unsigned int limit; unsigned int num; unsigned n; @@ -127,22 +222,20 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp) limit = buf_limit(sdp); /* for 4k blocks, limit = 503 */ + gfs2_log_lock(sdp); + total = sdp->sd_log_num_buf; bd1 = bd2 = list_prepare_entry(bd1, &sdp->sd_log_le_buf, bd_le.le_list); while(total) { num = total; if (total > limit) num = limit; - bh = gfs2_log_get_buf(sdp); - ld = (struct gfs2_log_descriptor *)bh->b_data; - ptr = (__be64 *)(bh->b_data + offset); - ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC); - ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD); - ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD); - ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_METADATA); + gfs2_log_unlock(sdp); + bh = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_METADATA); + gfs2_log_lock(sdp); + ld = bh_log_desc(bh); + ptr = bh_log_ptr(bh); ld->ld_length = cpu_to_be32(num + 1); ld->ld_data1 = cpu_to_be32(num); - ld->ld_data2 = cpu_to_be32(0); - memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved)); n = 0; list_for_each_entry_continue(bd1, &sdp->sd_log_le_buf, @@ -152,21 +245,27 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp) break; } - set_buffer_dirty(bh); - ll_rw_block(WRITE, 1, &bh); + gfs2_log_unlock(sdp); + submit_bh(WRITE, bh); + gfs2_log_lock(sdp); n = 0; list_for_each_entry_continue(bd2, &sdp->sd_log_le_buf, bd_le.le_list) { + get_bh(bd2->bd_bh); + gfs2_log_unlock(sdp); + lock_buffer(bd2->bd_bh); bh = gfs2_log_fake_buf(sdp, bd2->bd_bh); - set_buffer_dirty(bh); - ll_rw_block(WRITE, 1, &bh); + submit_bh(WRITE, bh); + gfs2_log_lock(sdp); if (++n >= num) break; } + BUG_ON(total < num); total -= num; } + gfs2_log_unlock(sdp); } static void buf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) @@ -270,11 +369,8 @@ static void revoke_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) tr = current->journal_info; tr->tr_touched = 1; tr->tr_num_revoke++; - - gfs2_log_lock(sdp); sdp->sd_log_num_revoke++; list_add(&le->le_list, &sdp->sd_log_le_revoke); - gfs2_log_unlock(sdp); } static void revoke_lo_before_commit(struct gfs2_sbd *sdp) @@ -284,32 +380,25 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) struct buffer_head *bh; unsigned int offset; struct list_head *head = &sdp->sd_log_le_revoke; - struct gfs2_revoke *rv; + struct gfs2_bufdata *bd; if (!sdp->sd_log_num_revoke) return; - bh = gfs2_log_get_buf(sdp); - ld = (struct gfs2_log_descriptor *)bh->b_data; - ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC); - ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD); - ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD); - ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_REVOKE); + bh = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_REVOKE); + ld = bh_log_desc(bh); ld->ld_length = cpu_to_be32(gfs2_struct2blk(sdp, sdp->sd_log_num_revoke, sizeof(u64))); ld->ld_data1 = cpu_to_be32(sdp->sd_log_num_revoke); - ld->ld_data2 = cpu_to_be32(0); - memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved)); offset = sizeof(struct gfs2_log_descriptor); while (!list_empty(head)) { - rv = list_entry(head->next, struct gfs2_revoke, rv_le.le_list); - list_del_init(&rv->rv_le.le_list); + bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list); + list_del_init(&bd->bd_le.le_list); sdp->sd_log_num_revoke--; if (offset + sizeof(u64) > sdp->sd_sb.sb_bsize) { - set_buffer_dirty(bh); - ll_rw_block(WRITE, 1, &bh); + submit_bh(WRITE, bh); bh = gfs2_log_get_buf(sdp); mh = (struct gfs2_meta_header *)bh->b_data; @@ -319,15 +408,14 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) offset = sizeof(struct gfs2_meta_header); } - *(__be64 *)(bh->b_data + offset) = cpu_to_be64(rv->rv_blkno); - kfree(rv); + *(__be64 *)(bh->b_data + offset) = cpu_to_be64(bd->bd_blkno); + kmem_cache_free(gfs2_bufdata_cachep, bd); offset += sizeof(u64); } gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); - set_buffer_dirty(bh); - ll_rw_block(WRITE, 1, &bh); + submit_bh(WRITE, bh); } static void revoke_lo_before_scan(struct gfs2_jdesc *jd, @@ -466,222 +554,136 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) struct address_space *mapping = bd->bd_bh->b_page->mapping; struct gfs2_inode *ip = GFS2_I(mapping->host); + lock_buffer(bd->bd_bh); gfs2_log_lock(sdp); - if (!list_empty(&bd->bd_list_tr)) { - gfs2_log_unlock(sdp); - return; - } + if (!list_empty(&bd->bd_list_tr)) + goto out; tr->tr_touched = 1; if (gfs2_is_jdata(ip)) { tr->tr_num_buf++; list_add(&bd->bd_list_tr, &tr->tr_list_buf); } - gfs2_log_unlock(sdp); if (!list_empty(&le->le_list)) - return; + goto out; - gfs2_trans_add_gl(bd->bd_gl); + __glock_lo_add(sdp, &bd->bd_gl->gl_le); if (gfs2_is_jdata(ip)) { - sdp->sd_log_num_jdata++; gfs2_pin(sdp, bd->bd_bh); tr->tr_num_databuf_new++; + sdp->sd_log_num_databuf++; + list_add(&le->le_list, &sdp->sd_log_le_databuf); + } else { + list_add(&le->le_list, &sdp->sd_log_le_ordered); } - gfs2_log_lock(sdp); - sdp->sd_log_num_databuf++; - list_add(&le->le_list, &sdp->sd_log_le_databuf); +out: gfs2_log_unlock(sdp); + unlock_buffer(bd->bd_bh); } -static int gfs2_check_magic(struct buffer_head *bh) +static void gfs2_check_magic(struct buffer_head *bh) { - struct page *page = bh->b_page; void *kaddr; __be32 *ptr; - int rv = 0; - kaddr = kmap_atomic(page, KM_USER0); + clear_buffer_escaped(bh); + kaddr = kmap_atomic(bh->b_page, KM_USER0); ptr = kaddr + bh_offset(bh); if (*ptr == cpu_to_be32(GFS2_MAGIC)) - rv = 1; + set_buffer_escaped(bh); kunmap_atomic(kaddr, KM_USER0); - - return rv; } -/** - * databuf_lo_before_commit - Scan the data buffers, writing as we go - * - * Here we scan through the lists of buffers and make the assumption - * that any buffer thats been pinned is being journaled, and that - * any unpinned buffer is an ordered write data buffer and therefore - * will be written back rather than journaled. - */ -static void databuf_lo_before_commit(struct gfs2_sbd *sdp) +static void gfs2_write_blocks(struct gfs2_sbd *sdp, struct buffer_head *bh, + struct list_head *list, struct list_head *done, + unsigned int n) { - LIST_HEAD(started); - struct gfs2_bufdata *bd1 = NULL, *bd2, *bdt; - struct buffer_head *bh = NULL,*bh1 = NULL; + struct buffer_head *bh1; struct gfs2_log_descriptor *ld; - unsigned int limit; - unsigned int total_dbuf; - unsigned int total_jdata = sdp->sd_log_num_jdata; - unsigned int num, n; - __be64 *ptr = NULL; + struct gfs2_bufdata *bd; + __be64 *ptr; + + if (!bh) + return; - limit = databuf_limit(sdp); + ld = bh_log_desc(bh); + ld->ld_length = cpu_to_be32(n + 1); + ld->ld_data1 = cpu_to_be32(n); - /* - * Start writing ordered buffers, write journaled buffers - * into the log along with a header - */ + ptr = bh_log_ptr(bh); + + get_bh(bh); + submit_bh(WRITE, bh); gfs2_log_lock(sdp); - total_dbuf = sdp->sd_log_num_databuf; - bd2 = bd1 = list_prepare_entry(bd1, &sdp->sd_log_le_databuf, - bd_le.le_list); - while(total_dbuf) { - num = total_jdata; - if (num > limit) - num = limit; - n = 0; - list_for_each_entry_safe_continue(bd1, bdt, - &sdp->sd_log_le_databuf, - bd_le.le_list) { - /* store off the buffer head in a local ptr since - * gfs2_bufdata might change when we drop the log lock - */ - bh1 = bd1->bd_bh; - - /* An ordered write buffer */ - if (bh1 && !buffer_pinned(bh1)) { - list_move(&bd1->bd_le.le_list, &started); - if (bd1 == bd2) { - bd2 = NULL; - bd2 = list_prepare_entry(bd2, - &sdp->sd_log_le_databuf, - bd_le.le_list); - } - total_dbuf--; - if (bh1) { - if (buffer_dirty(bh1)) { - get_bh(bh1); - - gfs2_log_unlock(sdp); - - ll_rw_block(SWRITE, 1, &bh1); - brelse(bh1); - - gfs2_log_lock(sdp); - } - continue; - } - continue; - } else if (bh1) { /* A journaled buffer */ - int magic; - gfs2_log_unlock(sdp); - if (!bh) { - bh = gfs2_log_get_buf(sdp); - ld = (struct gfs2_log_descriptor *) - bh->b_data; - ptr = (__be64 *)(bh->b_data + - DATABUF_OFFSET); - ld->ld_header.mh_magic = - cpu_to_be32(GFS2_MAGIC); - ld->ld_header.mh_type = - cpu_to_be32(GFS2_METATYPE_LD); - ld->ld_header.mh_format = - cpu_to_be32(GFS2_FORMAT_LD); - ld->ld_type = - cpu_to_be32(GFS2_LOG_DESC_JDATA); - ld->ld_length = cpu_to_be32(num + 1); - ld->ld_data1 = cpu_to_be32(num); - ld->ld_data2 = cpu_to_be32(0); - memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved)); - } - magic = gfs2_check_magic(bh1); - *ptr++ = cpu_to_be64(bh1->b_blocknr); - *ptr++ = cpu_to_be64((__u64)magic); - clear_buffer_escaped(bh1); - if (unlikely(magic != 0)) - set_buffer_escaped(bh1); - gfs2_log_lock(sdp); - if (++n >= num) - break; - } else if (!bh1) { - total_dbuf--; - sdp->sd_log_num_databuf--; - list_del_init(&bd1->bd_le.le_list); - if (bd1 == bd2) { - bd2 = NULL; - bd2 = list_prepare_entry(bd2, - &sdp->sd_log_le_databuf, - bd_le.le_list); - } - kmem_cache_free(gfs2_bufdata_cachep, bd1); - } + while(!list_empty(list)) { + bd = list_entry(list->next, struct gfs2_bufdata, bd_le.le_list); + list_move_tail(&bd->bd_le.le_list, done); + get_bh(bd->bd_bh); + while (be64_to_cpu(*ptr) != bd->bd_bh->b_blocknr) { + gfs2_log_incr_head(sdp); + ptr += 2; } gfs2_log_unlock(sdp); - if (bh) { - set_buffer_mapped(bh); - set_buffer_dirty(bh); - ll_rw_block(WRITE, 1, &bh); - bh = NULL; + lock_buffer(bd->bd_bh); + if (buffer_escaped(bd->bd_bh)) { + void *kaddr; + bh1 = gfs2_log_get_buf(sdp); + kaddr = kmap_atomic(bd->bd_bh->b_page, KM_USER0); + memcpy(bh1->b_data, kaddr + bh_offset(bd->bd_bh), + bh1->b_size); + kunmap_atomic(kaddr, KM_USER0); + *(__be32 *)bh1->b_data = 0; + clear_buffer_escaped(bd->bd_bh); + unlock_buffer(bd->bd_bh); + brelse(bd->bd_bh); + } else { + bh1 = gfs2_log_fake_buf(sdp, bd->bd_bh); } - n = 0; + submit_bh(WRITE, bh1); gfs2_log_lock(sdp); - list_for_each_entry_continue(bd2, &sdp->sd_log_le_databuf, - bd_le.le_list) { - if (!bd2->bd_bh) - continue; - /* copy buffer if it needs escaping */ - gfs2_log_unlock(sdp); - if (unlikely(buffer_escaped(bd2->bd_bh))) { - void *kaddr; - struct page *page = bd2->bd_bh->b_page; - bh = gfs2_log_get_buf(sdp); - kaddr = kmap_atomic(page, KM_USER0); - memcpy(bh->b_data, - kaddr + bh_offset(bd2->bd_bh), - sdp->sd_sb.sb_bsize); - kunmap_atomic(kaddr, KM_USER0); - *(__be32 *)bh->b_data = 0; - } else { - bh = gfs2_log_fake_buf(sdp, bd2->bd_bh); - } - set_buffer_dirty(bh); - ll_rw_block(WRITE, 1, &bh); - gfs2_log_lock(sdp); - if (++n >= num) - break; - } - bh = NULL; - BUG_ON(total_dbuf < num); - total_dbuf -= num; - total_jdata -= num; + ptr += 2; } gfs2_log_unlock(sdp); + brelse(bh); +} - /* Wait on all ordered buffers */ - while (!list_empty(&started)) { - gfs2_log_lock(sdp); - bd1 = list_entry(started.next, struct gfs2_bufdata, - bd_le.le_list); - list_del_init(&bd1->bd_le.le_list); - sdp->sd_log_num_databuf--; - bh = bd1->bd_bh; - if (bh) { - bh->b_private = NULL; - get_bh(bh); - gfs2_log_unlock(sdp); - wait_on_buffer(bh); - brelse(bh); - } else - gfs2_log_unlock(sdp); +/** + * databuf_lo_before_commit - Scan the data buffers, writing as we go + * + */ - kmem_cache_free(gfs2_bufdata_cachep, bd1); - } +static void databuf_lo_before_commit(struct gfs2_sbd *sdp) +{ + struct gfs2_bufdata *bd = NULL; + struct buffer_head *bh = NULL; + unsigned int n = 0; + __be64 *ptr = NULL, *end = NULL; + LIST_HEAD(processed); + LIST_HEAD(in_progress); - /* We've removed all the ordered write bufs here, so only jdata left */ - gfs2_assert_warn(sdp, sdp->sd_log_num_databuf == sdp->sd_log_num_jdata); + gfs2_log_lock(sdp); + while (!list_empty(&sdp->sd_log_le_databuf)) { + if (ptr == end) { + gfs2_log_unlock(sdp); + gfs2_write_blocks(sdp, bh, &in_progress, &processed, n); + n = 0; + bh = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_JDATA); + ptr = bh_log_ptr(bh); + end = bh_ptr_end(bh) - 1; + gfs2_log_lock(sdp); + continue; + } + bd = list_entry(sdp->sd_log_le_databuf.next, struct gfs2_bufdata, bd_le.le_list); + list_move_tail(&bd->bd_le.le_list, &in_progress); + gfs2_check_magic(bd->bd_bh); + *ptr++ = cpu_to_be64(bd->bd_bh->b_blocknr); + *ptr++ = cpu_to_be64(buffer_escaped(bh) ? 1 : 0); + n++; + } + gfs2_log_unlock(sdp); + gfs2_write_blocks(sdp, bh, &in_progress, &processed, n); + gfs2_log_lock(sdp); + list_splice(&processed, &sdp->sd_log_le_databuf); + gfs2_log_unlock(sdp); } static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, @@ -765,11 +767,9 @@ static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list); list_del_init(&bd->bd_le.le_list); sdp->sd_log_num_databuf--; - sdp->sd_log_num_jdata--; gfs2_unpin(sdp, bd->bd_bh, ai); } gfs2_assert_warn(sdp, !sdp->sd_log_num_databuf); - gfs2_assert_warn(sdp, !sdp->sd_log_num_jdata); } @@ -817,10 +817,10 @@ const struct gfs2_log_operations gfs2_databuf_lops = { const struct gfs2_log_operations *gfs2_log_ops[] = { &gfs2_glock_lops, + &gfs2_databuf_lops, &gfs2_buf_lops, - &gfs2_revoke_lops, &gfs2_rg_lops, - &gfs2_databuf_lops, + &gfs2_revoke_lops, NULL, }; diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index d5d4e68b8807..7ecfe0d3a491 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -24,7 +24,7 @@ #include "util.h" #include "glock.h" -static void gfs2_init_inode_once(void *foo, struct kmem_cache *cachep, unsigned long flags) +static void gfs2_init_inode_once(struct kmem_cache *cachep, void *foo) { struct gfs2_inode *ip = foo; @@ -34,7 +34,7 @@ static void gfs2_init_inode_once(void *foo, struct kmem_cache *cachep, unsigned memset(ip->i_cache, 0, sizeof(ip->i_cache)); } -static void gfs2_init_glock_once(void *foo, struct kmem_cache *cachep, unsigned long flags) +static void gfs2_init_glock_once(struct kmem_cache *cachep, void *foo) { struct gfs2_glock *gl = foo; @@ -107,6 +107,8 @@ static int __init init_gfs2_fs(void) fail_unregister: unregister_filesystem(&gfs2_fs_type); fail: + gfs2_glock_exit(); + if (gfs2_bufdata_cachep) kmem_cache_destroy(gfs2_bufdata_cachep); @@ -127,6 +129,7 @@ fail: static void __exit exit_gfs2_fs(void) { + gfs2_glock_exit(); gfs2_unregister_debugfs(); unregister_filesystem(&gfs2_fs_type); unregister_filesystem(&gfs2meta_fs_type); diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 8da343b34ae7..4da423985e4f 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -297,74 +297,35 @@ void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, unlock_page(bh->b_page); } -/** - * gfs2_pin - Pin a buffer in memory - * @sdp: the filesystem the buffer belongs to - * @bh: The buffer to be pinned - * - */ - -void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh) +void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr, int meta) { + struct gfs2_sbd *sdp = GFS2_SB(bh->b_page->mapping->host); struct gfs2_bufdata *bd = bh->b_private; - - gfs2_assert_withdraw(sdp, test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)); - - if (test_set_buffer_pinned(bh)) - gfs2_assert_withdraw(sdp, 0); - - wait_on_buffer(bh); - - /* If this buffer is in the AIL and it has already been written - to in-place disk block, remove it from the AIL. */ - - gfs2_log_lock(sdp); - if (bd->bd_ail && !buffer_in_io(bh)) - list_move(&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list); - gfs2_log_unlock(sdp); - - clear_buffer_dirty(bh); - wait_on_buffer(bh); - - if (!buffer_uptodate(bh)) - gfs2_io_error_bh(sdp, bh); - - get_bh(bh); -} - -/** - * gfs2_unpin - Unpin a buffer - * @sdp: the filesystem the buffer belongs to - * @bh: The buffer to unpin - * @ai: - * - */ - -void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh, - struct gfs2_ail *ai) -{ - struct gfs2_bufdata *bd = bh->b_private; - - gfs2_assert_withdraw(sdp, buffer_uptodate(bh)); - - if (!buffer_pinned(bh)) - gfs2_assert_withdraw(sdp, 0); - - mark_buffer_dirty(bh); - clear_buffer_pinned(bh); - - gfs2_log_lock(sdp); - if (bd->bd_ail) { - list_del(&bd->bd_ail_st_list); + if (test_clear_buffer_pinned(bh)) { + list_del_init(&bd->bd_le.le_list); + if (meta) { + gfs2_assert_warn(sdp, sdp->sd_log_num_buf); + sdp->sd_log_num_buf--; + tr->tr_num_buf_rm++; + } else { + gfs2_assert_warn(sdp, sdp->sd_log_num_databuf); + sdp->sd_log_num_databuf--; + tr->tr_num_databuf_rm++; + } + tr->tr_touched = 1; brelse(bh); - } else { - struct gfs2_glock *gl = bd->bd_gl; - list_add(&bd->bd_ail_gl_list, &gl->gl_ail_list); - atomic_inc(&gl->gl_ail_count); } - bd->bd_ail = ai; - list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list); - gfs2_log_unlock(sdp); + if (bd) { + if (bd->bd_ail) { + gfs2_remove_from_ail(NULL, bd); + bh->b_private = NULL; + bd->bd_bh = NULL; + bd->bd_blkno = bh->b_blocknr; + gfs2_trans_add_revoke(sdp, bd); + } + } + clear_buffer_dirty(bh); + clear_buffer_uptodate(bh); } /** @@ -383,44 +344,11 @@ void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen) while (blen) { bh = getbuf(ip->i_gl, bstart, NO_CREATE); if (bh) { - struct gfs2_bufdata *bd = bh->b_private; - - if (test_clear_buffer_pinned(bh)) { - struct gfs2_trans *tr = current->journal_info; - struct gfs2_inode *bh_ip = - GFS2_I(bh->b_page->mapping->host); - - gfs2_log_lock(sdp); - list_del_init(&bd->bd_le.le_list); - gfs2_assert_warn(sdp, sdp->sd_log_num_buf); - sdp->sd_log_num_buf--; - gfs2_log_unlock(sdp); - if (bh_ip->i_inode.i_private != NULL) - tr->tr_num_databuf_rm++; - else - tr->tr_num_buf_rm++; - brelse(bh); - } - if (bd) { - gfs2_log_lock(sdp); - if (bd->bd_ail) { - u64 blkno = bh->b_blocknr; - bd->bd_ail = NULL; - list_del(&bd->bd_ail_st_list); - list_del(&bd->bd_ail_gl_list); - atomic_dec(&bd->bd_gl->gl_ail_count); - brelse(bh); - gfs2_log_unlock(sdp); - gfs2_trans_add_revoke(sdp, blkno); - } else - gfs2_log_unlock(sdp); - } - lock_buffer(bh); - clear_buffer_dirty(bh); - clear_buffer_uptodate(bh); + gfs2_log_lock(sdp); + gfs2_remove_from_journal(bh, current->journal_info, 1); + gfs2_log_unlock(sdp); unlock_buffer(bh); - brelse(bh); } @@ -446,10 +374,10 @@ void gfs2_meta_cache_flush(struct gfs2_inode *ip) for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) { bh_slot = &ip->i_cache[x]; - if (!*bh_slot) - break; - brelse(*bh_slot); - *bh_slot = NULL; + if (*bh_slot) { + brelse(*bh_slot); + *bh_slot = NULL; + } } spin_unlock(&ip->i_spin); diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h index 527bf19d9690..b7048222ebb4 100644 --- a/fs/gfs2/meta_io.h +++ b/fs/gfs2/meta_io.h @@ -50,9 +50,9 @@ int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh); void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, int meta); -void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh); -void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh, - struct gfs2_ail *ai); + +void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr, + int meta); void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen); diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c index 4864659555d4..b941f9f9f958 100644 --- a/fs/gfs2/mount.c +++ b/fs/gfs2/mount.c @@ -42,6 +42,7 @@ enum { Opt_nosuiddir, Opt_data_writeback, Opt_data_ordered, + Opt_err, }; static match_table_t tokens = { @@ -64,7 +65,8 @@ static match_table_t tokens = { {Opt_suiddir, "suiddir"}, {Opt_nosuiddir, "nosuiddir"}, {Opt_data_writeback, "data=writeback"}, - {Opt_data_ordered, "data=ordered"} + {Opt_data_ordered, "data=ordered"}, + {Opt_err, NULL} }; /** @@ -237,6 +239,7 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount) case Opt_data_ordered: args->ar_data = GFS2_DATA_ORDERED; break; + case Opt_err: default: fs_info(sdp, "unknown option: %s\n", o); error = -EINVAL; diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 42a5f58f6fca..9679f8b9870d 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -17,6 +17,7 @@ #include <linux/mpage.h> #include <linux/fs.h> #include <linux/writeback.h> +#include <linux/swap.h> #include <linux/gfs2_ondisk.h> #include <linux/lm_interface.h> @@ -90,7 +91,7 @@ static int gfs2_get_block_noalloc(struct inode *inode, sector_t lblock, error = gfs2_block_map(inode, lblock, 0, bh_result); if (error) return error; - if (bh_result->b_blocknr == 0) + if (!buffer_mapped(bh_result)) return -EIO; return 0; } @@ -349,45 +350,49 @@ out_unlock: } /** - * gfs2_prepare_write - Prepare to write a page to a file + * gfs2_write_begin - Begin to write to a file * @file: The file to write to - * @page: The page which is to be prepared for writing - * @from: From (byte range within page) - * @to: To (byte range within page) + * @mapping: The mapping in which to write + * @pos: The file offset at which to start writing + * @len: Length of the write + * @flags: Various flags + * @pagep: Pointer to return the page + * @fsdata: Pointer to return fs data (unused by GFS2) * * Returns: errno */ -static int gfs2_prepare_write(struct file *file, struct page *page, - unsigned from, unsigned to) +static int gfs2_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - struct gfs2_inode *ip = GFS2_I(page->mapping->host); - struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); + struct gfs2_inode *ip = GFS2_I(mapping->host); + struct gfs2_sbd *sdp = GFS2_SB(mapping->host); unsigned int data_blocks, ind_blocks, rblocks; int alloc_required; int error = 0; - loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + from; - loff_t end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; struct gfs2_alloc *al; - unsigned int write_len = to - from; - + pgoff_t index = pos >> PAGE_CACHE_SHIFT; + unsigned from = pos & (PAGE_CACHE_SIZE - 1); + unsigned to = from + len; + struct page *page; - gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME|LM_FLAG_TRY_1CB, &ip->i_gh); + gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME, &ip->i_gh); error = gfs2_glock_nq_atime(&ip->i_gh); - if (unlikely(error)) { - if (error == GLR_TRYFAILED) { - unlock_page(page); - error = AOP_TRUNCATED_PAGE; - yield(); - } + if (unlikely(error)) goto out_uninit; - } - gfs2_write_calc_reserv(ip, write_len, &data_blocks, &ind_blocks); + error = -ENOMEM; + page = __grab_cache_page(mapping, index); + *pagep = page; + if (!page) + goto out_unlock; + + gfs2_write_calc_reserv(ip, len, &data_blocks, &ind_blocks); - error = gfs2_write_alloc_required(ip, pos, write_len, &alloc_required); + error = gfs2_write_alloc_required(ip, pos, len, &alloc_required); if (error) - goto out_unlock; + goto out_putpage; ip->i_alloc.al_requested = 0; @@ -414,12 +419,13 @@ static int gfs2_prepare_write(struct file *file, struct page *page, if (ind_blocks || data_blocks) rblocks += RES_STATFS + RES_QUOTA; - error = gfs2_trans_begin(sdp, rblocks, 0); + error = gfs2_trans_begin(sdp, rblocks, + PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize); if (error) goto out_trans_fail; if (gfs2_is_stuffed(ip)) { - if (end > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) { + if (pos + len > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) { error = gfs2_unstuff_dinode(ip, page); if (error == 0) goto prepare_write; @@ -442,6 +448,10 @@ out_qunlock: out_alloc_put: gfs2_alloc_put(ip); } +out_putpage: + page_cache_release(page); + if (pos + len > ip->i_inode.i_size) + vmtruncate(&ip->i_inode, ip->i_inode.i_size); out_unlock: gfs2_glock_dq_m(1, &ip->i_gh); out_uninit: @@ -477,65 +487,117 @@ static void adjust_fs_space(struct inode *inode) } /** - * gfs2_commit_write - Commit write to a file + * gfs2_stuffed_write_end - Write end for stuffed files + * @inode: The inode + * @dibh: The buffer_head containing the on-disk inode + * @pos: The file position + * @len: The length of the write + * @copied: How much was actually copied by the VFS + * @page: The page + * + * This copies the data from the page into the inode block after + * the inode data structure itself. + * + * Returns: errno + */ +static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh, + loff_t pos, unsigned len, unsigned copied, + struct page *page) +{ + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); + u64 to = pos + copied; + void *kaddr; + unsigned char *buf = dibh->b_data + sizeof(struct gfs2_dinode); + struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data; + + BUG_ON((pos + len) > (dibh->b_size - sizeof(struct gfs2_dinode))); + kaddr = kmap_atomic(page, KM_USER0); + memcpy(buf + pos, kaddr + pos, copied); + memset(kaddr + pos + copied, 0, len - copied); + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); + + if (!PageUptodate(page)) + SetPageUptodate(page); + unlock_page(page); + page_cache_release(page); + + if (inode->i_size < to) { + i_size_write(inode, to); + ip->i_di.di_size = inode->i_size; + di->di_size = cpu_to_be64(inode->i_size); + mark_inode_dirty(inode); + } + + if (inode == sdp->sd_rindex) + adjust_fs_space(inode); + + brelse(dibh); + gfs2_trans_end(sdp); + gfs2_glock_dq(&ip->i_gh); + gfs2_holder_uninit(&ip->i_gh); + return copied; +} + +/** + * gfs2_write_end * @file: The file to write to - * @page: The page containing the data - * @from: From (byte range within page) - * @to: To (byte range within page) + * @mapping: The address space to write to + * @pos: The file position + * @len: The length of the data + * @copied: + * @page: The page that has been written + * @fsdata: The fsdata (unused in GFS2) + * + * The main write_end function for GFS2. We have a separate one for + * stuffed files as they are slightly different, otherwise we just + * put our locking around the VFS provided functions. * * Returns: errno */ -static int gfs2_commit_write(struct file *file, struct page *page, - unsigned from, unsigned to) +static int gfs2_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) { struct inode *inode = page->mapping->host; struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); - int error = -EOPNOTSUPP; struct buffer_head *dibh; struct gfs2_alloc *al = &ip->i_alloc; struct gfs2_dinode *di; + unsigned int from = pos & (PAGE_CACHE_SIZE - 1); + unsigned int to = from + len; + int ret; - if (gfs2_assert_withdraw(sdp, gfs2_glock_is_locked_by_me(ip->i_gl))) - goto fail_nounlock; + BUG_ON(gfs2_glock_is_locked_by_me(ip->i_gl) == 0); - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) - goto fail_endtrans; + ret = gfs2_meta_inode_buffer(ip, &dibh); + if (unlikely(ret)) { + unlock_page(page); + page_cache_release(page); + goto failed; + } gfs2_trans_add_bh(ip->i_gl, dibh, 1); - di = (struct gfs2_dinode *)dibh->b_data; - - if (gfs2_is_stuffed(ip)) { - u64 file_size; - void *kaddr; - file_size = ((u64)page->index << PAGE_CACHE_SHIFT) + to; + if (gfs2_is_stuffed(ip)) + return gfs2_stuffed_write_end(inode, dibh, pos, len, copied, page); - kaddr = kmap_atomic(page, KM_USER0); - memcpy(dibh->b_data + sizeof(struct gfs2_dinode) + from, - kaddr + from, to - from); - kunmap_atomic(kaddr, KM_USER0); + if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) + gfs2_page_add_databufs(ip, page, from, to); - SetPageUptodate(page); + ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata); - if (inode->i_size < file_size) { - i_size_write(inode, file_size); + if (likely(ret >= 0)) { + copied = ret; + if ((pos + copied) > inode->i_size) { + di = (struct gfs2_dinode *)dibh->b_data; + ip->i_di.di_size = inode->i_size; + di->di_size = cpu_to_be64(inode->i_size); mark_inode_dirty(inode); } - } else { - if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || - gfs2_is_jdata(ip)) - gfs2_page_add_databufs(ip, page, from, to); - error = generic_commit_write(file, page, from, to); - if (error) - goto fail; - } - - if (ip->i_di.di_size < inode->i_size) { - ip->i_di.di_size = inode->i_size; - di->di_size = cpu_to_be64(inode->i_size); } if (inode == sdp->sd_rindex) @@ -543,33 +605,15 @@ static int gfs2_commit_write(struct file *file, struct page *page, brelse(dibh); gfs2_trans_end(sdp); +failed: if (al->al_requested) { gfs2_inplace_release(ip); gfs2_quota_unlock(ip); gfs2_alloc_put(ip); } - unlock_page(page); - gfs2_glock_dq_m(1, &ip->i_gh); - lock_page(page); - gfs2_holder_uninit(&ip->i_gh); - return 0; - -fail: - brelse(dibh); -fail_endtrans: - gfs2_trans_end(sdp); - if (al->al_requested) { - gfs2_inplace_release(ip); - gfs2_quota_unlock(ip); - gfs2_alloc_put(ip); - } - unlock_page(page); - gfs2_glock_dq_m(1, &ip->i_gh); - lock_page(page); + gfs2_glock_dq(&ip->i_gh); gfs2_holder_uninit(&ip->i_gh); -fail_nounlock: - ClearPageUptodate(page); - return error; + return ret; } /** @@ -616,58 +660,50 @@ static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock) return dblock; } -static void discard_buffer(struct gfs2_sbd *sdp, struct buffer_head *bh) +static void gfs2_discard(struct gfs2_sbd *sdp, struct buffer_head *bh) { struct gfs2_bufdata *bd; + lock_buffer(bh); gfs2_log_lock(sdp); + clear_buffer_dirty(bh); bd = bh->b_private; if (bd) { - bd->bd_bh = NULL; - bh->b_private = NULL; - if (!bd->bd_ail && list_empty(&bd->bd_le.le_list)) - kmem_cache_free(gfs2_bufdata_cachep, bd); + if (!list_empty(&bd->bd_le.le_list) && !buffer_pinned(bh)) + list_del_init(&bd->bd_le.le_list); + else + gfs2_remove_from_journal(bh, current->journal_info, 0); } - gfs2_log_unlock(sdp); - - lock_buffer(bh); - clear_buffer_dirty(bh); bh->b_bdev = NULL; clear_buffer_mapped(bh); clear_buffer_req(bh); clear_buffer_new(bh); - clear_buffer_delay(bh); + gfs2_log_unlock(sdp); unlock_buffer(bh); } static void gfs2_invalidatepage(struct page *page, unsigned long offset) { struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); - struct buffer_head *head, *bh, *next; - unsigned int curr_off = 0; + struct buffer_head *bh, *head; + unsigned long pos = 0; BUG_ON(!PageLocked(page)); if (offset == 0) ClearPageChecked(page); if (!page_has_buffers(page)) - return; + goto out; bh = head = page_buffers(page); do { - unsigned int next_off = curr_off + bh->b_size; - next = bh->b_this_page; - - if (offset <= curr_off) - discard_buffer(sdp, bh); - - curr_off = next_off; - bh = next; + if (offset <= pos) + gfs2_discard(sdp, bh); + pos += bh->b_size; + bh = bh->b_this_page; } while (bh != head); - - if (!offset) +out: + if (offset == 0) try_to_release_page(page, 0); - - return; } /** @@ -736,59 +772,6 @@ out: } /** - * stuck_releasepage - We're stuck in gfs2_releasepage(). Print stuff out. - * @bh: the buffer we're stuck on - * - */ - -static void stuck_releasepage(struct buffer_head *bh) -{ - struct inode *inode = bh->b_page->mapping->host; - struct gfs2_sbd *sdp = inode->i_sb->s_fs_info; - struct gfs2_bufdata *bd = bh->b_private; - struct gfs2_glock *gl; -static unsigned limit = 0; - - if (limit > 3) - return; - limit++; - - fs_warn(sdp, "stuck in gfs2_releasepage() %p\n", inode); - fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n", - (unsigned long long)bh->b_blocknr, atomic_read(&bh->b_count)); - fs_warn(sdp, "pinned = %u\n", buffer_pinned(bh)); - fs_warn(sdp, "bh->b_private = %s\n", (bd) ? "!NULL" : "NULL"); - - if (!bd) - return; - - gl = bd->bd_gl; - - fs_warn(sdp, "gl = (%u, %llu)\n", - gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number); - - fs_warn(sdp, "bd_list_tr = %s, bd_le.le_list = %s\n", - (list_empty(&bd->bd_list_tr)) ? "no" : "yes", - (list_empty(&bd->bd_le.le_list)) ? "no" : "yes"); - - if (gl->gl_ops == &gfs2_inode_glops) { - struct gfs2_inode *ip = gl->gl_object; - unsigned int x; - - if (!ip) - return; - - fs_warn(sdp, "ip = %llu %llu\n", - (unsigned long long)ip->i_no_formal_ino, - (unsigned long long)ip->i_no_addr); - - for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) - fs_warn(sdp, "ip->i_cache[%u] = %s\n", - x, (ip->i_cache[x]) ? "!NULL" : "NULL"); - } -} - -/** * gfs2_releasepage - free the metadata associated with a page * @page: the page that's being released * @gfp_mask: passed from Linux VFS, ignored by us @@ -805,41 +788,39 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) struct gfs2_sbd *sdp = aspace->i_sb->s_fs_info; struct buffer_head *bh, *head; struct gfs2_bufdata *bd; - unsigned long t = jiffies + gfs2_tune_get(sdp, gt_stall_secs) * HZ; if (!page_has_buffers(page)) - goto out; + return 0; + gfs2_log_lock(sdp); head = bh = page_buffers(page); do { - while (atomic_read(&bh->b_count)) { - if (!atomic_read(&aspace->i_writecount)) - return 0; - - if (!(gfp_mask & __GFP_WAIT)) - return 0; - - if (time_after_eq(jiffies, t)) { - stuck_releasepage(bh); - /* should we withdraw here? */ - return 0; - } - - yield(); - } - + if (atomic_read(&bh->b_count)) + goto cannot_release; + bd = bh->b_private; + if (bd && bd->bd_ail) + goto cannot_release; gfs2_assert_warn(sdp, !buffer_pinned(bh)); gfs2_assert_warn(sdp, !buffer_dirty(bh)); + bh = bh->b_this_page; + } while(bh != head); + gfs2_log_unlock(sdp); + head = bh = page_buffers(page); + do { gfs2_log_lock(sdp); bd = bh->b_private; if (bd) { gfs2_assert_warn(sdp, bd->bd_bh == bh); gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr)); - gfs2_assert_warn(sdp, !bd->bd_ail); - bd->bd_bh = NULL; - if (!list_empty(&bd->bd_le.le_list)) - bd = NULL; + if (!list_empty(&bd->bd_le.le_list)) { + if (!buffer_pinned(bh)) + list_del_init(&bd->bd_le.le_list); + else + bd = NULL; + } + if (bd) + bd->bd_bh = NULL; bh->b_private = NULL; } gfs2_log_unlock(sdp); @@ -849,8 +830,10 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) bh = bh->b_this_page; } while (bh != head); -out: return try_to_free_buffers(page); +cannot_release: + gfs2_log_unlock(sdp); + return 0; } const struct address_space_operations gfs2_file_aops = { @@ -859,8 +842,8 @@ const struct address_space_operations gfs2_file_aops = { .readpage = gfs2_readpage, .readpages = gfs2_readpages, .sync_page = block_sync_page, - .prepare_write = gfs2_prepare_write, - .commit_write = gfs2_commit_write, + .write_begin = gfs2_write_begin, + .write_end = gfs2_write_end, .set_page_dirty = gfs2_set_page_dirty, .bmap = gfs2_bmap, .invalidatepage = gfs2_invalidatepage, diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index b8312edee0e4..e2d1347796a9 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -237,7 +237,7 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_obj) inode = gfs2_inode_lookup(sb, DT_UNKNOWN, inum->no_addr, - 0); + 0, 0); if (!inode) goto fail; if (IS_ERR(inode)) { diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 94d76ace0b95..bb11fd6752d3 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -406,7 +406,7 @@ static int gfs2_open(struct inode *inode, struct file *file) if (!(file->f_flags & O_LARGEFILE) && ip->i_di.di_size > MAX_NON_LFS) { - error = -EFBIG; + error = -EOVERFLOW; goto fail_gunlock; } @@ -535,7 +535,7 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl) if (!(fl->fl_flags & FL_POSIX)) return -ENOLCK; - if ((ip->i_inode.i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) + if (__mandatory_lock(&ip->i_inode)) return -ENOLCK; if (sdp->sd_args.ar_localflocks) { @@ -571,7 +571,8 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl) int error = 0; state = (fl->fl_type == F_WRLCK) ? LM_ST_EXCLUSIVE : LM_ST_SHARED; - flags = (IS_SETLKW(cmd) ? 0 : LM_FLAG_TRY) | GL_EXACT | GL_NOCACHE; + flags = (IS_SETLKW(cmd) ? 0 : LM_FLAG_TRY) | GL_EXACT | GL_NOCACHE + | GL_FLOCK; mutex_lock(&fp->f_fl_mutex); @@ -579,21 +580,19 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl) if (gl) { if (fl_gh->gh_state == state) goto out; - gfs2_glock_hold(gl); flock_lock_file_wait(file, &(struct file_lock){.fl_type = F_UNLCK}); - gfs2_glock_dq_uninit(fl_gh); + gfs2_glock_dq_wait(fl_gh); + gfs2_holder_reinit(state, flags, fl_gh); } else { error = gfs2_glock_get(GFS2_SB(&ip->i_inode), ip->i_no_addr, &gfs2_flock_glops, CREATE, &gl); if (error) goto out; + gfs2_holder_init(gl, state, flags, fl_gh); + gfs2_glock_put(gl); } - - gfs2_holder_init(gl, state, flags, fl_gh); - gfs2_glock_put(gl); - error = gfs2_glock_nq(fl_gh); if (error) { gfs2_holder_uninit(fl_gh); @@ -637,7 +636,7 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl) if (!(fl->fl_flags & FL_FLOCK)) return -ENOLCK; - if ((ip->i_inode.i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) + if (__mandatory_lock(&ip->i_inode)) return -ENOLCK; if (sdp->sd_args.ar_localflocks) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index cf5aa5050548..17de58e83d92 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -28,18 +28,18 @@ #include "lm.h" #include "mount.h" #include "ops_fstype.h" +#include "ops_dentry.h" #include "ops_super.h" #include "recovery.h" #include "rgrp.h" #include "super.h" #include "sys.h" #include "util.h" +#include "log.h" #define DO 0 #define UNDO 1 -extern struct dentry_operations gfs2_dops; - static struct gfs2_sbd *init_sbd(struct super_block *sb) { struct gfs2_sbd *sdp; @@ -82,13 +82,15 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) INIT_LIST_HEAD(&sdp->sd_log_le_revoke); INIT_LIST_HEAD(&sdp->sd_log_le_rg); INIT_LIST_HEAD(&sdp->sd_log_le_databuf); + INIT_LIST_HEAD(&sdp->sd_log_le_ordered); mutex_init(&sdp->sd_log_reserve_mutex); INIT_LIST_HEAD(&sdp->sd_ail1_list); INIT_LIST_HEAD(&sdp->sd_ail2_list); init_rwsem(&sdp->sd_log_flush_lock); - INIT_LIST_HEAD(&sdp->sd_log_flush_list); + atomic_set(&sdp->sd_log_in_flight, 0); + init_waitqueue_head(&sdp->sd_log_flush_wait); INIT_LIST_HEAD(&sdp->sd_revoke_list); @@ -145,7 +147,8 @@ static int init_names(struct gfs2_sbd *sdp, int silent) snprintf(sdp->sd_proto_name, GFS2_FSNAME_LEN, "%s", proto); snprintf(sdp->sd_table_name, GFS2_FSNAME_LEN, "%s", table); - while ((table = strchr(sdp->sd_table_name, '/'))) + table = sdp->sd_table_name; + while ((table = strchr(table, '/'))) *table = '_'; out: @@ -161,14 +164,6 @@ static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh, if (undo) goto fail_trans; - p = kthread_run(gfs2_scand, sdp, "gfs2_scand"); - error = IS_ERR(p); - if (error) { - fs_err(sdp, "can't start scand thread: %d\n", error); - return error; - } - sdp->sd_scand_process = p; - for (sdp->sd_glockd_num = 0; sdp->sd_glockd_num < sdp->sd_args.ar_num_glockd; sdp->sd_glockd_num++) { @@ -229,14 +224,13 @@ fail: while (sdp->sd_glockd_num--) kthread_stop(sdp->sd_glockd_process[sdp->sd_glockd_num]); - kthread_stop(sdp->sd_scand_process); return error; } static inline struct inode *gfs2_lookup_root(struct super_block *sb, u64 no_addr) { - return gfs2_inode_lookup(sb, DT_DIR, no_addr, 0); + return gfs2_inode_lookup(sb, DT_DIR, no_addr, 0, 0); } static int init_sb(struct gfs2_sbd *sdp, int silent, int undo) @@ -301,8 +295,9 @@ static int init_sb(struct gfs2_sbd *sdp, int silent, int undo) fs_err(sdp, "can't get root dentry\n"); error = -ENOMEM; iput(inode); - } - sb->s_root->d_op = &gfs2_dops; + } else + sb->s_root->d_op = &gfs2_dops; + out: gfs2_glock_dq_uninit(&sb_gh); return error; @@ -368,7 +363,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) ip = GFS2_I(sdp->sd_jdesc->jd_inode); error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, - LM_FLAG_NOEXP | GL_EXACT, + LM_FLAG_NOEXP | GL_EXACT | GL_NOCACHE, &sdp->sd_jinode_gh); if (error) { fs_err(sdp, "can't acquire journal inode glock: %d\n", @@ -818,7 +813,6 @@ static struct super_block* get_gfs2_sb(const char *dev_name) struct nameidata nd; struct file_system_type *fstype; struct super_block *sb = NULL, *s; - struct list_head *l; int error; error = path_lookup(dev_name, LOOKUP_FOLLOW, &nd); @@ -830,8 +824,7 @@ static struct super_block* get_gfs2_sb(const char *dev_name) error = vfs_getattr(nd.mnt, nd.dentry, &stat); fstype = get_fs_type("gfs2"); - list_for_each(l, &fstype->fs_supers) { - s = list_entry(l, struct super_block, s_instances); + list_for_each_entry(s, &fstype->fs_supers, s_instances) { if ((S_ISBLK(stat.mode) && s->s_dev == stat.rdev) || (S_ISDIR(stat.mode) && s == nd.dentry->d_inode->i_sb)) { sb = s; @@ -861,7 +854,7 @@ static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags, error = -ENOENT; goto error; } - sdp = (struct gfs2_sbd*) sb->s_fs_info; + sdp = sb->s_fs_info; if (sdp->sd_vfs_meta) { printk(KERN_WARNING "GFS2: gfs2meta mount already exists\n"); error = -EBUSY; @@ -896,7 +889,10 @@ error: static void gfs2_kill_sb(struct super_block *sb) { - gfs2_delete_debugfs_file(sb->s_fs_info); + if (sb->s_fs_info) { + gfs2_delete_debugfs_file(sb->s_fs_info); + gfs2_meta_syncfs(sb->s_fs_info); + } kill_block_super(sb); } diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 911c115b5c6c..291f0c7eaa3b 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -69,7 +69,7 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, mark_inode_dirty(inode); break; } else if (PTR_ERR(inode) != -EEXIST || - (nd->intent.open.flags & O_EXCL)) { + (nd && (nd->intent.open.flags & O_EXCL))) { gfs2_holder_uninit(ghs); return PTR_ERR(inode); } @@ -278,17 +278,25 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2); - error = gfs2_glock_nq_m(3, ghs); + error = gfs2_glock_nq(ghs); /* parent */ if (error) - goto out; + goto out_parent; + + error = gfs2_glock_nq(ghs + 1); /* child */ + if (error) + goto out_child; + + error = gfs2_glock_nq(ghs + 2); /* rgrp */ + if (error) + goto out_rgrp; error = gfs2_unlink_ok(dip, &dentry->d_name, ip); if (error) - goto out_gunlock; + goto out_rgrp; error = gfs2_trans_begin(sdp, 2*RES_DINODE + RES_LEAF + RES_RG_BIT, 0); if (error) - goto out_gunlock; + goto out_rgrp; error = gfs2_dir_del(dip, &dentry->d_name); if (error) @@ -298,12 +306,15 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) out_end_trans: gfs2_trans_end(sdp); -out_gunlock: - gfs2_glock_dq_m(3, ghs); -out: - gfs2_holder_uninit(ghs); - gfs2_holder_uninit(ghs + 1); + gfs2_glock_dq(ghs + 2); +out_rgrp: gfs2_holder_uninit(ghs + 2); + gfs2_glock_dq(ghs + 1); +out_child: + gfs2_holder_uninit(ghs + 1); + gfs2_glock_dq(ghs); +out_parent: + gfs2_holder_uninit(ghs); gfs2_glock_dq_uninit(&ri_gh); return error; } @@ -894,12 +905,17 @@ static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd) static int setattr_size(struct inode *inode, struct iattr *attr) { struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); int error; if (attr->ia_size != ip->i_di.di_size) { - error = vmtruncate(inode, attr->ia_size); + error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks); if (error) return error; + error = vmtruncate(inode, attr->ia_size); + gfs2_trans_end(sdp); + if (error) + return error; } error = gfs2_truncatei(ip, attr->ia_size); diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 603d940f1159..950f31460e8b 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -92,7 +92,6 @@ static void gfs2_put_super(struct super_block *sb) kthread_stop(sdp->sd_recoverd_process); while (sdp->sd_glockd_num--) kthread_stop(sdp->sd_glockd_process[sdp->sd_glockd_num]); - kthread_stop(sdp->sd_scand_process); if (!(sb->s_flags & MS_RDONLY)) { error = gfs2_make_fs_ro(sdp); @@ -456,12 +455,15 @@ static void gfs2_delete_inode(struct inode *inode) } error = gfs2_dinode_dealloc(ip); - /* - * Must do this before unlock to avoid trying to write back - * potentially dirty data now that inode no longer exists - * on disk. - */ + if (error) + goto out_unlock; + + error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks); + if (error) + goto out_unlock; + /* Needs to be done before glock release & also in a transaction */ truncate_inode_pages(&inode->i_data, 0); + gfs2_trans_end(sdp); out_unlock: gfs2_glock_dq(&ip->i_iopen_gh); diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 6e546ee8f3d4..addb51e0f135 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -70,6 +70,7 @@ struct gfs2_quota_host { u64 qu_limit; u64 qu_warn; s64 qu_value; + u32 qu_ll_next; }; struct gfs2_quota_change_host { @@ -580,6 +581,7 @@ static void gfs2_quota_in(struct gfs2_quota_host *qu, const void *buf) qu->qu_limit = be64_to_cpu(str->qu_limit); qu->qu_warn = be64_to_cpu(str->qu_warn); qu->qu_value = be64_to_cpu(str->qu_value); + qu->qu_ll_next = be32_to_cpu(str->qu_ll_next); } static void gfs2_quota_out(const struct gfs2_quota_host *qu, void *buf) @@ -589,6 +591,7 @@ static void gfs2_quota_out(const struct gfs2_quota_host *qu, void *buf) str->qu_limit = cpu_to_be64(qu->qu_limit); str->qu_warn = cpu_to_be64(qu->qu_warn); str->qu_value = cpu_to_be64(qu->qu_value); + str->qu_ll_next = cpu_to_be32(qu->qu_ll_next); memset(&str->qu_reserved, 0, sizeof(str->qu_reserved)); } @@ -614,6 +617,16 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, s64 value; int err = -EIO; + if (gfs2_is_stuffed(ip)) { + struct gfs2_alloc *al = NULL; + al = gfs2_alloc_get(ip); + /* just request 1 blk */ + al->al_requested = 1; + gfs2_inplace_reserve(ip); + gfs2_unstuff_dinode(ip, NULL); + gfs2_inplace_release(ip); + gfs2_alloc_put(ip); + } page = grab_cache_page(mapping, index); if (!page) return -ENOMEM; diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 5ada38c99a2c..beb6c7ac0086 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -469,7 +469,7 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd) }; error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, - LM_FLAG_NOEXP, &ji_gh); + LM_FLAG_NOEXP | GL_NOCACHE, &ji_gh); if (error) goto fail_gunlock_j; } else { diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index ce48c4594ec8..708c287e1d0e 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -31,6 +31,7 @@ #include "inode.h" #define BFITNOENT ((u32)~0) +#define NO_BLOCK ((u64)~0) /* * These routines are used by the resource group routines (rgrp.c) @@ -116,8 +117,7 @@ static unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, * @buffer: the buffer that holds the bitmaps * @buflen: the length (in bytes) of the buffer * @goal: start search at this block's bit-pair (within @buffer) - * @old_state: GFS2_BLKST_XXX the state of the block we're looking for; - * bit 0 = alloc(1)/free(0), bit 1 = meta(1)/data(0) + * @old_state: GFS2_BLKST_XXX the state of the block we're looking for. * * Scope of @goal and returned block number is only within this bitmap buffer, * not entire rgrp or filesystem. @buffer will be offset from the actual @@ -137,9 +137,13 @@ static u32 gfs2_bitfit(struct gfs2_rgrpd *rgd, unsigned char *buffer, byte = buffer + (goal / GFS2_NBBY); bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE; end = buffer + buflen; - alloc = (old_state & 1) ? 0 : 0x55; + alloc = (old_state == GFS2_BLKST_FREE) ? 0x55 : 0; while (byte < end) { + /* If we're looking for a free block we can eliminate all + bitmap settings with 0x55, which represents four data + blocks in a row. If we're looking for a data block, we can + eliminate 0x00 which corresponds to four free blocks. */ if ((*byte & 0x55) == alloc) { blk += (8 - bit) >> 1; @@ -859,23 +863,28 @@ static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al) static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked) { struct inode *inode; - u32 goal = 0; + u32 goal = 0, block; u64 no_addr; + struct gfs2_sbd *sdp = rgd->rd_sbd; for(;;) { if (goal >= rgd->rd_data) break; - goal = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED, - GFS2_BLKST_UNLINKED); - if (goal == BFITNOENT) + down_write(&sdp->sd_log_flush_lock); + block = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED, + GFS2_BLKST_UNLINKED); + up_write(&sdp->sd_log_flush_lock); + if (block == BFITNOENT) break; - no_addr = goal + rgd->rd_data0; + /* rgblk_search can return a block < goal, so we need to + keep it marching forward. */ + no_addr = block + rgd->rd_data0; goal++; - if (no_addr < *last_unlinked) + if (*last_unlinked != NO_BLOCK && no_addr <= *last_unlinked) continue; *last_unlinked = no_addr; inode = gfs2_inode_lookup(rgd->rd_sbd->sd_vfs, DT_UNKNOWN, - no_addr, -1); + no_addr, -1, 1); if (!IS_ERR(inode)) return inode; } @@ -1152,7 +1161,7 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line) struct gfs2_alloc *al = &ip->i_alloc; struct inode *inode; int error = 0; - u64 last_unlinked = 0; + u64 last_unlinked = NO_BLOCK; if (gfs2_assert_warn(sdp, al->al_requested)) return -EINVAL; @@ -1289,7 +1298,9 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, allocatable block anywhere else, we want to be able wrap around and search in the first part of our first-searched bit block. */ for (x = 0; x <= length; x++) { - if (bi->bi_clone) + /* The GFS2_BLKST_UNLINKED state doesn't apply to the clone + bitmaps, so we must search the originals for that. */ + if (old_state != GFS2_BLKST_UNLINKED && bi->bi_clone) blk = gfs2_bitfit(rgd, bi->bi_clone + bi->bi_offset, bi->bi_len, goal, old_state); else @@ -1305,9 +1316,7 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, goal = 0; } - if (old_state != new_state) { - gfs2_assert_withdraw(rgd->rd_sbd, blk != BFITNOENT); - + if (blk != BFITNOENT && old_state != new_state) { gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1); gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset, bi->bi_len, blk, new_state); diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index f916b9740c75..dd3e737f528e 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -58,7 +58,6 @@ void gfs2_tune_init(struct gfs2_tune *gt) gt->gt_incore_log_blocks = 1024; gt->gt_log_flush_secs = 60; gt->gt_jindex_refresh_secs = 60; - gt->gt_scand_secs = 15; gt->gt_recoverd_secs = 60; gt->gt_logd_secs = 1; gt->gt_quotad_secs = 5; @@ -160,18 +159,15 @@ int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb_host *sb, int silent) } -static int end_bio_io_page(struct bio *bio, unsigned int bytes_done, int error) +static void end_bio_io_page(struct bio *bio, int error) { struct page *page = bio->bi_private; - if (bio->bi_size) - return 1; if (!error) SetPageUptodate(page); else printk(KERN_WARNING "gfs2: error %d reading superblock\n", error); unlock_page(page); - return 0; } static void gfs2_sb_in(struct gfs2_sb_host *sb, const void *buf) diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index c26c21b53c19..06e0b7768d97 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -222,7 +222,6 @@ static struct kobj_type gfs2_ktype = { }; static struct kset gfs2_kset = { - .kobj = {.name = "gfs2"}, .ktype = &gfs2_ktype, }; @@ -442,7 +441,6 @@ TUNE_ATTR(quota_simul_sync, 1); TUNE_ATTR(quota_cache_secs, 1); TUNE_ATTR(stall_secs, 1); TUNE_ATTR(statfs_quantum, 1); -TUNE_ATTR_DAEMON(scand_secs, scand_process); TUNE_ATTR_DAEMON(recoverd_secs, recoverd_process); TUNE_ATTR_DAEMON(logd_secs, logd_process); TUNE_ATTR_DAEMON(quotad_secs, quotad_process); @@ -464,7 +462,6 @@ static struct attribute *tune_attrs[] = { &tune_attr_quota_cache_secs.attr, &tune_attr_stall_secs.attr, &tune_attr_statfs_quantum.attr, - &tune_attr_scand_secs.attr, &tune_attr_recoverd_secs.attr, &tune_attr_logd_secs.attr, &tune_attr_quotad_secs.attr, @@ -553,6 +550,7 @@ int gfs2_sys_init(void) { gfs2_sys_margs = NULL; spin_lock_init(&gfs2_sys_margs_lock); + kobject_set_name(&gfs2_kset.kobj, "gfs2"); kobj_set_kset_s(&gfs2_kset, fs_subsys); return kset_register(&gfs2_kset); } diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index f8dabf8446bb..717983e2c2ae 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -142,25 +142,25 @@ void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta) lops_add(sdp, &bd->bd_le); } -void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, u64 blkno) +void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd) { - struct gfs2_revoke *rv = kmalloc(sizeof(struct gfs2_revoke), - GFP_NOFS | __GFP_NOFAIL); - lops_init_le(&rv->rv_le, &gfs2_revoke_lops); - rv->rv_blkno = blkno; - lops_add(sdp, &rv->rv_le); + BUG_ON(!list_empty(&bd->bd_le.le_list)); + BUG_ON(!list_empty(&bd->bd_ail_st_list)); + BUG_ON(!list_empty(&bd->bd_ail_gl_list)); + lops_init_le(&bd->bd_le, &gfs2_revoke_lops); + lops_add(sdp, &bd->bd_le); } void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno) { - struct gfs2_revoke *rv; + struct gfs2_bufdata *bd; int found = 0; gfs2_log_lock(sdp); - list_for_each_entry(rv, &sdp->sd_log_le_revoke, rv_le.le_list) { - if (rv->rv_blkno == blkno) { - list_del(&rv->rv_le.le_list); + list_for_each_entry(bd, &sdp->sd_log_le_revoke, bd_le.le_list) { + if (bd->bd_blkno == blkno) { + list_del_init(&bd->bd_le.le_list); gfs2_assert_withdraw(sdp, sdp->sd_log_num_revoke); sdp->sd_log_num_revoke--; found = 1; @@ -172,7 +172,7 @@ void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno) if (found) { struct gfs2_trans *tr = current->journal_info; - kfree(rv); + kmem_cache_free(gfs2_bufdata_cachep, bd); tr->tr_num_revoke_rm++; } } diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h index 23d4cbe1de5b..043d5f4b9c4c 100644 --- a/fs/gfs2/trans.h +++ b/fs/gfs2/trans.h @@ -32,7 +32,7 @@ void gfs2_trans_end(struct gfs2_sbd *sdp); void gfs2_trans_add_gl(struct gfs2_glock *gl); void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta); -void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, u64 blkno); +void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd); void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno); void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd); diff --git a/fs/hfs/extent.c b/fs/hfs/extent.c index 5ea6b3d45eaa..c176f67ba0a5 100644 --- a/fs/hfs/extent.c +++ b/fs/hfs/extent.c @@ -464,23 +464,20 @@ void hfs_file_truncate(struct inode *inode) (long long)HFS_I(inode)->phys_size, inode->i_size); if (inode->i_size > HFS_I(inode)->phys_size) { struct address_space *mapping = inode->i_mapping; + void *fsdata; struct page *page; int res; + /* XXX: Can use generic_cont_expand? */ size = inode->i_size - 1; - page = grab_cache_page(mapping, size >> PAGE_CACHE_SHIFT); - if (!page) - return; - size &= PAGE_CACHE_SIZE - 1; - size++; - res = mapping->a_ops->prepare_write(NULL, page, size, size); - if (!res) - res = mapping->a_ops->commit_write(NULL, page, size, size); + res = pagecache_write_begin(NULL, mapping, size+1, 0, + AOP_FLAG_UNINTERRUPTIBLE, &page, &fsdata); + if (!res) { + res = pagecache_write_end(NULL, mapping, size+1, 0, 0, + page, fsdata); + } if (res) inode->i_size = HFS_I(inode)->phys_size; - unlock_page(page); - page_cache_release(page); - mark_inode_dirty(inode); return; } else if (inode->i_size == HFS_I(inode)->phys_size) return; diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index bc835f272a6e..97f8446c4ff4 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c @@ -35,10 +35,14 @@ static int hfs_readpage(struct file *file, struct page *page) return block_read_full_page(page, hfs_get_block); } -static int hfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) +static int hfs_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - return cont_prepare_write(page, from, to, hfs_get_block, - &HFS_I(page->mapping->host)->phys_size); + *pagep = NULL; + return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + hfs_get_block, + &HFS_I(mapping->host)->phys_size); } static sector_t hfs_bmap(struct address_space *mapping, sector_t block) @@ -119,8 +123,8 @@ const struct address_space_operations hfs_btree_aops = { .readpage = hfs_readpage, .writepage = hfs_writepage, .sync_page = block_sync_page, - .prepare_write = hfs_prepare_write, - .commit_write = generic_commit_write, + .write_begin = hfs_write_begin, + .write_end = generic_write_end, .bmap = hfs_bmap, .releasepage = hfs_releasepage, }; @@ -129,8 +133,8 @@ const struct address_space_operations hfs_aops = { .readpage = hfs_readpage, .writepage = hfs_writepage, .sync_page = block_sync_page, - .prepare_write = hfs_prepare_write, - .commit_write = generic_commit_write, + .write_begin = hfs_write_begin, + .write_end = generic_write_end, .bmap = hfs_bmap, .direct_IO = hfs_direct_IO, .writepages = hfs_writepages, diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 6c5f92dfb500..16cbd902f8b9 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -430,7 +430,7 @@ static struct file_system_type hfs_fs_type = { .fs_flags = FS_REQUIRES_DEV, }; -static void hfs_init_once(void *p, struct kmem_cache *cachep, unsigned long flags) +static void hfs_init_once(struct kmem_cache *cachep, void *p) { struct hfs_inode_info *i = p; diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c index 1a7480089e82..12e899cd7886 100644 --- a/fs/hfsplus/extents.c +++ b/fs/hfsplus/extents.c @@ -443,21 +443,18 @@ void hfsplus_file_truncate(struct inode *inode) if (inode->i_size > HFSPLUS_I(inode).phys_size) { struct address_space *mapping = inode->i_mapping; struct page *page; - u32 size = inode->i_size - 1; + void *fsdata; + u32 size = inode->i_size; int res; - page = grab_cache_page(mapping, size >> PAGE_CACHE_SHIFT); - if (!page) - return; - size &= PAGE_CACHE_SIZE - 1; - size++; - res = mapping->a_ops->prepare_write(NULL, page, size, size); - if (!res) - res = mapping->a_ops->commit_write(NULL, page, size, size); + res = pagecache_write_begin(NULL, mapping, size, 0, + AOP_FLAG_UNINTERRUPTIBLE, + &page, &fsdata); if (res) - inode->i_size = HFSPLUS_I(inode).phys_size; - unlock_page(page); - page_cache_release(page); + return; + res = pagecache_write_end(NULL, mapping, size, 0, 0, page, fsdata); + if (res < 0) + return; mark_inode_dirty(inode); return; } else if (inode->i_size == HFSPLUS_I(inode).phys_size) diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 6f7c662174db..37744cf3706a 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -27,10 +27,14 @@ static int hfsplus_writepage(struct page *page, struct writeback_control *wbc) return block_write_full_page(page, hfsplus_get_block, wbc); } -static int hfsplus_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) +static int hfsplus_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - return cont_prepare_write(page, from, to, hfsplus_get_block, - &HFSPLUS_I(page->mapping->host).phys_size); + *pagep = NULL; + return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + hfsplus_get_block, + &HFSPLUS_I(mapping->host).phys_size); } static sector_t hfsplus_bmap(struct address_space *mapping, sector_t block) @@ -114,8 +118,8 @@ const struct address_space_operations hfsplus_btree_aops = { .readpage = hfsplus_readpage, .writepage = hfsplus_writepage, .sync_page = block_sync_page, - .prepare_write = hfsplus_prepare_write, - .commit_write = generic_commit_write, + .write_begin = hfsplus_write_begin, + .write_end = generic_write_end, .bmap = hfsplus_bmap, .releasepage = hfsplus_releasepage, }; @@ -124,8 +128,8 @@ const struct address_space_operations hfsplus_aops = { .readpage = hfsplus_readpage, .writepage = hfsplus_writepage, .sync_page = block_sync_page, - .prepare_write = hfsplus_prepare_write, - .commit_write = generic_commit_write, + .write_begin = hfsplus_write_begin, + .write_end = generic_write_end, .bmap = hfsplus_bmap, .direct_IO = hfsplus_direct_IO, .writepages = hfsplus_writepages, diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 7b0f2e5a44e2..ecf70dafb643 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -466,7 +466,7 @@ static struct file_system_type hfsplus_fs_type = { .fs_flags = FS_REQUIRES_DEV, }; -static void hfsplus_init_once(void *p, struct kmem_cache *cachep, unsigned long flags) +static void hfsplus_init_once(struct kmem_cache *cachep, void *p) { struct hfsplus_inode_info *i = p; diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h index 06e5930515fe..6ae9011b95eb 100644 --- a/fs/hostfs/hostfs.h +++ b/fs/hostfs/hostfs.h @@ -3,7 +3,8 @@ #include "os.h" -/* These are exactly the same definitions as in fs.h, but the names are +/* + * These are exactly the same definitions as in fs.h, but the names are * changed so that this file can be included in both kernel and user files. */ @@ -21,7 +22,8 @@ #define HOSTFS_ATTR_FORCE 512 /* Not a change, but a change it */ #define HOSTFS_ATTR_ATTR_FLAG 1024 -/* If you are very careful, you'll notice that these two are missing: +/* + * If you are very careful, you'll notice that these two are missing: * * #define ATTR_KILL_SUID 2048 * #define ATTR_KILL_SGID 4096 @@ -76,7 +78,8 @@ extern int make_symlink(const char *from, const char *to); extern int unlink_file(const char *file); extern int do_mkdir(const char *file, int mode); extern int do_rmdir(const char *file); -extern int do_mknod(const char *file, int mode, unsigned int major, unsigned int minor); +extern int do_mknod(const char *file, int mode, unsigned int major, + unsigned int minor); extern int link_file(const char *from, const char *to); extern int do_readlink(char *file, char *buf, int size); extern int rename_file(char *from, char *to); diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index c77862032e84..8966b050196e 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -6,21 +6,14 @@ * 2003-02-10 Petr Baudis <pasky@ucw.cz> */ -#include <linux/stddef.h> #include <linux/fs.h> #include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> +#include <linux/mm.h> #include <linux/pagemap.h> -#include <linux/blkdev.h> -#include <linux/list.h> #include <linux/statfs.h> -#include <linux/kdev_t.h> -#include <asm/uaccess.h> #include "hostfs.h" -#include "kern_util.h" -#include "kern.h" #include "init.h" +#include "kern.h" struct hostfs_inode_info { char *host_filename; @@ -61,18 +54,18 @@ static int __init hostfs_args(char *options, int *add) char *ptr; ptr = strchr(options, ','); - if(ptr != NULL) + if (ptr != NULL) *ptr++ = '\0'; - if(*options != '\0') + if (*options != '\0') root_ino = options; options = ptr; - while(options){ + while (options) { ptr = strchr(options, ','); - if(ptr != NULL) + if (ptr != NULL) *ptr++ = '\0'; - if(*options != '\0'){ - if(!strcmp(options, "append")) + if (*options != '\0') { + if (!strcmp(options, "append")) append = 1; else printf("hostfs_args - unsupported option - %s\n", options); @@ -102,7 +95,7 @@ static char *dentry_name(struct dentry *dentry, int extra) len = 0; parent = dentry; - while(parent->d_parent != parent){ + while (parent->d_parent != parent) { len += parent->d_name.len + 1; parent = parent->d_parent; } @@ -110,12 +103,12 @@ static char *dentry_name(struct dentry *dentry, int extra) root = HOSTFS_I(parent->d_inode)->host_filename; len += strlen(root); name = kmalloc(len + extra + 1, GFP_KERNEL); - if(name == NULL) + if (name == NULL) return NULL; name[len] = '\0'; parent = dentry; - while(parent->d_parent != parent){ + while (parent->d_parent != parent) { len -= parent->d_name.len + 1; name[len] = '/'; strncpy(&name[len + 1], parent->d_name.name, @@ -136,7 +129,8 @@ static char *inode_name(struct inode *ino, int extra) static int read_name(struct inode *ino, char *name) { - /* The non-int inode fields are copied into ints by stat_file and + /* + * The non-int inode fields are copied into ints by stat_file and * then copied into the inode because passing the actual pointers * in and having them treated as int * breaks on big-endian machines */ @@ -149,7 +143,7 @@ static int read_name(struct inode *ino, char *name) err = stat_file(name, &i_ino, &i_mode, &i_nlink, &ino->i_uid, &ino->i_gid, &i_size, &ino->i_atime, &ino->i_mtime, &ino->i_ctime, &i_blksize, &i_blocks, -1); - if(err) + if (err) return err; ino->i_ino = i_ino; @@ -166,33 +160,33 @@ static char *follow_link(char *link) char *name, *resolved, *end; len = 64; - while(1){ + while (1) { n = -ENOMEM; name = kmalloc(len, GFP_KERNEL); - if(name == NULL) + if (name == NULL) goto out; n = do_readlink(link, name, len); - if(n < len) + if (n < len) break; len *= 2; kfree(name); } - if(n < 0) + if (n < 0) goto out_free; - if(*name == '/') + if (*name == '/') return name; end = strrchr(link, '/'); - if(end == NULL) + if (end == NULL) return name; *(end + 1) = '\0'; len = strlen(link) + strlen(name) + 1; resolved = kmalloc(len, GFP_KERNEL); - if(resolved == NULL){ + if (resolved == NULL) { n = -ENOMEM; goto out_free; } @@ -213,20 +207,21 @@ static int read_inode(struct inode *ino) char *name; int err = 0; - /* Unfortunately, we are called from iget() when we don't have a dentry + /* + * Unfortunately, we are called from iget() when we don't have a dentry * allocated yet. */ - if(list_empty(&ino->i_dentry)) + if (list_empty(&ino->i_dentry)) goto out; err = -ENOMEM; name = inode_name(ino, 0); - if(name == NULL) + if (name == NULL) goto out; - if(file_type(name, NULL, NULL) == OS_TYPE_SYMLINK){ + if (file_type(name, NULL, NULL) == OS_TYPE_SYMLINK) { name = follow_link(name); - if(IS_ERR(name)){ + if (IS_ERR(name)) { err = PTR_ERR(name); goto out; } @@ -240,7 +235,8 @@ static int read_inode(struct inode *ino) int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf) { - /* do_statfs uses struct statfs64 internally, but the linux kernel + /* + * do_statfs uses struct statfs64 internally, but the linux kernel * struct statfs still has 32-bit versions for most of these fields, * so we convert them here */ @@ -255,7 +251,7 @@ int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf) &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files, &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid), &sf->f_namelen, sf->f_spare); - if(err) + if (err) return err; sf->f_blocks = f_blocks; sf->f_bfree = f_bfree; @@ -271,7 +267,7 @@ static struct inode *hostfs_alloc_inode(struct super_block *sb) struct hostfs_inode_info *hi; hi = kmalloc(sizeof(*hi), GFP_KERNEL); - if(hi == NULL) + if (hi == NULL) return NULL; *hi = ((struct hostfs_inode_info) { .host_filename = NULL, @@ -284,7 +280,7 @@ static struct inode *hostfs_alloc_inode(struct super_block *sb) static void hostfs_delete_inode(struct inode *inode) { truncate_inode_pages(&inode->i_data, 0); - if(HOSTFS_I(inode)->fd != -1) { + if (HOSTFS_I(inode)->fd != -1) { close_file(&HOSTFS_I(inode)->fd); HOSTFS_I(inode)->fd = -1; } @@ -295,9 +291,11 @@ static void hostfs_destroy_inode(struct inode *inode) { kfree(HOSTFS_I(inode)->host_filename); - /*XXX: This should not happen, probably. The check is here for - * additional safety.*/ - if(HOSTFS_I(inode)->fd != -1) { + /* + * XXX: This should not happen, probably. The check is here for + * additional safety. + */ + if (HOSTFS_I(inode)->fd != -1) { close_file(&HOSTFS_I(inode)->fd); printk(KERN_DEBUG "Closing host fd in .destroy_inode\n"); } @@ -327,17 +325,17 @@ int hostfs_readdir(struct file *file, void *ent, filldir_t filldir) int error, len; name = dentry_name(file->f_path.dentry, 0); - if(name == NULL) + if (name == NULL) return -ENOMEM; dir = open_dir(name, &error); kfree(name); - if(dir == NULL) + if (dir == NULL) return -error; next = file->f_pos; - while((name = read_dir(dir, &next, &ino, &len)) != NULL){ + while ((name = read_dir(dir, &next, &ino, &len)) != NULL) { error = (*filldir)(ent, name, len, file->f_pos, ino, DT_UNKNOWN); - if(error) break; + if (error) break; file->f_pos = next; } close_dir(dir); @@ -350,32 +348,33 @@ int hostfs_file_open(struct inode *ino, struct file *file) int mode = 0, r = 0, w = 0, fd; mode = file->f_mode & (FMODE_READ | FMODE_WRITE); - if((mode & HOSTFS_I(ino)->mode) == mode) + if ((mode & HOSTFS_I(ino)->mode) == mode) return 0; - /* The file may already have been opened, but with the wrong access, + /* + * The file may already have been opened, but with the wrong access, * so this resets things and reopens the file with the new access. */ - if(HOSTFS_I(ino)->fd != -1){ + if (HOSTFS_I(ino)->fd != -1) { close_file(&HOSTFS_I(ino)->fd); HOSTFS_I(ino)->fd = -1; } HOSTFS_I(ino)->mode |= mode; - if(HOSTFS_I(ino)->mode & FMODE_READ) + if (HOSTFS_I(ino)->mode & FMODE_READ) r = 1; - if(HOSTFS_I(ino)->mode & FMODE_WRITE) + if (HOSTFS_I(ino)->mode & FMODE_WRITE) w = 1; - if(w) + if (w) r = 1; name = dentry_name(file->f_path.dentry, 0); - if(name == NULL) + if (name == NULL) return -ENOMEM; fd = open_file(name, r, w, append); kfree(name); - if(fd < 0) + if (fd < 0) return fd; FILE_HOSTFS_I(file)->fd = fd; @@ -423,7 +422,7 @@ int hostfs_writepage(struct page *page, struct writeback_control *wbc) base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT; err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count); - if(err != count){ + if (err != count) { ClearPageUptodate(page); goto out; } @@ -452,7 +451,8 @@ int hostfs_readpage(struct file *file, struct page *page) buffer = kmap(page); err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer, PAGE_CACHE_SIZE); - if(err < 0) goto out; + if (err < 0) + goto out; memset(&buffer[err], 0, PAGE_CACHE_SIZE - err); @@ -466,56 +466,43 @@ int hostfs_readpage(struct file *file, struct page *page) return err; } -int hostfs_prepare_write(struct file *file, struct page *page, - unsigned int from, unsigned int to) +int hostfs_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - char *buffer; - long long start, tmp; - int err; + pgoff_t index = pos >> PAGE_CACHE_SHIFT; - start = (long long) page->index << PAGE_CACHE_SHIFT; - buffer = kmap(page); - if(from != 0){ - tmp = start; - err = read_file(FILE_HOSTFS_I(file)->fd, &tmp, buffer, - from); - if(err < 0) goto out; - } - if(to != PAGE_CACHE_SIZE){ - start += to; - err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer + to, - PAGE_CACHE_SIZE - to); - if(err < 0) goto out; - } - err = 0; - out: - kunmap(page); - return err; + *pagep = __grab_cache_page(mapping, index); + if (!*pagep) + return -ENOMEM; + return 0; } -int hostfs_commit_write(struct file *file, struct page *page, unsigned from, - unsigned to) +int hostfs_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) { - struct address_space *mapping = page->mapping; struct inode *inode = mapping->host; - char *buffer; - long long start; - int err = 0; + void *buffer; + unsigned from = pos & (PAGE_CACHE_SIZE - 1); + int err; - start = (((long long) page->index) << PAGE_CACHE_SHIFT) + from; buffer = kmap(page); - err = write_file(FILE_HOSTFS_I(file)->fd, &start, buffer + from, - to - from); - if(err > 0) err = 0; + err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied); + kunmap(page); - /* Actually, if !err, write_file has added to-from to start, so, despite - * the appearance, we are comparing i_size against the _last_ written - * location, as we should. */ + if (!PageUptodate(page) && err == PAGE_CACHE_SIZE) + SetPageUptodate(page); - if(!err && (start > inode->i_size)) - inode->i_size = start; + /* + * If err > 0, write_file has added err to pos, so we are comparing + * i_size against the last byte written. + */ + if (err > 0 && (pos > inode->i_size)) + inode->i_size = pos; + unlock_page(page); + page_cache_release(page); - kunmap(page); return err; } @@ -523,8 +510,8 @@ static const struct address_space_operations hostfs_aops = { .writepage = hostfs_writepage, .readpage = hostfs_readpage, .set_page_dirty = __set_page_dirty_nobuffers, - .prepare_write = hostfs_prepare_write, - .commit_write = hostfs_commit_write + .write_begin = hostfs_write_begin, + .write_end = hostfs_write_end, }; static int init_inode(struct inode *inode, struct dentry *dentry) @@ -534,28 +521,28 @@ static int init_inode(struct inode *inode, struct dentry *dentry) int maj, min; dev_t rdev = 0; - if(dentry){ + if (dentry) { name = dentry_name(dentry, 0); - if(name == NULL) + if (name == NULL) goto out; type = file_type(name, &maj, &min); - /*Reencode maj and min with the kernel encoding.*/ + /* Reencode maj and min with the kernel encoding.*/ rdev = MKDEV(maj, min); kfree(name); } else type = OS_TYPE_DIR; err = 0; - if(type == OS_TYPE_SYMLINK) + if (type == OS_TYPE_SYMLINK) inode->i_op = &page_symlink_inode_operations; - else if(type == OS_TYPE_DIR) + else if (type == OS_TYPE_DIR) inode->i_op = &hostfs_dir_iops; else inode->i_op = &hostfs_iops; - if(type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops; + if (type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops; else inode->i_fop = &hostfs_file_fops; - if(type == OS_TYPE_SYMLINK) + if (type == OS_TYPE_SYMLINK) inode->i_mapping->a_ops = &hostfs_link_aops; else inode->i_mapping->a_ops = &hostfs_aops; @@ -578,7 +565,7 @@ static int init_inode(struct inode *inode, struct dentry *dentry) } int hostfs_create(struct inode *dir, struct dentry *dentry, int mode, - struct nameidata *nd) + struct nameidata *nd) { struct inode *inode; char *name; @@ -586,27 +573,28 @@ int hostfs_create(struct inode *dir, struct dentry *dentry, int mode, error = -ENOMEM; inode = iget(dir->i_sb, 0); - if(inode == NULL) goto out; + if (inode == NULL) + goto out; error = init_inode(inode, dentry); - if(error) + if (error) goto out_put; error = -ENOMEM; name = dentry_name(dentry, 0); - if(name == NULL) + if (name == NULL) goto out_put; fd = file_create(name, mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR, mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP, mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH); - if(fd < 0) + if (fd < 0) error = fd; else error = read_name(inode, name); kfree(name); - if(error) + if (error) goto out_put; HOSTFS_I(inode)->fd = fd; @@ -629,25 +617,25 @@ struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry, err = -ENOMEM; inode = iget(ino->i_sb, 0); - if(inode == NULL) + if (inode == NULL) goto out; err = init_inode(inode, dentry); - if(err) + if (err) goto out_put; err = -ENOMEM; name = dentry_name(dentry, 0); - if(name == NULL) + if (name == NULL) goto out_put; err = read_name(inode, name); kfree(name); - if(err == -ENOENT){ + if (err == -ENOENT) { iput(inode); inode = NULL; } - else if(err) + else if (err) goto out_put; d_add(dentry, inode); @@ -666,7 +654,7 @@ static char *inode_dentry_name(struct inode *ino, struct dentry *dentry) int len; file = inode_name(ino, dentry->d_name.len + 1); - if(file == NULL) + if (file == NULL) return NULL; strcat(file, "/"); len = strlen(file); @@ -680,10 +668,10 @@ int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from) char *from_name, *to_name; int err; - if((from_name = inode_dentry_name(ino, from)) == NULL) + if ((from_name = inode_dentry_name(ino, from)) == NULL) return -ENOMEM; to_name = dentry_name(to, 0); - if(to_name == NULL){ + if (to_name == NULL) { kfree(from_name); return -ENOMEM; } @@ -698,9 +686,9 @@ int hostfs_unlink(struct inode *ino, struct dentry *dentry) char *file; int err; - if((file = inode_dentry_name(ino, dentry)) == NULL) + if ((file = inode_dentry_name(ino, dentry)) == NULL) return -ENOMEM; - if(append) + if (append) return -EPERM; err = unlink_file(file); @@ -713,7 +701,7 @@ int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to) char *file; int err; - if((file = inode_dentry_name(ino, dentry)) == NULL) + if ((file = inode_dentry_name(ino, dentry)) == NULL) return -ENOMEM; err = make_symlink(file, to); kfree(file); @@ -725,7 +713,7 @@ int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode) char *file; int err; - if((file = inode_dentry_name(ino, dentry)) == NULL) + if ((file = inode_dentry_name(ino, dentry)) == NULL) return -ENOMEM; err = do_mkdir(file, mode); kfree(file); @@ -737,7 +725,7 @@ int hostfs_rmdir(struct inode *ino, struct dentry *dentry) char *file; int err; - if((file = inode_dentry_name(ino, dentry)) == NULL) + if ((file = inode_dentry_name(ino, dentry)) == NULL) return -ENOMEM; err = do_rmdir(file); kfree(file); @@ -751,26 +739,26 @@ int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) int err = -ENOMEM; inode = iget(dir->i_sb, 0); - if(inode == NULL) + if (inode == NULL) goto out; err = init_inode(inode, dentry); - if(err) + if (err) goto out_put; err = -ENOMEM; name = dentry_name(dentry, 0); - if(name == NULL) + if (name == NULL) goto out_put; init_special_inode(inode, mode, dev); err = do_mknod(name, mode, MAJOR(dev), MINOR(dev)); - if(err) + if (err) goto out_free; err = read_name(inode, name); kfree(name); - if(err) + if (err) goto out_put; d_instantiate(dentry, inode); @@ -790,9 +778,9 @@ int hostfs_rename(struct inode *from_ino, struct dentry *from, char *from_name, *to_name; int err; - if((from_name = inode_dentry_name(from_ino, from)) == NULL) + if ((from_name = inode_dentry_name(from_ino, from)) == NULL) return -ENOMEM; - if((to_name = inode_dentry_name(to_ino, to)) == NULL){ + if ((to_name = inode_dentry_name(to_ino, to)) == NULL) { kfree(from_name); return -ENOMEM; } @@ -815,12 +803,12 @@ int hostfs_permission(struct inode *ino, int desired, struct nameidata *nd) return -ENOMEM; if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) || - S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode)) + S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode)) err = 0; else err = access_file(name, r, w, x); kfree(name); - if(!err) + if (!err) err = generic_permission(ino, desired, NULL); return err; } @@ -837,62 +825,55 @@ int hostfs_setattr(struct dentry *dentry, struct iattr *attr) if (err) return err; - if(append) + if (append) attr->ia_valid &= ~ATTR_SIZE; attrs.ia_valid = 0; - if(attr->ia_valid & ATTR_MODE){ + if (attr->ia_valid & ATTR_MODE) { attrs.ia_valid |= HOSTFS_ATTR_MODE; attrs.ia_mode = attr->ia_mode; } - if(attr->ia_valid & ATTR_UID){ + if (attr->ia_valid & ATTR_UID) { attrs.ia_valid |= HOSTFS_ATTR_UID; attrs.ia_uid = attr->ia_uid; } - if(attr->ia_valid & ATTR_GID){ + if (attr->ia_valid & ATTR_GID) { attrs.ia_valid |= HOSTFS_ATTR_GID; attrs.ia_gid = attr->ia_gid; } - if(attr->ia_valid & ATTR_SIZE){ + if (attr->ia_valid & ATTR_SIZE) { attrs.ia_valid |= HOSTFS_ATTR_SIZE; attrs.ia_size = attr->ia_size; } - if(attr->ia_valid & ATTR_ATIME){ + if (attr->ia_valid & ATTR_ATIME) { attrs.ia_valid |= HOSTFS_ATTR_ATIME; attrs.ia_atime = attr->ia_atime; } - if(attr->ia_valid & ATTR_MTIME){ + if (attr->ia_valid & ATTR_MTIME) { attrs.ia_valid |= HOSTFS_ATTR_MTIME; attrs.ia_mtime = attr->ia_mtime; } - if(attr->ia_valid & ATTR_CTIME){ + if (attr->ia_valid & ATTR_CTIME) { attrs.ia_valid |= HOSTFS_ATTR_CTIME; attrs.ia_ctime = attr->ia_ctime; } - if(attr->ia_valid & ATTR_ATIME_SET){ + if (attr->ia_valid & ATTR_ATIME_SET) { attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET; } - if(attr->ia_valid & ATTR_MTIME_SET){ + if (attr->ia_valid & ATTR_MTIME_SET) { attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET; } name = dentry_name(dentry, 0); - if(name == NULL) + if (name == NULL) return -ENOMEM; err = set_attr(name, &attrs, fd); kfree(name); - if(err) + if (err) return err; return inode_setattr(dentry->d_inode, attr); } -int hostfs_getattr(struct vfsmount *mnt, struct dentry *dentry, - struct kstat *stat) -{ - generic_fillattr(dentry->d_inode, stat); - return 0; -} - static const struct inode_operations hostfs_iops = { .create = hostfs_create, .link = hostfs_link, @@ -904,7 +885,6 @@ static const struct inode_operations hostfs_iops = { .rename = hostfs_rename, .permission = hostfs_permission, .setattr = hostfs_setattr, - .getattr = hostfs_getattr, }; static const struct inode_operations hostfs_dir_iops = { @@ -919,7 +899,6 @@ static const struct inode_operations hostfs_dir_iops = { .rename = hostfs_rename, .permission = hostfs_permission, .setattr = hostfs_setattr, - .getattr = hostfs_getattr, }; int hostfs_link_readpage(struct file *file, struct page *page) @@ -929,13 +908,13 @@ int hostfs_link_readpage(struct file *file, struct page *page) buffer = kmap(page); name = inode_name(page->mapping->host, 0); - if(name == NULL) + if (name == NULL) return -ENOMEM; err = do_readlink(name, buffer, PAGE_CACHE_SIZE); kfree(name); - if(err == PAGE_CACHE_SIZE) + if (err == PAGE_CACHE_SIZE) err = -E2BIG; - else if(err > 0){ + else if (err > 0) { flush_dcache_page(page); SetPageUptodate(page); if (PageError(page)) ClearPageError(page); @@ -968,31 +947,33 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent) err = -ENOMEM; host_root_path = kmalloc(strlen(root_ino) + 1 + strlen(req_root) + 1, GFP_KERNEL); - if(host_root_path == NULL) + if (host_root_path == NULL) goto out; sprintf(host_root_path, "%s/%s", root_ino, req_root); root_inode = iget(sb, 0); - if(root_inode == NULL) + if (root_inode == NULL) goto out_free; err = init_inode(root_inode, NULL); - if(err) + if (err) goto out_put; HOSTFS_I(root_inode)->host_filename = host_root_path; - /* Avoid that in the error path, iput(root_inode) frees again - * host_root_path through hostfs_destroy_inode! */ + /* + * Avoid that in the error path, iput(root_inode) frees again + * host_root_path through hostfs_destroy_inode! + */ host_root_path = NULL; err = -ENOMEM; sb->s_root = d_alloc_root(root_inode); - if(sb->s_root == NULL) + if (sb->s_root == NULL) goto out_put; err = read_inode(root_inode); - if(err){ + if (err) { /* No iput in this case because the dput does that for us */ dput(sb->s_root); sb->s_root = NULL; diff --git a/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c index 5625e2481dd3..35c1a9f33f47 100644 --- a/fs/hostfs/hostfs_user.c +++ b/fs/hostfs/hostfs_user.c @@ -3,19 +3,21 @@ * Licensed under the GPL */ -#include <unistd.h> #include <stdio.h> -#include <fcntl.h> +#include <stddef.h> +#include <unistd.h> #include <dirent.h> #include <errno.h> -#include <utime.h> +#include <fcntl.h> #include <string.h> #include <sys/stat.h> #include <sys/time.h> +#include <sys/types.h> #include <sys/vfs.h> #include "hostfs.h" -#include "kern_util.h" +#include "os.h" #include "user.h" +#include <utime.h> int stat_file(const char *path, unsigned long long *inode_out, int *mode_out, int *nlink_out, int *uid_out, int *gid_out, @@ -25,33 +27,41 @@ int stat_file(const char *path, unsigned long long *inode_out, int *mode_out, { struct stat64 buf; - if(fd >= 0) { + if (fd >= 0) { if (fstat64(fd, &buf) < 0) return -errno; - } else if(lstat64(path, &buf) < 0) { + } else if (lstat64(path, &buf) < 0) { return -errno; } - if(inode_out != NULL) *inode_out = buf.st_ino; - if(mode_out != NULL) *mode_out = buf.st_mode; - if(nlink_out != NULL) *nlink_out = buf.st_nlink; - if(uid_out != NULL) *uid_out = buf.st_uid; - if(gid_out != NULL) *gid_out = buf.st_gid; - if(size_out != NULL) *size_out = buf.st_size; - if(atime_out != NULL) { + if (inode_out != NULL) + *inode_out = buf.st_ino; + if (mode_out != NULL) + *mode_out = buf.st_mode; + if (nlink_out != NULL) + *nlink_out = buf.st_nlink; + if (uid_out != NULL) + *uid_out = buf.st_uid; + if (gid_out != NULL) + *gid_out = buf.st_gid; + if (size_out != NULL) + *size_out = buf.st_size; + if (atime_out != NULL) { atime_out->tv_sec = buf.st_atime; atime_out->tv_nsec = 0; } - if(mtime_out != NULL) { + if (mtime_out != NULL) { mtime_out->tv_sec = buf.st_mtime; mtime_out->tv_nsec = 0; } - if(ctime_out != NULL) { + if (ctime_out != NULL) { ctime_out->tv_sec = buf.st_ctime; ctime_out->tv_nsec = 0; } - if(blksize_out != NULL) *blksize_out = buf.st_blksize; - if(blocks_out != NULL) *blocks_out = buf.st_blocks; + if (blksize_out != NULL) + *blksize_out = buf.st_blksize; + if (blocks_out != NULL) + *blocks_out = buf.st_blocks; return 0; } @@ -59,21 +69,29 @@ int file_type(const char *path, int *maj, int *min) { struct stat64 buf; - if(lstat64(path, &buf) < 0) + if (lstat64(path, &buf) < 0) return -errno; - /*We cannot pass rdev as is because glibc and the kernel disagree - *about its definition.*/ - if(maj != NULL) + /* + * We cannot pass rdev as is because glibc and the kernel disagree + * about its definition. + */ + if (maj != NULL) *maj = major(buf.st_rdev); - if(min != NULL) + if (min != NULL) *min = minor(buf.st_rdev); - if(S_ISDIR(buf.st_mode)) return OS_TYPE_DIR; - else if(S_ISLNK(buf.st_mode)) return OS_TYPE_SYMLINK; - else if(S_ISCHR(buf.st_mode)) return OS_TYPE_CHARDEV; - else if(S_ISBLK(buf.st_mode)) return OS_TYPE_BLOCKDEV; - else if(S_ISFIFO(buf.st_mode))return OS_TYPE_FIFO; - else if(S_ISSOCK(buf.st_mode))return OS_TYPE_SOCK; + if (S_ISDIR(buf.st_mode)) + return OS_TYPE_DIR; + else if (S_ISLNK(buf.st_mode)) + return OS_TYPE_SYMLINK; + else if (S_ISCHR(buf.st_mode)) + return OS_TYPE_CHARDEV; + else if (S_ISBLK(buf.st_mode)) + return OS_TYPE_BLOCKDEV; + else if (S_ISFIFO(buf.st_mode)) + return OS_TYPE_FIFO; + else if (S_ISSOCK(buf.st_mode)) + return OS_TYPE_SOCK; else return OS_TYPE_FILE; } @@ -81,10 +99,13 @@ int access_file(char *path, int r, int w, int x) { int mode = 0; - if(r) mode = R_OK; - if(w) mode |= W_OK; - if(x) mode |= X_OK; - if(access(path, mode) != 0) + if (r) + mode = R_OK; + if (w) + mode |= W_OK; + if (x) + mode |= X_OK; + if (access(path, mode) != 0) return -errno; else return 0; } @@ -93,18 +114,18 @@ int open_file(char *path, int r, int w, int append) { int mode = 0, fd; - if(r && !w) + if (r && !w) mode = O_RDONLY; - else if(!r && w) + else if (!r && w) mode = O_WRONLY; - else if(r && w) + else if (r && w) mode = O_RDWR; else panic("Impossible mode in open_file"); - if(append) + if (append) mode |= O_APPEND; fd = open64(path, mode); - if(fd < 0) + if (fd < 0) return -errno; else return fd; } @@ -115,7 +136,7 @@ void *open_dir(char *path, int *err_out) dir = opendir(path); *err_out = errno; - if(dir == NULL) + if (dir == NULL) return NULL; return dir; } @@ -128,7 +149,7 @@ char *read_dir(void *stream, unsigned long long *pos, seekdir(dir, *pos); ent = readdir(dir); - if(ent == NULL) + if (ent == NULL) return NULL; *len_out = strlen(ent->d_name); *ino_out = ent->d_ino; @@ -141,7 +162,7 @@ int read_file(int fd, unsigned long long *offset, char *buf, int len) int n; n = pread64(fd, buf, len, *offset); - if(n < 0) + if (n < 0) return -errno; *offset += n; return n; @@ -152,7 +173,7 @@ int write_file(int fd, unsigned long long *offset, const char *buf, int len) int n; n = pwrite64(fd, buf, len, *offset); - if(n < 0) + if (n < 0) return -errno; *offset += n; return n; @@ -163,7 +184,7 @@ int lseek_file(int fd, long long offset, int whence) int ret; ret = lseek64(fd, offset, whence); - if(ret < 0) + if (ret < 0) return -errno; return 0; } @@ -207,7 +228,7 @@ int file_create(char *name, int ur, int uw, int ux, int gr, mode |= ow ? S_IWOTH : 0; mode |= ox ? S_IXOTH : 0; fd = open64(name, O_CREAT | O_RDWR, mode); - if(fd < 0) + if (fd < 0) return -errno; return fd; } @@ -230,7 +251,7 @@ int set_attr(const char *file, struct hostfs_iattr *attrs, int fd) if (fd >= 0) { if (fchown(fd, attrs->ia_uid, -1)) return -errno; - } else if(chown(file, attrs->ia_uid, -1)) { + } else if (chown(file, attrs->ia_uid, -1)) { return -errno; } } @@ -251,9 +272,11 @@ int set_attr(const char *file, struct hostfs_iattr *attrs, int fd) } } - /* Update accessed and/or modified time, in two parts: first set + /* + * Update accessed and/or modified time, in two parts: first set * times according to the changes to perform, and then call futimes() - * or utimes() to apply them. */ + * or utimes() to apply them. + */ ma = (HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET); if (attrs->ia_valid & ma) { err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL, @@ -283,12 +306,12 @@ int set_attr(const char *file, struct hostfs_iattr *attrs, int fd) } } - if(attrs->ia_valid & HOSTFS_ATTR_CTIME) ; - if(attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)){ + /* Note: ctime is not handled */ + if (attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)) { err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL, &attrs->ia_atime, &attrs->ia_mtime, NULL, NULL, NULL, fd); - if(err != 0) + if (err != 0) return err; } return 0; @@ -299,7 +322,7 @@ int make_symlink(const char *from, const char *to) int err; err = symlink(to, from); - if(err) + if (err) return -errno; return 0; } @@ -309,7 +332,7 @@ int unlink_file(const char *file) int err; err = unlink(file); - if(err) + if (err) return -errno; return 0; } @@ -319,7 +342,7 @@ int do_mkdir(const char *file, int mode) int err; err = mkdir(file, mode); - if(err) + if (err) return -errno; return 0; } @@ -329,7 +352,7 @@ int do_rmdir(const char *file) int err; err = rmdir(file); - if(err) + if (err) return -errno; return 0; } @@ -339,7 +362,7 @@ int do_mknod(const char *file, int mode, unsigned int major, unsigned int minor) int err; err = mknod(file, mode, makedev(major, minor)); - if(err) + if (err) return -errno; return 0; } @@ -349,7 +372,7 @@ int link_file(const char *to, const char *from) int err; err = link(to, from); - if(err) + if (err) return -errno; return 0; } @@ -359,9 +382,9 @@ int do_readlink(char *file, char *buf, int size) int n; n = readlink(file, buf, size); - if(n < 0) + if (n < 0) return -errno; - if(n < size) + if (n < size) buf[n] = '\0'; return n; } @@ -371,7 +394,7 @@ int rename_file(char *from, char *to) int err; err = rename(from, to); - if(err < 0) + if (err < 0) return -errno; return 0; } @@ -386,7 +409,7 @@ int do_statfs(char *root, long *bsize_out, long long *blocks_out, int err; err = statfs64(root, &buf); - if(err < 0) + if (err < 0) return -errno; *bsize_out = buf.f_bsize; diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c index 5b53e5c5d8df..be8be5040e07 100644 --- a/fs/hpfs/file.c +++ b/fs/hpfs/file.c @@ -86,25 +86,33 @@ static int hpfs_writepage(struct page *page, struct writeback_control *wbc) { return block_write_full_page(page,hpfs_get_block, wbc); } + static int hpfs_readpage(struct file *file, struct page *page) { return block_read_full_page(page,hpfs_get_block); } -static int hpfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) + +static int hpfs_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - return cont_prepare_write(page,from,to,hpfs_get_block, - &hpfs_i(page->mapping->host)->mmu_private); + *pagep = NULL; + return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + hpfs_get_block, + &hpfs_i(mapping->host)->mmu_private); } + static sector_t _hpfs_bmap(struct address_space *mapping, sector_t block) { return generic_block_bmap(mapping,block,hpfs_get_block); } + const struct address_space_operations hpfs_aops = { .readpage = hpfs_readpage, .writepage = hpfs_writepage, .sync_page = block_sync_page, - .prepare_write = hpfs_prepare_write, - .commit_write = generic_commit_write, + .write_begin = hpfs_write_begin, + .write_end = generic_write_end, .bmap = _hpfs_bmap }; diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 89612ee7c80d..00971d999964 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -173,7 +173,7 @@ static void hpfs_destroy_inode(struct inode *inode) kmem_cache_free(hpfs_inode_cachep, hpfs_i(inode)); } -static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(struct kmem_cache *cachep, void *foo) { struct hpfs_inode_info *ei = (struct hpfs_inode_info *) foo; diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 950c2fbb815b..12aca8ed605f 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -179,6 +179,130 @@ full_search: } #endif +static int +hugetlbfs_read_actor(struct page *page, unsigned long offset, + char __user *buf, unsigned long count, + unsigned long size) +{ + char *kaddr; + unsigned long left, copied = 0; + int i, chunksize; + + if (size > count) + size = count; + + /* Find which 4k chunk and offset with in that chunk */ + i = offset >> PAGE_CACHE_SHIFT; + offset = offset & ~PAGE_CACHE_MASK; + + while (size) { + chunksize = PAGE_CACHE_SIZE; + if (offset) + chunksize -= offset; + if (chunksize > size) + chunksize = size; + kaddr = kmap(&page[i]); + left = __copy_to_user(buf, kaddr + offset, chunksize); + kunmap(&page[i]); + if (left) { + copied += (chunksize - left); + break; + } + offset = 0; + size -= chunksize; + buf += chunksize; + copied += chunksize; + i++; + } + return copied ? copied : -EFAULT; +} + +/* + * Support for read() - Find the page attached to f_mapping and copy out the + * data. Its *very* similar to do_generic_mapping_read(), we can't use that + * since it has PAGE_CACHE_SIZE assumptions. + */ +static ssize_t hugetlbfs_read(struct file *filp, char __user *buf, + size_t len, loff_t *ppos) +{ + struct address_space *mapping = filp->f_mapping; + struct inode *inode = mapping->host; + unsigned long index = *ppos >> HPAGE_SHIFT; + unsigned long offset = *ppos & ~HPAGE_MASK; + unsigned long end_index; + loff_t isize; + ssize_t retval = 0; + + mutex_lock(&inode->i_mutex); + + /* validate length */ + if (len == 0) + goto out; + + isize = i_size_read(inode); + if (!isize) + goto out; + + end_index = (isize - 1) >> HPAGE_SHIFT; + for (;;) { + struct page *page; + int nr, ret; + + /* nr is the maximum number of bytes to copy from this page */ + nr = HPAGE_SIZE; + if (index >= end_index) { + if (index > end_index) + goto out; + nr = ((isize - 1) & ~HPAGE_MASK) + 1; + if (nr <= offset) { + goto out; + } + } + nr = nr - offset; + + /* Find the page */ + page = find_get_page(mapping, index); + if (unlikely(page == NULL)) { + /* + * We have a HOLE, zero out the user-buffer for the + * length of the hole or request. + */ + ret = len < nr ? len : nr; + if (clear_user(buf, ret)) + ret = -EFAULT; + } else { + /* + * We have the page, copy it to user space buffer. + */ + ret = hugetlbfs_read_actor(page, offset, buf, len, nr); + } + if (ret < 0) { + if (retval == 0) + retval = ret; + if (page) + page_cache_release(page); + goto out; + } + + offset += ret; + retval += ret; + len -= ret; + index += offset >> HPAGE_SHIFT; + offset &= ~HPAGE_MASK; + + if (page) + page_cache_release(page); + + /* short read or no more work */ + if ((ret != nr) || (len == 0)) + break; + } +out: + *ppos = ((loff_t)index << HPAGE_SHIFT) + offset; + mutex_unlock(&inode->i_mutex); + return retval; +} + /* * Read a page. Again trivial. If it didn't already exist * in the page cache, it is zero-filled. @@ -189,15 +313,19 @@ static int hugetlbfs_readpage(struct file *file, struct page * page) return -EINVAL; } -static int hugetlbfs_prepare_write(struct file *file, - struct page *page, unsigned offset, unsigned to) +static int hugetlbfs_write_begin(struct file *file, + struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { return -EINVAL; } -static int hugetlbfs_commit_write(struct file *file, - struct page *page, unsigned offset, unsigned to) +static int hugetlbfs_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) { + BUG(); return -EINVAL; } @@ -256,7 +384,7 @@ static void hugetlbfs_forget_inode(struct inode *inode) __releases(inode_lock) struct super_block *sb = inode->i_sb; if (!hlist_unhashed(&inode->i_hash)) { - if (!(inode->i_state & (I_DIRTY|I_LOCK))) + if (!(inode->i_state & (I_DIRTY|I_SYNC))) list_move(&inode->i_list, &inode_unused); inodes_stat.nr_unused++; if (!sb || (sb->s_flags & MS_ACTIVE)) { @@ -318,21 +446,15 @@ hugetlb_vmtruncate_list(struct prio_tree_root *root, pgoff_t pgoff) } } -/* - * Expanding truncates are not allowed. - */ static int hugetlb_vmtruncate(struct inode *inode, loff_t offset) { pgoff_t pgoff; struct address_space *mapping = inode->i_mapping; - if (offset > inode->i_size) - return -EINVAL; - BUG_ON(offset & ~HPAGE_MASK); pgoff = offset >> PAGE_SHIFT; - inode->i_size = offset; + i_size_write(inode, offset); spin_lock(&mapping->i_mmap_lock); if (!prio_tree_empty(&mapping->i_mmap)) hugetlb_vmtruncate_list(&mapping->i_mmap, pgoff); @@ -569,13 +691,13 @@ static void hugetlbfs_destroy_inode(struct inode *inode) static const struct address_space_operations hugetlbfs_aops = { .readpage = hugetlbfs_readpage, - .prepare_write = hugetlbfs_prepare_write, - .commit_write = hugetlbfs_commit_write, + .write_begin = hugetlbfs_write_begin, + .write_end = hugetlbfs_write_end, .set_page_dirty = hugetlbfs_set_page_dirty, }; -static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags) +static void init_once(struct kmem_cache *cachep, void *foo) { struct hugetlbfs_inode_info *ei = (struct hugetlbfs_inode_info *)foo; @@ -583,6 +705,7 @@ static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags) } const struct file_operations hugetlbfs_file_operations = { + .read = hugetlbfs_read, .mmap = hugetlbfs_file_mmap, .fsync = simple_sync_file, .get_unmapped_area = hugetlb_get_unmapped_area, @@ -810,16 +933,11 @@ struct file *hugetlb_file_setup(const char *name, size_t size) if (!dentry) goto out_shm_unlock; - error = -ENFILE; - file = get_empty_filp(); - if (!file) - goto out_dentry; - error = -ENOSPC; inode = hugetlbfs_get_inode(root->d_sb, current->fsuid, current->fsgid, S_IFREG | S_IRWXUGO, 0); if (!inode) - goto out_file; + goto out_dentry; error = -ENOMEM; if (hugetlb_reserve_pages(inode, 0, size >> HPAGE_SHIFT)) @@ -828,17 +946,18 @@ struct file *hugetlb_file_setup(const char *name, size_t size) d_instantiate(dentry, inode); inode->i_size = size; inode->i_nlink = 0; - file->f_path.mnt = mntget(hugetlbfs_vfsmount); - file->f_path.dentry = dentry; - file->f_mapping = inode->i_mapping; - file->f_op = &hugetlbfs_file_operations; - file->f_mode = FMODE_WRITE | FMODE_READ; + + error = -ENFILE; + file = alloc_file(hugetlbfs_vfsmount, dentry, + FMODE_WRITE | FMODE_READ, + &hugetlbfs_file_operations); + if (!file) + goto out_inode; + return file; out_inode: iput(inode); -out_file: - put_filp(file); out_dentry: dput(dentry); out_shm_unlock: @@ -851,11 +970,15 @@ static int __init init_hugetlbfs_fs(void) int error; struct vfsmount *vfsmount; + error = bdi_init(&hugetlbfs_backing_dev_info); + if (error) + return error; + hugetlbfs_inode_cachep = kmem_cache_create("hugetlbfs_inode_cache", sizeof(struct hugetlbfs_inode_info), 0, 0, init_once); if (hugetlbfs_inode_cachep == NULL) - return -ENOMEM; + goto out2; error = register_filesystem(&hugetlbfs_fs_type); if (error) @@ -873,6 +996,8 @@ static int __init init_hugetlbfs_fs(void) out: if (error) kmem_cache_destroy(hugetlbfs_inode_cachep); + out2: + bdi_destroy(&hugetlbfs_backing_dev_info); return error; } @@ -880,6 +1005,7 @@ static void __exit exit_hugetlbfs_fs(void) { kmem_cache_destroy(hugetlbfs_inode_cachep); unregister_filesystem(&hugetlbfs_fs_type); + bdi_destroy(&hugetlbfs_backing_dev_info); } module_init(init_hugetlbfs_fs) diff --git a/fs/inode.c b/fs/inode.c index 29f5068f819b..ed35383d0b6c 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -99,6 +99,15 @@ struct inodes_stat_t inodes_stat; static struct kmem_cache * inode_cachep __read_mostly; +static void wake_up_inode(struct inode *inode) +{ + /* + * Prevent speculative execution through spin_unlock(&inode_lock); + */ + smp_mb(); + wake_up_bit(&inode->i_state, __I_LOCK); +} + static struct inode *alloc_inode(struct super_block *sb) { static const struct address_space_operations empty_aops; @@ -142,6 +151,15 @@ static struct inode *alloc_inode(struct super_block *sb) return NULL; } + spin_lock_init(&inode->i_lock); + lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key); + + mutex_init(&inode->i_mutex); + lockdep_set_class(&inode->i_mutex, &sb->s_type->i_mutex_key); + + init_rwsem(&inode->i_alloc_sem); + lockdep_set_class(&inode->i_alloc_sem, &sb->s_type->i_alloc_sem_key); + mapping->a_ops = &empty_aops; mapping->host = inode; mapping->flags = 0; @@ -190,8 +208,6 @@ void inode_init_once(struct inode *inode) INIT_HLIST_NODE(&inode->i_hash); INIT_LIST_HEAD(&inode->i_dentry); INIT_LIST_HEAD(&inode->i_devices); - mutex_init(&inode->i_mutex); - init_rwsem(&inode->i_alloc_sem); INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC); rwlock_init(&inode->i_data.tree_lock); spin_lock_init(&inode->i_data.i_mmap_lock); @@ -199,7 +215,6 @@ void inode_init_once(struct inode *inode) spin_lock_init(&inode->i_data.private_lock); INIT_RAW_PRIO_TREE_ROOT(&inode->i_data.i_mmap); INIT_LIST_HEAD(&inode->i_data.i_mmap_nonlinear); - spin_lock_init(&inode->i_lock); i_size_ordered_init(inode); #ifdef CONFIG_INOTIFY INIT_LIST_HEAD(&inode->inotify_watches); @@ -209,7 +224,7 @@ void inode_init_once(struct inode *inode) EXPORT_SYMBOL(inode_init_once); -static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(struct kmem_cache * cachep, void *foo) { struct inode * inode = (struct inode *) foo; @@ -226,7 +241,7 @@ void __iget(struct inode * inode) return; } atomic_inc(&inode->i_count); - if (!(inode->i_state & (I_DIRTY|I_LOCK))) + if (!(inode->i_state & (I_DIRTY|I_SYNC))) list_move(&inode->i_list, &inode_in_use); inodes_stat.nr_unused--; } @@ -247,7 +262,7 @@ void clear_inode(struct inode *inode) BUG_ON(inode->i_data.nrpages); BUG_ON(!(inode->i_state & I_FREEING)); BUG_ON(inode->i_state & I_CLEAR); - wait_on_inode(inode); + inode_sync_wait(inode); DQUOT_DROP(inode); if (inode->i_sb->s_op->clear_inode) inode->i_sb->s_op->clear_inode(inode); @@ -561,6 +576,18 @@ EXPORT_SYMBOL(new_inode); void unlock_new_inode(struct inode *inode) { +#ifdef CONFIG_DEBUG_LOCK_ALLOC + if (inode->i_mode & S_IFDIR) { + struct file_system_type *type = inode->i_sb->s_type; + + /* + * ensure nobody is actually holding i_mutex + */ + mutex_destroy(&inode->i_mutex); + mutex_init(&inode->i_mutex); + lockdep_set_class(&inode->i_mutex, &type->i_mutex_dir_key); + } +#endif /* * This is special! We do not need the spinlock * when clearing I_LOCK, because we're guaranteed @@ -1053,7 +1080,7 @@ static void generic_forget_inode(struct inode *inode) struct super_block *sb = inode->i_sb; if (!hlist_unhashed(&inode->i_hash)) { - if (!(inode->i_state & (I_DIRTY|I_LOCK))) + if (!(inode->i_state & (I_DIRTY|I_SYNC))) list_move(&inode->i_list, &inode_unused); inodes_stat.nr_unused++; if (sb->s_flags & MS_ACTIVE) { @@ -1296,15 +1323,6 @@ static void __wait_on_freeing_inode(struct inode *inode) spin_lock(&inode_lock); } -void wake_up_inode(struct inode *inode) -{ - /* - * Prevent speculative execution through spin_unlock(&inode_lock); - */ - smp_mb(); - wake_up_bit(&inode->i_state, __I_LOCK); -} - /* * We rarely want to lock two inodes that do not have a parent/child * relationship (such as directory, child inode) simultaneously. The @@ -1378,7 +1396,7 @@ void __init inode_init_early(void) INIT_HLIST_HEAD(&inode_hashtable[loop]); } -void __init inode_init(unsigned long mempages) +void __init inode_init(void) { int loop; diff --git a/fs/inotify_user.c b/fs/inotify_user.c index 9bf2f6c09df6..5e009331c01f 100644 --- a/fs/inotify_user.c +++ b/fs/inotify_user.c @@ -31,6 +31,7 @@ #include <linux/list.h> #include <linux/inotify.h> #include <linux/syscalls.h> +#include <linux/magic.h> #include <asm/ioctls.h> @@ -684,7 +685,8 @@ static int inotify_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_pseudo(fs_type, "inotify", NULL, 0xBAD1DEA, mnt); + return get_sb_pseudo(fs_type, "inotify", NULL, + INOTIFYFS_SUPER_MAGIC, mnt); } static struct file_system_type inotify_fs_type = { diff --git a/fs/ioprio.c b/fs/ioprio.c index 10d2c211d18b..d6ff77e8e7ec 100644 --- a/fs/ioprio.c +++ b/fs/ioprio.c @@ -25,6 +25,7 @@ #include <linux/capability.h> #include <linux/syscalls.h> #include <linux/security.h> +#include <linux/pid_namespace.h> static int set_task_ioprio(struct task_struct *task, int ioprio) { @@ -93,7 +94,7 @@ asmlinkage long sys_ioprio_set(int which, int who, int ioprio) if (!who) p = current; else - p = find_task_by_pid(who); + p = find_task_by_vpid(who); if (p) ret = set_task_ioprio(p, ioprio); break; @@ -101,7 +102,7 @@ asmlinkage long sys_ioprio_set(int which, int who, int ioprio) if (!who) pgrp = task_pgrp(current); else - pgrp = find_pid(who); + pgrp = find_vpid(who); do_each_pid_task(pgrp, PIDTYPE_PGID, p) { ret = set_task_ioprio(p, ioprio); if (ret) @@ -180,7 +181,7 @@ asmlinkage long sys_ioprio_get(int which, int who) if (!who) p = current; else - p = find_task_by_pid(who); + p = find_task_by_vpid(who); if (p) ret = get_task_ioprio(p); break; @@ -188,7 +189,7 @@ asmlinkage long sys_ioprio_get(int which, int who) if (!who) pgrp = task_pgrp(current); else - pgrp = find_pid(who); + pgrp = find_vpid(who); do_each_pid_task(pgrp, PIDTYPE_PGID, p) { tmpio = get_task_ioprio(p); if (tmpio < 0) diff --git a/fs/isofs/compress.c b/fs/isofs/compress.c index 6bbbdb53581d..37dbd6404787 100644 --- a/fs/isofs/compress.c +++ b/fs/isofs/compress.c @@ -33,7 +33,7 @@ static char zisofs_sink_page[PAGE_CACHE_SIZE]; * allocation; this avoids failures at block-decompression time. */ static void *zisofs_zlib_workspace; -static struct semaphore zisofs_zlib_semaphore; +static DEFINE_MUTEX(zisofs_zlib_lock); /* * When decompressing, we typically obtain more than one page @@ -180,9 +180,9 @@ static int zisofs_readpage(struct file *file, struct page *page) /* First block is special since it may be fractional. We also wait for it before grabbing the zlib - semaphore; odds are that the subsequent blocks are + mutex; odds are that the subsequent blocks are going to come in in short order so we don't hold - the zlib semaphore longer than necessary. */ + the zlib mutex longer than necessary. */ if ( !bh || (wait_on_buffer(bh), !buffer_uptodate(bh)) ) { printk(KERN_DEBUG "zisofs: Hit null buffer, fpage = %d, xpage = %d, csize = %ld\n", @@ -194,7 +194,7 @@ static int zisofs_readpage(struct file *file, struct page *page) csize -= stream.avail_in; stream.workspace = zisofs_zlib_workspace; - down(&zisofs_zlib_semaphore); + mutex_lock(&zisofs_zlib_lock); zerr = zlib_inflateInit(&stream); if ( zerr != Z_OK ) { @@ -281,7 +281,7 @@ static int zisofs_readpage(struct file *file, struct page *page) zlib_inflateEnd(&stream); z_eio: - up(&zisofs_zlib_semaphore); + mutex_unlock(&zisofs_zlib_lock); b_eio: for ( i = 0 ; i < haveblocks ; i++ ) { @@ -317,31 +317,16 @@ const struct address_space_operations zisofs_aops = { /* No bmap operation supported */ }; -static int initialized; - int __init zisofs_init(void) { - if ( initialized ) { - printk("zisofs_init: called more than once\n"); - return 0; - } - zisofs_zlib_workspace = vmalloc(zlib_inflate_workspacesize()); if ( !zisofs_zlib_workspace ) return -ENOMEM; - init_MUTEX(&zisofs_zlib_semaphore); - initialized = 1; return 0; } void zisofs_cleanup(void) { - if ( !initialized ) { - printk("zisofs_cleanup: called without initialization\n"); - return; - } - vfree(zisofs_zlib_workspace); - initialized = 0; } diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 043b470fd3b6..aa359a2e4ce6 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -73,7 +73,7 @@ static void isofs_destroy_inode(struct inode *inode) kmem_cache_free(isofs_inode_cachep, ISOFS_I(inode)); } -static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags) +static void init_once(struct kmem_cache *cachep, void *foo) { struct iso_inode_info *ei = foo; diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c index c8c7e5138a01..e2b4dad39ca9 100644 --- a/fs/isofs/namei.c +++ b/fs/isofs/namei.c @@ -158,7 +158,8 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry, struct dentry *isofs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { int found; - unsigned long block, offset; + unsigned long uninitialized_var(block); + unsigned long uninitialized_var(offset); struct inode *inode; struct page *page; diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index a003d50edcdb..8f1f2aa5fb39 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c @@ -375,7 +375,7 @@ void journal_commit_transaction(journal_t *journal) struct buffer_head *bh = jh2bh(jh); jbd_lock_bh_state(bh); - jbd_slab_free(jh->b_committed_data, bh->b_size); + jbd_free(jh->b_committed_data, bh->b_size); jh->b_committed_data = NULL; jbd_unlock_bh_state(bh); } @@ -466,7 +466,7 @@ void journal_commit_transaction(journal_t *journal) spin_unlock(&journal->j_list_lock); if (err) - __journal_abort_hard(journal); + journal_abort(journal, err); journal_write_revoke_records(journal, commit_transaction); @@ -524,7 +524,7 @@ void journal_commit_transaction(journal_t *journal) descriptor = journal_get_descriptor_buffer(journal); if (!descriptor) { - __journal_abort_hard(journal); + journal_abort(journal, -EIO); continue; } @@ -557,7 +557,7 @@ void journal_commit_transaction(journal_t *journal) and repeat this loop: we'll fall into the refile-on-abort condition above. */ if (err) { - __journal_abort_hard(journal); + journal_abort(journal, err); continue; } @@ -748,7 +748,7 @@ wait_for_iobuf: err = -EIO; if (err) - __journal_abort_hard(journal); + journal_abort(journal, err); /* End of a transaction! Finally, we can do checkpoint processing: any buffers committed as a result of this @@ -792,14 +792,14 @@ restart_loop: * Otherwise, we can just throw away the frozen data now. */ if (jh->b_committed_data) { - jbd_slab_free(jh->b_committed_data, bh->b_size); + jbd_free(jh->b_committed_data, bh->b_size); jh->b_committed_data = NULL; if (jh->b_frozen_data) { jh->b_committed_data = jh->b_frozen_data; jh->b_frozen_data = NULL; } } else if (jh->b_frozen_data) { - jbd_slab_free(jh->b_frozen_data, bh->b_size); + jbd_free(jh->b_frozen_data, bh->b_size); jh->b_frozen_data = NULL; } diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 06ab3c10b1b8..5d14243499d4 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -35,6 +35,7 @@ #include <linux/kthread.h> #include <linux/poison.h> #include <linux/proc_fs.h> +#include <linux/debugfs.h> #include <asm/uaccess.h> #include <asm/page.h> @@ -83,7 +84,6 @@ EXPORT_SYMBOL(journal_force_commit); static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *); static void __journal_abort_soft (journal_t *journal, int errno); -static int journal_create_jbd_slab(size_t slab_size); /* * Helper function used to manage commit timeouts @@ -218,7 +218,7 @@ static int journal_start_thread(journal_t *journal) if (IS_ERR(t)) return PTR_ERR(t); - wait_event(journal->j_wait_done_commit, journal->j_task != 0); + wait_event(journal->j_wait_done_commit, journal->j_task != NULL); return 0; } @@ -230,7 +230,8 @@ static void journal_kill_thread(journal_t *journal) while (journal->j_task) { wake_up(&journal->j_wait_commit); spin_unlock(&journal->j_state_lock); - wait_event(journal->j_wait_done_commit, journal->j_task == 0); + wait_event(journal->j_wait_done_commit, + journal->j_task == NULL); spin_lock(&journal->j_state_lock); } spin_unlock(&journal->j_state_lock); @@ -334,10 +335,10 @@ repeat: char *tmp; jbd_unlock_bh_state(bh_in); - tmp = jbd_slab_alloc(bh_in->b_size, GFP_NOFS); + tmp = jbd_alloc(bh_in->b_size, GFP_NOFS); jbd_lock_bh_state(bh_in); if (jh_in->b_frozen_data) { - jbd_slab_free(tmp, bh_in->b_size); + jbd_free(tmp, bh_in->b_size); goto repeat; } @@ -654,10 +655,9 @@ static journal_t * journal_init_common (void) journal_t *journal; int err; - journal = jbd_kmalloc(sizeof(*journal), GFP_KERNEL); + journal = kzalloc(sizeof(*journal), GFP_KERNEL); if (!journal) goto fail; - memset(journal, 0, sizeof(*journal)); init_waitqueue_head(&journal->j_wait_transaction_locked); init_waitqueue_head(&journal->j_wait_logspace); @@ -1095,13 +1095,6 @@ int journal_load(journal_t *journal) } } - /* - * Create a slab for this blocksize - */ - err = journal_create_jbd_slab(be32_to_cpu(sb->s_blocksize)); - if (err) - return err; - /* Let the recovery code check whether it needs to recover any * data from the journal. */ if (journal_recover(journal)) @@ -1615,86 +1608,6 @@ int journal_blocks_per_page(struct inode *inode) } /* - * Simple support for retrying memory allocations. Introduced to help to - * debug different VM deadlock avoidance strategies. - */ -void * __jbd_kmalloc (const char *where, size_t size, gfp_t flags, int retry) -{ - return kmalloc(size, flags | (retry ? __GFP_NOFAIL : 0)); -} - -/* - * jbd slab management: create 1k, 2k, 4k, 8k slabs as needed - * and allocate frozen and commit buffers from these slabs. - * - * Reason for doing this is to avoid, SLAB_DEBUG - since it could - * cause bh to cross page boundary. - */ - -#define JBD_MAX_SLABS 5 -#define JBD_SLAB_INDEX(size) (size >> 11) - -static struct kmem_cache *jbd_slab[JBD_MAX_SLABS]; -static const char *jbd_slab_names[JBD_MAX_SLABS] = { - "jbd_1k", "jbd_2k", "jbd_4k", NULL, "jbd_8k" -}; - -static void journal_destroy_jbd_slabs(void) -{ - int i; - - for (i = 0; i < JBD_MAX_SLABS; i++) { - if (jbd_slab[i]) - kmem_cache_destroy(jbd_slab[i]); - jbd_slab[i] = NULL; - } -} - -static int journal_create_jbd_slab(size_t slab_size) -{ - int i = JBD_SLAB_INDEX(slab_size); - - BUG_ON(i >= JBD_MAX_SLABS); - - /* - * Check if we already have a slab created for this size - */ - if (jbd_slab[i]) - return 0; - - /* - * Create a slab and force alignment to be same as slabsize - - * this will make sure that allocations won't cross the page - * boundary. - */ - jbd_slab[i] = kmem_cache_create(jbd_slab_names[i], - slab_size, slab_size, 0, NULL); - if (!jbd_slab[i]) { - printk(KERN_EMERG "JBD: no memory for jbd_slab cache\n"); - return -ENOMEM; - } - return 0; -} - -void * jbd_slab_alloc(size_t size, gfp_t flags) -{ - int idx; - - idx = JBD_SLAB_INDEX(size); - BUG_ON(jbd_slab[idx] == NULL); - return kmem_cache_alloc(jbd_slab[idx], flags | __GFP_NOFAIL); -} - -void jbd_slab_free(void *ptr, size_t size) -{ - int idx; - - idx = JBD_SLAB_INDEX(size); - BUG_ON(jbd_slab[idx] == NULL); - kmem_cache_free(jbd_slab[idx], ptr); -} - -/* * Journal_head storage management */ static struct kmem_cache *journal_head_cache; @@ -1710,7 +1623,7 @@ static int journal_init_journal_head_cache(void) journal_head_cache = kmem_cache_create("journal_head", sizeof(struct journal_head), 0, /* offset */ - 0, /* flags */ + SLAB_TEMPORARY, /* flags */ NULL); /* ctor */ retval = 0; if (journal_head_cache == 0) { @@ -1739,14 +1652,14 @@ static struct journal_head *journal_alloc_journal_head(void) atomic_inc(&nr_journal_heads); #endif ret = kmem_cache_alloc(journal_head_cache, GFP_NOFS); - if (ret == 0) { + if (ret == NULL) { jbd_debug(1, "out of memory for journal_head\n"); if (time_after(jiffies, last_warning + 5*HZ)) { printk(KERN_NOTICE "ENOMEM in %s, retrying.\n", __FUNCTION__); last_warning = jiffies; } - while (ret == 0) { + while (ret == NULL) { yield(); ret = kmem_cache_alloc(journal_head_cache, GFP_NOFS); } @@ -1881,13 +1794,13 @@ static void __journal_remove_journal_head(struct buffer_head *bh) printk(KERN_WARNING "%s: freeing " "b_frozen_data\n", __FUNCTION__); - jbd_slab_free(jh->b_frozen_data, bh->b_size); + jbd_free(jh->b_frozen_data, bh->b_size); } if (jh->b_committed_data) { printk(KERN_WARNING "%s: freeing " "b_committed_data\n", __FUNCTION__); - jbd_slab_free(jh->b_committed_data, bh->b_size); + jbd_free(jh->b_committed_data, bh->b_size); } bh->b_private = NULL; jh->b_bh = NULL; /* debug, really */ @@ -1939,64 +1852,41 @@ void journal_put_journal_head(struct journal_head *jh) } /* - * /proc tunables + * debugfs tunables */ -#if defined(CONFIG_JBD_DEBUG) -int journal_enable_debug; -EXPORT_SYMBOL(journal_enable_debug); -#endif +#ifdef CONFIG_JBD_DEBUG -#if defined(CONFIG_JBD_DEBUG) && defined(CONFIG_PROC_FS) +u8 journal_enable_debug __read_mostly; +EXPORT_SYMBOL(journal_enable_debug); -static struct proc_dir_entry *proc_jbd_debug; +static struct dentry *jbd_debugfs_dir; +static struct dentry *jbd_debug; -static int read_jbd_debug(char *page, char **start, off_t off, - int count, int *eof, void *data) +static void __init jbd_create_debugfs_entry(void) { - int ret; - - ret = sprintf(page + off, "%d\n", journal_enable_debug); - *eof = 1; - return ret; + jbd_debugfs_dir = debugfs_create_dir("jbd", NULL); + if (jbd_debugfs_dir) + jbd_debug = debugfs_create_u8("jbd-debug", S_IRUGO, + jbd_debugfs_dir, + &journal_enable_debug); } -static int write_jbd_debug(struct file *file, const char __user *buffer, - unsigned long count, void *data) +static void __exit jbd_remove_debugfs_entry(void) { - char buf[32]; - - if (count > ARRAY_SIZE(buf) - 1) - count = ARRAY_SIZE(buf) - 1; - if (copy_from_user(buf, buffer, count)) - return -EFAULT; - buf[ARRAY_SIZE(buf) - 1] = '\0'; - journal_enable_debug = simple_strtoul(buf, NULL, 10); - return count; + debugfs_remove(jbd_debug); + debugfs_remove(jbd_debugfs_dir); } -#define JBD_PROC_NAME "sys/fs/jbd-debug" +#else -static void __init create_jbd_proc_entry(void) +static inline void jbd_create_debugfs_entry(void) { - proc_jbd_debug = create_proc_entry(JBD_PROC_NAME, 0644, NULL); - if (proc_jbd_debug) { - /* Why is this so hard? */ - proc_jbd_debug->read_proc = read_jbd_debug; - proc_jbd_debug->write_proc = write_jbd_debug; - } } -static void __exit remove_jbd_proc_entry(void) +static inline void jbd_remove_debugfs_entry(void) { - if (proc_jbd_debug) - remove_proc_entry(JBD_PROC_NAME, NULL); } -#else - -#define create_jbd_proc_entry() do {} while (0) -#define remove_jbd_proc_entry() do {} while (0) - #endif struct kmem_cache *jbd_handle_cache; @@ -2006,7 +1896,7 @@ static int __init journal_init_handle_cache(void) jbd_handle_cache = kmem_cache_create("journal_handle", sizeof(handle_t), 0, /* offset */ - 0, /* flags */ + SLAB_TEMPORARY, /* flags */ NULL); /* ctor */ if (jbd_handle_cache == NULL) { printk(KERN_EMERG "JBD: failed to create handle cache\n"); @@ -2042,7 +1932,6 @@ static void journal_destroy_caches(void) journal_destroy_revoke_caches(); journal_destroy_journal_head_cache(); journal_destroy_handle_cache(); - journal_destroy_jbd_slabs(); } static int __init journal_init(void) @@ -2054,7 +1943,7 @@ static int __init journal_init(void) ret = journal_init_caches(); if (ret != 0) journal_destroy_caches(); - create_jbd_proc_entry(); + jbd_create_debugfs_entry(); return ret; } @@ -2065,7 +1954,7 @@ static void __exit journal_exit(void) if (n) printk(KERN_EMERG "JBD: leaked %d journal_heads!\n", n); #endif - remove_jbd_proc_entry(); + jbd_remove_debugfs_entry(); journal_destroy_caches(); } diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c index 2a5f4b833e35..c5d9694b6a2f 100644 --- a/fs/jbd/recovery.c +++ b/fs/jbd/recovery.c @@ -250,10 +250,10 @@ int journal_recover(journal_t *journal) if (!err) err = do_one_pass(journal, &info, PASS_REPLAY); - jbd_debug(0, "JBD: recovery, exit status %d, " + jbd_debug(1, "JBD: recovery, exit status %d, " "recovered transactions %u to %u\n", err, info.start_transaction, info.end_transaction); - jbd_debug(0, "JBD: Replayed %d and revoked %d/%d blocks\n", + jbd_debug(1, "JBD: Replayed %d and revoked %d/%d blocks\n", info.nr_replays, info.nr_revoke_hits, info.nr_revokes); /* Restart the log at the next transaction ID, thus invalidating @@ -297,7 +297,7 @@ int journal_skip_recovery(journal_t *journal) #ifdef CONFIG_JBD_DEBUG int dropped = info.end_transaction - be32_to_cpu(sb->s_sequence); #endif - jbd_debug(0, + jbd_debug(1, "JBD: ignoring %d transaction%s from the journal.\n", dropped, (dropped == 1) ? "" : "s"); journal->j_transaction_sequence = ++info.end_transaction; diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c index 62e13c8db132..ad2eacf570c6 100644 --- a/fs/jbd/revoke.c +++ b/fs/jbd/revoke.c @@ -170,13 +170,15 @@ int __init journal_init_revoke_caches(void) { revoke_record_cache = kmem_cache_create("revoke_record", sizeof(struct jbd_revoke_record_s), - 0, SLAB_HWCACHE_ALIGN, NULL); + 0, + SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY, + NULL); if (revoke_record_cache == 0) return -ENOMEM; revoke_table_cache = kmem_cache_create("revoke_table", sizeof(struct jbd_revoke_table_s), - 0, 0, NULL); + 0, SLAB_TEMPORARY, NULL); if (revoke_table_cache == 0) { kmem_cache_destroy(revoke_record_cache); revoke_record_cache = NULL; diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index 772b6531a2a2..08ff6c7028cc 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -96,13 +96,12 @@ static int start_this_handle(journal_t *journal, handle_t *handle) alloc_transaction: if (!journal->j_running_transaction) { - new_transaction = jbd_kmalloc(sizeof(*new_transaction), - GFP_NOFS); + new_transaction = kzalloc(sizeof(*new_transaction), + GFP_NOFS|__GFP_NOFAIL); if (!new_transaction) { ret = -ENOMEM; goto out; } - memset(new_transaction, 0, sizeof(*new_transaction)); } jbd_debug(3, "New handle %p going live.\n", handle); @@ -233,6 +232,8 @@ out: return ret; } +static struct lock_class_key jbd_handle_key; + /* Allocate a new handle. This should probably be in a slab... */ static handle_t *new_handle(int nblocks) { @@ -243,6 +244,8 @@ static handle_t *new_handle(int nblocks) handle->h_buffer_credits = nblocks; handle->h_ref = 1; + lockdep_init_map(&handle->h_lockdep_map, "jbd_handle", &jbd_handle_key, 0); + return handle; } @@ -286,6 +289,9 @@ handle_t *journal_start(journal_t *journal, int nblocks) current->journal_info = NULL; handle = ERR_PTR(err); } + + lock_acquire(&handle->h_lockdep_map, 0, 0, 0, 2, _THIS_IP_); + return handle; } @@ -668,7 +674,7 @@ repeat: JBUFFER_TRACE(jh, "allocate memory for buffer"); jbd_unlock_bh_state(bh); frozen_buffer = - jbd_slab_alloc(jh2bh(jh)->b_size, + jbd_alloc(jh2bh(jh)->b_size, GFP_NOFS); if (!frozen_buffer) { printk(KERN_EMERG @@ -728,7 +734,7 @@ done: out: if (unlikely(frozen_buffer)) /* It's usually NULL */ - jbd_slab_free(frozen_buffer, bh->b_size); + jbd_free(frozen_buffer, bh->b_size); JBUFFER_TRACE(jh, "exit"); return error; @@ -881,7 +887,7 @@ int journal_get_undo_access(handle_t *handle, struct buffer_head *bh) repeat: if (!jh->b_committed_data) { - committed_data = jbd_slab_alloc(jh2bh(jh)->b_size, GFP_NOFS); + committed_data = jbd_alloc(jh2bh(jh)->b_size, GFP_NOFS); if (!committed_data) { printk(KERN_EMERG "%s: No memory for committed data\n", __FUNCTION__); @@ -908,7 +914,7 @@ repeat: out: journal_put_journal_head(jh); if (unlikely(committed_data)) - jbd_slab_free(committed_data, bh->b_size); + jbd_free(committed_data, bh->b_size); return err; } @@ -1165,7 +1171,7 @@ int journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) } /* That test should have eliminated the following case: */ - J_ASSERT_JH(jh, jh->b_frozen_data == 0); + J_ASSERT_JH(jh, jh->b_frozen_data == NULL); JBUFFER_TRACE(jh, "file as BJ_Metadata"); spin_lock(&journal->j_list_lock); @@ -1411,6 +1417,8 @@ int journal_stop(handle_t *handle) spin_unlock(&journal->j_state_lock); } + lock_release(&handle->h_lockdep_map, 1, _THIS_IP_); + jbd_free_handle(handle); return err; } @@ -1513,7 +1521,7 @@ static void __journal_temp_unlink_buffer(struct journal_head *jh) J_ASSERT_JH(jh, jh->b_jlist < BJ_Types); if (jh->b_jlist != BJ_None) - J_ASSERT_JH(jh, transaction != 0); + J_ASSERT_JH(jh, transaction != NULL); switch (jh->b_jlist) { case BJ_None: @@ -1582,11 +1590,11 @@ __journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh) if (buffer_locked(bh) || buffer_dirty(bh)) goto out; - if (jh->b_next_transaction != 0) + if (jh->b_next_transaction != NULL) goto out; spin_lock(&journal->j_list_lock); - if (jh->b_transaction != 0 && jh->b_cp_transaction == 0) { + if (jh->b_transaction != NULL && jh->b_cp_transaction == NULL) { if (jh->b_jlist == BJ_SyncData || jh->b_jlist == BJ_Locked) { /* A written-back ordered data buffer */ JBUFFER_TRACE(jh, "release data"); @@ -1594,7 +1602,7 @@ __journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh) journal_remove_journal_head(bh); __brelse(bh); } - } else if (jh->b_cp_transaction != 0 && jh->b_transaction == 0) { + } else if (jh->b_cp_transaction != NULL && jh->b_transaction == NULL) { /* written-back checkpointed metadata buffer */ if (jh->b_jlist == BJ_None) { JBUFFER_TRACE(jh, "remove from checkpoint list"); @@ -1954,7 +1962,7 @@ void __journal_file_buffer(struct journal_head *jh, J_ASSERT_JH(jh, jh->b_jlist < BJ_Types); J_ASSERT_JH(jh, jh->b_transaction == transaction || - jh->b_transaction == 0); + jh->b_transaction == NULL); if (jh->b_transaction && jh->b_jlist == jlist) return; diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index c0f59d1b13dc..6986f334c643 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -278,7 +278,7 @@ static inline void write_tag_block(int tag_bytes, journal_block_tag_t *tag, unsigned long long block) { tag->t_blocknr = cpu_to_be32(block & (u32)~0); - if (tag_bytes > JBD_TAG_SIZE32) + if (tag_bytes > JBD2_TAG_SIZE32) tag->t_blocknr_high = cpu_to_be32((block >> 31) >> 1); } @@ -384,7 +384,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) struct buffer_head *bh = jh2bh(jh); jbd_lock_bh_state(bh); - jbd2_slab_free(jh->b_committed_data, bh->b_size); + jbd2_free(jh->b_committed_data, bh->b_size); jh->b_committed_data = NULL; jbd_unlock_bh_state(bh); } @@ -475,7 +475,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) spin_unlock(&journal->j_list_lock); if (err) - __jbd2_journal_abort_hard(journal); + jbd2_journal_abort(journal, err); jbd2_journal_write_revoke_records(journal, commit_transaction); @@ -533,7 +533,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) descriptor = jbd2_journal_get_descriptor_buffer(journal); if (!descriptor) { - __jbd2_journal_abort_hard(journal); + jbd2_journal_abort(journal, -EIO); continue; } @@ -566,7 +566,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) and repeat this loop: we'll fall into the refile-on-abort condition above. */ if (err) { - __jbd2_journal_abort_hard(journal); + jbd2_journal_abort(journal, err); continue; } @@ -757,7 +757,7 @@ wait_for_iobuf: err = -EIO; if (err) - __jbd2_journal_abort_hard(journal); + jbd2_journal_abort(journal, err); /* End of a transaction! Finally, we can do checkpoint processing: any buffers committed as a result of this @@ -801,14 +801,14 @@ restart_loop: * Otherwise, we can just throw away the frozen data now. */ if (jh->b_committed_data) { - jbd2_slab_free(jh->b_committed_data, bh->b_size); + jbd2_free(jh->b_committed_data, bh->b_size); jh->b_committed_data = NULL; if (jh->b_frozen_data) { jh->b_committed_data = jh->b_frozen_data; jh->b_frozen_data = NULL; } } else if (jh->b_frozen_data) { - jbd2_slab_free(jh->b_frozen_data, bh->b_size); + jbd2_free(jh->b_frozen_data, bh->b_size); jh->b_frozen_data = NULL; } diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index f37324aee817..6ddc5531587c 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -84,7 +84,6 @@ EXPORT_SYMBOL(jbd2_journal_force_commit); static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *); static void __journal_abort_soft (journal_t *journal, int errno); -static int jbd2_journal_create_jbd_slab(size_t slab_size); /* * Helper function used to manage commit timeouts @@ -335,10 +334,10 @@ repeat: char *tmp; jbd_unlock_bh_state(bh_in); - tmp = jbd2_slab_alloc(bh_in->b_size, GFP_NOFS); + tmp = jbd2_alloc(bh_in->b_size, GFP_NOFS); jbd_lock_bh_state(bh_in); if (jh_in->b_frozen_data) { - jbd2_slab_free(tmp, bh_in->b_size); + jbd2_free(tmp, bh_in->b_size); goto repeat; } @@ -655,10 +654,9 @@ static journal_t * journal_init_common (void) journal_t *journal; int err; - journal = jbd_kmalloc(sizeof(*journal), GFP_KERNEL); + journal = kzalloc(sizeof(*journal), GFP_KERNEL|__GFP_NOFAIL); if (!journal) goto fail; - memset(journal, 0, sizeof(*journal)); init_waitqueue_head(&journal->j_wait_transaction_locked); init_waitqueue_head(&journal->j_wait_logspace); @@ -672,7 +670,7 @@ static journal_t * journal_init_common (void) spin_lock_init(&journal->j_list_lock); spin_lock_init(&journal->j_state_lock); - journal->j_commit_interval = (HZ * JBD_DEFAULT_MAX_COMMIT_AGE); + journal->j_commit_interval = (HZ * JBD2_DEFAULT_MAX_COMMIT_AGE); /* The journal is marked for error until we succeed with recovery! */ journal->j_flags = JBD2_ABORT; @@ -1096,13 +1094,6 @@ int jbd2_journal_load(journal_t *journal) } } - /* - * Create a slab for this blocksize - */ - err = jbd2_journal_create_jbd_slab(be32_to_cpu(sb->s_blocksize)); - if (err) - return err; - /* Let the recovery code check whether it needs to recover any * data from the journal. */ if (jbd2_journal_recover(journal)) @@ -1621,89 +1612,9 @@ int jbd2_journal_blocks_per_page(struct inode *inode) size_t journal_tag_bytes(journal_t *journal) { if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) - return JBD_TAG_SIZE64; + return JBD2_TAG_SIZE64; else - return JBD_TAG_SIZE32; -} - -/* - * Simple support for retrying memory allocations. Introduced to help to - * debug different VM deadlock avoidance strategies. - */ -void * __jbd2_kmalloc (const char *where, size_t size, gfp_t flags, int retry) -{ - return kmalloc(size, flags | (retry ? __GFP_NOFAIL : 0)); -} - -/* - * jbd slab management: create 1k, 2k, 4k, 8k slabs as needed - * and allocate frozen and commit buffers from these slabs. - * - * Reason for doing this is to avoid, SLAB_DEBUG - since it could - * cause bh to cross page boundary. - */ - -#define JBD_MAX_SLABS 5 -#define JBD_SLAB_INDEX(size) (size >> 11) - -static struct kmem_cache *jbd_slab[JBD_MAX_SLABS]; -static const char *jbd_slab_names[JBD_MAX_SLABS] = { - "jbd2_1k", "jbd2_2k", "jbd2_4k", NULL, "jbd2_8k" -}; - -static void jbd2_journal_destroy_jbd_slabs(void) -{ - int i; - - for (i = 0; i < JBD_MAX_SLABS; i++) { - if (jbd_slab[i]) - kmem_cache_destroy(jbd_slab[i]); - jbd_slab[i] = NULL; - } -} - -static int jbd2_journal_create_jbd_slab(size_t slab_size) -{ - int i = JBD_SLAB_INDEX(slab_size); - - BUG_ON(i >= JBD_MAX_SLABS); - - /* - * Check if we already have a slab created for this size - */ - if (jbd_slab[i]) - return 0; - - /* - * Create a slab and force alignment to be same as slabsize - - * this will make sure that allocations won't cross the page - * boundary. - */ - jbd_slab[i] = kmem_cache_create(jbd_slab_names[i], - slab_size, slab_size, 0, NULL); - if (!jbd_slab[i]) { - printk(KERN_EMERG "JBD: no memory for jbd_slab cache\n"); - return -ENOMEM; - } - return 0; -} - -void * jbd2_slab_alloc(size_t size, gfp_t flags) -{ - int idx; - - idx = JBD_SLAB_INDEX(size); - BUG_ON(jbd_slab[idx] == NULL); - return kmem_cache_alloc(jbd_slab[idx], flags | __GFP_NOFAIL); -} - -void jbd2_slab_free(void *ptr, size_t size) -{ - int idx; - - idx = JBD_SLAB_INDEX(size); - BUG_ON(jbd_slab[idx] == NULL); - kmem_cache_free(jbd_slab[idx], ptr); + return JBD2_TAG_SIZE32; } /* @@ -1770,7 +1681,7 @@ static void journal_free_journal_head(struct journal_head *jh) { #ifdef CONFIG_JBD2_DEBUG atomic_dec(&nr_journal_heads); - memset(jh, JBD_POISON_FREE, sizeof(*jh)); + memset(jh, JBD2_POISON_FREE, sizeof(*jh)); #endif kmem_cache_free(jbd2_journal_head_cache, jh); } @@ -1893,13 +1804,13 @@ static void __journal_remove_journal_head(struct buffer_head *bh) printk(KERN_WARNING "%s: freeing " "b_frozen_data\n", __FUNCTION__); - jbd2_slab_free(jh->b_frozen_data, bh->b_size); + jbd2_free(jh->b_frozen_data, bh->b_size); } if (jh->b_committed_data) { printk(KERN_WARNING "%s: freeing " "b_committed_data\n", __FUNCTION__); - jbd2_slab_free(jh->b_committed_data, bh->b_size); + jbd2_free(jh->b_committed_data, bh->b_size); } bh->b_private = NULL; jh->b_bh = NULL; /* debug, really */ @@ -1953,16 +1864,14 @@ void jbd2_journal_put_journal_head(struct journal_head *jh) /* * debugfs tunables */ -#if defined(CONFIG_JBD2_DEBUG) -u8 jbd2_journal_enable_debug; +#ifdef CONFIG_JBD2_DEBUG +u8 jbd2_journal_enable_debug __read_mostly; EXPORT_SYMBOL(jbd2_journal_enable_debug); -#endif - -#if defined(CONFIG_JBD2_DEBUG) && defined(CONFIG_DEBUG_FS) #define JBD2_DEBUG_NAME "jbd2-debug" -struct dentry *jbd2_debugfs_dir, *jbd2_debug; +static struct dentry *jbd2_debugfs_dir; +static struct dentry *jbd2_debug; static void __init jbd2_create_debugfs_entry(void) { @@ -1975,24 +1884,18 @@ static void __init jbd2_create_debugfs_entry(void) static void __exit jbd2_remove_debugfs_entry(void) { - if (jbd2_debug) - debugfs_remove(jbd2_debug); - if (jbd2_debugfs_dir) - debugfs_remove(jbd2_debugfs_dir); + debugfs_remove(jbd2_debug); + debugfs_remove(jbd2_debugfs_dir); } #else static void __init jbd2_create_debugfs_entry(void) { - do { - } while (0); } static void __exit jbd2_remove_debugfs_entry(void) { - do { - } while (0); } #endif @@ -2040,7 +1943,6 @@ static void jbd2_journal_destroy_caches(void) jbd2_journal_destroy_revoke_caches(); jbd2_journal_destroy_jbd2_journal_head_cache(); jbd2_journal_destroy_handle_cache(); - jbd2_journal_destroy_jbd_slabs(); } static int __init journal_init(void) diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c index b50be8a044eb..d0ce627539ef 100644 --- a/fs/jbd2/recovery.c +++ b/fs/jbd2/recovery.c @@ -311,7 +311,7 @@ int jbd2_journal_skip_recovery(journal_t *journal) static inline unsigned long long read_tag_block(int tag_bytes, journal_block_tag_t *tag) { unsigned long long block = be32_to_cpu(tag->t_blocknr); - if (tag_bytes > JBD_TAG_SIZE32) + if (tag_bytes > JBD2_TAG_SIZE32) block |= (u64)be32_to_cpu(tag->t_blocknr_high) << 32; return block; } diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c index 01d88975e0c5..3595fd432d5b 100644 --- a/fs/jbd2/revoke.c +++ b/fs/jbd2/revoke.c @@ -352,7 +352,7 @@ int jbd2_journal_revoke(handle_t *handle, unsigned long long blocknr, if (bh) BUFFER_TRACE(bh, "found on hash"); } -#ifdef JBD_EXPENSIVE_CHECKING +#ifdef JBD2_EXPENSIVE_CHECKING else { struct buffer_head *bh2; @@ -453,7 +453,7 @@ int jbd2_journal_cancel_revoke(handle_t *handle, struct journal_head *jh) } } -#ifdef JBD_EXPENSIVE_CHECKING +#ifdef JBD2_EXPENSIVE_CHECKING /* There better not be one left behind by now! */ record = find_revoke_record(journal, bh->b_blocknr); J_ASSERT_JH(jh, record == NULL); diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 7946ff43fc40..b1fcf2b3dca3 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -96,13 +96,12 @@ static int start_this_handle(journal_t *journal, handle_t *handle) alloc_transaction: if (!journal->j_running_transaction) { - new_transaction = jbd_kmalloc(sizeof(*new_transaction), - GFP_NOFS); + new_transaction = kzalloc(sizeof(*new_transaction), + GFP_NOFS|__GFP_NOFAIL); if (!new_transaction) { ret = -ENOMEM; goto out; } - memset(new_transaction, 0, sizeof(*new_transaction)); } jbd_debug(3, "New handle %p going live.\n", handle); @@ -236,7 +235,7 @@ out: /* Allocate a new handle. This should probably be in a slab... */ static handle_t *new_handle(int nblocks) { - handle_t *handle = jbd_alloc_handle(GFP_NOFS); + handle_t *handle = jbd2_alloc_handle(GFP_NOFS); if (!handle) return NULL; memset(handle, 0, sizeof(*handle)); @@ -282,7 +281,7 @@ handle_t *jbd2_journal_start(journal_t *journal, int nblocks) err = start_this_handle(journal, handle); if (err < 0) { - jbd_free_handle(handle); + jbd2_free_handle(handle); current->journal_info = NULL; handle = ERR_PTR(err); } @@ -668,7 +667,7 @@ repeat: JBUFFER_TRACE(jh, "allocate memory for buffer"); jbd_unlock_bh_state(bh); frozen_buffer = - jbd2_slab_alloc(jh2bh(jh)->b_size, + jbd2_alloc(jh2bh(jh)->b_size, GFP_NOFS); if (!frozen_buffer) { printk(KERN_EMERG @@ -728,7 +727,7 @@ done: out: if (unlikely(frozen_buffer)) /* It's usually NULL */ - jbd2_slab_free(frozen_buffer, bh->b_size); + jbd2_free(frozen_buffer, bh->b_size); JBUFFER_TRACE(jh, "exit"); return error; @@ -881,7 +880,7 @@ int jbd2_journal_get_undo_access(handle_t *handle, struct buffer_head *bh) repeat: if (!jh->b_committed_data) { - committed_data = jbd2_slab_alloc(jh2bh(jh)->b_size, GFP_NOFS); + committed_data = jbd2_alloc(jh2bh(jh)->b_size, GFP_NOFS); if (!committed_data) { printk(KERN_EMERG "%s: No memory for committed data\n", __FUNCTION__); @@ -908,7 +907,7 @@ repeat: out: jbd2_journal_put_journal_head(jh); if (unlikely(committed_data)) - jbd2_slab_free(committed_data, bh->b_size); + jbd2_free(committed_data, bh->b_size); return err; } @@ -1411,7 +1410,7 @@ int jbd2_journal_stop(handle_t *handle) spin_unlock(&journal->j_state_lock); } - jbd_free_handle(handle); + jbd2_free_handle(handle); return err; } diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile index c32b241e3d91..60e5d49ca03e 100644 --- a/fs/jffs2/Makefile +++ b/fs/jffs2/Makefile @@ -17,4 +17,5 @@ jffs2-$(CONFIG_JFFS2_FS_POSIX_ACL) += acl.o jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o +jffs2-$(CONFIG_JFFS2_LZO) += compr_lzo.o jffs2-$(CONFIG_JFFS2_SUMMARY) += summary.o diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c index 65b3a1b5b88d..8ec9323e830a 100644 --- a/fs/jffs2/acl.c +++ b/fs/jffs2/acl.c @@ -176,7 +176,7 @@ static void jffs2_iset_acl(struct inode *inode, struct posix_acl **i_acl, struct spin_unlock(&inode->i_lock); } -static struct posix_acl *jffs2_get_acl(struct inode *inode, int type) +struct posix_acl *jffs2_get_acl(struct inode *inode, int type) { struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct posix_acl *acl; @@ -247,8 +247,13 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) if (rc < 0) return rc; if (inode->i_mode != mode) { - inode->i_mode = mode; - jffs2_dirty_inode(inode); + struct iattr attr; + + attr.ia_valid = ATTR_MODE; + attr.ia_mode = mode; + rc = jffs2_do_setattr(inode, &attr); + if (rc < 0) + return rc; } if (rc == 0) acl = NULL; @@ -307,22 +312,16 @@ int jffs2_permission(struct inode *inode, int mask, struct nameidata *nd) return generic_permission(inode, mask, jffs2_check_acl); } -int jffs2_init_acl(struct inode *inode, struct inode *dir) +int jffs2_init_acl(struct inode *inode, struct posix_acl *acl) { struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - struct posix_acl *acl = NULL, *clone; + struct posix_acl *clone; mode_t mode; int rc = 0; f->i_acl_access = JFFS2_ACL_NOT_CACHED; f->i_acl_default = JFFS2_ACL_NOT_CACHED; - if (!S_ISLNK(inode->i_mode)) { - acl = jffs2_get_acl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (!acl) - inode->i_mode &= ~current->fs->umask; - } + if (acl) { if (S_ISDIR(inode->i_mode)) { rc = jffs2_set_acl(inode, ACL_TYPE_DEFAULT, acl); diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h index c84378cee82a..90a2dbf59051 100644 --- a/fs/jffs2/acl.h +++ b/fs/jffs2/acl.h @@ -28,9 +28,10 @@ struct jffs2_acl_header { #define JFFS2_ACL_NOT_CACHED ((void *)-1) +extern struct posix_acl *jffs2_get_acl(struct inode *inode, int type); extern int jffs2_permission(struct inode *, int, struct nameidata *); extern int jffs2_acl_chmod(struct inode *); -extern int jffs2_init_acl(struct inode *, struct inode *); +extern int jffs2_init_acl(struct inode *, struct posix_acl *); extern void jffs2_clear_acl(struct jffs2_inode_info *); extern struct xattr_handler jffs2_acl_access_xattr_handler; @@ -38,6 +39,7 @@ extern struct xattr_handler jffs2_acl_default_xattr_handler; #else +#define jffs2_get_acl(inode, type) (NULL) #define jffs2_permission NULL #define jffs2_acl_chmod(inode) (0) #define jffs2_init_acl(inode,dir) (0) diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 504643f2e98b..d568ae846741 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c @@ -23,8 +23,8 @@ static int jffs2_garbage_collect_thread(void *); void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c) { spin_lock(&c->erase_completion_lock); - if (c->gc_task && jffs2_thread_should_wake(c)) - send_sig(SIGHUP, c->gc_task, 1); + if (c->gc_task && jffs2_thread_should_wake(c)) + send_sig(SIGHUP, c->gc_task, 1); spin_unlock(&c->erase_completion_lock); } diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index 0ca2fff2617f..722a6b682951 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c @@ -285,6 +285,14 @@ static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c) than actually making progress? */ c->resv_blocks_gcbad = 0;//c->resv_blocks_deletion + 2; + /* What number of 'very dirty' eraseblocks do we allow before we + trigger the GC thread even if we don't _need_ the space. When we + can't mark nodes obsolete on the medium, the old dirty nodes cause + performance problems because we have to inspect and discard them. */ + c->vdirty_blocks_gctrigger = c->resv_blocks_gctrigger; + if (jffs2_can_mark_obsolete(c)) + c->vdirty_blocks_gctrigger *= 10; + /* If there's less than this amount of dirty space, don't bother trying to GC to make more space. It'll be a fruitless task */ c->nospc_dirty_size = c->sector_size + (c->flash_size / 100); @@ -303,6 +311,8 @@ static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c) c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024); dbg_fsbuild("Amount of dirty space required to GC: %d bytes\n", c->nospc_dirty_size); + dbg_fsbuild("Very dirty blocks before GC triggered: %d\n", + c->vdirty_blocks_gctrigger); } int jffs2_do_mount_fs(struct jffs2_sb_info *c) diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c index 485d065de41f..86739ee53b37 100644 --- a/fs/jffs2/compr.c +++ b/fs/jffs2/compr.c @@ -5,7 +5,7 @@ * Created by Arjan van de Ven <arjanv@redhat.com> * * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, - * University of Szeged, Hungary + * University of Szeged, Hungary * * For licensing information, see the file 'LICENCE' in this directory. * @@ -24,6 +24,34 @@ static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY; /* Statistics for blocks stored without compression */ static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0; + +/* + * Return 1 to use this compression + */ +static int jffs2_is_best_compression(struct jffs2_compressor *this, + struct jffs2_compressor *best, uint32_t size, uint32_t bestsize) +{ + switch (jffs2_compression_mode) { + case JFFS2_COMPR_MODE_SIZE: + if (bestsize > size) + return 1; + return 0; + case JFFS2_COMPR_MODE_FAVOURLZO: + if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > size)) + return 1; + if ((best->compr != JFFS2_COMPR_LZO) && (bestsize > size)) + return 1; + if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > (size * FAVOUR_LZO_PERCENT / 100))) + return 1; + if ((bestsize * FAVOUR_LZO_PERCENT / 100) > size) + return 1; + + return 0; + } + /* Shouldn't happen */ + return 0; +} + /* jffs2_compress: * @data: Pointer to uncompressed data * @cdata: Pointer to returned pointer to buffer for compressed data @@ -43,121 +71,124 @@ static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_co * *datalen accordingly to show the amount of data which were compressed. */ uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, - unsigned char *data_in, unsigned char **cpage_out, - uint32_t *datalen, uint32_t *cdatalen) + unsigned char *data_in, unsigned char **cpage_out, + uint32_t *datalen, uint32_t *cdatalen) { int ret = JFFS2_COMPR_NONE; - int compr_ret; - struct jffs2_compressor *this, *best=NULL; - unsigned char *output_buf = NULL, *tmp_buf; - uint32_t orig_slen, orig_dlen; - uint32_t best_slen=0, best_dlen=0; + int compr_ret; + struct jffs2_compressor *this, *best=NULL; + unsigned char *output_buf = NULL, *tmp_buf; + uint32_t orig_slen, orig_dlen; + uint32_t best_slen=0, best_dlen=0; - switch (jffs2_compression_mode) { - case JFFS2_COMPR_MODE_NONE: - break; - case JFFS2_COMPR_MODE_PRIORITY: - output_buf = kmalloc(*cdatalen,GFP_KERNEL); - if (!output_buf) { - printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n"); - goto out; - } - orig_slen = *datalen; - orig_dlen = *cdatalen; - spin_lock(&jffs2_compressor_list_lock); - list_for_each_entry(this, &jffs2_compressor_list, list) { - /* Skip decompress-only backwards-compatibility and disabled modules */ - if ((!this->compress)||(this->disabled)) - continue; + switch (jffs2_compression_mode) { + case JFFS2_COMPR_MODE_NONE: + break; + case JFFS2_COMPR_MODE_PRIORITY: + output_buf = kmalloc(*cdatalen,GFP_KERNEL); + if (!output_buf) { + printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n"); + goto out; + } + orig_slen = *datalen; + orig_dlen = *cdatalen; + spin_lock(&jffs2_compressor_list_lock); + list_for_each_entry(this, &jffs2_compressor_list, list) { + /* Skip decompress-only backwards-compatibility and disabled modules */ + if ((!this->compress)||(this->disabled)) + continue; - this->usecount++; - spin_unlock(&jffs2_compressor_list_lock); - *datalen = orig_slen; - *cdatalen = orig_dlen; - compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL); - spin_lock(&jffs2_compressor_list_lock); - this->usecount--; - if (!compr_ret) { - ret = this->compr; - this->stat_compr_blocks++; - this->stat_compr_orig_size += *datalen; - this->stat_compr_new_size += *cdatalen; - break; - } - } - spin_unlock(&jffs2_compressor_list_lock); - if (ret == JFFS2_COMPR_NONE) kfree(output_buf); - break; - case JFFS2_COMPR_MODE_SIZE: - orig_slen = *datalen; - orig_dlen = *cdatalen; - spin_lock(&jffs2_compressor_list_lock); - list_for_each_entry(this, &jffs2_compressor_list, list) { - /* Skip decompress-only backwards-compatibility and disabled modules */ - if ((!this->compress)||(this->disabled)) - continue; - /* Allocating memory for output buffer if necessary */ - if ((this->compr_buf_size<orig_dlen)&&(this->compr_buf)) { - spin_unlock(&jffs2_compressor_list_lock); - kfree(this->compr_buf); - spin_lock(&jffs2_compressor_list_lock); - this->compr_buf_size=0; - this->compr_buf=NULL; - } - if (!this->compr_buf) { - spin_unlock(&jffs2_compressor_list_lock); - tmp_buf = kmalloc(orig_dlen,GFP_KERNEL); - spin_lock(&jffs2_compressor_list_lock); - if (!tmp_buf) { - printk(KERN_WARNING "JFFS2: No memory for compressor allocation. (%d bytes)\n",orig_dlen); - continue; - } - else { - this->compr_buf = tmp_buf; - this->compr_buf_size = orig_dlen; - } - } - this->usecount++; - spin_unlock(&jffs2_compressor_list_lock); - *datalen = orig_slen; - *cdatalen = orig_dlen; - compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL); - spin_lock(&jffs2_compressor_list_lock); - this->usecount--; - if (!compr_ret) { - if ((!best_dlen)||(best_dlen>*cdatalen)) { - best_dlen = *cdatalen; - best_slen = *datalen; - best = this; - } - } - } - if (best_dlen) { - *cdatalen = best_dlen; - *datalen = best_slen; - output_buf = best->compr_buf; - best->compr_buf = NULL; - best->compr_buf_size = 0; - best->stat_compr_blocks++; - best->stat_compr_orig_size += best_slen; - best->stat_compr_new_size += best_dlen; - ret = best->compr; - } - spin_unlock(&jffs2_compressor_list_lock); - break; - default: - printk(KERN_ERR "JFFS2: unknow compression mode.\n"); - } + this->usecount++; + spin_unlock(&jffs2_compressor_list_lock); + *datalen = orig_slen; + *cdatalen = orig_dlen; + compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL); + spin_lock(&jffs2_compressor_list_lock); + this->usecount--; + if (!compr_ret) { + ret = this->compr; + this->stat_compr_blocks++; + this->stat_compr_orig_size += *datalen; + this->stat_compr_new_size += *cdatalen; + break; + } + } + spin_unlock(&jffs2_compressor_list_lock); + if (ret == JFFS2_COMPR_NONE) + kfree(output_buf); + break; + case JFFS2_COMPR_MODE_SIZE: + case JFFS2_COMPR_MODE_FAVOURLZO: + orig_slen = *datalen; + orig_dlen = *cdatalen; + spin_lock(&jffs2_compressor_list_lock); + list_for_each_entry(this, &jffs2_compressor_list, list) { + /* Skip decompress-only backwards-compatibility and disabled modules */ + if ((!this->compress)||(this->disabled)) + continue; + /* Allocating memory for output buffer if necessary */ + if ((this->compr_buf_size < orig_slen) && (this->compr_buf)) { + spin_unlock(&jffs2_compressor_list_lock); + kfree(this->compr_buf); + spin_lock(&jffs2_compressor_list_lock); + this->compr_buf_size=0; + this->compr_buf=NULL; + } + if (!this->compr_buf) { + spin_unlock(&jffs2_compressor_list_lock); + tmp_buf = kmalloc(orig_slen, GFP_KERNEL); + spin_lock(&jffs2_compressor_list_lock); + if (!tmp_buf) { + printk(KERN_WARNING "JFFS2: No memory for compressor allocation. (%d bytes)\n", orig_slen); + continue; + } + else { + this->compr_buf = tmp_buf; + this->compr_buf_size = orig_slen; + } + } + this->usecount++; + spin_unlock(&jffs2_compressor_list_lock); + *datalen = orig_slen; + *cdatalen = orig_dlen; + compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL); + spin_lock(&jffs2_compressor_list_lock); + this->usecount--; + if (!compr_ret) { + if (((!best_dlen) || jffs2_is_best_compression(this, best, *cdatalen, best_dlen)) + && (*cdatalen < *datalen)) { + best_dlen = *cdatalen; + best_slen = *datalen; + best = this; + } + } + } + if (best_dlen) { + *cdatalen = best_dlen; + *datalen = best_slen; + output_buf = best->compr_buf; + best->compr_buf = NULL; + best->compr_buf_size = 0; + best->stat_compr_blocks++; + best->stat_compr_orig_size += best_slen; + best->stat_compr_new_size += best_dlen; + ret = best->compr; + } + spin_unlock(&jffs2_compressor_list_lock); + break; + default: + printk(KERN_ERR "JFFS2: unknow compression mode.\n"); + } out: - if (ret == JFFS2_COMPR_NONE) { - *cpage_out = data_in; - *datalen = *cdatalen; - none_stat_compr_blocks++; - none_stat_compr_size += *datalen; - } - else { - *cpage_out = output_buf; - } + if (ret == JFFS2_COMPR_NONE) { + *cpage_out = data_in; + *datalen = *cdatalen; + none_stat_compr_blocks++; + none_stat_compr_size += *datalen; + } + else { + *cpage_out = output_buf; + } return ret; } @@ -165,8 +196,8 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint16_t comprtype, unsigned char *cdata_in, unsigned char *data_out, uint32_t cdatalen, uint32_t datalen) { - struct jffs2_compressor *this; - int ret; + struct jffs2_compressor *this; + int ret; /* Older code had a bug where it would write non-zero 'usercompr' fields. Deal with it. */ @@ -177,32 +208,32 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, case JFFS2_COMPR_NONE: /* This should be special-cased elsewhere, but we might as well deal with it */ memcpy(data_out, cdata_in, datalen); - none_stat_decompr_blocks++; + none_stat_decompr_blocks++; break; case JFFS2_COMPR_ZERO: memset(data_out, 0, datalen); break; default: - spin_lock(&jffs2_compressor_list_lock); - list_for_each_entry(this, &jffs2_compressor_list, list) { - if (comprtype == this->compr) { - this->usecount++; - spin_unlock(&jffs2_compressor_list_lock); - ret = this->decompress(cdata_in, data_out, cdatalen, datalen, NULL); - spin_lock(&jffs2_compressor_list_lock); - if (ret) { - printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret); - } - else { - this->stat_decompr_blocks++; - } - this->usecount--; - spin_unlock(&jffs2_compressor_list_lock); - return ret; - } - } + spin_lock(&jffs2_compressor_list_lock); + list_for_each_entry(this, &jffs2_compressor_list, list) { + if (comprtype == this->compr) { + this->usecount++; + spin_unlock(&jffs2_compressor_list_lock); + ret = this->decompress(cdata_in, data_out, cdatalen, datalen, NULL); + spin_lock(&jffs2_compressor_list_lock); + if (ret) { + printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret); + } + else { + this->stat_decompr_blocks++; + } + this->usecount--; + spin_unlock(&jffs2_compressor_list_lock); + return ret; + } + } printk(KERN_WARNING "JFFS2 compression type 0x%02x not available.\n", comprtype); - spin_unlock(&jffs2_compressor_list_lock); + spin_unlock(&jffs2_compressor_list_lock); return -EIO; } return 0; @@ -210,108 +241,119 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, int jffs2_register_compressor(struct jffs2_compressor *comp) { - struct jffs2_compressor *this; + struct jffs2_compressor *this; - if (!comp->name) { - printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n"); - return -1; - } - comp->compr_buf_size=0; - comp->compr_buf=NULL; - comp->usecount=0; - comp->stat_compr_orig_size=0; - comp->stat_compr_new_size=0; - comp->stat_compr_blocks=0; - comp->stat_decompr_blocks=0; - D1(printk(KERN_DEBUG "Registering JFFS2 compressor \"%s\"\n", comp->name)); + if (!comp->name) { + printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n"); + return -1; + } + comp->compr_buf_size=0; + comp->compr_buf=NULL; + comp->usecount=0; + comp->stat_compr_orig_size=0; + comp->stat_compr_new_size=0; + comp->stat_compr_blocks=0; + comp->stat_decompr_blocks=0; + D1(printk(KERN_DEBUG "Registering JFFS2 compressor \"%s\"\n", comp->name)); - spin_lock(&jffs2_compressor_list_lock); + spin_lock(&jffs2_compressor_list_lock); - list_for_each_entry(this, &jffs2_compressor_list, list) { - if (this->priority < comp->priority) { - list_add(&comp->list, this->list.prev); - goto out; - } - } - list_add_tail(&comp->list, &jffs2_compressor_list); + list_for_each_entry(this, &jffs2_compressor_list, list) { + if (this->priority < comp->priority) { + list_add(&comp->list, this->list.prev); + goto out; + } + } + list_add_tail(&comp->list, &jffs2_compressor_list); out: - D2(list_for_each_entry(this, &jffs2_compressor_list, list) { - printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority); - }) + D2(list_for_each_entry(this, &jffs2_compressor_list, list) { + printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority); + }) - spin_unlock(&jffs2_compressor_list_lock); + spin_unlock(&jffs2_compressor_list_lock); - return 0; + return 0; } int jffs2_unregister_compressor(struct jffs2_compressor *comp) { - D2(struct jffs2_compressor *this;) + D2(struct jffs2_compressor *this;) - D1(printk(KERN_DEBUG "Unregistering JFFS2 compressor \"%s\"\n", comp->name)); + D1(printk(KERN_DEBUG "Unregistering JFFS2 compressor \"%s\"\n", comp->name)); - spin_lock(&jffs2_compressor_list_lock); + spin_lock(&jffs2_compressor_list_lock); - if (comp->usecount) { - spin_unlock(&jffs2_compressor_list_lock); - printk(KERN_WARNING "JFFS2: Compressor modul is in use. Unregister failed.\n"); - return -1; - } - list_del(&comp->list); + if (comp->usecount) { + spin_unlock(&jffs2_compressor_list_lock); + printk(KERN_WARNING "JFFS2: Compressor modul is in use. Unregister failed.\n"); + return -1; + } + list_del(&comp->list); - D2(list_for_each_entry(this, &jffs2_compressor_list, list) { - printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority); - }) - spin_unlock(&jffs2_compressor_list_lock); - return 0; + D2(list_for_each_entry(this, &jffs2_compressor_list, list) { + printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority); + }) + spin_unlock(&jffs2_compressor_list_lock); + return 0; } void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig) { - if (orig != comprbuf) - kfree(comprbuf); + if (orig != comprbuf) + kfree(comprbuf); } int __init jffs2_compressors_init(void) { /* Registering compressors */ #ifdef CONFIG_JFFS2_ZLIB - jffs2_zlib_init(); + jffs2_zlib_init(); #endif #ifdef CONFIG_JFFS2_RTIME - jffs2_rtime_init(); + jffs2_rtime_init(); #endif #ifdef CONFIG_JFFS2_RUBIN - jffs2_rubinmips_init(); - jffs2_dynrubin_init(); + jffs2_rubinmips_init(); + jffs2_dynrubin_init(); +#endif +#ifdef CONFIG_JFFS2_LZO + jffs2_lzo_init(); #endif /* Setting default compression mode */ #ifdef CONFIG_JFFS2_CMODE_NONE - jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; - D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");) + jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; + D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");) #else #ifdef CONFIG_JFFS2_CMODE_SIZE - jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE; - D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");) + jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE; + D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");) +#else +#ifdef CONFIG_JFFS2_CMODE_FAVOURLZO + jffs2_compression_mode = JFFS2_COMPR_MODE_FAVOURLZO; + D1(printk(KERN_INFO "JFFS2: default compression mode: favourlzo\n");) #else - D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");) + D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");) +#endif #endif #endif - return 0; + return 0; } int jffs2_compressors_exit(void) { /* Unregistering compressors */ +#ifdef CONFIG_JFFS2_LZO + jffs2_lzo_exit(); +#endif #ifdef CONFIG_JFFS2_RUBIN - jffs2_dynrubin_exit(); - jffs2_rubinmips_exit(); + jffs2_dynrubin_exit(); + jffs2_rubinmips_exit(); #endif #ifdef CONFIG_JFFS2_RTIME - jffs2_rtime_exit(); + jffs2_rtime_exit(); #endif #ifdef CONFIG_JFFS2_ZLIB - jffs2_zlib_exit(); + jffs2_zlib_exit(); #endif - return 0; + return 0; } diff --git a/fs/jffs2/compr.h b/fs/jffs2/compr.h index 68cc7010dbdf..7d1d72faa774 100644 --- a/fs/jffs2/compr.h +++ b/fs/jffs2/compr.h @@ -2,7 +2,7 @@ * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, - * University of Szeged, Hungary + * University of Szeged, Hungary * * For licensing information, see the file 'LICENCE' in this directory. * @@ -27,34 +27,38 @@ #define JFFS2_RUBINMIPS_PRIORITY 10 #define JFFS2_DYNRUBIN_PRIORITY 20 #define JFFS2_LZARI_PRIORITY 30 -#define JFFS2_LZO_PRIORITY 40 #define JFFS2_RTIME_PRIORITY 50 #define JFFS2_ZLIB_PRIORITY 60 +#define JFFS2_LZO_PRIORITY 80 + #define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */ -#define JFFS2_DYNRUBIN_DISABLED /* for decompression */ +#define JFFS2_DYNRUBIN_DISABLED /* for decompression */ #define JFFS2_COMPR_MODE_NONE 0 #define JFFS2_COMPR_MODE_PRIORITY 1 #define JFFS2_COMPR_MODE_SIZE 2 +#define JFFS2_COMPR_MODE_FAVOURLZO 3 + +#define FAVOUR_LZO_PERCENT 80 struct jffs2_compressor { - struct list_head list; - int priority; /* used by prirority comr. mode */ - char *name; - char compr; /* JFFS2_COMPR_XXX */ - int (*compress)(unsigned char *data_in, unsigned char *cpage_out, - uint32_t *srclen, uint32_t *destlen, void *model); - int (*decompress)(unsigned char *cdata_in, unsigned char *data_out, - uint32_t cdatalen, uint32_t datalen, void *model); - int usecount; - int disabled; /* if seted the compressor won't compress */ - unsigned char *compr_buf; /* used by size compr. mode */ - uint32_t compr_buf_size; /* used by size compr. mode */ - uint32_t stat_compr_orig_size; - uint32_t stat_compr_new_size; - uint32_t stat_compr_blocks; - uint32_t stat_decompr_blocks; + struct list_head list; + int priority; /* used by prirority comr. mode */ + char *name; + char compr; /* JFFS2_COMPR_XXX */ + int (*compress)(unsigned char *data_in, unsigned char *cpage_out, + uint32_t *srclen, uint32_t *destlen, void *model); + int (*decompress)(unsigned char *cdata_in, unsigned char *data_out, + uint32_t cdatalen, uint32_t datalen, void *model); + int usecount; + int disabled; /* if set the compressor won't compress */ + unsigned char *compr_buf; /* used by size compr. mode */ + uint32_t compr_buf_size; /* used by size compr. mode */ + uint32_t stat_compr_orig_size; + uint32_t stat_compr_new_size; + uint32_t stat_compr_blocks; + uint32_t stat_decompr_blocks; }; int jffs2_register_compressor(struct jffs2_compressor *comp); @@ -64,12 +68,12 @@ int jffs2_compressors_init(void); int jffs2_compressors_exit(void); uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, - unsigned char *data_in, unsigned char **cpage_out, - uint32_t *datalen, uint32_t *cdatalen); + unsigned char *data_in, unsigned char **cpage_out, + uint32_t *datalen, uint32_t *cdatalen); int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, - uint16_t comprtype, unsigned char *cdata_in, - unsigned char *data_out, uint32_t cdatalen, uint32_t datalen); + uint16_t comprtype, unsigned char *cdata_in, + unsigned char *data_out, uint32_t cdatalen, uint32_t datalen); void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig); @@ -90,5 +94,9 @@ void jffs2_rtime_exit(void); int jffs2_zlib_init(void); void jffs2_zlib_exit(void); #endif +#ifdef CONFIG_JFFS2_LZO +int jffs2_lzo_init(void); +void jffs2_lzo_exit(void); +#endif #endif /* __JFFS2_COMPR_H__ */ diff --git a/fs/jffs2/compr_lzo.c b/fs/jffs2/compr_lzo.c new file mode 100644 index 000000000000..47b045797e42 --- /dev/null +++ b/fs/jffs2/compr_lzo.c @@ -0,0 +1,108 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright © 2007 Nokia Corporation. All rights reserved. + * + * Created by Richard Purdie <rpurdie@openedhand.com> + * + * For licensing information, see the file 'LICENCE' in this directory. + * + */ + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/init.h> +#include <linux/lzo.h> +#include "compr.h" + +static void *lzo_mem; +static void *lzo_compress_buf; +static DEFINE_MUTEX(deflate_mutex); + +static void free_workspace(void) +{ + vfree(lzo_mem); + vfree(lzo_compress_buf); +} + +static int __init alloc_workspace(void) +{ + lzo_mem = vmalloc(LZO1X_MEM_COMPRESS); + lzo_compress_buf = vmalloc(lzo1x_worst_compress(PAGE_SIZE)); + + if (!lzo_mem || !lzo_compress_buf) { + printk(KERN_WARNING "Failed to allocate lzo deflate workspace\n"); + free_workspace(); + return -ENOMEM; + } + + return 0; +} + +static int jffs2_lzo_compress(unsigned char *data_in, unsigned char *cpage_out, + uint32_t *sourcelen, uint32_t *dstlen, void *model) +{ + size_t compress_size; + int ret; + + mutex_lock(&deflate_mutex); + ret = lzo1x_1_compress(data_in, *sourcelen, lzo_compress_buf, &compress_size, lzo_mem); + mutex_unlock(&deflate_mutex); + + if (ret != LZO_E_OK) + return -1; + + if (compress_size > *dstlen) + return -1; + + memcpy(cpage_out, lzo_compress_buf, compress_size); + *dstlen = compress_size; + + return 0; +} + +static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out, + uint32_t srclen, uint32_t destlen, void *model) +{ + size_t dl = destlen; + int ret; + + ret = lzo1x_decompress_safe(data_in, srclen, cpage_out, &dl); + + if (ret != LZO_E_OK || dl != destlen) + return -1; + + return 0; +} + +static struct jffs2_compressor jffs2_lzo_comp = { + .priority = JFFS2_LZO_PRIORITY, + .name = "lzo", + .compr = JFFS2_COMPR_LZO, + .compress = &jffs2_lzo_compress, + .decompress = &jffs2_lzo_decompress, + .disabled = 0, +}; + +int __init jffs2_lzo_init(void) +{ + int ret; + + ret = alloc_workspace(); + if (ret < 0) + return ret; + + ret = jffs2_register_compressor(&jffs2_lzo_comp); + if (ret) + free_workspace(); + + return ret; +} + +void jffs2_lzo_exit(void) +{ + jffs2_unregister_compressor(&jffs2_lzo_comp); + free_workspace(); +} diff --git a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c index 0d0bfd2e4e0d..546d1538d076 100644 --- a/fs/jffs2/compr_rtime.c +++ b/fs/jffs2/compr_rtime.c @@ -104,7 +104,7 @@ static int jffs2_rtime_decompress(unsigned char *data_in, } } } - return 0; + return 0; } static struct jffs2_compressor jffs2_rtime_comp = { diff --git a/fs/jffs2/compr_rubin.c b/fs/jffs2/compr_rubin.c index ea0431e047d5..c73fa89b5f8a 100644 --- a/fs/jffs2/compr_rubin.c +++ b/fs/jffs2/compr_rubin.c @@ -384,7 +384,7 @@ static int jffs2_rubinmips_decompress(unsigned char *data_in, void *model) { rubin_do_decompress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen); - return 0; + return 0; } static int jffs2_dynrubin_decompress(unsigned char *data_in, @@ -399,7 +399,7 @@ static int jffs2_dynrubin_decompress(unsigned char *data_in, bits[c] = data_in[c]; rubin_do_decompress(256, bits, data_in+8, cpage_out, sourcelen-8, dstlen); - return 0; + return 0; } static struct jffs2_compressor jffs2_rubinmips_comp = { diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c index 2b87fccc1557..cfd301a5edfc 100644 --- a/fs/jffs2/compr_zlib.c +++ b/fs/jffs2/compr_zlib.c @@ -181,7 +181,7 @@ static int jffs2_zlib_decompress(unsigned char *data_in, } zlib_inflateEnd(&inf_strm); mutex_unlock(&inflate_mutex); - return 0; + return 0; } static struct jffs2_compressor jffs2_zlib_comp = { @@ -203,11 +203,11 @@ int __init jffs2_zlib_init(void) ret = alloc_workspaces(); if (ret) - return ret; + return ret; ret = jffs2_register_compressor(&jffs2_zlib_comp); if (ret) - free_workspaces(); + free_workspaces(); return ret; } diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h index 2a49f2c51a9f..4130adabd76e 100644 --- a/fs/jffs2/debug.h +++ b/fs/jffs2/debug.h @@ -80,28 +80,28 @@ #define JFFS2_ERROR(fmt, ...) \ do { \ printk(JFFS2_ERR_MSG_PREFIX \ - " (%d) %s: " fmt, current->pid, \ + " (%d) %s: " fmt, task_pid_nr(current), \ __FUNCTION__ , ##__VA_ARGS__); \ } while(0) #define JFFS2_WARNING(fmt, ...) \ do { \ printk(JFFS2_WARN_MSG_PREFIX \ - " (%d) %s: " fmt, current->pid, \ + " (%d) %s: " fmt, task_pid_nr(current), \ __FUNCTION__ , ##__VA_ARGS__); \ } while(0) #define JFFS2_NOTICE(fmt, ...) \ do { \ printk(JFFS2_NOTICE_MSG_PREFIX \ - " (%d) %s: " fmt, current->pid, \ + " (%d) %s: " fmt, task_pid_nr(current), \ __FUNCTION__ , ##__VA_ARGS__); \ } while(0) #define JFFS2_DEBUG(fmt, ...) \ do { \ printk(JFFS2_DBG_MSG_PREFIX \ - " (%d) %s: " fmt, current->pid, \ + " (%d) %s: " fmt, task_pid_nr(current), \ __FUNCTION__ , ##__VA_ARGS__); \ } while(0) diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index c1dfca310dd6..8353eb9c1799 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -32,7 +32,7 @@ static int jffs2_mkdir (struct inode *,struct dentry *,int); static int jffs2_rmdir (struct inode *,struct dentry *); static int jffs2_mknod (struct inode *,struct dentry *,int,dev_t); static int jffs2_rename (struct inode *, struct dentry *, - struct inode *, struct dentry *); + struct inode *, struct dentry *); const struct file_operations jffs2_dir_operations = { @@ -182,6 +182,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; struct inode *inode; + struct posix_acl *acl; int ret; ri = jffs2_alloc_raw_inode(); @@ -192,7 +193,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, D1(printk(KERN_DEBUG "jffs2_create()\n")); - inode = jffs2_new_inode(dir_i, mode, ri); + inode = jffs2_new_inode(dir_i, mode, ri, &acl); if (IS_ERR(inode)) { D1(printk(KERN_DEBUG "jffs2_new_inode() failed\n")); @@ -212,12 +213,12 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, dentry->d_name.name, dentry->d_name.len); if (ret) - goto fail; + goto fail_acl; ret = jffs2_init_security(inode, dir_i); if (ret) - goto fail; - ret = jffs2_init_acl(inode, dir_i); + goto fail_acl; + ret = jffs2_init_acl(inode, acl); if (ret) goto fail; @@ -230,6 +231,8 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->nlink, inode->i_mapping->nrpages)); return 0; + fail_acl: + posix_acl_release(acl); fail: make_bad_inode(inode); iput(inode); @@ -306,6 +309,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char struct jffs2_full_dirent *fd; int namelen; uint32_t alloclen; + struct posix_acl *acl; int ret, targetlen = strlen(target); /* FIXME: If you care. We'd need to use frags for the target @@ -332,7 +336,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char return ret; } - inode = jffs2_new_inode(dir_i, S_IFLNK | S_IRWXUGO, ri); + inode = jffs2_new_inode(dir_i, S_IFLNK | S_IRWXUGO, ri, &acl); if (IS_ERR(inode)) { jffs2_free_raw_inode(ri); @@ -362,6 +366,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char up(&f->sem); jffs2_complete_reservation(c); jffs2_clear_inode(inode); + posix_acl_release(acl); return PTR_ERR(fn); } @@ -372,6 +377,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char up(&f->sem); jffs2_complete_reservation(c); jffs2_clear_inode(inode); + posix_acl_release(acl); return -ENOMEM; } @@ -389,9 +395,10 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char ret = jffs2_init_security(inode, dir_i); if (ret) { jffs2_clear_inode(inode); + posix_acl_release(acl); return ret; } - ret = jffs2_init_acl(inode, dir_i); + ret = jffs2_init_acl(inode, acl); if (ret) { jffs2_clear_inode(inode); return ret; @@ -469,6 +476,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) struct jffs2_full_dirent *fd; int namelen; uint32_t alloclen; + struct posix_acl *acl; int ret; mode |= S_IFDIR; @@ -491,7 +499,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) return ret; } - inode = jffs2_new_inode(dir_i, mode, ri); + inode = jffs2_new_inode(dir_i, mode, ri, &acl); if (IS_ERR(inode)) { jffs2_free_raw_inode(ri); @@ -518,6 +526,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) up(&f->sem); jffs2_complete_reservation(c); jffs2_clear_inode(inode); + posix_acl_release(acl); return PTR_ERR(fn); } /* No data here. Only a metadata node, which will be @@ -531,9 +540,10 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) ret = jffs2_init_security(inode, dir_i); if (ret) { jffs2_clear_inode(inode); + posix_acl_release(acl); return ret; } - ret = jffs2_init_acl(inode, dir_i); + ret = jffs2_init_acl(inode, acl); if (ret) { jffs2_clear_inode(inode); return ret; @@ -629,6 +639,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de union jffs2_device_node dev; int devlen = 0; uint32_t alloclen; + struct posix_acl *acl; int ret; if (!new_valid_dev(rdev)) @@ -655,7 +666,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de return ret; } - inode = jffs2_new_inode(dir_i, mode, ri); + inode = jffs2_new_inode(dir_i, mode, ri, &acl); if (IS_ERR(inode)) { jffs2_free_raw_inode(ri); @@ -684,6 +695,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de up(&f->sem); jffs2_complete_reservation(c); jffs2_clear_inode(inode); + posix_acl_release(acl); return PTR_ERR(fn); } /* No data here. Only a metadata node, which will be @@ -697,9 +709,10 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de ret = jffs2_init_security(inode, dir_i); if (ret) { jffs2_clear_inode(inode); + posix_acl_release(acl); return ret; } - ret = jffs2_init_acl(inode, dir_i); + ret = jffs2_init_acl(inode, acl); if (ret) { jffs2_clear_inode(inode); return ret; @@ -770,7 +783,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de } static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, - struct inode *new_dir_i, struct dentry *new_dentry) + struct inode *new_dir_i, struct dentry *new_dentry) { int ret; struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index 66e7c2f1e644..a1db9180633f 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -38,8 +38,8 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, #ifdef __ECOS ret = jffs2_flash_erase(c, jeb); if (!ret) { - jffs2_erase_succeeded(c, jeb); - return; + jffs2_erase_succeeded(c, jeb); + return; } bad_offset = jeb->offset; #else /* Linux */ @@ -50,12 +50,14 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); if (!instr) { printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); + down(&c->erase_free_sem); spin_lock(&c->erase_completion_lock); list_move(&jeb->list, &c->erase_pending_list); c->erasing_size -= c->sector_size; c->dirty_size += c->sector_size; jeb->dirty_size = c->sector_size; spin_unlock(&c->erase_completion_lock); + up(&c->erase_free_sem); return; } @@ -82,12 +84,14 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, if (ret == -ENOMEM || ret == -EAGAIN) { /* Erase failed immediately. Refile it on the list */ D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret)); + down(&c->erase_free_sem); spin_lock(&c->erase_completion_lock); list_move(&jeb->list, &c->erase_pending_list); c->erasing_size -= c->sector_size; c->dirty_size += c->sector_size; jeb->dirty_size = c->sector_size; spin_unlock(&c->erase_completion_lock); + up(&c->erase_free_sem); return; } @@ -114,6 +118,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list); list_del(&jeb->list); spin_unlock(&c->erase_completion_lock); + up(&c->erase_free_sem); jffs2_mark_erased_block(c, jeb); if (!--count) { @@ -134,6 +139,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) jffs2_free_jeb_node_refs(c, jeb); list_add(&jeb->list, &c->erasing_list); spin_unlock(&c->erase_completion_lock); + up(&c->erase_free_sem); jffs2_erase_block(c, jeb); @@ -142,23 +148,25 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) } /* Be nice */ - cond_resched(); + yield(); + down(&c->erase_free_sem); spin_lock(&c->erase_completion_lock); } spin_unlock(&c->erase_completion_lock); + up(&c->erase_free_sem); done: D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n")); - - up(&c->erase_free_sem); } static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", jeb->offset)); + down(&c->erase_free_sem); spin_lock(&c->erase_completion_lock); list_move_tail(&jeb->list, &c->erase_complete_list); spin_unlock(&c->erase_completion_lock); + up(&c->erase_free_sem); /* Ensure that kupdated calls us again to mark them clean */ jffs2_erase_pending_trigger(c); } @@ -172,22 +180,26 @@ static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock failed too many times. */ if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) { /* We'd like to give this block another try. */ + down(&c->erase_free_sem); spin_lock(&c->erase_completion_lock); list_move(&jeb->list, &c->erase_pending_list); c->erasing_size -= c->sector_size; c->dirty_size += c->sector_size; jeb->dirty_size = c->sector_size; spin_unlock(&c->erase_completion_lock); + up(&c->erase_free_sem); return; } } + down(&c->erase_free_sem); spin_lock(&c->erase_completion_lock); c->erasing_size -= c->sector_size; c->bad_size += c->sector_size; list_move(&jeb->list, &c->bad_list); c->nr_erasing_blocks--; spin_unlock(&c->erase_completion_lock); + up(&c->erase_free_sem); wake_up(&c->erase_wait); } @@ -317,6 +329,33 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl size_t retlen; int ret = -EIO; + if (c->mtd->point) { + unsigned long *wordebuf; + + ret = c->mtd->point(c->mtd, jeb->offset, c->sector_size, &retlen, (unsigned char **)&ebuf); + if (ret) { + D1(printk(KERN_DEBUG "MTD point failed %d\n", ret)); + goto do_flash_read; + } + if (retlen < c->sector_size) { + /* Don't muck about if it won't let us point to the whole erase sector */ + D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen)); + c->mtd->unpoint(c->mtd, ebuf, jeb->offset, retlen); + goto do_flash_read; + } + wordebuf = ebuf-sizeof(*wordebuf); + retlen /= sizeof(*wordebuf); + do { + if (*++wordebuf != ~0) + break; + } while(--retlen); + c->mtd->unpoint(c->mtd, ebuf, jeb->offset, c->sector_size); + if (retlen) + printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08tx\n", + *wordebuf, jeb->offset + c->sector_size-retlen*sizeof(*wordebuf)); + return 0; + } + do_flash_read: ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!ebuf) { printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Refiling\n", jeb->offset); @@ -362,7 +401,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb { size_t retlen; int ret; - uint32_t bad_offset; + uint32_t uninitialized_var(bad_offset); switch (jffs2_block_check_erase(c, jeb, &bad_offset)) { case -EAGAIN: goto refile; @@ -417,6 +456,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, c->cleanmarker_size, NULL); } + down(&c->erase_free_sem); spin_lock(&c->erase_completion_lock); c->erasing_size -= c->sector_size; c->free_size += jeb->free_size; @@ -429,23 +469,28 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb c->nr_erasing_blocks--; c->nr_free_blocks++; spin_unlock(&c->erase_completion_lock); + up(&c->erase_free_sem); wake_up(&c->erase_wait); return; filebad: + down(&c->erase_free_sem); spin_lock(&c->erase_completion_lock); /* Stick it on a list (any list) so erase_failed can take it right off again. Silly, but shouldn't happen often. */ list_add(&jeb->list, &c->erasing_list); spin_unlock(&c->erase_completion_lock); + up(&c->erase_free_sem); jffs2_erase_failed(c, jeb, bad_offset); return; refile: /* Stick it back on the list from whence it came and come back later */ jffs2_erase_pending_trigger(c); + down(&c->erase_free_sem); spin_lock(&c->erase_completion_lock); list_add(&jeb->list, &c->erase_complete_list); spin_unlock(&c->erase_completion_lock); + up(&c->erase_free_sem); return; } diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index c2530197be0c..023a17539dd4 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -19,10 +19,12 @@ #include <linux/jffs2.h> #include "nodelist.h" -static int jffs2_commit_write (struct file *filp, struct page *pg, - unsigned start, unsigned end); -static int jffs2_prepare_write (struct file *filp, struct page *pg, - unsigned start, unsigned end); +static int jffs2_write_end(struct file *filp, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *pg, void *fsdata); +static int jffs2_write_begin(struct file *filp, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata); static int jffs2_readpage (struct file *filp, struct page *pg); int jffs2_fsync(struct file *filp, struct dentry *dentry, int datasync) @@ -65,8 +67,8 @@ const struct inode_operations jffs2_file_inode_operations = const struct address_space_operations jffs2_file_address_operations = { .readpage = jffs2_readpage, - .prepare_write =jffs2_prepare_write, - .commit_write = jffs2_commit_write + .write_begin = jffs2_write_begin, + .write_end = jffs2_write_end, }; static int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg) @@ -119,15 +121,23 @@ static int jffs2_readpage (struct file *filp, struct page *pg) return ret; } -static int jffs2_prepare_write (struct file *filp, struct page *pg, - unsigned start, unsigned end) +static int jffs2_write_begin(struct file *filp, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - struct inode *inode = pg->mapping->host; + struct page *pg; + struct inode *inode = mapping->host; struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - uint32_t pageofs = pg->index << PAGE_CACHE_SHIFT; + pgoff_t index = pos >> PAGE_CACHE_SHIFT; + uint32_t pageofs = pos & (PAGE_CACHE_SIZE - 1); int ret = 0; - D1(printk(KERN_DEBUG "jffs2_prepare_write()\n")); + pg = __grab_cache_page(mapping, index); + if (!pg) + return -ENOMEM; + *pagep = pg; + + D1(printk(KERN_DEBUG "jffs2_write_begin()\n")); if (pageofs > inode->i_size) { /* Make new hole frag from old EOF to new page */ @@ -142,7 +152,7 @@ static int jffs2_prepare_write (struct file *filp, struct page *pg, ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); if (ret) - return ret; + goto out_page; down(&f->sem); memset(&ri, 0, sizeof(ri)); @@ -172,7 +182,7 @@ static int jffs2_prepare_write (struct file *filp, struct page *pg, ret = PTR_ERR(fn); jffs2_complete_reservation(c); up(&f->sem); - return ret; + goto out_page; } ret = jffs2_add_full_dnode_to_inode(c, f, fn); if (f->metadata) { @@ -181,65 +191,79 @@ static int jffs2_prepare_write (struct file *filp, struct page *pg, f->metadata = NULL; } if (ret) { - D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in prepare_write, returned %d\n", ret)); + D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in write_begin, returned %d\n", ret)); jffs2_mark_node_obsolete(c, fn->raw); jffs2_free_full_dnode(fn); jffs2_complete_reservation(c); up(&f->sem); - return ret; + goto out_page; } jffs2_complete_reservation(c); inode->i_size = pageofs; up(&f->sem); } - /* Read in the page if it wasn't already present, unless it's a whole page */ - if (!PageUptodate(pg) && (start || end < PAGE_CACHE_SIZE)) { + /* + * Read in the page if it wasn't already present. Cannot optimize away + * the whole page write case until jffs2_write_end can handle the + * case of a short-copy. + */ + if (!PageUptodate(pg)) { down(&f->sem); ret = jffs2_do_readpage_nolock(inode, pg); up(&f->sem); + if (ret) + goto out_page; } - D1(printk(KERN_DEBUG "end prepare_write(). pg->flags %lx\n", pg->flags)); + D1(printk(KERN_DEBUG "end write_begin(). pg->flags %lx\n", pg->flags)); + return ret; + +out_page: + unlock_page(pg); + page_cache_release(pg); return ret; } -static int jffs2_commit_write (struct file *filp, struct page *pg, - unsigned start, unsigned end) +static int jffs2_write_end(struct file *filp, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *pg, void *fsdata) { /* Actually commit the write from the page cache page we're looking at. * For now, we write the full page out each time. It sucks, but it's simple */ - struct inode *inode = pg->mapping->host; + struct inode *inode = mapping->host; struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); struct jffs2_raw_inode *ri; + unsigned start = pos & (PAGE_CACHE_SIZE - 1); + unsigned end = start + copied; unsigned aligned_start = start & ~3; int ret = 0; uint32_t writtenlen = 0; - D1(printk(KERN_DEBUG "jffs2_commit_write(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx\n", + D1(printk(KERN_DEBUG "jffs2_write_end(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT, start, end, pg->flags)); + /* We need to avoid deadlock with page_cache_read() in + jffs2_garbage_collect_pass(). So the page must be + up to date to prevent page_cache_read() from trying + to re-lock it. */ + BUG_ON(!PageUptodate(pg)); + if (end == PAGE_CACHE_SIZE) { - if (!start) { - /* We need to avoid deadlock with page_cache_read() in - jffs2_garbage_collect_pass(). So we have to mark the - page up to date, to prevent page_cache_read() from - trying to re-lock it. */ - SetPageUptodate(pg); - } else { - /* When writing out the end of a page, write out the - _whole_ page. This helps to reduce the number of - nodes in files which have many short writes, like - syslog files. */ - start = aligned_start = 0; - } + /* When writing out the end of a page, write out the + _whole_ page. This helps to reduce the number of + nodes in files which have many short writes, like + syslog files. */ + start = aligned_start = 0; } ri = jffs2_alloc_raw_inode(); if (!ri) { - D1(printk(KERN_DEBUG "jffs2_commit_write(): Allocation of raw inode failed\n")); + D1(printk(KERN_DEBUG "jffs2_write_end(): Allocation of raw inode failed\n")); + unlock_page(pg); + page_cache_release(pg); return -ENOMEM; } @@ -287,11 +311,14 @@ static int jffs2_commit_write (struct file *filp, struct page *pg, /* generic_file_write has written more to the page cache than we've actually written to the medium. Mark the page !Uptodate so that it gets reread */ - D1(printk(KERN_DEBUG "jffs2_commit_write(): Not all bytes written. Marking page !uptodate\n")); + D1(printk(KERN_DEBUG "jffs2_write_end(): Not all bytes written. Marking page !uptodate\n")); SetPageError(pg); ClearPageUptodate(pg); } - D1(printk(KERN_DEBUG "jffs2_commit_write() returning %d\n",start+writtenlen==end?0:ret)); - return start+writtenlen==end?0:ret; + D1(printk(KERN_DEBUG "jffs2_write_end() returning %d\n", + writtenlen > 0 ? writtenlen : ret)); + unlock_page(pg); + page_cache_release(pg); + return writtenlen > 0 ? writtenlen : ret; } diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 8bc727b71696..ed85f9afdbc8 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -24,7 +24,7 @@ static int jffs2_flash_setup(struct jffs2_sb_info *c); -static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) +int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) { struct jffs2_full_dnode *old_metadata, *new_metadata; struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); @@ -36,10 +36,8 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) unsigned int ivalid; uint32_t alloclen; int ret; + D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino)); - ret = inode_change_ok(inode, iattr); - if (ret) - return ret; /* Special cases - we don't want more than one data node for these types on the medium at any time. So setattr @@ -183,9 +181,14 @@ int jffs2_setattr(struct dentry *dentry, struct iattr *iattr) { int rc; + rc = inode_change_ok(dentry->d_inode, iattr); + if (rc) + return rc; + rc = jffs2_do_setattr(dentry->d_inode, iattr); if (!rc && (iattr->ia_valid & ATTR_MODE)) rc = jffs2_acl_chmod(dentry->d_inode); + return rc; } @@ -399,7 +402,8 @@ void jffs2_write_super (struct super_block *sb) /* jffs2_new_inode: allocate a new inode and inocache, add it to the hash, fill in the raw_inode while you're at it. */ -struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri) +struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri, + struct posix_acl **acl) { struct inode *inode; struct super_block *sb = dir_i->i_sb; @@ -431,7 +435,23 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i } else { ri->gid = cpu_to_je16(current->fsgid); } - ri->mode = cpu_to_jemode(mode); + + /* POSIX ACLs have to be processed now, at least partly. + The umask is only applied if there's no default ACL */ + if (!S_ISLNK(mode)) { + *acl = jffs2_get_acl(dir_i, ACL_TYPE_DEFAULT); + if (IS_ERR(*acl)) { + make_bad_inode(inode); + iput(inode); + inode = (void *)*acl; + *acl = NULL; + return inode; + } + if (!(*acl)) + mode &= ~current->fs->umask; + } else { + *acl = NULL; + } ret = jffs2_do_new_inode (c, f, mode, ri); if (ret) { make_bad_inode(inode); diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 2d99e06ab223..32ff0373aa04 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -122,6 +122,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) struct jffs2_inode_cache *ic; struct jffs2_eraseblock *jeb; struct jffs2_raw_node_ref *raw; + uint32_t gcblock_dirty; int ret = 0, inum, nlink; int xattr = 0; @@ -236,6 +237,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) } raw = jeb->gc_node; + gcblock_dirty = jeb->dirty_size; while(ref_obsolete(raw)) { D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", ref_offset(raw))); @@ -282,7 +284,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) } else { ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic, raw); } - goto release_sem; + goto test_gcnode; } #endif @@ -376,7 +378,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) if (ret != -EBADFD) { spin_unlock(&c->inocache_lock); - goto release_sem; + goto test_gcnode; } /* Fall through if it wanted us to, with inocache_lock held */ @@ -407,6 +409,12 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) jffs2_gc_release_inode(c, f); + test_gcnode: + if (jeb->dirty_size == gcblock_dirty && !ref_obsolete(jeb->gc_node)) { + /* Eep. This really should never happen. GC is broken */ + printk(KERN_ERR "Error garbage collecting node at %08x!\n", ref_offset(jeb->gc_node)); + ret = -ENOSPC; + } release_sem: up(&c->alloc_sem); @@ -556,7 +564,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, node = kmalloc(rawlen, GFP_KERNEL); if (!node) - return -ENOMEM; + return -ENOMEM; ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)node); if (!ret && retlen != rawlen) @@ -598,10 +606,15 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, goto bail; } + if (strnlen(node->d.name, node->d.nsize) != node->d.nsize) { + printk(KERN_WARNING "Name in dirent node at 0x%08x contains zeroes\n", ref_offset(raw)); + goto bail; + } + if (node->d.nsize) { crc = crc32(0, node->d.name, node->d.nsize); if (je32_to_cpu(node->d.name_crc) != crc) { - printk(KERN_WARNING "Name CRC failed on REF_PRISTINE dirent ode at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + printk(KERN_WARNING "Name CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", ref_offset(raw), je32_to_cpu(node->d.name_crc), crc); goto bail; } @@ -624,7 +637,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, if (ret || (retlen != rawlen)) { printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n", - rawlen, phys_ofs, ret, retlen); + rawlen, phys_ofs, ret, retlen); if (retlen) { jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, rawlen, NULL); } else { diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index b13298a824ed..3a2197f3c812 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h @@ -69,6 +69,8 @@ struct jffs2_sb_info { uint8_t resv_blocks_gctrigger; /* ... wake up the GC thread */ uint8_t resv_blocks_gcbad; /* ... pick a block from the bad_list to GC */ uint8_t resv_blocks_gcmerge; /* ... merge pages when garbage collecting */ + /* Number of 'very dirty' blocks before we trigger immediate GC */ + uint8_t vdirty_blocks_gctrigger; uint32_t nospc_dirty_size; @@ -106,6 +108,9 @@ struct jffs2_sb_info { uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */ +#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY + unsigned char *wbuf_verify; /* read-back buffer for verification */ +#endif #ifdef CONFIG_JFFS2_FS_WRITEBUFFER unsigned char *wbuf; /* Write-behind buffer for NAND flash */ uint32_t wbuf_ofs; diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index bc5509fe577b..ec1aae9e695e 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -127,7 +127,7 @@ static inline struct jffs2_inode_cache *jffs2_raw_ref_to_ic(struct jffs2_raw_nod return ((struct jffs2_inode_cache *)raw); } - /* flash_offset & 3 always has to be zero, because nodes are + /* flash_offset & 3 always has to be zero, because nodes are always aligned at 4 bytes. So we have a couple of extra bits to play with, which indicate the node's status; see below: */ #define REF_UNCHECKED 0 /* We haven't yet checked the CRC or built its inode */ diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index dbc908ad622b..a0313fa8748e 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -154,7 +154,7 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, while(ret == -EAGAIN) { ret = jffs2_do_reserve_space(c, minsize, len, sumsize); if (ret) { - D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret)); + D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret)); } } spin_unlock(&c->erase_completion_lock); @@ -423,7 +423,12 @@ struct jffs2_raw_node_ref *jffs2_add_physical_node_ref(struct jffs2_sb_info *c, even after refiling c->nextblock */ if ((c->nextblock || ((ofs & 3) != REF_OBSOLETE)) && (jeb != c->nextblock || (ofs & ~3) != jeb->offset + (c->sector_size - jeb->free_size))) { - printk(KERN_WARNING "argh. node added in wrong place\n"); + printk(KERN_WARNING "argh. node added in wrong place at 0x%08x(%d)\n", ofs & ~3, ofs & 3); + if (c->nextblock) + printk(KERN_WARNING "nextblock 0x%08x", c->nextblock->offset); + else + printk(KERN_WARNING "No nextblock"); + printk(", expected at %08x\n", jeb->offset + (c->sector_size - jeb->free_size)); return ERR_PTR(-EINVAL); } #endif @@ -717,6 +722,8 @@ int jffs2_thread_should_wake(struct jffs2_sb_info *c) { int ret = 0; uint32_t dirty; + int nr_very_dirty = 0; + struct jffs2_eraseblock *jeb; if (c->unchecked_size) { D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): unchecked_size %d, checked_ino #%d\n", @@ -738,8 +745,18 @@ int jffs2_thread_should_wake(struct jffs2_sb_info *c) (dirty > c->nospc_dirty_size)) ret = 1; - D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n", - c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, ret?"yes":"no")); + list_for_each_entry(jeb, &c->very_dirty_list, list) { + nr_very_dirty++; + if (nr_very_dirty == c->vdirty_blocks_gctrigger) { + ret = 1; + /* In debug mode, actually go through and count them all */ + D1(continue); + break; + } + } + + D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x, vdirty_blocks %d: %s\n", + c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, nr_very_dirty, ret?"yes":"no")); return ret; } diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 80daea96bbc2..f6743a915cf3 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -173,12 +173,15 @@ int jffs2_ioctl(struct inode *, struct file *, unsigned int, unsigned long); extern const struct inode_operations jffs2_symlink_inode_operations; /* fs.c */ +struct posix_acl; + int jffs2_setattr (struct dentry *, struct iattr *); +int jffs2_do_setattr (struct inode *, struct iattr *); void jffs2_read_inode (struct inode *); void jffs2_clear_inode (struct inode *); void jffs2_dirty_inode(struct inode *inode); struct inode *jffs2_new_inode (struct inode *dir_i, int mode, - struct jffs2_raw_inode *ri); + struct jffs2_raw_inode *ri, struct posix_acl **acl); int jffs2_statfs (struct dentry *, struct kstatfs *); void jffs2_write_super (struct super_block *); int jffs2_remount_fs (struct super_block *, int *, char *); diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index b5baa356fed2..2eae5d2dbebe 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c @@ -65,7 +65,7 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer); if (!err && retlen < tn->csize) { JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize); - c->mtd->unpoint(c->mtd, buffer, ofs, len); + c->mtd->unpoint(c->mtd, buffer, ofs, retlen); } else if (err) JFFS2_WARNING("MTD point failed: error code %d.\n", err); else @@ -211,7 +211,7 @@ static void jffs2_kill_tn(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info * * ordering. * * Returns 0 if the node was handled (including marking it obsolete) - * < 0 an if error occurred + * < 0 an if error occurred */ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c, struct jffs2_readinode_info *rii, @@ -862,8 +862,8 @@ static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_re JFFS2_ERROR("REF_UNCHECKED but unknown node at %#08x\n", ref_offset(ref)); JFFS2_ERROR("Node is {%04x,%04x,%08x,%08x}. Please report this error.\n", - je16_to_cpu(un->magic), je16_to_cpu(un->nodetype), - je32_to_cpu(un->totlen), je32_to_cpu(un->hdr_crc)); + je16_to_cpu(un->magic), je16_to_cpu(un->nodetype), + je32_to_cpu(un->totlen), je32_to_cpu(un->hdr_crc)); jffs2_mark_node_obsolete(c, ref); return 0; } diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 6c75cd433342..272872d27fd5 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -101,7 +101,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) if (!ret && pointlen < c->mtd->size) { /* Don't muck about if it won't let us point to the whole flash */ D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen)); - c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size); + c->mtd->unpoint(c->mtd, flashbuf, 0, pointlen); flashbuf = NULL; } if (ret) @@ -863,7 +863,7 @@ scan_more: switch (je16_to_cpu(node->nodetype) & JFFS2_COMPAT_MASK) { case JFFS2_FEATURE_ROCOMPAT: printk(KERN_NOTICE "Read-only compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs); - c->flags |= JFFS2_SB_FLAG_RO; + c->flags |= JFFS2_SB_FLAG_RO; if (!(jffs2_is_readonly(c))) return -EROFS; if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen))))) @@ -1004,6 +1004,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo { struct jffs2_full_dirent *fd; struct jffs2_inode_cache *ic; + uint32_t checkedlen; uint32_t crc; int err; @@ -1024,12 +1025,18 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo pseudo_random += je32_to_cpu(rd->version); - fd = jffs2_alloc_full_dirent(rd->nsize+1); + /* Should never happen. Did. (OLPC trac #4184)*/ + checkedlen = strnlen(rd->name, rd->nsize); + if (checkedlen < rd->nsize) { + printk(KERN_ERR "Dirent at %08x has zeroes in name. Truncating to %d chars\n", + ofs, checkedlen); + } + fd = jffs2_alloc_full_dirent(checkedlen+1); if (!fd) { return -ENOMEM; } - memcpy(&fd->name, rd->name, rd->nsize); - fd->name[rd->nsize] = 0; + memcpy(&fd->name, rd->name, checkedlen); + fd->name[checkedlen] = 0; crc = crc32(0, fd->name, rd->nsize); if (crc != je32_to_cpu(rd->name_crc)) { @@ -1055,7 +1062,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo fd->next = NULL; fd->version = je32_to_cpu(rd->version); fd->ino = je32_to_cpu(rd->ino); - fd->nhash = full_name_hash(fd->name, rd->nsize); + fd->nhash = full_name_hash(fd->name, checkedlen); fd->type = rd->type; jffs2_add_fd_to_list(c, fd, &ic->scan_dents); diff --git a/fs/jffs2/security.c b/fs/jffs2/security.c index bc9f6ba10823..02c39c64ecb3 100644 --- a/fs/jffs2/security.c +++ b/fs/jffs2/security.c @@ -38,9 +38,9 @@ int jffs2_init_security(struct inode *inode, struct inode *dir) } rc = do_jffs2_setxattr(inode, JFFS2_XPREFIX_SECURITY, name, value, len, 0); - kfree(name); - kfree(value); - return rc; + kfree(name); + kfree(value); + return rc; } /* ---- XATTR Handler for "security.*" ----------------- */ diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index d828b296392a..629af01e5ade 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -2,10 +2,10 @@ * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, - * Zoltan Sogor <weth@inf.u-szeged.hu>, - * Patrik Kluba <pajko@halom.u-szeged.hu>, - * University of Szeged, Hungary - * 2006 KaiGai Kohei <kaigai@ak.jp.nec.com> + * Zoltan Sogor <weth@inf.u-szeged.hu>, + * Patrik Kluba <pajko@halom.u-szeged.hu>, + * University of Szeged, Hungary + * 2006 KaiGai Kohei <kaigai@ak.jp.nec.com> * * For licensing information, see the file 'LICENCE' in this directory. * @@ -429,6 +429,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras case JFFS2_NODETYPE_DIRENT: { struct jffs2_sum_dirent_flash *spd; + int checkedlen; spd = sp; dbg_summary("Dirent at 0x%08x-0x%08x\n", @@ -436,12 +437,25 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras jeb->offset + je32_to_cpu(spd->offset) + je32_to_cpu(spd->totlen)); - fd = jffs2_alloc_full_dirent(spd->nsize+1); + /* This should never happen, but https://dev.laptop.org/ticket/4184 */ + checkedlen = strnlen(spd->name, spd->nsize); + if (!checkedlen) { + printk(KERN_ERR "Dirent at %08x has zero at start of name. Aborting mount.\n", + jeb->offset + je32_to_cpu(spd->offset)); + return -EIO; + } + if (checkedlen < spd->nsize) { + printk(KERN_ERR "Dirent at %08x has zeroes in name. Truncating to %d chars\n", + jeb->offset + je32_to_cpu(spd->offset), checkedlen); + } + + + fd = jffs2_alloc_full_dirent(checkedlen+1); if (!fd) return -ENOMEM; - memcpy(&fd->name, spd->name, spd->nsize); - fd->name[spd->nsize] = 0; + memcpy(&fd->name, spd->name, checkedlen); + fd->name[checkedlen] = 0; ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino)); if (!ic) { @@ -455,7 +469,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras fd->next = NULL; fd->version = je32_to_cpu(spd->version); fd->ino = je32_to_cpu(spd->ino); - fd->nhash = full_name_hash(fd->name, spd->nsize); + fd->nhash = full_name_hash(fd->name, checkedlen); fd->type = spd->type; jffs2_add_fd_to_list(c, fd, &ic->scan_dents); diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h index 0c6669e21390..8bf34f2fa5ce 100644 --- a/fs/jffs2/summary.h +++ b/fs/jffs2/summary.h @@ -2,9 +2,9 @@ * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, - * Zoltan Sogor <weth@inf.u-szeged.hu>, - * Patrik Kluba <pajko@halom.u-szeged.hu>, - * University of Szeged, Hungary + * Zoltan Sogor <weth@inf.u-szeged.hu>, + * Patrik Kluba <pajko@halom.u-szeged.hu>, + * University of Szeged, Hungary * * For licensing information, see the file 'LICENCE' in this directory. * diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index be2b70c2ec16..ffa447511e6a 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -43,7 +43,7 @@ static void jffs2_destroy_inode(struct inode *inode) kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode)); } -static void jffs2_i_init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) +static void jffs2_i_init_once(struct kmem_cache *cachep, void *foo) { struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo; diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 91d1d0f1c66c..d1d4f27464ba 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -220,6 +220,47 @@ static struct jffs2_raw_node_ref **jffs2_incore_replace_raw(struct jffs2_sb_info return NULL; } +#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY +static int jffs2_verify_write(struct jffs2_sb_info *c, unsigned char *buf, + uint32_t ofs) +{ + int ret; + size_t retlen; + char *eccstr; + + ret = c->mtd->read(c->mtd, ofs, c->wbuf_pagesize, &retlen, c->wbuf_verify); + if (ret && ret != -EUCLEAN && ret != -EBADMSG) { + printk(KERN_WARNING "jffs2_verify_write(): Read back of page at %08x failed: %d\n", c->wbuf_ofs, ret); + return ret; + } else if (retlen != c->wbuf_pagesize) { + printk(KERN_WARNING "jffs2_verify_write(): Read back of page at %08x gave short read: %zd not %d.\n", ofs, retlen, c->wbuf_pagesize); + return -EIO; + } + if (!memcmp(buf, c->wbuf_verify, c->wbuf_pagesize)) + return 0; + + if (ret == -EUCLEAN) + eccstr = "corrected"; + else if (ret == -EBADMSG) + eccstr = "correction failed"; + else + eccstr = "OK or unused"; + + printk(KERN_WARNING "Write verify error (ECC %s) at %08x. Wrote:\n", + eccstr, c->wbuf_ofs); + print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, + c->wbuf, c->wbuf_pagesize, 0); + + printk(KERN_WARNING "Read back:\n"); + print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, + c->wbuf_verify, c->wbuf_pagesize, 0); + + return -EIO; +} +#else +#define jffs2_verify_write(c,b,o) (0) +#endif + /* Recover from failure to write wbuf. Recover the nodes up to the * wbuf, not the one which we were starting to try to write. */ @@ -380,7 +421,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, rewrite_buf); - if (ret || retlen != towrite) { + if (ret || retlen != towrite || jffs2_verify_write(c, rewrite_buf, ofs)) { /* Argh. We tried. Really we did. */ printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n"); kfree(buf); @@ -587,15 +628,16 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf); - if (ret || retlen != c->wbuf_pagesize) { - if (ret) - printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n",ret); - else { - printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n", - retlen, c->wbuf_pagesize); - ret = -EIO; - } - + if (ret) { + printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n", ret); + goto wfail; + } else if (retlen != c->wbuf_pagesize) { + printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n", + retlen, c->wbuf_pagesize); + ret = -EIO; + goto wfail; + } else if ((ret = jffs2_verify_write(c, c->wbuf, c->wbuf_ofs))) { + wfail: jffs2_wbuf_recover(c); return ret; @@ -966,8 +1008,8 @@ exit: #define NR_OOB_SCAN_PAGES 4 -/* For historical reasons we use only 12 bytes for OOB clean marker */ -#define OOB_CM_SIZE 12 +/* For historical reasons we use only 8 bytes for OOB clean marker */ +#define OOB_CM_SIZE 8 static const struct jffs2_unknown_node oob_cleanmarker = { @@ -1021,8 +1063,8 @@ int jffs2_check_oob_empty(struct jffs2_sb_info *c, /* * Check for a valid cleanmarker. * Returns: 0 if a valid cleanmarker was found - * 1 if no cleanmarker was found - * negative error code if an error occurred + * 1 if no cleanmarker was found + * negative error code if an error occurred */ int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) @@ -1138,11 +1180,22 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c) return -ENOMEM; } +#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY + c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL); + if (!c->wbuf_verify) { + kfree(c->oobbuf); + kfree(c->wbuf); + return -ENOMEM; + } +#endif return 0; } void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c) { +#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY + kfree(c->wbuf_verify); +#endif kfree(c->wbuf); kfree(c->oobbuf); } diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index 664c164aa67c..2f5695446d0f 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c @@ -215,6 +215,17 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff BUG(); }); + if (strnlen(name, namelen) != namelen) { + /* This should never happen, but seems to have done on at least one + occasion: https://dev.laptop.org/ticket/4184 */ + printk(KERN_CRIT "Error in jffs2_write_dirent() -- name contains zero bytes!\n"); + printk(KERN_CRIT "Directory inode #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x\n", + je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino), + je32_to_cpu(rd->name_crc)); + WARN_ON(1); + return ERR_PTR(-EIO); + } + vecs[0].iov_base = rd; vecs[0].iov_len = sizeof(*rd); vecs[1].iov_base = (unsigned char *)name; @@ -226,7 +237,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff fd->version = je32_to_cpu(rd->version); fd->ino = je32_to_cpu(rd->ino); - fd->nhash = full_name_hash(name, strlen(name)); + fd->nhash = full_name_hash(name, namelen); fd->type = rd->type; memcpy(fd->name, name, namelen); fd->name[namelen]=0; diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h index 3b0ff2925937..6e3b5ddfb7ab 100644 --- a/fs/jffs2/xattr.h +++ b/fs/jffs2/xattr.h @@ -75,7 +75,7 @@ extern void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c); extern void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c); extern struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c, - uint32_t xid, uint32_t version); + uint32_t xid, uint32_t version); extern void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic); extern void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic); diff --git a/fs/jffs2/xattr_user.c b/fs/jffs2/xattr_user.c index 40942bc516bb..8bbeab90ada1 100644 --- a/fs/jffs2/xattr_user.c +++ b/fs/jffs2/xattr_user.c @@ -17,7 +17,7 @@ #include "nodelist.h" static int jffs2_user_getxattr(struct inode *inode, const char *name, - void *buffer, size_t size) + void *buffer, size_t size) { if (!strcmp(name, "")) return -EINVAL; @@ -25,7 +25,7 @@ static int jffs2_user_getxattr(struct inode *inode, const char *name, } static int jffs2_user_setxattr(struct inode *inode, const char *name, const void *buffer, - size_t size, int flags) + size_t size, int flags) { if (!strcmp(name, "")) return -EINVAL; diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index 3467dde27e5a..4672013802e1 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c @@ -255,7 +255,7 @@ int jfs_get_block(struct inode *ip, sector_t lblock, static int jfs_writepage(struct page *page, struct writeback_control *wbc) { - return nobh_writepage(page, jfs_get_block, wbc); + return block_write_full_page(page, jfs_get_block, wbc); } static int jfs_writepages(struct address_space *mapping, @@ -275,10 +275,12 @@ static int jfs_readpages(struct file *file, struct address_space *mapping, return mpage_readpages(mapping, pages, nr_pages, jfs_get_block); } -static int jfs_prepare_write(struct file *file, - struct page *page, unsigned from, unsigned to) +static int jfs_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - return nobh_prepare_write(page, from, to, jfs_get_block); + return nobh_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + jfs_get_block); } static sector_t jfs_bmap(struct address_space *mapping, sector_t block) @@ -302,8 +304,8 @@ const struct address_space_operations jfs_aops = { .writepage = jfs_writepage, .writepages = jfs_writepages, .sync_page = block_sync_page, - .prepare_write = jfs_prepare_write, - .commit_write = nobh_commit_write, + .write_begin = jfs_write_begin, + .write_end = nobh_write_end, .bmap = jfs_bmap, .direct_IO = jfs_direct_IO, }; @@ -356,7 +358,7 @@ void jfs_truncate(struct inode *ip) { jfs_info("jfs_truncate: size = 0x%lx", (ulong) ip->i_size); - nobh_truncate_page(ip->i_mapping, ip->i_size); + nobh_truncate_page(ip->i_mapping, ip->i_size, jfs_get_block); IWRITE_LOCK(ip, RDWRLOCK_NORMAL); jfs_truncate_nolock(ip, ip->i_size); diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c index c14ba3cfa818..df0b8535de84 100644 --- a/fs/jfs/jfs_dtree.c +++ b/fs/jfs/jfs_dtree.c @@ -520,7 +520,7 @@ static void free_index(tid_t tid, struct inode *ip, u32 index, u32 next) * Changes an entry in the directory index table */ static void modify_index(tid_t tid, struct inode *ip, u32 index, s64 bn, - int slot, struct metapage ** mp, u64 *lblock) + int slot, struct metapage ** mp, s64 *lblock) { struct dir_table_slot *dirtab_slot; diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h index cb8f30985ad1..439901d205fe 100644 --- a/fs/jfs/jfs_incore.h +++ b/fs/jfs/jfs_incore.h @@ -49,7 +49,7 @@ struct jfs_inode_info { short btorder; /* access order */ short btindex; /* btpage entry index*/ struct inode *ipimap; /* inode map */ - long cflag; /* commit flags */ + unsigned long cflag; /* commit flags */ u16 bxflag; /* xflag of pseudo buffer? */ unchar agno; /* ag number */ signed char active_ag; /* ag currently allocating from */ diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index de3e4a506dbc..15a3974cdeeb 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -2162,7 +2162,7 @@ static void lbmStartIO(struct lbuf * bp) /* check if journaling to disk has been disabled */ if (log->no_integrity) { bio->bi_size = 0; - lbmIODone(bio, 0, 0); + lbmIODone(bio, 0); } else { submit_bio(WRITE_SYNC, bio); INCREMENT(lmStat.submitted); @@ -2200,16 +2200,13 @@ static int lbmIOWait(struct lbuf * bp, int flag) * * executed at INTIODONE level */ -static int lbmIODone(struct bio *bio, unsigned int bytes_done, int error) +static void lbmIODone(struct bio *bio, int error) { struct lbuf *bp = bio->bi_private; struct lbuf *nextbp, *tail; struct jfs_log *log; unsigned long flags; - if (bio->bi_size) - return 1; - /* * get back jfs buffer bound to the i/o buffer */ @@ -2238,7 +2235,7 @@ static int lbmIODone(struct bio *bio, unsigned int bytes_done, int error) /* wakeup I/O initiator */ LCACHE_WAKEUP(&bp->l_ioevent); - return 0; + return; } /* @@ -2263,7 +2260,7 @@ static int lbmIODone(struct bio *bio, unsigned int bytes_done, int error) if (bp->l_flag & lbmDIRECT) { LCACHE_WAKEUP(&bp->l_ioevent); LCACHE_UNLOCK(flags); - return 0; + return; } tail = log->wqueue; @@ -2342,8 +2339,6 @@ static int lbmIODone(struct bio *bio, unsigned int bytes_done, int error) LCACHE_UNLOCK(flags); /* unlock+enable */ } - - return 0; } int jfsIOWait(void *arg) diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h index 1f85ef0ec045..9236bc49ae7f 100644 --- a/fs/jfs/jfs_logmgr.h +++ b/fs/jfs/jfs_logmgr.h @@ -376,7 +376,7 @@ struct jfs_log { int size; /* 4: log size in log page (in page) */ int l2bsize; /* 4: log2 of bsize */ - long flag; /* 4: flag */ + unsigned long flag; /* 4: flag */ struct lbuf *lbuf_free; /* 4: free lbufs */ wait_queue_head_t free_wait; /* 4: */ diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index 62e96be02acf..f5cd8d38af7a 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -180,7 +180,7 @@ static inline void remove_metapage(struct page *page, struct metapage *mp) #endif -static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags) +static void init_once(struct kmem_cache *cachep, void *foo) { struct metapage *mp = (struct metapage *)foo; @@ -280,14 +280,10 @@ static void last_read_complete(struct page *page) unlock_page(page); } -static int metapage_read_end_io(struct bio *bio, unsigned int bytes_done, - int err) +static void metapage_read_end_io(struct bio *bio, int err) { struct page *page = bio->bi_private; - if (bio->bi_size) - return 1; - if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) { printk(KERN_ERR "metapage_read_end_io: I/O error\n"); SetPageError(page); @@ -295,8 +291,6 @@ static int metapage_read_end_io(struct bio *bio, unsigned int bytes_done, dec_io(page, last_read_complete); bio_put(bio); - - return 0; } static void remove_from_logsync(struct metapage *mp) @@ -341,23 +335,18 @@ static void last_write_complete(struct page *page) end_page_writeback(page); } -static int metapage_write_end_io(struct bio *bio, unsigned int bytes_done, - int err) +static void metapage_write_end_io(struct bio *bio, int err) { struct page *page = bio->bi_private; BUG_ON(!PagePrivate(page)); - if (bio->bi_size) - return 1; - if (! test_bit(BIO_UPTODATE, &bio->bi_flags)) { printk(KERN_ERR "metapage_write_end_io: I/O error\n"); SetPageError(page); } dec_io(page, last_write_complete); bio_put(bio); - return 0; } static int metapage_writepage(struct page *page, struct writeback_control *wbc) diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index 7aa1f7004eaf..e7c60ae6b5b2 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c @@ -1289,7 +1289,14 @@ int txCommit(tid_t tid, /* transaction identifier */ * commit the transaction synchronously, so the last iput * will be done by the calling thread (or later) */ - if (tblk->u.ip->i_state & I_LOCK) + /* + * I believe this code is no longer needed. Splitting I_LOCK + * into two bits, I_LOCK and I_SYNC should prevent this + * deadlock as well. But since I don't have a JFS testload + * to verify this, only a trivial s/I_LOCK/I_SYNC/ was done. + * Joern + */ + if (tblk->u.ip->i_state & I_SYNC) tblk->xflag &= ~COMMIT_LAZY; } diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 4b372f550652..cff60c171943 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -750,7 +750,7 @@ static struct file_system_type jfs_fs_type = { .fs_flags = FS_REQUIRES_DEV, }; -static void init_once(void *foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(struct kmem_cache *cachep, void *foo) { struct jfs_inode_info *jfs_ip = (struct jfs_inode_info *) foo; diff --git a/fs/libfs.c b/fs/libfs.c index 5294de1f40c4..ae51481e45e5 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -351,8 +351,28 @@ int simple_prepare_write(struct file *file, struct page *page, return 0; } -int simple_commit_write(struct file *file, struct page *page, - unsigned from, unsigned to) +int simple_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) +{ + struct page *page; + pgoff_t index; + unsigned from; + + index = pos >> PAGE_CACHE_SHIFT; + from = pos & (PAGE_CACHE_SIZE - 1); + + page = __grab_cache_page(mapping, index); + if (!page) + return -ENOMEM; + + *pagep = page; + + return simple_prepare_write(file, page, from, from+len); +} + +static int simple_commit_write(struct file *file, struct page *page, + unsigned from, unsigned to) { struct inode *inode = page->mapping->host; loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; @@ -369,6 +389,28 @@ int simple_commit_write(struct file *file, struct page *page, return 0; } +int simple_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) +{ + unsigned from = pos & (PAGE_CACHE_SIZE - 1); + + /* zero the stale part of the page if we did a short copy */ + if (copied < len) { + void *kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr + from + copied, 0, len - copied); + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); + } + + simple_commit_write(file, page, from, from+copied); + + unlock_page(page); + page_cache_release(page); + + return copied; +} + /* * the inodes created here are not hashed. If you use iunique to generate * unique inode values later for this filesystem, then you must take care @@ -642,7 +684,8 @@ EXPORT_SYMBOL(dcache_dir_open); EXPORT_SYMBOL(dcache_readdir); EXPORT_SYMBOL(generic_read_dir); EXPORT_SYMBOL(get_sb_pseudo); -EXPORT_SYMBOL(simple_commit_write); +EXPORT_SYMBOL(simple_write_begin); +EXPORT_SYMBOL(simple_write_end); EXPORT_SYMBOL(simple_dir_inode_operations); EXPORT_SYMBOL(simple_dir_operations); EXPORT_SYMBOL(simple_empty); diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 3353ed8421a7..908b23fadd05 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -10,6 +10,7 @@ #include <linux/utsname.h> #include <linux/kernel.h> #include <linux/sunrpc/clnt.h> +#include <linux/sunrpc/xprtsock.h> #include <linux/sunrpc/svc.h> #include <linux/lockd/lockd.h> #include <linux/lockd/sm_inter.h> @@ -132,7 +133,7 @@ nsm_create(void) .sin_port = 0, }; struct rpc_create_args args = { - .protocol = IPPROTO_UDP, + .protocol = XPRT_TRANSPORT_UDP, .address = (struct sockaddr *)&sin, .addrsize = sizeof(sin), .servername = "localhost", diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index 5316e307a49d..633653bff944 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c @@ -62,8 +62,9 @@ static __be32 *nlm_decode_cookie(__be32 *p, struct nlm_cookie *c) } else { - printk(KERN_NOTICE - "lockd: bad cookie size %d (only cookies under %d bytes are supported.)\n", len, NLM_MAXCOOKIELEN); + dprintk("lockd: bad cookie size %d (only cookies under " + "%d bytes are supported.)\n", + len, NLM_MAXCOOKIELEN); return NULL; } return p; @@ -84,8 +85,7 @@ nlm_decode_fh(__be32 *p, struct nfs_fh *f) unsigned int len; if ((len = ntohl(*p++)) != NFS2_FHSIZE) { - printk(KERN_NOTICE - "lockd: bad fhandle size %d (should be %d)\n", + dprintk("lockd: bad fhandle size %d (should be %d)\n", len, NFS2_FHSIZE); return NULL; } diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c index 846fc1d639dd..43ff9397e6c6 100644 --- a/fs/lockd/xdr4.c +++ b/fs/lockd/xdr4.c @@ -64,8 +64,9 @@ nlm4_decode_cookie(__be32 *p, struct nlm_cookie *c) } else { - printk(KERN_NOTICE - "lockd: bad cookie size %d (only cookies under %d bytes are supported.)\n", len, NLM_MAXCOOKIELEN); + dprintk("lockd: bad cookie size %d (only cookies under " + "%d bytes are supported.)\n", + len, NLM_MAXCOOKIELEN); return NULL; } return p; @@ -86,8 +87,7 @@ nlm4_decode_fh(__be32 *p, struct nfs_fh *f) memset(f->data, 0, sizeof(f->data)); f->size = ntohl(*p++); if (f->size > NFS_MAXFHSIZE) { - printk(KERN_NOTICE - "lockd: bad fhandle size %d (should be <=%d)\n", + dprintk("lockd: bad fhandle size %d (should be <=%d)\n", f->size, NFS_MAXFHSIZE); return NULL; } diff --git a/fs/locks.c b/fs/locks.c index c795eaaf6c4c..0127a2846819 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -199,7 +199,7 @@ EXPORT_SYMBOL(locks_init_lock); * Initialises the fields of the file lock which are invariant for * free file_locks. */ -static void init_once(void *foo, struct kmem_cache *cache, unsigned long flags) +static void init_once(struct kmem_cache *cache, void *foo) { struct file_lock *lock = (struct file_lock *) foo; @@ -534,7 +534,9 @@ static void locks_insert_block(struct file_lock *blocker, static void locks_wake_up_blocks(struct file_lock *blocker) { while (!list_empty(&blocker->fl_block)) { - struct file_lock *waiter = list_entry(blocker->fl_block.next, + struct file_lock *waiter; + + waiter = list_first_entry(&blocker->fl_block, struct file_lock, fl_block); __locks_delete_block(waiter); if (waiter->fl_lmops && waiter->fl_lmops->fl_notify) @@ -668,7 +670,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl) for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) { if (!IS_POSIX(cfl)) continue; - if (posix_locks_conflict(cfl, fl)) + if (posix_locks_conflict(fl, cfl)) break; } if (cfl) @@ -698,13 +700,12 @@ EXPORT_SYMBOL(posix_test_lock); static int posix_locks_deadlock(struct file_lock *caller_fl, struct file_lock *block_fl) { - struct list_head *tmp; + struct file_lock *fl; next_task: if (posix_same_owner(caller_fl, block_fl)) return 1; - list_for_each(tmp, &blocked_list) { - struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link); + list_for_each_entry(fl, &blocked_list, fl_link) { if (posix_same_owner(fl, block_fl)) { fl = fl->fl_next; block_fl = fl; @@ -715,8 +716,7 @@ next_task: } /* Try to create a FLOCK lock on filp. We always insert new FLOCK locks - * at the head of the list, but that's secret knowledge known only to - * flock_lock_file and posix_lock_file. + * after any leases, but before any posix locks. * * Note that if called with an FL_EXISTS argument, the caller may determine * whether or not a lock was successfully freed by testing the return @@ -733,6 +733,15 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) lock_kernel(); if (request->fl_flags & FL_ACCESS) goto find_conflict; + + if (request->fl_type != F_UNLCK) { + error = -ENOMEM; + new_fl = locks_alloc_lock(); + if (new_fl == NULL) + goto out; + error = 0; + } + for_each_lock(inode, before) { struct file_lock *fl = *before; if (IS_POSIX(fl)) @@ -754,10 +763,6 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) goto out; } - error = -ENOMEM; - new_fl = locks_alloc_lock(); - if (new_fl == NULL) - goto out; /* * If a higher-priority process was blocked on the old file lock, * give it the opportunity to lock the file. @@ -819,7 +824,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str lock_kernel(); if (request->fl_type != F_UNLCK) { for_each_lock(inode, before) { - struct file_lock *fl = *before; + fl = *before; if (!IS_POSIX(fl)) continue; if (!posix_locks_conflict(request, fl)) @@ -1113,7 +1118,7 @@ int locks_mandatory_area(int read_write, struct inode *inode, * If we've been sleeping someone might have * changed the permissions behind our back. */ - if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) + if (__mandatory_lock(inode)) continue; } @@ -1337,6 +1342,7 @@ int fcntl_getlease(struct file *filp) int generic_setlease(struct file *filp, long arg, struct file_lock **flp) { struct file_lock *fl, **before, **my_before = NULL, *lease; + struct file_lock *new_fl = NULL; struct dentry *dentry = filp->f_path.dentry; struct inode *inode = dentry->d_inode; int error, rdlease_count = 0, wrlease_count = 0; @@ -1363,6 +1369,11 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) || (atomic_read(&inode->i_count) > 1))) goto out; + error = -ENOMEM; + new_fl = locks_alloc_lock(); + if (new_fl == NULL) + goto out; + /* * At this point, we know that if there is an exclusive * lease on this file, then we hold it on this filp @@ -1405,18 +1416,15 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) if (!leases_enable) goto out; - error = -ENOMEM; - fl = locks_alloc_lock(); - if (fl == NULL) - goto out; - - locks_copy_lock(fl, lease); + locks_copy_lock(new_fl, lease); + locks_insert_lock(before, new_fl); - locks_insert_lock(before, fl); + *flp = new_fl; + return 0; - *flp = fl; - error = 0; out: + if (new_fl != NULL) + locks_free_lock(new_fl); return error; } EXPORT_SYMBOL(generic_setlease); @@ -1752,9 +1760,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, /* Don't allow mandatory locks on files that may be memory mapped * and shared. */ - if (IS_MANDLOCK(inode) && - (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID && - mapping_writably_mapped(filp->f_mapping)) { + if (mandatory_lock(inode) && mapping_writably_mapped(filp->f_mapping)) { error = -EAGAIN; goto out; } @@ -1878,9 +1884,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, /* Don't allow mandatory locks on files that may be memory mapped * and shared. */ - if (IS_MANDLOCK(inode) && - (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID && - mapping_writably_mapped(filp->f_mapping)) { + if (mandatory_lock(inode) && mapping_writably_mapped(filp->f_mapping)) { error = -EAGAIN; goto out; } @@ -2062,138 +2066,114 @@ int vfs_cancel_lock(struct file *filp, struct file_lock *fl) EXPORT_SYMBOL_GPL(vfs_cancel_lock); -static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx) +#ifdef CONFIG_PROC_FS +#include <linux/seq_file.h> + +static void lock_get_status(struct seq_file *f, struct file_lock *fl, + int id, char *pfx) { struct inode *inode = NULL; if (fl->fl_file != NULL) inode = fl->fl_file->f_path.dentry->d_inode; - out += sprintf(out, "%d:%s ", id, pfx); + seq_printf(f, "%d:%s ", id, pfx); if (IS_POSIX(fl)) { - out += sprintf(out, "%6s %s ", + seq_printf(f, "%6s %s ", (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ", (inode == NULL) ? "*NOINODE*" : - (IS_MANDLOCK(inode) && - (inode->i_mode & (S_IXGRP | S_ISGID)) == S_ISGID) ? - "MANDATORY" : "ADVISORY "); + mandatory_lock(inode) ? "MANDATORY" : "ADVISORY "); } else if (IS_FLOCK(fl)) { if (fl->fl_type & LOCK_MAND) { - out += sprintf(out, "FLOCK MSNFS "); + seq_printf(f, "FLOCK MSNFS "); } else { - out += sprintf(out, "FLOCK ADVISORY "); + seq_printf(f, "FLOCK ADVISORY "); } } else if (IS_LEASE(fl)) { - out += sprintf(out, "LEASE "); + seq_printf(f, "LEASE "); if (fl->fl_type & F_INPROGRESS) - out += sprintf(out, "BREAKING "); + seq_printf(f, "BREAKING "); else if (fl->fl_file) - out += sprintf(out, "ACTIVE "); + seq_printf(f, "ACTIVE "); else - out += sprintf(out, "BREAKER "); + seq_printf(f, "BREAKER "); } else { - out += sprintf(out, "UNKNOWN UNKNOWN "); + seq_printf(f, "UNKNOWN UNKNOWN "); } if (fl->fl_type & LOCK_MAND) { - out += sprintf(out, "%s ", + seq_printf(f, "%s ", (fl->fl_type & LOCK_READ) ? (fl->fl_type & LOCK_WRITE) ? "RW " : "READ " : (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE "); } else { - out += sprintf(out, "%s ", + seq_printf(f, "%s ", (fl->fl_type & F_INPROGRESS) ? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ " : (fl->fl_type & F_WRLCK) ? "WRITE" : "READ "); } if (inode) { #ifdef WE_CAN_BREAK_LSLK_NOW - out += sprintf(out, "%d %s:%ld ", fl->fl_pid, + seq_printf(f, "%d %s:%ld ", fl->fl_pid, inode->i_sb->s_id, inode->i_ino); #else /* userspace relies on this representation of dev_t ;-( */ - out += sprintf(out, "%d %02x:%02x:%ld ", fl->fl_pid, + seq_printf(f, "%d %02x:%02x:%ld ", fl->fl_pid, MAJOR(inode->i_sb->s_dev), MINOR(inode->i_sb->s_dev), inode->i_ino); #endif } else { - out += sprintf(out, "%d <none>:0 ", fl->fl_pid); + seq_printf(f, "%d <none>:0 ", fl->fl_pid); } if (IS_POSIX(fl)) { if (fl->fl_end == OFFSET_MAX) - out += sprintf(out, "%Ld EOF\n", fl->fl_start); + seq_printf(f, "%Ld EOF\n", fl->fl_start); else - out += sprintf(out, "%Ld %Ld\n", fl->fl_start, - fl->fl_end); + seq_printf(f, "%Ld %Ld\n", fl->fl_start, fl->fl_end); } else { - out += sprintf(out, "0 EOF\n"); + seq_printf(f, "0 EOF\n"); } } -static void move_lock_status(char **p, off_t* pos, off_t offset) +static int locks_show(struct seq_file *f, void *v) { - int len; - len = strlen(*p); - if(*pos >= offset) { - /* the complete line is valid */ - *p += len; - *pos += len; - return; - } - if(*pos+len > offset) { - /* use the second part of the line */ - int i = offset-*pos; - memmove(*p,*p+i,len-i); - *p += len-i; - *pos += len; - return; - } - /* discard the complete line */ - *pos += len; + struct file_lock *fl, *bfl; + + fl = list_entry(v, struct file_lock, fl_link); + + lock_get_status(f, fl, (long)f->private, ""); + + list_for_each_entry(bfl, &fl->fl_block, fl_block) + lock_get_status(f, bfl, (long)f->private, " ->"); + + f->private++; + return 0; } -/** - * get_locks_status - reports lock usage in /proc/locks - * @buffer: address in userspace to write into - * @start: ? - * @offset: how far we are through the buffer - * @length: how much to read - */ +static void *locks_start(struct seq_file *f, loff_t *pos) +{ + lock_kernel(); + f->private = (void *)1; + return seq_list_start(&file_lock_list, *pos); +} -int get_locks_status(char *buffer, char **start, off_t offset, int length) +static void *locks_next(struct seq_file *f, void *v, loff_t *pos) { - struct list_head *tmp; - char *q = buffer; - off_t pos = 0; - int i = 0; + return seq_list_next(v, &file_lock_list, pos); +} - lock_kernel(); - list_for_each(tmp, &file_lock_list) { - struct list_head *btmp; - struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link); - lock_get_status(q, fl, ++i, ""); - move_lock_status(&q, &pos, offset); - - if(pos >= offset+length) - goto done; - - list_for_each(btmp, &fl->fl_block) { - struct file_lock *bfl = list_entry(btmp, - struct file_lock, fl_block); - lock_get_status(q, bfl, i, " ->"); - move_lock_status(&q, &pos, offset); - - if(pos >= offset+length) - goto done; - } - } -done: +static void locks_stop(struct seq_file *f, void *v) +{ unlock_kernel(); - *start = buffer; - if(q-buffer < length) - return (q-buffer); - return length; } +struct seq_operations locks_seq_operations = { + .start = locks_start, + .next = locks_next, + .stop = locks_stop, + .show = locks_show, +}; +#endif + /** * lock_may_read - checks that the region is free of locks * @inode: the inode that is being read diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c index 99a12f127769..703cc35e04b9 100644 --- a/fs/minix/bitmap.c +++ b/fs/minix/bitmap.c @@ -17,7 +17,7 @@ #include <linux/bitops.h> #include <linux/sched.h> -static int nibblemap[] = { 4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0 }; +static const int nibblemap[] = { 4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0 }; static unsigned long count_free(struct buffer_head *map[], unsigned numblocks, __u32 numbits) { diff --git a/fs/minix/dir.c b/fs/minix/dir.c index e207cbe70951..f70433816a38 100644 --- a/fs/minix/dir.c +++ b/fs/minix/dir.c @@ -9,8 +9,10 @@ */ #include "minix.h" +#include <linux/buffer_head.h> #include <linux/highmem.h> #include <linux/smp_lock.h> +#include <linux/swap.h> typedef struct minix_dir_entry minix_dirent; typedef struct minix3_dir_entry minix3_dirent; @@ -48,11 +50,17 @@ static inline unsigned long dir_pages(struct inode *inode) return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT; } -static int dir_commit_chunk(struct page *page, unsigned from, unsigned to) +static int dir_commit_chunk(struct page *page, loff_t pos, unsigned len) { - struct inode *dir = (struct inode *)page->mapping->host; + struct address_space *mapping = page->mapping; + struct inode *dir = mapping->host; int err = 0; - page->mapping->a_ops->commit_write(NULL, page, from, to); + block_write_end(NULL, mapping, pos, len, len, page, NULL); + + if (pos+len > dir->i_size) { + i_size_write(dir, pos+len); + mark_inode_dirty(dir); + } if (IS_DIRSYNC(dir)) err = write_one_page(page, 1); else @@ -220,7 +228,7 @@ int minix_add_link(struct dentry *dentry, struct inode *inode) char *kaddr, *p; minix_dirent *de; minix3_dirent *de3; - unsigned from, to; + loff_t pos; int err; char *namx = NULL; __u32 inumber; @@ -272,9 +280,9 @@ int minix_add_link(struct dentry *dentry, struct inode *inode) return -EINVAL; got_it: - from = p - (char*)page_address(page); - to = from + sbi->s_dirsize; - err = page->mapping->a_ops->prepare_write(NULL, page, from, to); + pos = (page->index >> PAGE_CACHE_SHIFT) + p - (char*)page_address(page); + err = __minix_write_begin(NULL, page->mapping, pos, sbi->s_dirsize, + AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); if (err) goto out_unlock; memcpy (namx, name, namelen); @@ -285,7 +293,7 @@ got_it: memset (namx + namelen, 0, sbi->s_dirsize - namelen - 2); de->inode = inode->i_ino; } - err = dir_commit_chunk(page, from, to); + err = dir_commit_chunk(page, pos, sbi->s_dirsize); dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(dir); out_put: @@ -302,15 +310,16 @@ int minix_delete_entry(struct minix_dir_entry *de, struct page *page) struct address_space *mapping = page->mapping; struct inode *inode = (struct inode*)mapping->host; char *kaddr = page_address(page); - unsigned from = (char*)de - kaddr; - unsigned to = from + minix_sb(inode->i_sb)->s_dirsize; + loff_t pos = page_offset(page) + (char*)de - kaddr; + unsigned len = minix_sb(inode->i_sb)->s_dirsize; int err; lock_page(page); - err = mapping->a_ops->prepare_write(NULL, page, from, to); + err = __minix_write_begin(NULL, mapping, pos, len, + AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); if (err == 0) { de->inode = 0; - err = dir_commit_chunk(page, from, to); + err = dir_commit_chunk(page, pos, len); } else { unlock_page(page); } @@ -330,7 +339,8 @@ int minix_make_empty(struct inode *inode, struct inode *dir) if (!page) return -ENOMEM; - err = mapping->a_ops->prepare_write(NULL, page, 0, 2 * sbi->s_dirsize); + err = __minix_write_begin(NULL, mapping, 0, 2 * sbi->s_dirsize, + AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); if (err) { unlock_page(page); goto fail; @@ -421,17 +431,20 @@ not_empty: void minix_set_link(struct minix_dir_entry *de, struct page *page, struct inode *inode) { - struct inode *dir = (struct inode*)page->mapping->host; + struct address_space *mapping = page->mapping; + struct inode *dir = mapping->host; struct minix_sb_info *sbi = minix_sb(dir->i_sb); - unsigned from = (char *)de-(char*)page_address(page); - unsigned to = from + sbi->s_dirsize; + loff_t pos = page_offset(page) + + (char *)de-(char*)page_address(page); int err; lock_page(page); - err = page->mapping->a_ops->prepare_write(NULL, page, from, to); + + err = __minix_write_begin(NULL, mapping, pos, sbi->s_dirsize, + AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); if (err == 0) { de->inode = inode->i_ino; - err = dir_commit_chunk(page, from, to); + err = dir_commit_chunk(page, pos, sbi->s_dirsize); } else { unlock_page(page); } diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 43668d7d668f..bf4cd316af81 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -69,7 +69,7 @@ static void minix_destroy_inode(struct inode *inode) kmem_cache_free(minix_inode_cachep, minix_i(inode)); } -static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(struct kmem_cache * cachep, void *foo) { struct minix_inode_info *ei = (struct minix_inode_info *) foo; @@ -346,24 +346,39 @@ static int minix_writepage(struct page *page, struct writeback_control *wbc) { return block_write_full_page(page, minix_get_block, wbc); } + static int minix_readpage(struct file *file, struct page *page) { return block_read_full_page(page,minix_get_block); } -static int minix_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) + +int __minix_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - return block_prepare_write(page,from,to,minix_get_block); + return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + minix_get_block); } + +static int minix_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) +{ + *pagep = NULL; + return __minix_write_begin(file, mapping, pos, len, flags, pagep, fsdata); +} + static sector_t minix_bmap(struct address_space *mapping, sector_t block) { return generic_block_bmap(mapping,block,minix_get_block); } + static const struct address_space_operations minix_aops = { .readpage = minix_readpage, .writepage = minix_writepage, .sync_page = block_sync_page, - .prepare_write = minix_prepare_write, - .commit_write = generic_commit_write, + .write_begin = minix_write_begin, + .write_end = generic_write_end, .bmap = minix_bmap }; diff --git a/fs/minix/itree_v1.c b/fs/minix/itree_v1.c index 1a5f3bf0bcec..82d6554b02fe 100644 --- a/fs/minix/itree_v1.c +++ b/fs/minix/itree_v1.c @@ -23,11 +23,16 @@ static inline block_t *i_data(struct inode *inode) static int block_to_path(struct inode * inode, long block, int offsets[DEPTH]) { int n = 0; + char b[BDEVNAME_SIZE]; if (block < 0) { - printk("minix_bmap: block<0\n"); + printk("MINIX-fs: block_to_path: block %ld < 0 on dev %s\n", + block, bdevname(inode->i_sb->s_bdev, b)); } else if (block >= (minix_sb(inode->i_sb)->s_max_size/BLOCK_SIZE)) { - printk("minix_bmap: block>big\n"); + if (printk_ratelimit()) + printk("MINIX-fs: block_to_path: " + "block %ld too big on dev %s\n", + block, bdevname(inode->i_sb->s_bdev, b)); } else if (block < 7) { offsets[n++] = block; } else if ((block -= 7) < 512) { diff --git a/fs/minix/itree_v2.c b/fs/minix/itree_v2.c index ad8f0dec4ef4..f23010969369 100644 --- a/fs/minix/itree_v2.c +++ b/fs/minix/itree_v2.c @@ -23,12 +23,17 @@ static inline block_t *i_data(struct inode *inode) static int block_to_path(struct inode * inode, long block, int offsets[DEPTH]) { int n = 0; + char b[BDEVNAME_SIZE]; struct super_block *sb = inode->i_sb; if (block < 0) { - printk("minix_bmap: block<0\n"); + printk("MINIX-fs: block_to_path: block %ld < 0 on dev %s\n", + block, bdevname(sb->s_bdev, b)); } else if (block >= (minix_sb(inode->i_sb)->s_max_size/sb->s_blocksize)) { - printk("minix_bmap: block>big\n"); + if (printk_ratelimit()) + printk("MINIX-fs: block_to_path: " + "block %ld too big on dev %s\n", + block, bdevname(sb->s_bdev, b)); } else if (block < 7) { offsets[n++] = block; } else if ((block -= 7) < 256) { diff --git a/fs/minix/minix.h b/fs/minix/minix.h index 73ef84f8fb0b..ac5d3a75cb0d 100644 --- a/fs/minix/minix.h +++ b/fs/minix/minix.h @@ -54,6 +54,9 @@ extern int minix_new_block(struct inode * inode); extern void minix_free_block(struct inode *inode, unsigned long block); extern unsigned long minix_count_free_blocks(struct minix_sb_info *sbi); extern int minix_getattr(struct vfsmount *, struct dentry *, struct kstat *); +extern int __minix_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata); extern void V1_minix_truncate(struct inode *); extern void V2_minix_truncate(struct inode *); diff --git a/fs/mpage.c b/fs/mpage.c index c1698f2291aa..d54f8f897224 100644 --- a/fs/mpage.c +++ b/fs/mpage.c @@ -39,14 +39,11 @@ * status of that page is hard. See end_buffer_async_read() for the details. * There is no point in duplicating all that complexity. */ -static int mpage_end_io_read(struct bio *bio, unsigned int bytes_done, int err) +static void mpage_end_io_read(struct bio *bio, int err) { const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; - if (bio->bi_size) - return 1; - do { struct page *page = bvec->bv_page; @@ -62,17 +59,13 @@ static int mpage_end_io_read(struct bio *bio, unsigned int bytes_done, int err) unlock_page(page); } while (bvec >= bio->bi_io_vec); bio_put(bio); - return 0; } -static int mpage_end_io_write(struct bio *bio, unsigned int bytes_done, int err) +static void mpage_end_io_write(struct bio *bio, int err) { const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; - if (bio->bi_size) - return 1; - do { struct page *page = bvec->bv_page; @@ -87,7 +80,6 @@ static int mpage_end_io_write(struct bio *bio, unsigned int bytes_done, int err) end_page_writeback(page); } while (bvec >= bio->bi_io_vec); bio_put(bio); - return 0; } static struct bio *mpage_bio_submit(int rw, struct bio *bio) @@ -387,31 +379,25 @@ mpage_readpages(struct address_space *mapping, struct list_head *pages, struct bio *bio = NULL; unsigned page_idx; sector_t last_block_in_bio = 0; - struct pagevec lru_pvec; struct buffer_head map_bh; unsigned long first_logical_block = 0; clear_buffer_mapped(&map_bh); - pagevec_init(&lru_pvec, 0); for (page_idx = 0; page_idx < nr_pages; page_idx++) { struct page *page = list_entry(pages->prev, struct page, lru); prefetchw(&page->flags); list_del(&page->lru); - if (!add_to_page_cache(page, mapping, + if (!add_to_page_cache_lru(page, mapping, page->index, GFP_KERNEL)) { bio = do_mpage_readpage(bio, page, nr_pages - page_idx, &last_block_in_bio, &map_bh, &first_logical_block, get_block); - if (!pagevec_add(&lru_pvec, page)) - __pagevec_lru_add(&lru_pvec); - } else { - page_cache_release(page); } + page_cache_release(page); } - pagevec_lru_add(&lru_pvec); BUG_ON(!list_empty(pages)); if (bio) mpage_bio_submit(READ, bio); diff --git a/fs/namei.c b/fs/namei.c index a83160acd748..1e5c71669164 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -30,7 +30,6 @@ #include <linux/capability.h> #include <linux/file.h> #include <linux/fcntl.h> -#include <linux/namei.h> #include <asm/namei.h> #include <asm/uaccess.h> @@ -228,10 +227,14 @@ int generic_permission(struct inode *inode, int mask, int permission(struct inode *inode, int mask, struct nameidata *nd) { - umode_t mode = inode->i_mode; int retval, submask; + struct vfsmount *mnt = NULL; + + if (nd) + mnt = nd->mnt; if (mask & MAY_WRITE) { + umode_t mode = inode->i_mode; /* * Nobody gets write access to a read-only fs. @@ -247,22 +250,34 @@ int permission(struct inode *inode, int mask, struct nameidata *nd) return -EACCES; } - - /* - * MAY_EXEC on regular files requires special handling: We override - * filesystem execute permissions if the mode bits aren't set or - * the fs is mounted with the "noexec" flag. - */ - if ((mask & MAY_EXEC) && S_ISREG(mode) && (!(mode & S_IXUGO) || - (nd && nd->mnt && (nd->mnt->mnt_flags & MNT_NOEXEC)))) - return -EACCES; + if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) { + /* + * MAY_EXEC on regular files is denied if the fs is mounted + * with the "noexec" flag. + */ + if (mnt && (mnt->mnt_flags & MNT_NOEXEC)) + return -EACCES; + } /* Ordinary permission routines do not understand MAY_APPEND. */ submask = mask & ~MAY_APPEND; - if (inode->i_op && inode->i_op->permission) + if (inode->i_op && inode->i_op->permission) { retval = inode->i_op->permission(inode, submask, nd); - else + if (!retval) { + /* + * Exec permission on a regular file is denied if none + * of the execute bits are set. + * + * This check should be done by the ->permission() + * method. + */ + if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode) && + !(inode->i_mode & S_IXUGO)) + return -EACCES; + } + } else { retval = generic_permission(inode, submask, NULL); + } if (retval) return retval; @@ -1273,7 +1288,8 @@ int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, return err; } -static inline struct dentry *__lookup_hash_kern(struct qstr *name, struct dentry *base, struct nameidata *nd) +static struct dentry *__lookup_hash(struct qstr *name, + struct dentry *base, struct nameidata *nd) { struct dentry *dentry; struct inode *inode; @@ -1313,31 +1329,18 @@ out: * needs parent already locked. Doesn't follow mounts. * SMP-safe. */ -static inline struct dentry * __lookup_hash(struct qstr *name, struct dentry *base, struct nameidata *nd) +static struct dentry *lookup_hash(struct nameidata *nd) { - struct dentry *dentry; - struct inode *inode; int err; - inode = base->d_inode; - - err = permission(inode, MAY_EXEC, nd); - dentry = ERR_PTR(err); + err = permission(nd->dentry->d_inode, MAY_EXEC, nd); if (err) - goto out; - - dentry = __lookup_hash_kern(name, base, nd); -out: - return dentry; -} - -static struct dentry *lookup_hash(struct nameidata *nd) -{ + return ERR_PTR(err); return __lookup_hash(&nd->last, nd->dentry, nd); } -/* SMP-safe */ -static inline int __lookup_one_len(const char *name, struct qstr *this, struct dentry *base, int len) +static int __lookup_one_len(const char *name, struct qstr *this, + struct dentry *base, int len) { unsigned long hash; unsigned int c; @@ -1358,6 +1361,17 @@ static inline int __lookup_one_len(const char *name, struct qstr *this, struct d return 0; } +/** + * lookup_one_len: filesystem helper to lookup single pathname component + * @name: pathname component to lookup + * @base: base directory to lookup from + * @len: maximum length @len should be interpreted to + * + * Note that this routine is purely a helper for filesystem useage and should + * not be called by generic code. Also note that by using this function to + * nameidata argument is passed to the filesystem methods and a filesystem + * using this helper needs to be prepared for that. + */ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) { int err; @@ -1366,18 +1380,33 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) err = __lookup_one_len(name, &this, base, len); if (err) return ERR_PTR(err); + + err = permission(base->d_inode, MAY_EXEC, NULL); + if (err) + return ERR_PTR(err); return __lookup_hash(&this, base, NULL); } -struct dentry *lookup_one_len_kern(const char *name, struct dentry *base, int len) +/** + * lookup_one_noperm - bad hack for sysfs + * @name: pathname component to lookup + * @base: base directory to lookup from + * + * This is a variant of lookup_one_len that doesn't perform any permission + * checks. It's a horrible hack to work around the braindead sysfs + * architecture and should not be used anywhere else. + * + * DON'T USE THIS FUNCTION EVER, thanks. + */ +struct dentry *lookup_one_noperm(const char *name, struct dentry *base) { int err; struct qstr this; - err = __lookup_one_len(name, &this, base, len); + err = __lookup_one_len(name, &this, base, strlen(name)); if (err) return ERR_PTR(err); - return __lookup_hash_kern(&this, base, NULL); + return __lookup_hash(&this, base, NULL); } int fastcall __user_walk_fd(int dfd, const char __user *name, unsigned flags, @@ -1579,10 +1608,6 @@ int may_open(struct nameidata *nd, int acc_mode, int flag) if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE)) return -EISDIR; - error = vfs_permission(nd, acc_mode); - if (error) - return error; - /* * FIFO's, sockets and device files are special: they don't * actually live on the filesystem itself, and as such you @@ -1597,6 +1622,10 @@ int may_open(struct nameidata *nd, int acc_mode, int flag) flag &= ~O_TRUNC; } else if (IS_RDONLY(inode) && (flag & FMODE_WRITE)) return -EROFS; + + error = vfs_permission(nd, acc_mode); + if (error) + return error; /* * An append-only file must be opened in append mode for writing. */ @@ -1630,8 +1659,10 @@ int may_open(struct nameidata *nd, int acc_mode, int flag) error = locks_verify_locked(inode); if (!error) { DQUOT_INIT(inode); - - error = do_truncate(dentry, 0, ATTR_MTIME|ATTR_CTIME, NULL); + + error = do_truncate(dentry, 0, + ATTR_MTIME|ATTR_CTIME|ATTR_OPEN, + NULL); } put_write_access(inode); if (error) @@ -2729,53 +2760,29 @@ int __page_symlink(struct inode *inode, const char *symname, int len, { struct address_space *mapping = inode->i_mapping; struct page *page; + void *fsdata; int err; char *kaddr; retry: - err = -ENOMEM; - page = find_or_create_page(mapping, 0, gfp_mask); - if (!page) - goto fail; - err = mapping->a_ops->prepare_write(NULL, page, 0, len-1); - if (err == AOP_TRUNCATED_PAGE) { - page_cache_release(page); - goto retry; - } + err = pagecache_write_begin(NULL, mapping, 0, len-1, + AOP_FLAG_UNINTERRUPTIBLE, &page, &fsdata); if (err) - goto fail_map; + goto fail; + kaddr = kmap_atomic(page, KM_USER0); memcpy(kaddr, symname, len-1); kunmap_atomic(kaddr, KM_USER0); - err = mapping->a_ops->commit_write(NULL, page, 0, len-1); - if (err == AOP_TRUNCATED_PAGE) { - page_cache_release(page); - goto retry; - } - if (err) - goto fail_map; - /* - * 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. - */ - if (!PageUptodate(page)) { - err = mapping->a_ops->readpage(NULL, page); - if (err != AOP_TRUNCATED_PAGE) - wait_on_page_locked(page); - } else { - unlock_page(page); - } - page_cache_release(page); + + err = pagecache_write_end(NULL, mapping, 0, len-1, len-1, + page, fsdata); if (err < 0) goto fail; + if (err < len-1) + goto retry; + mark_inode_dirty(inode); return 0; -fail_map: - unlock_page(page); - page_cache_release(page); fail: return err; } diff --git a/fs/namespace.c b/fs/namespace.c index ddbda13c2d31..860752998fb3 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1411,7 +1411,7 @@ long do_mount(char *dev_name, char *dir_name, char *type_page, mnt_flags |= MNT_RELATIME; flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | - MS_NOATIME | MS_NODIRATIME | MS_RELATIME); + MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT); /* ... and get the mountpoint */ retval = path_lookup(dir_name, LOOKUP_FOLLOW, &nd); @@ -1791,7 +1791,7 @@ static void __init init_mount_tree(void) set_fs_root(current->fs, ns->root, ns->root->mnt_root); } -void __init mnt_init(unsigned long mempages) +void __init mnt_init(void) { struct list_head *d; unsigned int nr_hash; diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 7f8536dbdedc..e1cb70c643f8 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -56,7 +56,7 @@ static void ncp_destroy_inode(struct inode *inode) kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode)); } -static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(struct kmem_cache *cachep, void *foo) { struct ncp_inode_info *ei = (struct ncp_inode_info *) foo; diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index b55cb236cf74..df0f41e09885 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile @@ -16,4 +16,3 @@ nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ nfs4namespace.o nfs-$(CONFIG_NFS_DIRECTIO) += direct.o nfs-$(CONFIG_SYSCTL) += sysctl.o -nfs-objs := $(nfs-y) diff --git a/fs/nfs/client.c b/fs/nfs/client.c index a204484072f3..70587f383f10 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -23,6 +23,8 @@ #include <linux/sunrpc/clnt.h> #include <linux/sunrpc/stats.h> #include <linux/sunrpc/metrics.h> +#include <linux/sunrpc/xprtsock.h> +#include <linux/sunrpc/xprtrdma.h> #include <linux/nfs_fs.h> #include <linux/nfs_mount.h> #include <linux/nfs4_mount.h> @@ -340,7 +342,8 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, to->to_retries = 2; switch (proto) { - case IPPROTO_TCP: + case XPRT_TRANSPORT_TCP: + case XPRT_TRANSPORT_RDMA: if (!to->to_initval) to->to_initval = 60 * HZ; if (to->to_initval > NFS_MAX_TCP_TIMEOUT) @@ -349,7 +352,7 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, to->to_maxval = to->to_initval + (to->to_increment * to->to_retries); to->to_exponential = 0; break; - case IPPROTO_UDP: + case XPRT_TRANSPORT_UDP: default: if (!to->to_initval) to->to_initval = 11 * HZ / 10; @@ -501,9 +504,9 @@ static int nfs_init_server_rpcclient(struct nfs_server *server, rpc_authflavor_t /* * Initialise an NFS2 or NFS3 client */ -static int nfs_init_client(struct nfs_client *clp, const struct nfs_mount_data *data) +static int nfs_init_client(struct nfs_client *clp, + const struct nfs_parsed_mount_data *data) { - int proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP; int error; if (clp->cl_cons_state == NFS_CS_READY) { @@ -522,8 +525,8 @@ static int nfs_init_client(struct nfs_client *clp, const struct nfs_mount_data * * Create a client RPC handle for doing FSSTAT with UNIX auth only * - RFC 2623, sec 2.3.2 */ - error = nfs_create_rpc_client(clp, proto, data->timeo, data->retrans, - RPC_AUTH_UNIX, 0); + error = nfs_create_rpc_client(clp, data->nfs_server.protocol, + data->timeo, data->retrans, RPC_AUTH_UNIX, 0); if (error < 0) goto error; nfs_mark_client_ready(clp, NFS_CS_READY); @@ -538,7 +541,8 @@ error: /* * Create a version 2 or 3 client */ -static int nfs_init_server(struct nfs_server *server, const struct nfs_mount_data *data) +static int nfs_init_server(struct nfs_server *server, + const struct nfs_parsed_mount_data *data) { struct nfs_client *clp; int error, nfsvers = 2; @@ -551,7 +555,8 @@ static int nfs_init_server(struct nfs_server *server, const struct nfs_mount_dat #endif /* Allocate or find a client reference we can use */ - clp = nfs_get_client(data->hostname, &data->addr, nfsvers); + clp = nfs_get_client(data->nfs_server.hostname, + &data->nfs_server.address, nfsvers); if (IS_ERR(clp)) { dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp)); return PTR_ERR(clp); @@ -581,7 +586,7 @@ static int nfs_init_server(struct nfs_server *server, const struct nfs_mount_dat if (error < 0) goto error; - error = nfs_init_server_rpcclient(server, data->pseudoflavor); + error = nfs_init_server_rpcclient(server, data->auth_flavors[0]); if (error < 0) goto error; @@ -622,6 +627,7 @@ static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo * if (server->rsize > NFS_MAX_FILE_IO_SIZE) server->rsize = NFS_MAX_FILE_IO_SIZE; server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; + server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD; if (server->wsize > max_rpc_payload) @@ -672,6 +678,10 @@ static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, str goto out_error; nfs_server_set_fsinfo(server, &fsinfo); + error = bdi_init(&server->backing_dev_info); + if (error) + goto out_error; + /* Get some general file system info */ if (server->namelen == 0) { @@ -751,6 +761,7 @@ void nfs_free_server(struct nfs_server *server) nfs_put_client(server->nfs_client); nfs_free_iostats(server->io_stats); + bdi_destroy(&server->backing_dev_info); kfree(server); nfs_release_automount_timer(); dprintk("<-- nfs_free_server()\n"); @@ -760,7 +771,7 @@ void nfs_free_server(struct nfs_server *server) * Create a version 2 or 3 volume record * - keyed on server and FSID */ -struct nfs_server *nfs_create_server(const struct nfs_mount_data *data, +struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, struct nfs_fh *mntfh) { struct nfs_server *server; @@ -906,7 +917,7 @@ error: * Create a version 4 volume record */ static int nfs4_init_server(struct nfs_server *server, - const struct nfs4_mount_data *data, rpc_authflavor_t authflavour) + const struct nfs_parsed_mount_data *data) { int error; @@ -926,7 +937,7 @@ static int nfs4_init_server(struct nfs_server *server, server->acdirmin = data->acdirmin * HZ; server->acdirmax = data->acdirmax * HZ; - error = nfs_init_server_rpcclient(server, authflavour); + error = nfs_init_server_rpcclient(server, data->auth_flavors[0]); /* Done */ dprintk("<-- nfs4_init_server() = %d\n", error); @@ -937,12 +948,7 @@ static int nfs4_init_server(struct nfs_server *server, * Create a version 4 volume record * - keyed on server and FSID */ -struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *data, - const char *hostname, - const struct sockaddr_in *addr, - const char *mntpath, - const char *ip_addr, - rpc_authflavor_t authflavour, +struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, struct nfs_fh *mntfh) { struct nfs_fattr fattr; @@ -956,13 +962,18 @@ struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *data, return ERR_PTR(-ENOMEM); /* Get a client record */ - error = nfs4_set_client(server, hostname, addr, ip_addr, authflavour, - data->proto, data->timeo, data->retrans); + error = nfs4_set_client(server, + data->nfs_server.hostname, + &data->nfs_server.address, + data->client_address, + data->auth_flavors[0], + data->nfs_server.protocol, + data->timeo, data->retrans); if (error < 0) goto error; /* set up the general RPC client */ - error = nfs4_init_server(server, data, authflavour); + error = nfs4_init_server(server, data); if (error < 0) goto error; @@ -971,7 +982,7 @@ struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *data, BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); /* Probe the root fh to retrieve its FSID */ - error = nfs4_path_walk(server, mntfh, mntpath); + error = nfs4_path_walk(server, mntfh, data->nfs_server.export_path); if (error < 0) goto error; diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index c55a761c22bb..af8b235d405d 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -52,7 +52,7 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_ for (fl = inode->i_flock; fl != 0; fl = fl->fl_next) { if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) continue; - if ((struct nfs_open_context *)fl->fl_file->private_data != ctx) + if (nfs_file_open_context(fl->fl_file) != ctx) continue; status = nfs4_lock_delegation_recall(state, fl); if (status >= 0) @@ -109,6 +109,7 @@ again: void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res) { struct nfs_delegation *delegation = NFS_I(inode)->delegation; + struct rpc_cred *oldcred; if (delegation == NULL) return; @@ -116,11 +117,12 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st sizeof(delegation->stateid.data)); delegation->type = res->delegation_type; delegation->maxsize = res->maxsize; - put_rpccred(cred); + oldcred = delegation->cred; delegation->cred = get_rpccred(cred); delegation->flags &= ~NFS_DELEGATION_NEED_RECLAIM; NFS_I(inode)->delegation_state = delegation->type; smp_wmb(); + put_rpccred(oldcred); } /* diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index e4a04d16b8b0..8ec7fbd8240c 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -200,9 +200,6 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) desc->timestamp = timestamp; desc->timestamp_valid = 1; SetPageUptodate(page); - spin_lock(&inode->i_lock); - NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME; - spin_unlock(&inode->i_lock); /* Ensure consistent page alignment of the data. * Note: assumes we have exclusive access to this mapping either * through inode->i_mutex or some other mechanism. @@ -214,9 +211,7 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) unlock_page(page); return 0; error: - SetPageError(page); unlock_page(page); - nfs_zap_caches(inode); desc->error = error; return -EIO; } @@ -407,7 +402,7 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, struct file *file = desc->file; struct nfs_entry *entry = desc->entry; struct dentry *dentry = NULL; - unsigned long fileid; + u64 fileid; int loop_count = 0, res; @@ -418,7 +413,7 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, unsigned d_type = DT_UNKNOWN; /* Note: entry->prev_cookie contains the cookie for * retrieving the current dirent on the server */ - fileid = nfs_fileid_to_ino_t(entry->ino); + fileid = entry->ino; /* Get a dentry if we have one */ if (dentry != NULL) @@ -428,11 +423,12 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, /* Use readdirplus info */ if (dentry != NULL && dentry->d_inode != NULL) { d_type = dt_type(dentry->d_inode); - fileid = dentry->d_inode->i_ino; + fileid = NFS_FILEID(dentry->d_inode); } res = filldir(dirent, entry->name, entry->len, - file->f_pos, fileid, d_type); + file->f_pos, nfs_compat_user_ino64(fileid), + d_type); if (res < 0) break; file->f_pos++; @@ -490,9 +486,6 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, page, NFS_SERVER(inode)->dtsize, desc->plus); - spin_lock(&inode->i_lock); - NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME; - spin_unlock(&inode->i_lock); desc->page = page; desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ if (desc->error >= 0) { @@ -558,7 +551,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) memset(desc, 0, sizeof(*desc)); desc->file = filp; - desc->dir_cookie = &((struct nfs_open_context *)filp->private_data)->dir_cookie; + desc->dir_cookie = &nfs_file_open_context(filp)->dir_cookie; desc->decode = NFS_PROTO(inode)->decode_dirent; desc->plus = NFS_USE_READDIRPLUS(inode); @@ -623,7 +616,7 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin) } if (offset != filp->f_pos) { filp->f_pos = offset; - ((struct nfs_open_context *)filp->private_data)->dir_cookie = 0; + nfs_file_open_context(filp)->dir_cookie = 0; } out: mutex_unlock(&filp->f_path.dentry->d_inode->i_mutex); @@ -650,36 +643,18 @@ static int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync) */ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry) { - unsigned long verf; - if (IS_ROOT(dentry)) return 1; - verf = dentry->d_time; - if (nfs_caches_unstable(dir) - || verf != NFS_I(dir)->cache_change_attribute) + if (!nfs_verify_change_attribute(dir, dentry->d_time)) + return 0; + /* Revalidate nfsi->cache_change_attribute before we declare a match */ + if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0) + return 0; + if (!nfs_verify_change_attribute(dir, dentry->d_time)) return 0; return 1; } -static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf) -{ - dentry->d_time = verf; -} - -static void nfs_refresh_verifier(struct dentry * dentry, unsigned long verf) -{ - nfs_set_verifier(dentry, verf); -} - -/* - * Whenever an NFS operation succeeds, we know that the dentry - * is valid, so we update the revalidation timestamp. - */ -static inline void nfs_renew_times(struct dentry * dentry) -{ - dentry->d_time = jiffies; -} - /* * Return the intent data that applies to this particular path component * @@ -695,6 +670,19 @@ static inline unsigned int nfs_lookup_check_intent(struct nameidata *nd, unsigne } /* + * Use intent information to check whether or not we're going to do + * an O_EXCL create using this path component. + */ +static int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd) +{ + if (NFS_PROTO(dir)->version == 2) + return 0; + if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_CREATE) == 0) + return 0; + return (nd->intent.open.flags & O_EXCL) != 0; +} + +/* * Inode and filehandle revalidation for lookups. * * We force revalidation in the cases where the VFS sets LOOKUP_REVAL, @@ -717,6 +705,7 @@ int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd) (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) goto out_force; + return 0; } return nfs_revalidate_inode(server, inode); out_force: @@ -759,7 +748,6 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) int error; struct nfs_fh fhandle; struct nfs_fattr fattr; - unsigned long verifier; parent = dget_parent(dentry); lock_kernel(); @@ -767,10 +755,6 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE); inode = dentry->d_inode; - /* Revalidate parent directory attribute cache */ - if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0) - goto out_zap_parent; - if (!inode) { if (nfs_neg_need_reval(dir, dentry, nd)) goto out_bad; @@ -785,7 +769,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) } /* Force a full look up iff the parent directory has changed */ - if (nfs_check_verifier(dir, dentry)) { + if (!nfs_is_exclusive_create(dir, nd) && nfs_check_verifier(dir, dentry)) { if (nfs_lookup_verify_inode(inode, nd)) goto out_zap_parent; goto out_valid; @@ -794,7 +778,6 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) if (NFS_STALE(inode)) goto out_bad; - verifier = nfs_save_change_attribute(dir); error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); if (error) goto out_bad; @@ -803,8 +786,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) if ((error = nfs_refresh_inode(inode, &fattr)) != 0) goto out_bad; - nfs_renew_times(dentry); - nfs_refresh_verifier(dentry, verifier); + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); out_valid: unlock_kernel(); dput(parent); @@ -815,7 +797,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) out_zap_parent: nfs_zap_caches(dir); out_bad: - NFS_CACHEINV(dir); + nfs_mark_for_revalidate(dir); if (inode && S_ISDIR(inode->i_mode)) { /* Purge readdir caches. */ nfs_zap_caches(inode); @@ -872,8 +854,6 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode) nfs_complete_unlink(dentry, inode); unlock_kernel(); } - /* When creating a negative dentry, we want to renew d_time */ - nfs_renew_times(dentry); iput(inode); } @@ -883,30 +863,6 @@ struct dentry_operations nfs_dentry_operations = { .d_iput = nfs_dentry_iput, }; -/* - * Use intent information to check whether or not we're going to do - * an O_EXCL create using this path component. - */ -static inline -int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd) -{ - if (NFS_PROTO(dir)->version == 2) - return 0; - if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_CREATE) == 0) - return 0; - return (nd->intent.open.flags & O_EXCL) != 0; -} - -static inline int nfs_reval_fsid(struct inode *dir, const struct nfs_fattr *fattr) -{ - struct nfs_server *server = NFS_SERVER(dir); - - if (!nfs_fsid_equal(&server->fsid, &fattr->fsid)) - /* Revalidate fsid using the parent directory */ - return __nfs_revalidate_inode(server, dir); - return 0; -} - static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) { struct dentry *res; @@ -945,11 +901,6 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru res = ERR_PTR(error); goto out_unlock; } - error = nfs_reval_fsid(dir, &fattr); - if (error < 0) { - res = ERR_PTR(error); - goto out_unlock; - } inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr); res = (struct dentry *)inode; if (IS_ERR(res)) @@ -958,17 +909,10 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru no_entry: res = d_materialise_unique(dentry, inode); if (res != NULL) { - struct dentry *parent; if (IS_ERR(res)) goto out_unlock; - /* Was a directory renamed! */ - parent = dget_parent(res); - if (!IS_ROOT(parent)) - nfs_mark_for_revalidate(parent->d_inode); - dput(parent); dentry = res; } - nfs_renew_times(dentry); nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); out_unlock: unlock_kernel(); @@ -1020,28 +964,16 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry } dentry->d_op = NFS_PROTO(dir)->dentry_ops; - /* Let vfs_create() deal with O_EXCL */ + /* Let vfs_create() deal with O_EXCL. Instantiate, but don't hash + * the dentry. */ if (nd->intent.open.flags & O_EXCL) { - d_add(dentry, NULL); + d_instantiate(dentry, NULL); goto out; } /* Open the file on the server */ lock_kernel(); - /* Revalidate parent directory attribute cache */ - error = nfs_revalidate_inode(NFS_SERVER(dir), dir); - if (error < 0) { - res = ERR_PTR(error); - unlock_kernel(); - goto out; - } - - if (nd->intent.open.flags & O_CREAT) { - nfs_begin_data_update(dir); - res = nfs4_atomic_open(dir, dentry, nd); - nfs_end_data_update(dir); - } else - res = nfs4_atomic_open(dir, dentry, nd); + res = nfs4_atomic_open(dir, dentry, nd); unlock_kernel(); if (IS_ERR(res)) { error = PTR_ERR(res); @@ -1063,8 +995,6 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry } } else if (res != NULL) dentry = res; - nfs_renew_times(dentry); - nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); out: return res; no_open: @@ -1076,7 +1006,6 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) struct dentry *parent = NULL; struct inode *inode = dentry->d_inode; struct inode *dir; - unsigned long verifier; int openflags, ret = 0; parent = dget_parent(dentry); @@ -1086,8 +1015,12 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) /* We can't create new files in nfs_open_revalidate(), so we * optimize away revalidation of negative dentries. */ - if (inode == NULL) + if (inode == NULL) { + if (!nfs_neg_need_reval(dir, dentry, nd)) + ret = 1; goto out; + } + /* NFS only supports OPEN on regular files */ if (!S_ISREG(inode->i_mode)) goto no_open; @@ -1104,10 +1037,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) * change attribute *before* we do the RPC call. */ lock_kernel(); - verifier = nfs_save_change_attribute(dir); ret = nfs4_open_revalidate(dir, dentry, openflags, nd); - if (!ret) - nfs_refresh_verifier(dentry, verifier); unlock_kernel(); out: dput(parent); @@ -1133,6 +1063,7 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc) .len = entry->len, }; struct inode *inode; + unsigned long verf = nfs_save_change_attribute(dir); switch (name.len) { case 2: @@ -1143,6 +1074,14 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc) if (name.name[0] == '.') return dget(parent); } + + spin_lock(&dir->i_lock); + if (NFS_I(dir)->cache_validity & NFS_INO_INVALID_DATA) { + spin_unlock(&dir->i_lock); + return NULL; + } + spin_unlock(&dir->i_lock); + name.hash = full_name_hash(name.name, name.len); dentry = d_lookup(parent, &name); if (dentry != NULL) { @@ -1183,12 +1122,8 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc) dentry = alias; } - nfs_renew_times(dentry); - nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); - return dentry; out_renew: - nfs_renew_times(dentry); - nfs_refresh_verifier(dentry, nfs_save_change_attribute(dir)); + nfs_set_verifier(dentry, verf); return dentry; } @@ -1198,32 +1133,40 @@ out_renew: int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { + struct dentry *parent = dget_parent(dentry); + struct inode *dir = parent->d_inode; struct inode *inode; int error = -EACCES; + d_drop(dentry); + /* We may have been initialized further down */ if (dentry->d_inode) - return 0; + goto out; if (fhandle->size == 0) { - struct inode *dir = dentry->d_parent->d_inode; error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); if (error) - return error; + goto out_error; } + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); if (!(fattr->valid & NFS_ATTR_FATTR)) { struct nfs_server *server = NFS_SB(dentry->d_sb); error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr); if (error < 0) - return error; + goto out_error; } inode = nfs_fhget(dentry->d_sb, fhandle, fattr); error = PTR_ERR(inode); if (IS_ERR(inode)) - return error; - d_instantiate(dentry, inode); - if (d_unhashed(dentry)) - d_rehash(dentry); + goto out_error; + d_add(dentry, inode); +out: + dput(parent); return 0; +out_error: + nfs_mark_for_revalidate(dir); + dput(parent); + return error; } /* @@ -1249,13 +1192,9 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, open_flags = nd->intent.open.flags; lock_kernel(); - nfs_begin_data_update(dir); error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, nd); - nfs_end_data_update(dir); if (error != 0) goto out_err; - nfs_renew_times(dentry); - nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); unlock_kernel(); return 0; out_err: @@ -1283,13 +1222,9 @@ nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) attr.ia_valid = ATTR_MODE; lock_kernel(); - nfs_begin_data_update(dir); status = NFS_PROTO(dir)->mknod(dir, dentry, &attr, rdev); - nfs_end_data_update(dir); if (status != 0) goto out_err; - nfs_renew_times(dentry); - nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); unlock_kernel(); return 0; out_err: @@ -1313,13 +1248,9 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) attr.ia_mode = mode | S_IFDIR; lock_kernel(); - nfs_begin_data_update(dir); error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr); - nfs_end_data_update(dir); if (error != 0) goto out_err; - nfs_renew_times(dentry); - nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); unlock_kernel(); return 0; out_err: @@ -1336,12 +1267,10 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry) dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); lock_kernel(); - nfs_begin_data_update(dir); error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name); /* Ensure the VFS deletes this inode */ if (error == 0 && dentry->d_inode != NULL) clear_nlink(dentry->d_inode); - nfs_end_data_update(dir); unlock_kernel(); return error; @@ -1350,9 +1279,9 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry) static int nfs_sillyrename(struct inode *dir, struct dentry *dentry) { static unsigned int sillycounter; - const int i_inosize = sizeof(dir->i_ino)*2; + const int fileidsize = sizeof(NFS_FILEID(dentry->d_inode))*2; const int countersize = sizeof(sillycounter)*2; - const int slen = sizeof(".nfs") + i_inosize + countersize - 1; + const int slen = sizeof(".nfs")+fileidsize+countersize-1; char silly[slen+1]; struct qstr qsilly; struct dentry *sdentry; @@ -1370,8 +1299,9 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry) if (dentry->d_flags & DCACHE_NFSFS_RENAMED) goto out; - sprintf(silly, ".nfs%*.*lx", - i_inosize, i_inosize, dentry->d_inode->i_ino); + sprintf(silly, ".nfs%*.*Lx", + fileidsize, fileidsize, + (unsigned long long)NFS_FILEID(dentry->d_inode)); /* Return delegation in anticipation of the rename */ nfs_inode_return_delegation(dentry->d_inode); @@ -1398,19 +1328,14 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry) qsilly.name = silly; qsilly.len = strlen(silly); - nfs_begin_data_update(dir); if (dentry->d_inode) { - nfs_begin_data_update(dentry->d_inode); error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, dir, &qsilly); nfs_mark_for_revalidate(dentry->d_inode); - nfs_end_data_update(dentry->d_inode); } else error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, dir, &qsilly); - nfs_end_data_update(dir); if (!error) { - nfs_renew_times(dentry); nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); d_move(dentry, sdentry); error = nfs_async_unlink(dir, dentry); @@ -1443,19 +1368,15 @@ static int nfs_safe_remove(struct dentry *dentry) goto out; } - nfs_begin_data_update(dir); if (inode != NULL) { nfs_inode_return_delegation(inode); - nfs_begin_data_update(inode); error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); /* The VFS may want to delete this inode */ if (error == 0) drop_nlink(inode); nfs_mark_for_revalidate(inode); - nfs_end_data_update(inode); } else error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); - nfs_end_data_update(dir); out: return error; } @@ -1493,7 +1414,6 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry) spin_unlock(&dcache_lock); error = nfs_safe_remove(dentry); if (!error) { - nfs_renew_times(dentry); nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); } else if (need_rehash) d_rehash(dentry); @@ -1548,9 +1468,7 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen); kunmap_atomic(kaddr, KM_USER0); - nfs_begin_data_update(dir); error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr); - nfs_end_data_update(dir); if (error != 0) { dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s) error %d\n", dir->i_sb->s_id, dir->i_ino, @@ -1590,15 +1508,12 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) dentry->d_parent->d_name.name, dentry->d_name.name); lock_kernel(); - nfs_begin_data_update(dir); - nfs_begin_data_update(inode); + d_drop(dentry); error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name); if (error == 0) { atomic_inc(&inode->i_count); - d_instantiate(dentry, inode); + d_add(dentry, inode); } - nfs_end_data_update(inode); - nfs_end_data_update(dir); unlock_kernel(); return error; } @@ -1701,22 +1616,16 @@ go_ahead: d_delete(new_dentry); } - nfs_begin_data_update(old_dir); - nfs_begin_data_update(new_dir); - nfs_begin_data_update(old_inode); error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name, new_dir, &new_dentry->d_name); nfs_mark_for_revalidate(old_inode); - nfs_end_data_update(old_inode); - nfs_end_data_update(new_dir); - nfs_end_data_update(old_dir); out: if (rehash) d_rehash(rehash); if (!error) { d_move(old_dentry, new_dentry); - nfs_renew_times(new_dentry); - nfs_refresh_verifier(new_dentry, nfs_save_change_attribute(new_dir)); + nfs_set_verifier(new_dentry, + nfs_save_change_attribute(new_dir)); } /* new dentry created? */ @@ -1842,7 +1751,7 @@ static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, st return NULL; } -int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res) +static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res) { struct nfs_inode *nfsi = NFS_I(inode); struct nfs_access_entry *cache; @@ -1854,7 +1763,7 @@ int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs cache = nfs_access_search_rbtree(inode, cred); if (cache == NULL) goto out; - if (time_after(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode))) + if (!time_in_range(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo)) goto out_stale; res->jiffies = cache->jiffies; res->cred = cache->cred; @@ -1909,7 +1818,7 @@ found: nfs_access_free_entry(entry); } -void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set) +static void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set) { struct nfs_access_entry *cache = kmalloc(sizeof(*cache), GFP_KERNEL); if (cache == NULL) @@ -1957,6 +1866,24 @@ out: return -EACCES; } +static int nfs_open_permission_mask(int openflags) +{ + int mask = 0; + + if (openflags & FMODE_READ) + mask |= MAY_READ; + if (openflags & FMODE_WRITE) + mask |= MAY_WRITE; + if (openflags & FMODE_EXEC) + mask |= MAY_EXEC; + return mask; +} + +int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags) +{ + return nfs_do_access(inode, cred, nfs_open_permission_mask(openflags)); +} + int nfs_permission(struct inode *inode, int mask, struct nameidata *nd) { struct rpc_cred *cred; diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index fcf4d384610e..32fe97211eea 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -368,7 +368,7 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size return -ENOMEM; dreq->inode = inode; - dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data); + dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); if (!is_sync_kiocb(iocb)) dreq->iocb = iocb; @@ -510,7 +510,6 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode nfs_direct_write_reschedule(dreq); break; default: - nfs_end_data_update(inode); if (dreq->commit_data != NULL) nfs_commit_free(dreq->commit_data); nfs_direct_free_writedata(dreq); @@ -533,7 +532,6 @@ static inline void nfs_alloc_commit_data(struct nfs_direct_req *dreq) static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode) { - nfs_end_data_update(inode); nfs_direct_free_writedata(dreq); nfs_zap_mapping(inode, inode->i_mapping); nfs_direct_complete(dreq); @@ -718,14 +716,12 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz sync = FLUSH_STABLE; dreq->inode = inode; - dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data); + dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); if (!is_sync_kiocb(iocb)) dreq->iocb = iocb; nfs_add_stats(inode, NFSIOS_DIRECTWRITTENBYTES, count); - nfs_begin_data_update(inode); - rpc_clnt_sigmask(clnt, &oldset); result = nfs_direct_write_schedule(dreq, user_addr, count, pos, sync); if (!result) diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 579cf8a7d4a7..d29f90d00aa2 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -33,6 +33,7 @@ #include <asm/system.h> #include "delegation.h" +#include "internal.h" #include "iostat.h" #define NFSDBG_FACILITY NFSDBG_FILE @@ -55,6 +56,8 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl); static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl); static int nfs_setlease(struct file *file, long arg, struct file_lock **fl); +static struct vm_operations_struct nfs_file_vm_ops; + const struct file_operations nfs_file_operations = { .llseek = nfs_file_llseek, .read = do_sync_read, @@ -174,13 +177,38 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) } /* + * Helper for nfs_file_flush() and nfs_fsync() + * + * Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to + * disk, but it retrieves and clears ctx->error after synching, despite + * the two being set at the same time in nfs_context_set_write_error(). + * This is because the former is used to notify the _next_ call to + * nfs_file_write() that a write error occured, and hence cause it to + * fall back to doing a synchronous write. + */ +static int nfs_do_fsync(struct nfs_open_context *ctx, struct inode *inode) +{ + int have_error, status; + int ret = 0; + + have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); + status = nfs_wb_all(inode); + have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); + if (have_error) + ret = xchg(&ctx->error, 0); + if (!ret) + ret = status; + return ret; +} + +/* * Flush all dirty pages, and check for write errors. * */ static int nfs_file_flush(struct file *file, fl_owner_t id) { - struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; + struct nfs_open_context *ctx = nfs_file_open_context(file); struct inode *inode = file->f_path.dentry->d_inode; int status; @@ -189,16 +217,11 @@ nfs_file_flush(struct file *file, fl_owner_t id) if ((file->f_mode & FMODE_WRITE) == 0) return 0; nfs_inc_stats(inode, NFSIOS_VFSFLUSH); - lock_kernel(); + /* Ensure that data+attribute caches are up to date after close() */ - status = nfs_wb_all(inode); - if (!status) { - status = ctx->error; - ctx->error = 0; - if (!status) - nfs_revalidate_inode(NFS_SERVER(inode), inode); - } - unlock_kernel(); + status = nfs_do_fsync(ctx, inode); + if (!status) + nfs_revalidate_inode(NFS_SERVER(inode), inode); return status; } @@ -257,8 +280,11 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) dentry->d_parent->d_name.name, dentry->d_name.name); status = nfs_revalidate_mapping(inode, file->f_mapping); - if (!status) - status = generic_file_mmap(file, vma); + if (!status) { + vma->vm_ops = &nfs_file_vm_ops; + vma->vm_flags |= VM_CAN_NONLINEAR; + file_accessed(file); + } return status; } @@ -270,45 +296,60 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) static int nfs_fsync(struct file *file, struct dentry *dentry, int datasync) { - struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; + struct nfs_open_context *ctx = nfs_file_open_context(file); struct inode *inode = dentry->d_inode; - int status; dfprintk(VFS, "nfs: fsync(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino); nfs_inc_stats(inode, NFSIOS_VFSFSYNC); - lock_kernel(); - status = nfs_wb_all(inode); - if (!status) { - status = ctx->error; - ctx->error = 0; - } - unlock_kernel(); - return status; + return nfs_do_fsync(ctx, inode); } /* - * This does the "real" work of the write. The generic routine has - * allocated the page, locked it, done all the page alignment stuff - * calculations etc. Now we should just copy the data from user - * space and write it back to the real medium.. + * This does the "real" work of the write. We must allocate and lock the + * page to be sent back to the generic routine, which then copies the + * data from user space. * * If the writer ends up delaying the write, the writer needs to * increment the page use counts until he is done with the page. */ -static int nfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to) +static int nfs_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - return nfs_flush_incompatible(file, page); + int ret; + pgoff_t index; + struct page *page; + index = pos >> PAGE_CACHE_SHIFT; + + page = __grab_cache_page(mapping, index); + if (!page) + return -ENOMEM; + *pagep = page; + + ret = nfs_flush_incompatible(file, page); + if (ret) { + unlock_page(page); + page_cache_release(page); + } + return ret; } -static int nfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to) +static int nfs_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) { - long status; + unsigned offset = pos & (PAGE_CACHE_SIZE - 1); + int status; lock_kernel(); - status = nfs_updatepage(file, page, offset, to-offset); + status = nfs_updatepage(file, page, offset, copied); unlock_kernel(); - return status; + + unlock_page(page); + page_cache_release(page); + + return status < 0 ? status : copied; } static void nfs_invalidate_page(struct page *page, unsigned long offset) @@ -333,11 +374,11 @@ static int nfs_launder_page(struct page *page) const struct address_space_operations nfs_file_aops = { .readpage = nfs_readpage, .readpages = nfs_readpages, - .set_page_dirty = nfs_set_page_dirty, + .set_page_dirty = __set_page_dirty_nobuffers, .writepage = nfs_writepage, .writepages = nfs_writepages, - .prepare_write = nfs_prepare_write, - .commit_write = nfs_commit_write, + .write_begin = nfs_write_begin, + .write_end = nfs_write_end, .invalidatepage = nfs_invalidate_page, .releasepage = nfs_release_page, #ifdef CONFIG_NFS_DIRECTIO @@ -346,6 +387,60 @@ const struct address_space_operations nfs_file_aops = { .launder_page = nfs_launder_page, }; +static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page) +{ + struct file *filp = vma->vm_file; + unsigned pagelen; + int ret = -EINVAL; + void *fsdata; + struct address_space *mapping; + loff_t offset; + + lock_page(page); + mapping = page->mapping; + if (mapping != vma->vm_file->f_path.dentry->d_inode->i_mapping) { + unlock_page(page); + return -EINVAL; + } + pagelen = nfs_page_length(page); + offset = (loff_t)page->index << PAGE_CACHE_SHIFT; + unlock_page(page); + + /* + * we can use mapping after releasing the page lock, because: + * we hold mmap_sem on the fault path, which should pin the vma + * which should pin the file, which pins the dentry which should + * hold a reference on inode. + */ + + if (pagelen) { + struct page *page2 = NULL; + ret = nfs_write_begin(filp, mapping, offset, pagelen, + 0, &page2, &fsdata); + if (!ret) + ret = nfs_write_end(filp, mapping, offset, pagelen, + pagelen, page2, fsdata); + } + return ret; +} + +static struct vm_operations_struct nfs_file_vm_ops = { + .fault = filemap_fault, + .page_mkwrite = nfs_vm_page_mkwrite, +}; + +static int nfs_need_sync_write(struct file *filp, struct inode *inode) +{ + struct nfs_open_context *ctx; + + if (IS_SYNC(inode) || (filp->f_flags & O_SYNC)) + return 1; + ctx = nfs_file_open_context(filp); + if (test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags)) + return 1; + return 0; +} + static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { @@ -382,8 +477,8 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count); result = generic_file_aio_write(iocb, iov, nr_segs, pos); /* Return error values for O_SYNC and IS_SYNC() */ - if (result >= 0 && (IS_SYNC(inode) || (iocb->ki_filp->f_flags & O_SYNC))) { - int err = nfs_fsync(iocb->ki_filp, dentry, 1); + if (result >= 0 && nfs_need_sync_write(iocb->ki_filp, inode)) { + int err = nfs_do_fsync(nfs_file_open_context(iocb->ki_filp), inode); if (err < 0) result = err; } @@ -522,8 +617,7 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl) nfs_inc_stats(inode, NFSIOS_VFSLOCK); /* No mandatory locks over NFS */ - if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID && - fl->fl_type != F_UNLCK) + if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK) return -ENOLCK; if (IS_GETLK(cmd)) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 71a49c3acabd..6d2f2a3eccf8 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -49,6 +49,11 @@ #define NFSDBG_FACILITY NFSDBG_VFS +#define NFS_64_BIT_INODE_NUMBERS_ENABLED 1 + +/* Default is to see 64-bit inode numbers */ +static int enable_ino64 = NFS_64_BIT_INODE_NUMBERS_ENABLED; + static void nfs_invalidate_inode(struct inode *); static int nfs_update_inode(struct inode *, struct nfs_fattr *); @@ -62,6 +67,25 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr) return nfs_fileid_to_ino_t(fattr->fileid); } +/** + * nfs_compat_user_ino64 - returns the user-visible inode number + * @fileid: 64-bit fileid + * + * This function returns a 32-bit inode number if the boot parameter + * nfs.enable_ino64 is zero. + */ +u64 nfs_compat_user_ino64(u64 fileid) +{ + int ino; + + if (enable_ino64) + return fileid; + ino = fileid; + if (sizeof(ino) < sizeof(fileid)) + ino ^= fileid >> (sizeof(fileid)-sizeof(ino)) * 8; + return ino; +} + int nfs_write_inode(struct inode *inode, int sync) { int ret; @@ -85,7 +109,6 @@ void nfs_clear_inode(struct inode *inode) */ BUG_ON(nfs_have_writebacks(inode)); BUG_ON(!list_empty(&NFS_I(inode)->open_files)); - BUG_ON(atomic_read(&NFS_I(inode)->data_updates) != 0); nfs_zap_acl_cache(inode); nfs_access_zap_cache(inode); } @@ -118,8 +141,8 @@ static void nfs_zap_caches_locked(struct inode *inode) nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); - NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); - NFS_ATTRTIMEO_UPDATE(inode) = jiffies; + nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); + nfsi->attrtimeo_timestamp = jiffies; memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) @@ -156,6 +179,13 @@ static void nfs_zap_acl_cache(struct inode *inode) spin_unlock(&inode->i_lock); } +void nfs_invalidate_atime(struct inode *inode) +{ + spin_lock(&inode->i_lock); + NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME; + spin_unlock(&inode->i_lock); +} + /* * Invalidate, but do not unhash, the inode. * NB: must be called with inode->i_lock held! @@ -327,6 +357,10 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) nfs_inc_stats(inode, NFSIOS_VFSSETATTR); + /* skip mode change if it's just for clearing setuid/setgid */ + if (attr->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) + attr->ia_valid &= ~ATTR_MODE; + if (attr->ia_valid & ATTR_SIZE) { if (!S_ISREG(inode->i_mode) || attr->ia_size == i_size_read(inode)) attr->ia_valid &= ~ATTR_SIZE; @@ -338,7 +372,6 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) return 0; lock_kernel(); - nfs_begin_data_update(inode); /* Write all dirty data */ if (S_ISREG(inode->i_mode)) { filemap_write_and_wait(inode->i_mapping); @@ -352,7 +385,6 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr); if (error == 0) nfs_refresh_inode(inode, &fattr); - nfs_end_data_update(inode); unlock_kernel(); return error; } @@ -431,7 +463,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) /* Flush out writes to the server in order to update c/mtime */ if (S_ISREG(inode->i_mode)) - nfs_sync_mapping_range(inode->i_mapping, 0, 0, FLUSH_NOCOMMIT); + nfs_wb_nocommit(inode); /* * We may force a getattr if the user cares about atime. @@ -450,8 +482,10 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) err = __nfs_revalidate_inode(NFS_SERVER(inode), inode); else err = nfs_revalidate_inode(NFS_SERVER(inode), inode); - if (!err) + if (!err) { generic_fillattr(inode, stat); + stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode)); + } return err; } @@ -536,7 +570,7 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_c static void nfs_file_clear_open_context(struct file *filp) { struct inode *inode = filp->f_path.dentry->d_inode; - struct nfs_open_context *ctx = (struct nfs_open_context *)filp->private_data; + struct nfs_open_context *ctx = nfs_file_open_context(filp); if (ctx) { filp->private_data = NULL; @@ -598,16 +632,10 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) status = nfs_wait_on_inode(inode); if (status < 0) goto out; - if (NFS_STALE(inode)) { - status = -ESTALE; - /* Do we trust the cached ESTALE? */ - if (NFS_ATTRTIMEO(inode) != 0) { - if (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME)) { - /* no */ - } else - goto out; - } - } + + status = -ESTALE; + if (NFS_STALE(inode)) + goto out; status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), &fattr); if (status != 0) { @@ -654,7 +682,7 @@ int nfs_attribute_timeout(struct inode *inode) if (nfs_have_delegation(inode, FMODE_READ)) return 0; - return time_after(jiffies, nfsi->read_cache_jiffies+nfsi->attrtimeo); + return !time_in_range(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo); } /** @@ -683,11 +711,8 @@ static int nfs_invalidate_mapping_nolock(struct inode *inode, struct address_spa } spin_lock(&inode->i_lock); nfsi->cache_validity &= ~NFS_INO_INVALID_DATA; - if (S_ISDIR(inode->i_mode)) { + if (S_ISDIR(inode->i_mode)) memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); - /* This ensures we revalidate child dentries */ - nfsi->cache_change_attribute = jiffies; - } spin_unlock(&inode->i_lock); nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE); dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", @@ -756,56 +781,27 @@ out: return ret; } -/** - * nfs_begin_data_update - * @inode - pointer to inode - * Declare that a set of operations will update file data on the server - */ -void nfs_begin_data_update(struct inode *inode) -{ - atomic_inc(&NFS_I(inode)->data_updates); -} - -/** - * nfs_end_data_update - * @inode - pointer to inode - * Declare end of the operations that will update file data - * This will mark the inode as immediately needing revalidation - * of its attribute cache. - */ -void nfs_end_data_update(struct inode *inode) -{ - struct nfs_inode *nfsi = NFS_I(inode); - - /* Directories: invalidate page cache */ - if (S_ISDIR(inode->i_mode)) { - spin_lock(&inode->i_lock); - nfsi->cache_validity |= NFS_INO_INVALID_DATA; - spin_unlock(&inode->i_lock); - } - nfsi->cache_change_attribute = jiffies; - atomic_dec(&nfsi->data_updates); -} - static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr) { struct nfs_inode *nfsi = NFS_I(inode); - unsigned long now = jiffies; + if ((fattr->valid & NFS_ATTR_WCC_V4) != 0 && + nfsi->change_attr == fattr->pre_change_attr) { + nfsi->change_attr = fattr->change_attr; + if (S_ISDIR(inode->i_mode)) + nfsi->cache_validity |= NFS_INO_INVALID_DATA; + } /* If we have atomic WCC data, we may update some attributes */ if ((fattr->valid & NFS_ATTR_WCC) != 0) { - if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) { + if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); - nfsi->cache_change_attribute = now; - } if (timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) { memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); - nfsi->cache_change_attribute = now; + if (S_ISDIR(inode->i_mode)) + nfsi->cache_validity |= NFS_INO_INVALID_DATA; } - if (inode->i_size == fattr->pre_size && nfsi->npages == 0) { + if (inode->i_size == fattr->pre_size && nfsi->npages == 0) inode->i_size = fattr->size; - nfsi->cache_change_attribute = now; - } } } @@ -822,7 +818,7 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat { struct nfs_inode *nfsi = NFS_I(inode); loff_t cur_size, new_isize; - int data_unstable; + unsigned long invalid = 0; /* Has the inode gone and changed behind our back? */ @@ -831,37 +827,41 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat return -EIO; } - /* Are we in the process of updating data on the server? */ - data_unstable = nfs_caches_unstable(inode); - /* Do atomic weak cache consistency updates */ nfs_wcc_update_inode(inode, fattr); if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 && nfsi->change_attr != fattr->change_attr) - nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; + invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; /* Verify a few of the more important attributes */ if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) - nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; + invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; cur_size = i_size_read(inode); new_isize = nfs_size_to_loff_t(fattr->size); if (cur_size != new_isize && nfsi->npages == 0) - nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; + invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; /* Have any file permissions changed? */ if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) || inode->i_uid != fattr->uid || inode->i_gid != fattr->gid) - nfsi->cache_validity |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL; + invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL; /* Has the link count changed? */ if (inode->i_nlink != fattr->nlink) - nfsi->cache_validity |= NFS_INO_INVALID_ATTR; + invalid |= NFS_INO_INVALID_ATTR; if (!timespec_equal(&inode->i_atime, &fattr->atime)) - nfsi->cache_validity |= NFS_INO_INVALID_ATIME; + invalid |= NFS_INO_INVALID_ATIME; + + if (invalid != 0) + nfsi->cache_validity |= invalid; + else + nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_ATIME + | NFS_INO_REVAL_PAGECACHE); nfsi->read_cache_jiffies = fattr->time_start; return 0; @@ -911,17 +911,41 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr) { struct nfs_inode *nfsi = NFS_I(inode); - int status = 0; spin_lock(&inode->i_lock); - if (unlikely((fattr->valid & NFS_ATTR_FATTR) == 0)) { - nfsi->cache_validity |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; - goto out; - } - status = nfs_update_inode(inode, fattr); -out: + nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; + if (S_ISDIR(inode->i_mode)) + nfsi->cache_validity |= NFS_INO_INVALID_DATA; spin_unlock(&inode->i_lock); - return status; + return nfs_refresh_inode(inode, fattr); +} + +/** + * nfs_post_op_update_inode_force_wcc - try to update the inode attribute cache + * @inode - pointer to inode + * @fattr - updated attributes + * + * After an operation that has changed the inode metadata, mark the + * attribute cache as being invalid, then try to update it. Fake up + * weak cache consistency data, if none exist. + * + * This function is mainly designed to be used by the ->write_done() functions. + */ +int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr) +{ + if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 && + (fattr->valid & NFS_ATTR_WCC_V4) == 0) { + fattr->pre_change_attr = NFS_I(inode)->change_attr; + fattr->valid |= NFS_ATTR_WCC_V4; + } + if ((fattr->valid & NFS_ATTR_FATTR) != 0 && + (fattr->valid & NFS_ATTR_WCC) == 0) { + memcpy(&fattr->pre_ctime, &inode->i_ctime, sizeof(fattr->pre_ctime)); + memcpy(&fattr->pre_mtime, &inode->i_mtime, sizeof(fattr->pre_mtime)); + fattr->pre_size = inode->i_size; + fattr->valid |= NFS_ATTR_WCC; + } + return nfs_post_op_update_inode(inode, fattr); } /* @@ -941,9 +965,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) struct nfs_server *server; struct nfs_inode *nfsi = NFS_I(inode); loff_t cur_isize, new_isize; - unsigned int invalid = 0; + unsigned long invalid = 0; unsigned long now = jiffies; - int data_stable; dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", __FUNCTION__, inode->i_sb->s_id, inode->i_ino, @@ -968,57 +991,51 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) * Update the read time so we don't revalidate too often. */ nfsi->read_cache_jiffies = fattr->time_start; - nfsi->last_updated = now; - /* Fix a wraparound issue with nfsi->cache_change_attribute */ - if (time_before(now, nfsi->cache_change_attribute)) - nfsi->cache_change_attribute = now - 600*HZ; - - /* Are we racing with known updates of the metadata on the server? */ - data_stable = nfs_verify_change_attribute(inode, fattr->time_start); - if (data_stable) - nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_ATIME); + nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ATIME + | NFS_INO_REVAL_PAGECACHE); /* Do atomic weak cache consistency updates */ nfs_wcc_update_inode(inode, fattr); + /* More cache consistency checks */ + if (!(fattr->valid & NFS_ATTR_FATTR_V4)) { + /* NFSv2/v3: Check if the mtime agrees */ + if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { + dprintk("NFS: mtime change on server for file %s/%ld\n", + inode->i_sb->s_id, inode->i_ino); + invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; + nfsi->cache_change_attribute = now; + } + /* If ctime has changed we should definitely clear access+acl caches */ + if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) + invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; + } else if (nfsi->change_attr != fattr->change_attr) { + dprintk("NFS: change_attr change on server for file %s/%ld\n", + inode->i_sb->s_id, inode->i_ino); + invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; + nfsi->cache_change_attribute = now; + } + /* Check if our cached file size is stale */ new_isize = nfs_size_to_loff_t(fattr->size); cur_isize = i_size_read(inode); if (new_isize != cur_isize) { - /* Do we perhaps have any outstanding writes? */ - if (nfsi->npages == 0) { - /* No, but did we race with nfs_end_data_update()? */ - if (data_stable) { - inode->i_size = new_isize; - invalid |= NFS_INO_INVALID_DATA; - } - invalid |= NFS_INO_INVALID_ATTR; - } else if (new_isize > cur_isize) { + /* Do we perhaps have any outstanding writes, or has + * the file grown beyond our last write? */ + if (nfsi->npages == 0 || new_isize > cur_isize) { inode->i_size = new_isize; invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; } - nfsi->cache_change_attribute = now; dprintk("NFS: isize change on server for file %s/%ld\n", inode->i_sb->s_id, inode->i_ino); } - /* Check if the mtime agrees */ - if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { - memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); - dprintk("NFS: mtime change on server for file %s/%ld\n", - inode->i_sb->s_id, inode->i_ino); - invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; - nfsi->cache_change_attribute = now; - } - /* If ctime has changed we should definitely clear access+acl caches */ - if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) { - invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; - memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); - nfsi->cache_change_attribute = now; - } + memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); + memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); + nfsi->change_attr = fattr->change_attr; if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) || inode->i_uid != fattr->uid || @@ -1039,31 +1056,29 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) inode->i_blocks = fattr->du.nfs2.blocks; } - if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 && - nfsi->change_attr != fattr->change_attr) { - dprintk("NFS: change_attr change on server for file %s/%ld\n", - inode->i_sb->s_id, inode->i_ino); - nfsi->change_attr = fattr->change_attr; - invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; - nfsi->cache_change_attribute = now; - } - /* Update attrtimeo value if we're out of the unstable period */ if (invalid & NFS_INO_INVALID_ATTR) { nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); nfsi->attrtimeo_timestamp = now; - } else if (time_after(now, nfsi->attrtimeo_timestamp+nfsi->attrtimeo)) { - if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode)) - nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode); - nfsi->attrtimeo_timestamp = now; + nfsi->last_updated = now; + } else { + if (!time_in_range(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) { + if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode)) + nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode); + nfsi->attrtimeo_timestamp = now; + } + /* + * Avoid jiffy wraparound issues with nfsi->last_updated + */ + if (!time_in_range(nfsi->last_updated, nfsi->read_cache_jiffies, now)) + nfsi->last_updated = nfsi->read_cache_jiffies; } + invalid &= ~NFS_INO_INVALID_ATTR; /* Don't invalidate the data if we were to blame */ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) invalid &= ~NFS_INO_INVALID_DATA; - if (data_stable) - invalid &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME|NFS_INO_REVAL_PAGECACHE); if (!nfs_have_delegation(inode, FMODE_READ) || (nfsi->cache_validity & NFS_INO_REVAL_FORCED)) nfsi->cache_validity |= invalid; @@ -1143,7 +1158,7 @@ static inline void nfs4_init_once(struct nfs_inode *nfsi) #endif } -static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(struct kmem_cache * cachep, void *foo) { struct nfs_inode *nfsi = (struct nfs_inode *) foo; @@ -1152,7 +1167,6 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag INIT_LIST_HEAD(&nfsi->access_cache_entry_lru); INIT_LIST_HEAD(&nfsi->access_cache_inode_lru); INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC); - atomic_set(&nfsi->data_updates, 0); nfsi->ncommit = 0; nfsi->npages = 0; nfs4_init_once(nfsi); @@ -1249,6 +1263,7 @@ static void __exit exit_nfs_fs(void) /* Not quite true; I just maintain it */ MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>"); MODULE_LICENSE("GPL"); +module_param(enable_ino64, bool, 0644); module_init(init_nfs_fs) module_exit(exit_nfs_fs) diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 76cf55d57101..f3acf48412be 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -5,8 +5,6 @@ #include <linux/mount.h> struct nfs_string; -struct nfs_mount_data; -struct nfs4_mount_data; /* Maximum number of readahead requests * FIXME: this should really be a sysctl so that users may tune it to suit @@ -27,20 +25,50 @@ struct nfs_clone_mount { rpc_authflavor_t authflavor; }; +/* + * In-kernel mount arguments + */ +struct nfs_parsed_mount_data { + int flags; + int rsize, wsize; + int timeo, retrans; + int acregmin, acregmax, + acdirmin, acdirmax; + int namlen; + unsigned int bsize; + unsigned int auth_flavor_len; + rpc_authflavor_t auth_flavors[1]; + char *client_address; + + struct { + struct sockaddr_in address; + char *hostname; + unsigned int program; + unsigned int version; + unsigned short port; + int protocol; + } mount_server; + + struct { + struct sockaddr_in address; + char *hostname; + char *export_path; + unsigned int program; + int protocol; + } nfs_server; +}; + /* client.c */ extern struct rpc_program nfs_program; extern void nfs_put_client(struct nfs_client *); extern struct nfs_client *nfs_find_client(const struct sockaddr_in *, int); -extern struct nfs_server *nfs_create_server(const struct nfs_mount_data *, - struct nfs_fh *); -extern struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *, - const char *, - const struct sockaddr_in *, - const char *, - const char *, - rpc_authflavor_t, - struct nfs_fh *); +extern struct nfs_server *nfs_create_server( + const struct nfs_parsed_mount_data *, + struct nfs_fh *); +extern struct nfs_server *nfs4_create_server( + const struct nfs_parsed_mount_data *, + struct nfs_fh *); extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *, struct nfs_fh *); extern void nfs_free_server(struct nfs_server *server); diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index c5fce7567200..668ab96c7b59 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c @@ -251,6 +251,7 @@ nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2; xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, count); + req->rq_rcv_buf.flags |= XDRBUF_READ; return 0; } @@ -271,7 +272,7 @@ nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) res->eof = 0; hdrlen = (u8 *) p - (u8 *) iov->iov_base; if (iov->iov_len < hdrlen) { - printk(KERN_WARNING "NFS: READ reply header overflowed:" + dprintk("NFS: READ reply header overflowed:" "length %d > %Zu\n", hdrlen, iov->iov_len); return -errno_NFSERR_IO; } else if (iov->iov_len != hdrlen) { @@ -281,7 +282,7 @@ nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) recvd = req->rq_rcv_buf.len - hdrlen; if (count > recvd) { - printk(KERN_WARNING "NFS: server cheating in read reply: " + dprintk("NFS: server cheating in read reply: " "count %d > recvd %d\n", count, recvd); count = recvd; } @@ -313,6 +314,7 @@ nfs_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args) /* Copy the page array */ xdr_encode_pages(sndbuf, args->pages, args->pgbase, count); + sndbuf->flags |= XDRBUF_WRITE; return 0; } @@ -431,7 +433,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) hdrlen = (u8 *) p - (u8 *) iov->iov_base; if (iov->iov_len < hdrlen) { - printk(KERN_WARNING "NFS: READDIR reply header overflowed:" + dprintk("NFS: READDIR reply header overflowed:" "length %d > %Zu\n", hdrlen, iov->iov_len); return -errno_NFSERR_IO; } else if (iov->iov_len != hdrlen) { @@ -454,7 +456,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) len = ntohl(*p++); p += XDR_QUADLEN(len) + 1; /* name plus cookie */ if (len > NFS2_MAXNAMLEN) { - printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)!\n", + dprintk("NFS: giant filename in readdir (len 0x%x)!\n", len); goto err_unmap; } @@ -471,7 +473,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) entry[0] = entry[1] = 0; /* truncate listing ? */ if (!nr) { - printk(KERN_NOTICE "NFS: readdir reply truncated!\n"); + dprintk("NFS: readdir reply truncated!\n"); entry[1] = 1; } goto out; @@ -583,12 +585,12 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy) /* Convert length of symlink */ len = ntohl(*p++); if (len >= rcvbuf->page_len || len <= 0) { - dprintk(KERN_WARNING "nfs: server returned giant symlink!\n"); + dprintk("nfs: server returned giant symlink!\n"); return -ENAMETOOLONG; } hdrlen = (u8 *) p - (u8 *) iov->iov_base; if (iov->iov_len < hdrlen) { - printk(KERN_WARNING "NFS: READLINK reply header overflowed:" + dprintk("NFS: READLINK reply header overflowed:" "length %d > %Zu\n", hdrlen, iov->iov_len); return -errno_NFSERR_IO; } else if (iov->iov_len != hdrlen) { @@ -597,7 +599,7 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy) } recvd = req->rq_rcv_buf.len - hdrlen; if (recvd < len) { - printk(KERN_WARNING "NFS: server cheating in readlink reply: " + dprintk("NFS: server cheating in readlink reply: " "count %u > recvd %u\n", len, recvd); return -EIO; } @@ -695,7 +697,7 @@ nfs_stat_to_errno(int stat) if (nfs_errtbl[i].stat == stat) return nfs_errtbl[i].errno; } - printk(KERN_ERR "nfs_stat_to_errno: bad nfs status return value: %d\n", stat); + dprintk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat); return nfs_errtbl[i].errno; } diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index 7322da4d2055..9b7362565c0c 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c @@ -317,13 +317,11 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, } dprintk("NFS call setacl\n"); - nfs_begin_data_update(inode); msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL]; status = rpc_call_sync(server->client_acl, &msg, 0); spin_lock(&inode->i_lock); NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS; spin_unlock(&inode->i_lock); - nfs_end_data_update(inode); dprintk("NFS reply setacl: %d\n", status); /* pages may have been allocated at the xdr layer. */ diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index c7ca5d70870b..4cdc2361a669 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -166,6 +166,7 @@ nfs3_proc_lookup(struct inode *dir, struct qstr *name, nfs_fattr_init(&dir_attr); nfs_fattr_init(fattr); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + nfs_refresh_inode(dir, &dir_attr); if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) { msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR]; msg.rpc_argp = fhandle; @@ -173,8 +174,6 @@ nfs3_proc_lookup(struct inode *dir, struct qstr *name, status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); } dprintk("NFS reply lookup: %d\n", status); - if (status >= 0) - status = nfs_refresh_inode(dir, &dir_attr); return status; } @@ -607,6 +606,9 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, nfs_fattr_init(&dir_attr); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + + nfs_invalidate_atime(dir); + nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply readdir: %d\n", status); return status; @@ -724,9 +726,9 @@ static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data) { if (nfs3_async_handle_jukebox(task, data->inode)) return -EAGAIN; - /* Call back common NFS readpage processing */ - if (task->tk_status >= 0) - nfs_refresh_inode(data->inode, &data->fattr); + + nfs_invalidate_atime(data->inode); + nfs_refresh_inode(data->inode, &data->fattr); return 0; } @@ -747,7 +749,7 @@ static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data) if (nfs3_async_handle_jukebox(task, data->inode)) return -EAGAIN; if (task->tk_status >= 0) - nfs_post_op_update_inode(data->inode, data->res.fattr); + nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr); return 0; } @@ -775,8 +777,7 @@ static int nfs3_commit_done(struct rpc_task *task, struct nfs_write_data *data) { if (nfs3_async_handle_jukebox(task, data->inode)) return -EAGAIN; - if (task->tk_status >= 0) - nfs_post_op_update_inode(data->inode, data->res.fattr); + nfs_refresh_inode(data->inode, data->res.fattr); return 0; } diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index d9e08f0cf2a0..616d3267b7e7 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -346,6 +346,7 @@ nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2; xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, count); + req->rq_rcv_buf.flags |= XDRBUF_READ; return 0; } @@ -367,6 +368,7 @@ nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args) /* Copy the page array */ xdr_encode_pages(sndbuf, args->pages, args->pgbase, count); + sndbuf->flags |= XDRBUF_WRITE; return 0; } @@ -524,7 +526,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res hdrlen = (u8 *) p - (u8 *) iov->iov_base; if (iov->iov_len < hdrlen) { - printk(KERN_WARNING "NFS: READDIR reply header overflowed:" + dprintk("NFS: READDIR reply header overflowed:" "length %d > %Zu\n", hdrlen, iov->iov_len); return -errno_NFSERR_IO; } else if (iov->iov_len != hdrlen) { @@ -547,7 +549,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res len = ntohl(*p++); /* string length */ p += XDR_QUADLEN(len) + 2; /* name + cookie */ if (len > NFS3_MAXNAMLEN) { - printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n", + dprintk("NFS: giant filename in readdir (len %x)!\n", len); goto err_unmap; } @@ -567,7 +569,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res goto short_pkt; len = ntohl(*p++); if (len > NFS3_FHSIZE) { - printk(KERN_WARNING "NFS: giant filehandle in " + dprintk("NFS: giant filehandle in " "readdir (len %x)!\n", len); goto err_unmap; } @@ -588,7 +590,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res entry[0] = entry[1] = 0; /* truncate listing ? */ if (!nr) { - printk(KERN_NOTICE "NFS: readdir reply truncated!\n"); + dprintk("NFS: readdir reply truncated!\n"); entry[1] = 1; } goto out; @@ -826,22 +828,23 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) /* Convert length of symlink */ len = ntohl(*p++); if (len >= rcvbuf->page_len || len <= 0) { - dprintk(KERN_WARNING "nfs: server returned giant symlink!\n"); + dprintk("nfs: server returned giant symlink!\n"); return -ENAMETOOLONG; } hdrlen = (u8 *) p - (u8 *) iov->iov_base; if (iov->iov_len < hdrlen) { - printk(KERN_WARNING "NFS: READLINK reply header overflowed:" + dprintk("NFS: READLINK reply header overflowed:" "length %d > %Zu\n", hdrlen, iov->iov_len); return -errno_NFSERR_IO; } else if (iov->iov_len != hdrlen) { - dprintk("NFS: READLINK header is short. iovec will be shifted.\n"); + dprintk("NFS: READLINK header is short. " + "iovec will be shifted.\n"); xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen); } recvd = req->rq_rcv_buf.len - hdrlen; if (recvd < len) { - printk(KERN_WARNING "NFS: server cheating in readlink reply: " + dprintk("NFS: server cheating in readlink reply: " "count %u > recvd %u\n", len, recvd); return -EIO; } @@ -876,13 +879,13 @@ nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) ocount = ntohl(*p++); if (ocount != count) { - printk(KERN_WARNING "NFS: READ count doesn't match RPC opaque count.\n"); + dprintk("NFS: READ count doesn't match RPC opaque count.\n"); return -errno_NFSERR_IO; } hdrlen = (u8 *) p - (u8 *) iov->iov_base; if (iov->iov_len < hdrlen) { - printk(KERN_WARNING "NFS: READ reply header overflowed:" + dprintk("NFS: READ reply header overflowed:" "length %d > %Zu\n", hdrlen, iov->iov_len); return -errno_NFSERR_IO; } else if (iov->iov_len != hdrlen) { @@ -892,7 +895,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) recvd = req->rq_rcv_buf.len - hdrlen; if (count > recvd) { - printk(KERN_WARNING "NFS: server cheating in read reply: " + dprintk("NFS: server cheating in read reply: " "count %d > recvd %d\n", count, recvd); count = recvd; res->eof = 0; diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 4b90e17555a9..cb99fd90a9ac 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -62,10 +62,8 @@ struct nfs4_opendata; static int _nfs4_proc_open(struct nfs4_opendata *data); static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); -static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp); -static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags); static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); @@ -177,7 +175,7 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent *p++ = xdr_one; /* bitmap length */ *p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */ *p++ = htonl(8); /* attribute buffer length */ - p = xdr_encode_hyper(p, dentry->d_inode->i_ino); + p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_inode)); } *p++ = xdr_one; /* next */ @@ -189,7 +187,7 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent *p++ = xdr_one; /* bitmap length */ *p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */ *p++ = htonl(8); /* attribute buffer length */ - p = xdr_encode_hyper(p, dentry->d_parent->d_inode->i_ino); + p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_parent->d_inode)); readdir->pgbase = (char *)p - (char *)start; readdir->count -= readdir->pgbase; @@ -211,8 +209,9 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) spin_lock(&dir->i_lock); nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA; - if (cinfo->before == nfsi->change_attr && cinfo->atomic) - nfsi->change_attr = cinfo->after; + if (!cinfo->atomic || cinfo->before != nfsi->change_attr) + nfsi->cache_change_attribute = jiffies; + nfsi->change_attr = cinfo->after; spin_unlock(&dir->i_lock); } @@ -454,7 +453,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data)); rcu_read_unlock(); lock_kernel(); - ret = _nfs4_do_access(state->inode, state->owner->so_cred, open_mode); + ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode); unlock_kernel(); if (ret != 0) goto out; @@ -948,36 +947,6 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) return 0; } -static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags) -{ - struct nfs_access_entry cache; - int mask = 0; - int status; - - if (openflags & FMODE_READ) - mask |= MAY_READ; - if (openflags & FMODE_WRITE) - mask |= MAY_WRITE; - if (openflags & FMODE_EXEC) - mask |= MAY_EXEC; - status = nfs_access_get_cached(inode, cred, &cache); - if (status == 0) - goto out; - - /* Be clever: ask server to check for all possible rights */ - cache.mask = MAY_EXEC | MAY_WRITE | MAY_READ; - cache.cred = cred; - cache.jiffies = jiffies; - status = _nfs4_proc_access(inode, &cache); - if (status != 0) - return status; - nfs_access_add_cache(inode, &cache); -out: - if ((cache.mask & mask) == mask) - return 0; - return -EACCES; -} - static int nfs4_recover_expired_lease(struct nfs_server *server) { struct nfs_client *clp = server->nfs_client; @@ -1381,7 +1350,7 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct /* If the open_intent is for execute, we have an extra check to make */ if (nd->intent.open.flags & FMODE_EXEC) { - ret = _nfs4_do_access(state->inode, + ret = nfs_may_open(state->inode, state->owner->so_cred, nd->intent.open.flags); if (ret < 0) @@ -1390,7 +1359,7 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct filp = lookup_instantiate_filp(nd, path->dentry, NULL); if (!IS_ERR(filp)) { struct nfs_open_context *ctx; - ctx = (struct nfs_open_context *)filp->private_data; + ctx = nfs_file_open_context(filp); ctx->state = state; return 0; } @@ -1428,13 +1397,16 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred); put_rpccred(cred); if (IS_ERR(state)) { - if (PTR_ERR(state) == -ENOENT) + if (PTR_ERR(state) == -ENOENT) { d_add(dentry, NULL); + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); + } return (struct dentry *)state; } res = d_add_unique(dentry, igrab(state->inode)); if (res != NULL) path.dentry = res; + nfs_set_verifier(path.dentry, nfs_save_change_attribute(dir)); nfs4_intent_set_file(nd, &path, state); return res; } @@ -1468,6 +1440,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st } } if (state->inode == dentry->d_inode) { + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); nfs4_intent_set_file(nd, &path, state); return 1; } @@ -1757,10 +1730,16 @@ static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) { + struct nfs_server *server = NFS_SERVER(inode); + struct nfs_fattr fattr; struct nfs4_accessargs args = { .fh = NFS_FH(inode), + .bitmask = server->attr_bitmask, + }; + struct nfs4_accessres res = { + .server = server, + .fattr = &fattr, }; - struct nfs4_accessres res = { 0 }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS], .rpc_argp = &args, @@ -1786,6 +1765,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry if (mode & MAY_EXEC) args.access |= NFS4_ACCESS_EXECUTE; } + nfs_fattr_init(&fattr); status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); if (!status) { entry->mask = 0; @@ -1795,6 +1775,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry entry->mask |= MAY_WRITE; if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE)) entry->mask |= MAY_EXEC; + nfs_refresh_inode(inode, &fattr); } return status; } @@ -1900,11 +1881,13 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, } state = nfs4_do_open(dir, &path, flags, sattr, cred); put_rpccred(cred); + d_drop(dentry); if (IS_ERR(state)) { status = PTR_ERR(state); goto out; } - d_instantiate(dentry, igrab(state->inode)); + d_add(dentry, igrab(state->inode)); + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); if (flags & O_EXCL) { struct nfs_fattr fattr; status = nfs4_do_setattr(state->inode, &fattr, sattr, state); @@ -2218,6 +2201,9 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); if (status == 0) memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); + + nfs_invalidate_atime(dir); + dprintk("%s: returns %d\n", __FUNCTION__, status); return status; } @@ -2414,6 +2400,8 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) rpc_restart_call(task); return -EAGAIN; } + + nfs_invalidate_atime(data->inode); if (task->tk_status > 0) renew_lease(server, data->timestamp); return 0; @@ -2443,7 +2431,7 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) } if (task->tk_status >= 0) { renew_lease(NFS_SERVER(inode), data->timestamp); - nfs_post_op_update_inode(inode, data->res.fattr); + nfs_post_op_update_inode_force_wcc(inode, data->res.fattr); } return 0; } @@ -2485,8 +2473,7 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) rpc_restart_call(task); return -EAGAIN; } - if (task->tk_status >= 0) - nfs_post_op_update_inode(inode, data->res.fattr); + nfs_refresh_inode(inode, data->res.fattr); return 0; } @@ -3056,7 +3043,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co if (status == 0) { status = data->rpc_status; if (status == 0) - nfs_post_op_update_inode(inode, &data->fattr); + nfs_refresh_inode(inode, &data->fattr); } rpc_put_task(task); return status; @@ -3303,7 +3290,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * status = -ENOMEM; if (seqid == NULL) goto out; - task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid); + task = nfs4_do_unlck(request, nfs_file_open_context(request->fl_file), lsp, seqid); status = PTR_ERR(task); if (IS_ERR(task)) goto out; @@ -3447,7 +3434,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f int ret; dprintk("%s: begin!\n", __FUNCTION__); - data = nfs4_alloc_lockdata(fl, fl->fl_file->private_data, + data = nfs4_alloc_lockdata(fl, nfs_file_open_context(fl->fl_file), fl->fl_u.nfs4_fl.owner); if (data == NULL) return -ENOMEM; @@ -3573,7 +3560,7 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request) int status; /* verify open state */ - ctx = (struct nfs_open_context *)filp->private_data; + ctx = nfs_file_open_context(filp); state = ctx->state; if (request->fl_start < 0 || request->fl_end < 0) diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 3e4adf8c8312..bfb36261cecb 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -774,7 +774,7 @@ static int nfs4_reclaim_locks(struct nfs4_state_recovery_ops *ops, struct nfs4_s for (fl = inode->i_flock; fl != 0; fl = fl->fl_next) { if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) continue; - if (((struct nfs_open_context *)fl->fl_file->private_data)->state != state) + if (nfs_file_open_context(fl->fl_file)->state != state) continue; status = ops->recover_lock(state, fl); if (status >= 0) diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index badd73b7ca12..51dd3804866f 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -376,10 +376,12 @@ static int nfs4_stat_to_errno(int); decode_locku_maxsz) #define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - encode_access_maxsz) + encode_access_maxsz + \ + encode_getattr_maxsz) #define NFS4_dec_access_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - decode_access_maxsz) + decode_access_maxsz + \ + decode_getattr_maxsz) #define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ encode_getattr_maxsz) @@ -562,7 +564,6 @@ struct compound_hdr { #define RESERVE_SPACE(nbytes) do { \ p = xdr_reserve_space(xdr, nbytes); \ - if (!p) printk("RESERVE_SPACE(%d) failed in function %s\n", (int) (nbytes), __FUNCTION__); \ BUG_ON(!p); \ } while (0) @@ -628,8 +629,8 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s if (iap->ia_valid & ATTR_UID) { owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name); if (owner_namelen < 0) { - printk(KERN_WARNING "nfs: couldn't resolve uid %d to string\n", - iap->ia_uid); + dprintk("nfs: couldn't resolve uid %d to string\n", + iap->ia_uid); /* XXX */ strcpy(owner_name, "nobody"); owner_namelen = sizeof("nobody") - 1; @@ -640,8 +641,8 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s if (iap->ia_valid & ATTR_GID) { owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group); if (owner_grouplen < 0) { - printk(KERN_WARNING "nfs4: couldn't resolve gid %d to string\n", - iap->ia_gid); + dprintk("nfs: couldn't resolve gid %d to string\n", + iap->ia_gid); strcpy(owner_group, "nobody"); owner_grouplen = sizeof("nobody") - 1; /* goto out; */ @@ -711,7 +712,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s * Now we backfill the bitmap and the attribute buffer length. */ if (len != ((char *)p - (char *)q) + 4) { - printk ("encode_attr: Attr length calculation error! %u != %Zu\n", + printk(KERN_ERR "nfs: Attr length error, %u != %Zu\n", len, ((char *)p - (char *)q) + 4); BUG(); } @@ -1376,14 +1377,20 @@ static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs { struct xdr_stream xdr; struct compound_hdr hdr = { - .nops = 2, + .nops = 3, }; int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); - if ((status = encode_putfh(&xdr, args->fh)) == 0) - status = encode_access(&xdr, args->access); + status = encode_putfh(&xdr, args->fh); + if (status != 0) + goto out; + status = encode_access(&xdr, args->access); + if (status != 0) + goto out; + status = encode_getfattr(&xdr, args->bitmask); +out: return status; } @@ -1857,6 +1864,7 @@ static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readarg replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_read_sz) << 2; xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->count); + req->rq_rcv_buf.flags |= XDRBUF_READ; out: return status; } @@ -1933,6 +1941,7 @@ static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writea status = encode_write(&xdr, args); if (status) goto out; + req->rq_snd_buf.flags |= XDRBUF_WRITE; status = encode_getfattr(&xdr, args->bitmask); out: return status; @@ -2180,9 +2189,9 @@ out: #define READ_BUF(nbytes) do { \ p = xdr_inline_decode(xdr, nbytes); \ if (unlikely(!p)) { \ - printk(KERN_INFO "%s: prematurely hit end of receive" \ + dprintk("nfs: %s: prematurely hit end of receive" \ " buffer\n", __FUNCTION__); \ - printk(KERN_INFO "%s: xdr->p=%p, bytes=%u, xdr->end=%p\n", \ + dprintk("nfs: %s: xdr->p=%p, bytes=%u, xdr->end=%p\n", \ __FUNCTION__, xdr->p, nbytes, xdr->end); \ return -EIO; \ } \ @@ -2223,9 +2232,8 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) READ_BUF(8); READ32(opnum); if (opnum != expected) { - printk(KERN_NOTICE - "nfs4_decode_op_hdr: Server returned operation" - " %d but we issued a request for %d\n", + dprintk("nfs: Server returned operation" + " %d but we issued a request for %d\n", opnum, expected); return -EIO; } @@ -2758,7 +2766,7 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf dprintk("%s: nfs_map_name_to_uid failed!\n", __FUNCTION__); } else - printk(KERN_WARNING "%s: name too long (%u)!\n", + dprintk("%s: name too long (%u)!\n", __FUNCTION__, len); bitmap[1] &= ~FATTR4_WORD1_OWNER; } @@ -2783,7 +2791,7 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf dprintk("%s: nfs_map_group_to_gid failed!\n", __FUNCTION__); } else - printk(KERN_WARNING "%s: name too long (%u)!\n", + dprintk("%s: name too long (%u)!\n", __FUNCTION__, len); bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP; } @@ -2950,7 +2958,8 @@ static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrl unsigned int nwords = xdr->p - savep; if (unlikely(attrwords != nwords)) { - printk(KERN_WARNING "%s: server returned incorrect attribute length: %u %c %u\n", + dprintk("%s: server returned incorrect attribute length: " + "%u %c %u\n", __FUNCTION__, attrwords << 2, (attrwords < nwords) ? '<' : '>', @@ -3451,7 +3460,7 @@ static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_ hdrlen = (u8 *) p - (u8 *) iov->iov_base; recvd = req->rq_rcv_buf.len - hdrlen; if (count > recvd) { - printk(KERN_WARNING "NFS: server cheating in read reply: " + dprintk("NFS: server cheating in read reply: " "count %u > recvd %u\n", count, recvd); count = recvd; eof = 0; @@ -3500,7 +3509,8 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n p += 2; /* cookie */ len = ntohl(*p++); /* filename length */ if (len > NFS4_MAXNAMLEN) { - printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len); + dprintk("NFS: giant filename in readdir (len 0x%x)\n", + len); goto err_unmap; } xlen = XDR_QUADLEN(len); @@ -3528,7 +3538,7 @@ short_pkt: entry[0] = entry[1] = 0; /* truncate listing ? */ if (!nr) { - printk(KERN_NOTICE "NFS: readdir reply truncated!\n"); + dprintk("NFS: readdir reply truncated!\n"); entry[1] = 1; } goto out; @@ -3554,13 +3564,13 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) READ_BUF(4); READ32(len); if (len >= rcvbuf->page_len || len <= 0) { - dprintk(KERN_WARNING "nfs: server returned giant symlink!\n"); + dprintk("nfs: server returned giant symlink!\n"); return -ENAMETOOLONG; } hdrlen = (char *) xdr->p - (char *) iov->iov_base; recvd = req->rq_rcv_buf.len - hdrlen; if (recvd < len) { - printk(KERN_WARNING "NFS: server cheating in readlink reply: " + dprintk("NFS: server cheating in readlink reply: " "count %u > recvd %u\n", len, recvd); return -EIO; } @@ -3643,7 +3653,7 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base; recvd = req->rq_rcv_buf.len - hdrlen; if (attrlen > recvd) { - printk(KERN_WARNING "NFS: server cheating in getattr" + dprintk("NFS: server cheating in getattr" " acl reply: attrlen %u > recvd %u\n", attrlen, recvd); return -EINVAL; @@ -3688,8 +3698,7 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) READ_BUF(8); READ32(opnum); if (opnum != OP_SETCLIENTID) { - printk(KERN_NOTICE - "nfs4_decode_setclientid: Server returned operation" + dprintk("nfs: decode_setclientid: Server returned operation" " %d\n", opnum); return -EIO; } @@ -3783,8 +3792,13 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_ac xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) goto out; - if ((status = decode_putfh(&xdr)) == 0) - status = decode_access(&xdr, res); + status = decode_putfh(&xdr); + if (status != 0) + goto out; + status = decode_access(&xdr, res); + if (status != 0) + goto out; + decode_getfattr(&xdr, res->fattr, res->server); out: return status; } diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index 3490322d1145..e87b44ee9ac9 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -76,6 +76,7 @@ #include <linux/fs.h> #include <linux/init.h> #include <linux/sunrpc/clnt.h> +#include <linux/sunrpc/xprtsock.h> #include <linux/nfs.h> #include <linux/nfs_fs.h> #include <linux/nfs_mount.h> @@ -491,7 +492,7 @@ static int __init root_nfs_get_handle(void) struct sockaddr_in sin; int status; int protocol = (nfs_data.flags & NFS_MOUNT_TCP) ? - IPPROTO_TCP : IPPROTO_UDP; + XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP; int version = (nfs_data.flags & NFS_MOUNT_VER3) ? NFS_MNT3_VERSION : NFS_MNT_VERSION; diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 845cdde1d8b7..97669ed05500 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -476,6 +476,8 @@ nfs_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, dprintk("NFS call readdir %d\n", (unsigned int)cookie); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + nfs_invalidate_atime(dir); + dprintk("NFS reply readdir: %d\n", status); return status; } @@ -550,6 +552,7 @@ nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data) { + nfs_invalidate_atime(data->inode); if (task->tk_status >= 0) { nfs_refresh_inode(data->inode, data->res.fattr); /* Emulate the eof flag, which isn't normally needed in NFSv2 @@ -576,7 +579,7 @@ static void nfs_proc_read_setup(struct nfs_read_data *data) static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data) { if (task->tk_status >= 0) - nfs_post_op_update_inode(data->inode, data->res.fattr); + nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr); return 0; } diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 19e05633f4e3..4587a86adaac 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -341,9 +341,6 @@ int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) set_bit(NFS_INO_STALE, &NFS_FLAGS(data->inode)); nfs_mark_for_revalidate(data->inode); } - spin_lock(&data->inode->i_lock); - NFS_I(data->inode)->cache_validity |= NFS_INO_INVALID_ATIME; - spin_unlock(&data->inode->i_lock); return 0; } @@ -497,8 +494,7 @@ int nfs_readpage(struct file *file, struct page *page) if (ctx == NULL) goto out_unlock; } else - ctx = get_nfs_open_context((struct nfs_open_context *) - file->private_data); + ctx = get_nfs_open_context(nfs_file_open_context(file)); error = nfs_readpage_async(ctx, inode, page); @@ -576,8 +572,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, if (desc.ctx == NULL) return -EBADF; } else - desc.ctx = get_nfs_open_context((struct nfs_open_context *) - filp->private_data); + desc.ctx = get_nfs_open_context(nfs_file_open_context(filp)); if (rsize < PAGE_CACHE_SIZE) nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0); else diff --git a/fs/nfs/super.c b/fs/nfs/super.c index b878528b64c1..fa517ae9207f 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -33,6 +33,8 @@ #include <linux/sunrpc/clnt.h> #include <linux/sunrpc/stats.h> #include <linux/sunrpc/metrics.h> +#include <linux/sunrpc/xprtsock.h> +#include <linux/sunrpc/xprtrdma.h> #include <linux/nfs_fs.h> #include <linux/nfs_mount.h> #include <linux/nfs4_mount.h> @@ -58,36 +60,6 @@ #define NFSDBG_FACILITY NFSDBG_VFS - -struct nfs_parsed_mount_data { - int flags; - int rsize, wsize; - int timeo, retrans; - int acregmin, acregmax, - acdirmin, acdirmax; - int namlen; - unsigned int bsize; - unsigned int auth_flavor_len; - rpc_authflavor_t auth_flavors[1]; - char *client_address; - - struct { - struct sockaddr_in address; - unsigned int program; - unsigned int version; - unsigned short port; - int protocol; - } mount_server; - - struct { - struct sockaddr_in address; - char *hostname; - char *export_path; - unsigned int program; - int protocol; - } nfs_server; -}; - enum { /* Mount options that take no arguments */ Opt_soft, Opt_hard, @@ -97,7 +69,7 @@ enum { Opt_ac, Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, - Opt_udp, Opt_tcp, + Opt_udp, Opt_tcp, Opt_rdma, Opt_acl, Opt_noacl, Opt_rdirplus, Opt_nordirplus, Opt_sharecache, Opt_nosharecache, @@ -116,7 +88,7 @@ enum { /* Mount options that take string arguments */ Opt_sec, Opt_proto, Opt_mountproto, - Opt_addr, Opt_mounthost, Opt_clientaddr, + Opt_addr, Opt_mountaddr, Opt_clientaddr, /* Mount options that are ignored */ Opt_userspace, Opt_deprecated, @@ -143,6 +115,7 @@ static match_table_t nfs_mount_option_tokens = { { Opt_v3, "v3" }, { Opt_udp, "udp" }, { Opt_tcp, "tcp" }, + { Opt_rdma, "rdma" }, { Opt_acl, "acl" }, { Opt_noacl, "noacl" }, { Opt_rdirplus, "rdirplus" }, @@ -175,13 +148,14 @@ static match_table_t nfs_mount_option_tokens = { { Opt_mountproto, "mountproto=%s" }, { Opt_addr, "addr=%s" }, { Opt_clientaddr, "clientaddr=%s" }, - { Opt_mounthost, "mounthost=%s" }, + { Opt_userspace, "mounthost=%s" }, + { Opt_mountaddr, "mountaddr=%s" }, { Opt_err, NULL } }; enum { - Opt_xprt_udp, Opt_xprt_tcp, + Opt_xprt_udp, Opt_xprt_tcp, Opt_xprt_rdma, Opt_xprt_err }; @@ -189,6 +163,7 @@ enum { static match_table_t nfs_xprt_protocol_tokens = { { Opt_xprt_udp, "udp" }, { Opt_xprt_tcp, "tcp" }, + { Opt_xprt_rdma, "rdma" }, { Opt_xprt_err, NULL } }; @@ -449,7 +424,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, const char *nostr; } nfs_info[] = { { NFS_MOUNT_SOFT, ",soft", ",hard" }, - { NFS_MOUNT_INTR, ",intr", "" }, + { NFS_MOUNT_INTR, ",intr", ",nointr" }, { NFS_MOUNT_NOCTO, ",nocto", "" }, { NFS_MOUNT_NOAC, ",noac", "" }, { NFS_MOUNT_NONLM, ",nolock", "" }, @@ -460,8 +435,6 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, }; const struct proc_nfs_info *nfs_infop; struct nfs_client *clp = nfss->nfs_client; - char buf[12]; - const char *proto; seq_printf(m, ",vers=%d", clp->rpc_ops->version); seq_printf(m, ",rsize=%d", nfss->rsize); @@ -480,18 +453,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, else seq_puts(m, nfs_infop->nostr); } - switch (nfss->client->cl_xprt->prot) { - case IPPROTO_TCP: - proto = "tcp"; - break; - case IPPROTO_UDP: - proto = "udp"; - break; - default: - snprintf(buf, sizeof(buf), "%u", nfss->client->cl_xprt->prot); - proto = buf; - } - seq_printf(m, ",proto=%s", proto); + seq_printf(m, ",proto=%s", + rpc_peeraddr2str(nfss->client, RPC_DISPLAY_PROTO)); seq_printf(m, ",timeo=%lu", 10U * clp->retrans_timeo / HZ); seq_printf(m, ",retrans=%u", clp->retrans_count); seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor)); @@ -506,8 +469,8 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) nfs_show_mount_options(m, nfss, 0); - seq_puts(m, ",addr="); - seq_escape(m, nfss->nfs_client->cl_hostname, " \t\n\\"); + seq_printf(m, ",addr="NIPQUAD_FMT, + NIPQUAD(nfss->nfs_client->cl_addr.sin_addr)); return 0; } @@ -698,13 +661,19 @@ static int nfs_parse_mount_options(char *raw, break; case Opt_udp: mnt->flags &= ~NFS_MOUNT_TCP; - mnt->nfs_server.protocol = IPPROTO_UDP; + mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; mnt->timeo = 7; mnt->retrans = 5; break; case Opt_tcp: mnt->flags |= NFS_MOUNT_TCP; - mnt->nfs_server.protocol = IPPROTO_TCP; + mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; + mnt->timeo = 600; + mnt->retrans = 2; + break; + case Opt_rdma: + mnt->flags |= NFS_MOUNT_TCP; /* for side protocols */ + mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; mnt->timeo = 600; mnt->retrans = 2; break; @@ -913,13 +882,20 @@ static int nfs_parse_mount_options(char *raw, switch (token) { case Opt_xprt_udp: mnt->flags &= ~NFS_MOUNT_TCP; - mnt->nfs_server.protocol = IPPROTO_UDP; + mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; mnt->timeo = 7; mnt->retrans = 5; break; case Opt_xprt_tcp: mnt->flags |= NFS_MOUNT_TCP; - mnt->nfs_server.protocol = IPPROTO_TCP; + mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; + mnt->timeo = 600; + mnt->retrans = 2; + break; + case Opt_xprt_rdma: + /* vector side protocols to TCP */ + mnt->flags |= NFS_MOUNT_TCP; + mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; mnt->timeo = 600; mnt->retrans = 2; break; @@ -937,11 +913,12 @@ static int nfs_parse_mount_options(char *raw, switch (token) { case Opt_xprt_udp: - mnt->mount_server.protocol = IPPROTO_UDP; + mnt->mount_server.protocol = XPRT_TRANSPORT_UDP; break; case Opt_xprt_tcp: - mnt->mount_server.protocol = IPPROTO_TCP; + mnt->mount_server.protocol = XPRT_TRANSPORT_TCP; break; + case Opt_xprt_rdma: /* not used for side protocols */ default: goto out_unrec_xprt; } @@ -961,7 +938,7 @@ static int nfs_parse_mount_options(char *raw, goto out_nomem; mnt->client_address = string; break; - case Opt_mounthost: + case Opt_mountaddr: string = match_strdup(args); if (string == NULL) goto out_nomem; @@ -1027,16 +1004,10 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, sin = args->mount_server.address; else sin = args->nfs_server.address; - if (args->mount_server.port == 0) { - status = rpcb_getport_sync(&sin, - args->mount_server.program, - args->mount_server.version, - args->mount_server.protocol); - if (status < 0) - goto out_err; - sin.sin_port = htons(status); - } else - sin.sin_port = htons(args->mount_server.port); + /* + * autobind will be used if mount_server.port == 0 + */ + sin.sin_port = htons(args->mount_server.port); /* * Now ask the mount server to map our export path @@ -1049,14 +1020,11 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, args->mount_server.version, args->mount_server.protocol, root_fh); - if (status < 0) - goto out_err; - - return status; + if (status == 0) + return 0; -out_err: - dfprintk(MOUNT, "NFS: unable to contact server on host " - NIPQUAD_FMT "\n", NIPQUAD(sin.sin_addr.s_addr)); + dfprintk(MOUNT, "NFS: unable to mount server " NIPQUAD_FMT + ", error %d\n", NIPQUAD(sin.sin_addr.s_addr), status); return status; } @@ -1079,15 +1047,31 @@ out_err: * XXX: as far as I can tell, changing the NFS program number is not * supported in the NFS client. */ -static int nfs_validate_mount_data(struct nfs_mount_data **options, +static int nfs_validate_mount_data(void *options, + struct nfs_parsed_mount_data *args, struct nfs_fh *mntfh, const char *dev_name) { - struct nfs_mount_data *data = *options; + struct nfs_mount_data *data = (struct nfs_mount_data *)options; if (data == NULL) goto out_no_data; + memset(args, 0, sizeof(*args)); + args->flags = (NFS_MOUNT_VER3 | NFS_MOUNT_TCP); + args->rsize = NFS_MAX_FILE_IO_SIZE; + args->wsize = NFS_MAX_FILE_IO_SIZE; + args->timeo = 600; + args->retrans = 2; + args->acregmin = 3; + args->acregmax = 60; + args->acdirmin = 30; + args->acdirmax = 60; + args->mount_server.protocol = XPRT_TRANSPORT_UDP; + args->mount_server.program = NFS_MNT_PROGRAM; + args->nfs_server.protocol = XPRT_TRANSPORT_TCP; + args->nfs_server.program = NFS_PROGRAM; + switch (data->version) { case 1: data->namlen = 0; @@ -1116,92 +1100,73 @@ static int nfs_validate_mount_data(struct nfs_mount_data **options, if (mntfh->size < sizeof(mntfh->data)) memset(mntfh->data + mntfh->size, 0, sizeof(mntfh->data) - mntfh->size); + + if (!nfs_verify_server_address((struct sockaddr *) &data->addr)) + goto out_no_address; + + /* + * Translate to nfs_parsed_mount_data, which nfs_fill_super + * can deal with. + */ + args->flags = data->flags; + args->rsize = data->rsize; + args->wsize = data->wsize; + args->flags = data->flags; + args->timeo = data->timeo; + args->retrans = data->retrans; + args->acregmin = data->acregmin; + args->acregmax = data->acregmax; + args->acdirmin = data->acdirmin; + args->acdirmax = data->acdirmax; + args->nfs_server.address = data->addr; + if (!(data->flags & NFS_MOUNT_TCP)) + args->nfs_server.protocol = XPRT_TRANSPORT_UDP; + /* N.B. caller will free nfs_server.hostname in all cases */ + args->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL); + args->namlen = data->namlen; + args->bsize = data->bsize; + args->auth_flavors[0] = data->pseudoflavor; break; default: { unsigned int len; char *c; int status; - struct nfs_parsed_mount_data args = { - .flags = (NFS_MOUNT_VER3 | NFS_MOUNT_TCP), - .rsize = NFS_MAX_FILE_IO_SIZE, - .wsize = NFS_MAX_FILE_IO_SIZE, - .timeo = 600, - .retrans = 2, - .acregmin = 3, - .acregmax = 60, - .acdirmin = 30, - .acdirmax = 60, - .mount_server.protocol = IPPROTO_UDP, - .mount_server.program = NFS_MNT_PROGRAM, - .nfs_server.protocol = IPPROTO_TCP, - .nfs_server.program = NFS_PROGRAM, - }; - - if (nfs_parse_mount_options((char *) *options, &args) == 0) - return -EINVAL; - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (data == NULL) - return -ENOMEM; + if (nfs_parse_mount_options((char *)options, args) == 0) + return -EINVAL; - /* - * NB: after this point, caller will free "data" - * if we return an error - */ - *options = data; + if (!nfs_verify_server_address((struct sockaddr *) + &args->nfs_server.address)) + goto out_no_address; c = strchr(dev_name, ':'); if (c == NULL) return -EINVAL; len = c - dev_name; - if (len > sizeof(data->hostname)) - return -ENAMETOOLONG; - strncpy(data->hostname, dev_name, len); - args.nfs_server.hostname = data->hostname; + /* N.B. caller will free nfs_server.hostname in all cases */ + args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL); c++; if (strlen(c) > NFS_MAXPATHLEN) return -ENAMETOOLONG; - args.nfs_server.export_path = c; + args->nfs_server.export_path = c; - status = nfs_try_mount(&args, mntfh); + status = nfs_try_mount(args, mntfh); if (status) return status; - /* - * Translate to nfs_mount_data, which nfs_fill_super - * can deal with. - */ - data->version = 6; - data->flags = args.flags; - data->rsize = args.rsize; - data->wsize = args.wsize; - data->timeo = args.timeo; - data->retrans = args.retrans; - data->acregmin = args.acregmin; - data->acregmax = args.acregmax; - data->acdirmin = args.acdirmin; - data->acdirmax = args.acdirmax; - data->addr = args.nfs_server.address; - data->namlen = args.namlen; - data->bsize = args.bsize; - data->pseudoflavor = args.auth_flavors[0]; - break; } } - if (!(data->flags & NFS_MOUNT_SECFLAVOUR)) - data->pseudoflavor = RPC_AUTH_UNIX; + if (!(args->flags & NFS_MOUNT_SECFLAVOUR)) + args->auth_flavors[0] = RPC_AUTH_UNIX; #ifndef CONFIG_NFS_V3 - if (data->flags & NFS_MOUNT_VER3) + if (args->flags & NFS_MOUNT_VER3) goto out_v3_not_compiled; #endif /* !CONFIG_NFS_V3 */ - if (!nfs_verify_server_address((struct sockaddr *) &data->addr)) - goto out_no_address; - return 0; out_no_data: @@ -1258,7 +1223,8 @@ static inline void nfs_initialise_sb(struct super_block *sb) /* * Finish setting up an NFS2/3 superblock */ -static void nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data) +static void nfs_fill_super(struct super_block *sb, + struct nfs_parsed_mount_data *data) { struct nfs_server *server = NFS_SB(sb); @@ -1379,7 +1345,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, struct nfs_server *server = NULL; struct super_block *s; struct nfs_fh mntfh; - struct nfs_mount_data *data = raw_data; + struct nfs_parsed_mount_data data; struct dentry *mntroot; int (*compare_super)(struct super_block *, void *) = nfs_compare_super; struct nfs_sb_mountdata sb_mntdata = { @@ -1388,12 +1354,12 @@ static int nfs_get_sb(struct file_system_type *fs_type, int error; /* Validate the mount data */ - error = nfs_validate_mount_data(&data, &mntfh, dev_name); + error = nfs_validate_mount_data(raw_data, &data, &mntfh, dev_name); if (error < 0) goto out; /* Get a volume representation */ - server = nfs_create_server(data, &mntfh); + server = nfs_create_server(&data, &mntfh); if (IS_ERR(server)) { error = PTR_ERR(server); goto out; @@ -1417,7 +1383,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, if (!s->s_root) { /* initial superblock/root creation */ - nfs_fill_super(s, data); + nfs_fill_super(s, &data); } mntroot = nfs_get_root(s, &mntfh); @@ -1432,8 +1398,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, error = 0; out: - if (data != raw_data) - kfree(data); + kfree(data.nfs_server.hostname); return error; out_err_nosb: @@ -1559,38 +1524,49 @@ static void nfs4_fill_super(struct super_block *sb) /* * Validate NFSv4 mount options */ -static int nfs4_validate_mount_data(struct nfs4_mount_data **options, - const char *dev_name, - struct sockaddr_in *addr, - rpc_authflavor_t *authflavour, - char **hostname, - char **mntpath, - char **ip_addr) +static int nfs4_validate_mount_data(void *options, + struct nfs_parsed_mount_data *args, + const char *dev_name) { - struct nfs4_mount_data *data = *options; + struct nfs4_mount_data *data = (struct nfs4_mount_data *)options; char *c; if (data == NULL) goto out_no_data; + memset(args, 0, sizeof(*args)); + args->rsize = NFS_MAX_FILE_IO_SIZE; + args->wsize = NFS_MAX_FILE_IO_SIZE; + args->timeo = 600; + args->retrans = 2; + args->acregmin = 3; + args->acregmax = 60; + args->acdirmin = 30; + args->acdirmax = 60; + args->nfs_server.protocol = XPRT_TRANSPORT_TCP; + switch (data->version) { case 1: - if (data->host_addrlen != sizeof(*addr)) + if (data->host_addrlen != sizeof(args->nfs_server.address)) goto out_no_address; - if (copy_from_user(addr, data->host_addr, sizeof(*addr))) + if (copy_from_user(&args->nfs_server.address, + data->host_addr, + sizeof(args->nfs_server.address))) return -EFAULT; - if (addr->sin_port == 0) - addr->sin_port = htons(NFS_PORT); - if (!nfs_verify_server_address((struct sockaddr *) addr)) + if (args->nfs_server.address.sin_port == 0) + args->nfs_server.address.sin_port = htons(NFS_PORT); + if (!nfs_verify_server_address((struct sockaddr *) + &args->nfs_server.address)) goto out_no_address; switch (data->auth_flavourlen) { case 0: - *authflavour = RPC_AUTH_UNIX; + args->auth_flavors[0] = RPC_AUTH_UNIX; break; case 1: - if (copy_from_user(authflavour, data->auth_flavours, - sizeof(*authflavour))) + if (copy_from_user(&args->auth_flavors[0], + data->auth_flavours, + sizeof(args->auth_flavors[0]))) return -EFAULT; break; default: @@ -1600,75 +1576,57 @@ static int nfs4_validate_mount_data(struct nfs4_mount_data **options, c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN); if (IS_ERR(c)) return PTR_ERR(c); - *hostname = c; + args->nfs_server.hostname = c; c = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN); if (IS_ERR(c)) return PTR_ERR(c); - *mntpath = c; - dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", *mntpath); + args->nfs_server.export_path = c; + dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", c); c = strndup_user(data->client_addr.data, 16); if (IS_ERR(c)) return PTR_ERR(c); - *ip_addr = c; + args->client_address = c; + + /* + * Translate to nfs_parsed_mount_data, which nfs4_fill_super + * can deal with. + */ + + args->flags = data->flags & NFS4_MOUNT_FLAGMASK; + args->rsize = data->rsize; + args->wsize = data->wsize; + args->timeo = data->timeo; + args->retrans = data->retrans; + args->acregmin = data->acregmin; + args->acregmax = data->acregmax; + args->acdirmin = data->acdirmin; + args->acdirmax = data->acdirmax; + args->nfs_server.protocol = data->proto; break; default: { unsigned int len; - struct nfs_parsed_mount_data args = { - .rsize = NFS_MAX_FILE_IO_SIZE, - .wsize = NFS_MAX_FILE_IO_SIZE, - .timeo = 600, - .retrans = 2, - .acregmin = 3, - .acregmax = 60, - .acdirmin = 30, - .acdirmax = 60, - .nfs_server.protocol = IPPROTO_TCP, - }; - - if (nfs_parse_mount_options((char *) *options, &args) == 0) + + if (nfs_parse_mount_options((char *)options, args) == 0) return -EINVAL; if (!nfs_verify_server_address((struct sockaddr *) - &args.nfs_server.address)) + &args->nfs_server.address)) return -EINVAL; - *addr = args.nfs_server.address; - switch (args.auth_flavor_len) { + switch (args->auth_flavor_len) { case 0: - *authflavour = RPC_AUTH_UNIX; + args->auth_flavors[0] = RPC_AUTH_UNIX; break; case 1: - *authflavour = (rpc_authflavor_t) args.auth_flavors[0]; break; default: goto out_inval_auth; } /* - * Translate to nfs4_mount_data, which nfs4_fill_super - * can deal with. - */ - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (data == NULL) - return -ENOMEM; - *options = data; - - data->version = 1; - data->flags = args.flags & NFS4_MOUNT_FLAGMASK; - data->rsize = args.rsize; - data->wsize = args.wsize; - data->timeo = args.timeo; - data->retrans = args.retrans; - data->acregmin = args.acregmin; - data->acregmax = args.acregmax; - data->acdirmin = args.acdirmin; - data->acdirmax = args.acdirmax; - data->proto = args.nfs_server.protocol; - - /* * Split "dev_name" into "hostname:mntpath". */ c = strchr(dev_name, ':'); @@ -1678,27 +1636,25 @@ static int nfs4_validate_mount_data(struct nfs4_mount_data **options, len = c - dev_name; if (len > NFS4_MAXNAMLEN) return -ENAMETOOLONG; - *hostname = kzalloc(len, GFP_KERNEL); - if (*hostname == NULL) + args->nfs_server.hostname = kzalloc(len, GFP_KERNEL); + if (args->nfs_server.hostname == NULL) return -ENOMEM; - strncpy(*hostname, dev_name, len - 1); + strncpy(args->nfs_server.hostname, dev_name, len - 1); c++; /* step over the ':' */ len = strlen(c); if (len > NFS4_MAXPATHLEN) return -ENAMETOOLONG; - *mntpath = kzalloc(len + 1, GFP_KERNEL); - if (*mntpath == NULL) + args->nfs_server.export_path = kzalloc(len + 1, GFP_KERNEL); + if (args->nfs_server.export_path == NULL) return -ENOMEM; - strncpy(*mntpath, c, len); + strncpy(args->nfs_server.export_path, c, len); - dprintk("MNTPATH: %s\n", *mntpath); + dprintk("MNTPATH: %s\n", args->nfs_server.export_path); - if (args.client_address == NULL) + if (args->client_address == NULL) goto out_no_client_address; - *ip_addr = args.client_address; - break; } } @@ -1729,14 +1685,11 @@ out_no_client_address: static int nfs4_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) { - struct nfs4_mount_data *data = raw_data; + struct nfs_parsed_mount_data data; struct super_block *s; struct nfs_server *server; - struct sockaddr_in addr; - rpc_authflavor_t authflavour; struct nfs_fh mntfh; struct dentry *mntroot; - char *mntpath = NULL, *hostname = NULL, *ip_addr = NULL; int (*compare_super)(struct super_block *, void *) = nfs_compare_super; struct nfs_sb_mountdata sb_mntdata = { .mntflags = flags, @@ -1744,14 +1697,12 @@ static int nfs4_get_sb(struct file_system_type *fs_type, int error; /* Validate the mount data */ - error = nfs4_validate_mount_data(&data, dev_name, &addr, &authflavour, - &hostname, &mntpath, &ip_addr); + error = nfs4_validate_mount_data(raw_data, &data, dev_name); if (error < 0) goto out; /* Get a volume representation */ - server = nfs4_create_server(data, hostname, &addr, mntpath, ip_addr, - authflavour, &mntfh); + server = nfs4_create_server(&data, &mntfh); if (IS_ERR(server)) { error = PTR_ERR(server); goto out; @@ -1790,9 +1741,9 @@ static int nfs4_get_sb(struct file_system_type *fs_type, error = 0; out: - kfree(ip_addr); - kfree(mntpath); - kfree(hostname); + kfree(data.client_address); + kfree(data.nfs_server.export_path); + kfree(data.nfs_server.hostname); return error; out_free: diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 045ab805c17f..1aed850d18f2 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -66,7 +66,6 @@ static void nfs_async_unlink_init(struct rpc_task *task, void *calldata) .rpc_cred = data->cred, }; - nfs_begin_data_update(dir); NFS_PROTO(dir)->unlink_setup(&msg, dir); rpc_call_setup(task, &msg, 0); } @@ -84,8 +83,6 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata) if (!NFS_PROTO(dir)->unlink_done(task, dir)) rpc_restart_call(task); - else - nfs_end_data_update(dir); } /** diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 0d7a77cc394b..0cf9d1cd9bd2 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -110,6 +110,13 @@ void nfs_writedata_release(void *wdata) nfs_writedata_free(wdata); } +static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error) +{ + ctx->error = error; + smp_wmb(); + set_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); +} + static struct nfs_page *nfs_page_find_request_locked(struct page *page) { struct nfs_page *req = NULL; @@ -235,18 +242,13 @@ static void nfs_end_page_writeback(struct page *page) struct nfs_server *nfss = NFS_SERVER(inode); end_page_writeback(page); - if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) { + if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) clear_bdi_congested(&nfss->backing_dev_info, WRITE); - congestion_end(WRITE); - } } /* * Find an associated nfs write request, and prepare to flush it out - * Returns 1 if there was no write request, or if the request was - * already tagged by nfs_set_page_dirty.Returns 0 if the request - * was not tagged. - * May also return an error if the user signalled nfs_wait_on_request(). + * May return an error if the user signalled nfs_wait_on_request(). */ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, struct page *page) @@ -261,7 +263,7 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, req = nfs_page_find_request_locked(page); if (req == NULL) { spin_unlock(&inode->i_lock); - return 1; + return 0; } if (nfs_lock_request_dontget(req)) break; @@ -282,7 +284,7 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, spin_unlock(&inode->i_lock); nfs_unlock_request(req); nfs_pageio_complete(pgio); - return 1; + return 0; } if (nfs_set_page_writeback(page) != 0) { spin_unlock(&inode->i_lock); @@ -290,70 +292,56 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, } radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); - ret = test_bit(PG_NEED_FLUSH, &req->wb_flags); spin_unlock(&inode->i_lock); nfs_pageio_add_request(pgio, req); - return ret; + return 0; } -/* - * Write an mmapped page to the server. - */ -static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc) +static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio) { - struct nfs_pageio_descriptor mypgio, *pgio; - struct nfs_open_context *ctx; struct inode *inode = page->mapping->host; - unsigned offset; - int err; nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1); - if (wbc->for_writepages) - pgio = wbc->fs_private; - else { - nfs_pageio_init_write(&mypgio, inode, wb_priority(wbc)); - pgio = &mypgio; - } - nfs_pageio_cond_complete(pgio, page->index); + return nfs_page_async_flush(pgio, page); +} - err = nfs_page_async_flush(pgio, page); - if (err <= 0) - goto out; - err = 0; - offset = nfs_page_length(page); - if (!offset) - goto out; - - nfs_pageio_cond_complete(pgio, page->index); +/* + * Write an mmapped page to the server. + */ +static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc) +{ + struct nfs_pageio_descriptor pgio; + int err; - ctx = nfs_find_open_context(inode, NULL, FMODE_WRITE); - if (ctx == NULL) { - err = -EBADF; - goto out; - } - err = nfs_writepage_setup(ctx, page, 0, offset); - put_nfs_open_context(ctx); - if (err != 0) - goto out; - err = nfs_page_async_flush(pgio, page); - if (err > 0) - err = 0; -out: - if (!wbc->for_writepages) - nfs_pageio_complete(pgio); - return err; + nfs_pageio_init_write(&pgio, page->mapping->host, wb_priority(wbc)); + err = nfs_do_writepage(page, wbc, &pgio); + nfs_pageio_complete(&pgio); + if (err < 0) + return err; + if (pgio.pg_error < 0) + return pgio.pg_error; + return 0; } int nfs_writepage(struct page *page, struct writeback_control *wbc) { - int err; + int ret; + + ret = nfs_writepage_locked(page, wbc); + unlock_page(page); + return ret; +} + +static int nfs_writepages_callback(struct page *page, struct writeback_control *wbc, void *data) +{ + int ret; - err = nfs_writepage_locked(page, wbc); + ret = nfs_do_writepage(page, wbc, data); unlock_page(page); - return err; + return ret; } int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) @@ -365,12 +353,11 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES); nfs_pageio_init_write(&pgio, inode, wb_priority(wbc)); - wbc->fs_private = &pgio; - err = generic_writepages(mapping, wbc); + err = write_cache_pages(mapping, wbc, nfs_writepages_callback, &pgio); nfs_pageio_complete(&pgio); - if (err) + if (err < 0) return err; - if (pgio.pg_error) + if (pgio.pg_error < 0) return pgio.pg_error; return 0; } @@ -389,14 +376,11 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) return error; if (!nfsi->npages) { igrab(inode); - nfs_begin_data_update(inode); if (nfs_have_delegation(inode, FMODE_WRITE)) nfsi->change_attr++; } SetPagePrivate(req->wb_page); set_page_private(req->wb_page, (unsigned long)req); - if (PageDirty(req->wb_page)) - set_bit(PG_NEED_FLUSH, &req->wb_flags); nfsi->npages++; kref_get(&req->wb_kref); return 0; @@ -416,12 +400,9 @@ static void nfs_inode_remove_request(struct nfs_page *req) set_page_private(req->wb_page, 0); ClearPagePrivate(req->wb_page); radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); - if (test_and_clear_bit(PG_NEED_FLUSH, &req->wb_flags)) - __set_page_dirty_nobuffers(req->wb_page); nfsi->npages--; if (!nfsi->npages) { spin_unlock(&inode->i_lock); - nfs_end_data_update(inode); iput(inode); } else spin_unlock(&inode->i_lock); @@ -466,6 +447,7 @@ nfs_mark_request_commit(struct nfs_page *req) NFS_PAGE_TAG_COMMIT); spin_unlock(&inode->i_lock); inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); + inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE); __mark_inode_dirty(inode, I_DIRTY_DATASYNC); } @@ -552,6 +534,8 @@ static void nfs_cancel_commit_list(struct list_head *head) while(!list_empty(head)) { req = nfs_list_entry(head->next); dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); + dec_bdi_stat(req->wb_page->mapping->backing_dev_info, + BDI_RECLAIMABLE); nfs_list_remove_request(req); clear_bit(PG_NEED_COMMIT, &(req)->wb_flags); nfs_inode_remove_request(req); @@ -682,7 +666,7 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, int nfs_flush_incompatible(struct file *file, struct page *page) { - struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; + struct nfs_open_context *ctx = nfs_file_open_context(file); struct nfs_page *req; int do_flush, status; /* @@ -716,7 +700,7 @@ int nfs_flush_incompatible(struct file *file, struct page *page) int nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsigned int count) { - struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; + struct nfs_open_context *ctx = nfs_file_open_context(file); struct inode *inode = page->mapping->host; int status = 0; @@ -967,7 +951,7 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) if (task->tk_status < 0) { nfs_set_pageerror(page); - req->wb_context->error = task->tk_status; + nfs_context_set_write_error(req->wb_context, task->tk_status); dprintk(", error = %d\n", task->tk_status); goto out; } @@ -1030,7 +1014,7 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) if (task->tk_status < 0) { nfs_set_pageerror(page); - req->wb_context->error = task->tk_status; + nfs_context_set_write_error(req->wb_context, task->tk_status); dprintk(", error = %d\n", task->tk_status); goto remove_request; } @@ -1212,6 +1196,8 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how) nfs_list_remove_request(req); nfs_mark_request_commit(req); dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); + dec_bdi_stat(req->wb_page->mapping->backing_dev_info, + BDI_RECLAIMABLE); nfs_clear_page_tag_locked(req); } return -ENOMEM; @@ -1237,6 +1223,8 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) nfs_list_remove_request(req); clear_bit(PG_NEED_COMMIT, &(req)->wb_flags); dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); + dec_bdi_stat(req->wb_page->mapping->backing_dev_info, + BDI_RECLAIMABLE); dprintk("NFS: commit (%s/%Ld %d@%Ld)", req->wb_context->path.dentry->d_inode->i_sb->s_id, @@ -1244,7 +1232,7 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) req->wb_bytes, (long long)req_offset(req)); if (task->tk_status < 0) { - req->wb_context->error = task->tk_status; + nfs_context_set_write_error(req->wb_context, task->tk_status); nfs_inode_remove_request(req); dprintk(", error = %d\n", task->tk_status); goto next; @@ -1347,53 +1335,52 @@ long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_contr return ret; } -/* - * flush the inode to disk. - */ -int nfs_wb_all(struct inode *inode) +static int __nfs_write_mapping(struct address_space *mapping, struct writeback_control *wbc, int how) { - struct address_space *mapping = inode->i_mapping; - struct writeback_control wbc = { - .bdi = mapping->backing_dev_info, - .sync_mode = WB_SYNC_ALL, - .nr_to_write = LONG_MAX, - .for_writepages = 1, - .range_cyclic = 1, - }; int ret; - ret = nfs_writepages(mapping, &wbc); + ret = nfs_writepages(mapping, wbc); if (ret < 0) goto out; - ret = nfs_sync_mapping_wait(mapping, &wbc, 0); - if (ret >= 0) - return 0; + ret = nfs_sync_mapping_wait(mapping, wbc, how); + if (ret < 0) + goto out; + return 0; out: __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); return ret; } -int nfs_sync_mapping_range(struct address_space *mapping, loff_t range_start, loff_t range_end, int how) +/* Two pass sync: first using WB_SYNC_NONE, then WB_SYNC_ALL */ +static int nfs_write_mapping(struct address_space *mapping, int how) { struct writeback_control wbc = { .bdi = mapping->backing_dev_info, - .sync_mode = WB_SYNC_ALL, + .sync_mode = WB_SYNC_NONE, .nr_to_write = LONG_MAX, - .range_start = range_start, - .range_end = range_end, .for_writepages = 1, + .range_cyclic = 1, }; int ret; - ret = nfs_writepages(mapping, &wbc); + ret = __nfs_write_mapping(mapping, &wbc, how); if (ret < 0) - goto out; - ret = nfs_sync_mapping_wait(mapping, &wbc, how); - if (ret >= 0) - return 0; -out: - __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); - return ret; + return ret; + wbc.sync_mode = WB_SYNC_ALL; + return __nfs_write_mapping(mapping, &wbc, how); +} + +/* + * flush the inode to disk. + */ +int nfs_wb_all(struct inode *inode) +{ + return nfs_write_mapping(inode->i_mapping, 0); +} + +int nfs_wb_nocommit(struct inode *inode) +{ + return nfs_write_mapping(inode->i_mapping, FLUSH_NOCOMMIT); } int nfs_wb_page_cancel(struct inode *inode, struct page *page) @@ -1477,35 +1464,6 @@ int nfs_wb_page(struct inode *inode, struct page* page) return nfs_wb_page_priority(inode, page, FLUSH_STABLE); } -int nfs_set_page_dirty(struct page *page) -{ - struct address_space *mapping = page->mapping; - struct inode *inode; - struct nfs_page *req; - int ret; - - if (!mapping) - goto out_raced; - inode = mapping->host; - if (!inode) - goto out_raced; - spin_lock(&inode->i_lock); - req = nfs_page_find_request_locked(page); - if (req != NULL) { - /* Mark any existing write requests for flushing */ - ret = !test_and_set_bit(PG_NEED_FLUSH, &req->wb_flags); - spin_unlock(&inode->i_lock); - nfs_release_request(req); - return ret; - } - ret = __set_page_dirty_nobuffers(page); - spin_unlock(&inode->i_lock); - return ret; -out_raced: - return !TestSetPageDirty(page); -} - - int __init nfs_init_writepagecache(void) { nfs_wdata_cachep = kmem_cache_create("nfs_write_data", diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index cba899a3494e..04b266729802 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -861,9 +861,9 @@ exp_get_fsid_key(svc_client *clp, int fsid) return exp_find_key(clp, FSID_NUM, fsidv, NULL); } -svc_export * -exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry, - struct cache_req *reqp) +static svc_export *exp_get_by_name(svc_client *clp, struct vfsmount *mnt, + struct dentry *dentry, + struct cache_req *reqp) { struct svc_export *exp, key; int err; @@ -887,9 +887,9 @@ exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry, /* * Find the export entry for a given dentry. */ -struct svc_export * -exp_parent(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry, - struct cache_req *reqp) +static struct svc_export *exp_parent(svc_client *clp, struct vfsmount *mnt, + struct dentry *dentry, + struct cache_req *reqp) { svc_export *exp; @@ -1214,9 +1214,8 @@ out: return err; } -struct svc_export * -exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv, - struct cache_req *reqp) +static struct svc_export *exp_find(struct auth_domain *clp, int fsid_type, + u32 *fsidv, struct cache_req *reqp) { struct svc_export *exp; struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp); diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 10f6e7dcf633..2d116d2298f8 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -174,9 +174,6 @@ static __be32 * encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat) { - struct dentry *dentry = fhp->fh_dentry; - struct timespec time; - *p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]); *p++ = htonl((u32) stat->mode); *p++ = htonl((u32) stat->nlink); @@ -191,10 +188,9 @@ encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, *p++ = htonl((u32) MAJOR(stat->rdev)); *p++ = htonl((u32) MINOR(stat->rdev)); p = encode_fsid(p, fhp); - p = xdr_encode_hyper(p, (u64) stat->ino); + p = xdr_encode_hyper(p, stat->ino); p = encode_time3(p, &stat->atime); - lease_get_mtime(dentry->d_inode, &time); - p = encode_time3(p, &time); + p = encode_time3(p, &stat->mtime); p = encode_time3(p, &stat->ctime); return p; @@ -203,31 +199,9 @@ encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, static __be32 * encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) { - struct inode *inode = fhp->fh_dentry->d_inode; - /* Attributes to follow */ *p++ = xdr_one; - - *p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]); - *p++ = htonl((u32) fhp->fh_post_mode); - *p++ = htonl((u32) fhp->fh_post_nlink); - *p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid)); - *p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid)); - if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) { - p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN); - } else { - p = xdr_encode_hyper(p, (u64) fhp->fh_post_size); - } - p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9); - *p++ = fhp->fh_post_rdev[0]; - *p++ = fhp->fh_post_rdev[1]; - p = encode_fsid(p, fhp); - p = xdr_encode_hyper(p, (u64) inode->i_ino); - p = encode_time3(p, &fhp->fh_post_atime); - p = encode_time3(p, &fhp->fh_post_mtime); - p = encode_time3(p, &fhp->fh_post_ctime); - - return p; + return encode_fattr3(rqstp, p, fhp, &fhp->fh_post_attr); } /* @@ -246,6 +220,7 @@ encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) err = vfs_getattr(fhp->fh_export->ex_mnt, dentry, &stat); if (!err) { *p++ = xdr_one; /* attributes follow */ + lease_get_mtime(dentry->d_inode, &stat.mtime); return encode_fattr3(rqstp, p, fhp, &stat); } } @@ -284,6 +259,23 @@ encode_wcc_data(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) return encode_post_op_attr(rqstp, p, fhp); } +/* + * Fill in the post_op attr for the wcc data + */ +void fill_post_wcc(struct svc_fh *fhp) +{ + int err; + + if (fhp->fh_post_saved) + printk("nfsd: inode locked twice during operation.\n"); + + err = vfs_getattr(fhp->fh_export->ex_mnt, fhp->fh_dentry, + &fhp->fh_post_attr); + if (err) + fhp->fh_post_saved = 0; + else + fhp->fh_post_saved = 1; +} /* * XDR decode functions @@ -643,8 +635,11 @@ int nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_attrstat *resp) { - if (resp->status == 0) + if (resp->status == 0) { + lease_get_mtime(resp->fh.fh_dentry->d_inode, + &resp->stat.mtime); p = encode_fattr3(rqstp, p, &resp->fh, &resp->stat); + } return xdr_ressize_check(rqstp, p); } @@ -802,7 +797,7 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p, static __be32 * encode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, - int namlen, ino_t ino) + int namlen, u64 ino) { *p++ = xdr_one; /* mark entry present */ p = xdr_encode_hyper(p, ino); /* file id */ @@ -873,7 +868,7 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp, #define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2)) static int encode_entry(struct readdir_cd *ccd, const char *name, int namlen, - loff_t offset, ino_t ino, unsigned int d_type, int plus) + loff_t offset, u64 ino, unsigned int d_type, int plus) { struct nfsd3_readdirres *cd = container_of(ccd, struct nfsd3_readdirres, common); diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 31d6633c7fe4..9d536a8cb379 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -39,6 +39,7 @@ #include <linux/errno.h> #include <linux/delay.h> #include <linux/sched.h> +#include <linux/kthread.h> #include <linux/sunrpc/xdr.h> #include <linux/sunrpc/svc.h> #include <linux/sunrpc/clnt.h> @@ -343,26 +344,28 @@ static struct rpc_version * nfs_cb_version[] = { &nfs_cb_version4, }; -/* - * Use the SETCLIENTID credential - */ -static struct rpc_cred * -nfsd4_lookupcred(struct nfs4_client *clp, int taskflags) +/* Reference counting, callback cleanup, etc., all look racy as heck. + * And why is cb_set an atomic? */ + +static int do_probe_callback(void *data) { - struct auth_cred acred; - struct rpc_clnt *clnt = clp->cl_callback.cb_client; - struct rpc_cred *ret; - - get_group_info(clp->cl_cred.cr_group_info); - acred.uid = clp->cl_cred.cr_uid; - acred.gid = clp->cl_cred.cr_gid; - acred.group_info = clp->cl_cred.cr_group_info; - - dprintk("NFSD: looking up %s cred\n", - clnt->cl_auth->au_ops->au_name); - ret = rpcauth_lookup_credcache(clnt->cl_auth, &acred, taskflags); - put_group_info(clp->cl_cred.cr_group_info); - return ret; + struct nfs4_client *clp = data; + struct nfs4_callback *cb = &clp->cl_callback; + struct rpc_message msg = { + .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], + .rpc_argp = clp, + }; + int status; + + status = rpc_call_sync(cb->cb_client, &msg, RPC_TASK_SOFT); + + if (status) { + rpc_shutdown_client(cb->cb_client); + cb->cb_client = NULL; + } else + atomic_set(&cb->cb_set, 1); + put_nfs4_client(clp); + return 0; } /* @@ -390,11 +393,7 @@ nfsd4_probe_callback(struct nfs4_client *clp) .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */ .flags = (RPC_CLNT_CREATE_NOPING), }; - struct rpc_message msg = { - .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], - .rpc_argp = clp, - }; - int status; + struct task_struct *t; if (atomic_read(&cb->cb_set)) return; @@ -426,16 +425,11 @@ nfsd4_probe_callback(struct nfs4_client *clp) /* the task holds a reference to the nfs4_client struct */ atomic_inc(&clp->cl_count); - msg.rpc_cred = nfsd4_lookupcred(clp,0); - if (IS_ERR(msg.rpc_cred)) - goto out_release_clp; - status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL); - put_rpccred(msg.rpc_cred); + t = kthread_run(do_probe_callback, clp, "nfs4_cb_probe"); - if (status != 0) { - dprintk("NFSD: asynchronous NFSPROC4_CB_NULL failed!\n"); + if (IS_ERR(t)) goto out_release_clp; - } + return; out_release_clp: @@ -447,30 +441,6 @@ out_err: (int)clp->cl_name.len, clp->cl_name.data); } -static void -nfs4_cb_null(struct rpc_task *task, void *dummy) -{ - struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp; - struct nfs4_callback *cb = &clp->cl_callback; - __be32 addr = htonl(cb->cb_addr); - - dprintk("NFSD: nfs4_cb_null task->tk_status %d\n", task->tk_status); - - if (task->tk_status < 0) { - dprintk("NFSD: callback establishment to client %.*s failed\n", - (int)clp->cl_name.len, clp->cl_name.data); - goto out; - } - atomic_set(&cb->cb_set, 1); - dprintk("NFSD: callback set to client %u.%u.%u.%u\n", NIPQUAD(addr)); -out: - put_nfs4_client(clp); -} - -static const struct rpc_call_ops nfs4_cb_null_ops = { - .rpc_call_done = nfs4_cb_null, -}; - /* * called with dp->dl_count inc'ed. * nfs4_lock_state() may or may not have been called. @@ -491,10 +461,6 @@ nfsd4_cb_recall(struct nfs4_delegation *dp) if ((!atomic_read(&clp->cl_callback.cb_set)) || !clnt) return; - msg.rpc_cred = nfsd4_lookupcred(clp, 0); - if (IS_ERR(msg.rpc_cred)) - goto out; - cbr->cbr_trunc = 0; /* XXX need to implement truncate optimization */ cbr->cbr_dp = dp; @@ -515,13 +481,12 @@ nfsd4_cb_recall(struct nfs4_delegation *dp) status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT); } out_put_cred: - put_rpccred(msg.rpc_cred); -out: if (status == -EIO) atomic_set(&clp->cl_callback.cb_set, 0); /* Success or failure, now we're either waiting for lease expiration * or deleg_return. */ dprintk("NFSD: nfs4_cb_recall: dp %p dl_flock %p dl_count %d\n",dp, dp->dl_flock, atomic_read(&dp->dl_count)); + put_nfs4_client(clp); nfs4_put_delegation(dp); return; } diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index 2ccffde81b84..4c0c683ce07a 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c @@ -207,6 +207,7 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen) { struct ent ent, *res; char *buf1, *bp; + int len; int error = -EINVAL; if (buf[buflen - 1] != '\n') @@ -248,10 +249,11 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen) goto out; /* Name */ - error = qword_get(&buf, buf1, PAGE_SIZE); - if (error == -EINVAL) + error = -EINVAL; + len = qword_get(&buf, buf1, PAGE_SIZE); + if (len < 0) goto out; - if (error == -ENOENT) + if (len == 0) set_bit(CACHE_NEGATIVE, &ent.h.flags); else { if (error >= IDMAP_NAMESZ) { diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 29b7e63cb32c..18ead1790bb3 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -238,12 +238,12 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, break; case NFS4_OPEN_CLAIM_DELEGATE_PREV: open->op_stateowner->so_confirmed = 1; - printk("NFSD: unsupported OPEN claim type %d\n", + dprintk("NFSD: unsupported OPEN claim type %d\n", open->op_claim_type); status = nfserr_notsupp; goto out; default: - printk("NFSD: Invalid OPEN claim type %d\n", + dprintk("NFSD: Invalid OPEN claim type %d\n", open->op_claim_type); status = nfserr_inval; goto out; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 3f559700788f..31673cd251c3 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -358,9 +358,22 @@ alloc_client(struct xdr_netobj name) return clp; } +static void +shutdown_callback_client(struct nfs4_client *clp) +{ + struct rpc_clnt *clnt = clp->cl_callback.cb_client; + + /* shutdown rpc client, ending any outstanding recall rpcs */ + if (clnt) { + clp->cl_callback.cb_client = NULL; + rpc_shutdown_client(clnt); + } +} + static inline void free_client(struct nfs4_client *clp) { + shutdown_callback_client(clp); if (clp->cl_cred.cr_group_info) put_group_info(clp->cl_cred.cr_group_info); kfree(clp->cl_name.data); @@ -375,18 +388,6 @@ put_nfs4_client(struct nfs4_client *clp) } static void -shutdown_callback_client(struct nfs4_client *clp) -{ - struct rpc_clnt *clnt = clp->cl_callback.cb_client; - - /* shutdown rpc client, ending any outstanding recall rpcs */ - if (clnt) { - clp->cl_callback.cb_client = NULL; - rpc_shutdown_client(clnt); - } -} - -static void expire_client(struct nfs4_client *clp) { struct nfs4_stateowner *sop; @@ -396,8 +397,6 @@ expire_client(struct nfs4_client *clp) dprintk("NFSD: expire_client cl_count %d\n", atomic_read(&clp->cl_count)); - shutdown_callback_client(clp); - INIT_LIST_HEAD(&reaplist); spin_lock(&recall_lock); while (!list_empty(&clp->cl_delegations)) { @@ -462,26 +461,28 @@ copy_cred(struct svc_cred *target, struct svc_cred *source) { } static inline int -same_name(const char *n1, const char *n2) { +same_name(const char *n1, const char *n2) +{ return 0 == memcmp(n1, n2, HEXDIR_LEN); } static int -cmp_verf(nfs4_verifier *v1, nfs4_verifier *v2) { - return(!memcmp(v1->data,v2->data,sizeof(v1->data))); +same_verf(nfs4_verifier *v1, nfs4_verifier *v2) +{ + return 0 == memcmp(v1->data, v2->data, sizeof(v1->data)); } static int -cmp_clid(clientid_t * cl1, clientid_t * cl2) { - return((cl1->cl_boot == cl2->cl_boot) && - (cl1->cl_id == cl2->cl_id)); +same_clid(clientid_t *cl1, clientid_t *cl2) +{ + return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); } /* XXX what about NGROUP */ static int -cmp_creds(struct svc_cred *cr1, struct svc_cred *cr2){ - return(cr1->cr_uid == cr2->cr_uid); - +same_creds(struct svc_cred *cr1, struct svc_cred *cr2) +{ + return cr1->cr_uid == cr2->cr_uid; } static void @@ -507,7 +508,7 @@ check_name(struct xdr_netobj name) { if (name.len == 0) return 0; if (name.len > NFS4_OPAQUE_LIMIT) { - printk("NFSD: check_name: name too long(%d)!\n", name.len); + dprintk("NFSD: check_name: name too long(%d)!\n", name.len); return 0; } return 1; @@ -546,7 +547,7 @@ find_confirmed_client(clientid_t *clid) unsigned int idhashval = clientid_hashval(clid->cl_id); list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) { - if (cmp_clid(&clp->cl_clientid, clid)) + if (same_clid(&clp->cl_clientid, clid)) return clp; } return NULL; @@ -559,7 +560,7 @@ find_unconfirmed_client(clientid_t *clid) unsigned int idhashval = clientid_hashval(clid->cl_id); list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) { - if (cmp_clid(&clp->cl_clientid, clid)) + if (same_clid(&clp->cl_clientid, clid)) return clp; } return NULL; @@ -753,7 +754,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, * or different ip_address */ status = nfserr_clid_inuse; - if (!cmp_creds(&conf->cl_cred, &rqstp->rq_cred) + if (!same_creds(&conf->cl_cred, &rqstp->rq_cred) || conf->cl_addr != sin->sin_addr.s_addr) { dprintk("NFSD: setclientid: string in use by client" "at %u.%u.%u.%u\n", NIPQUAD(conf->cl_addr)); @@ -772,14 +773,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, new = create_client(clname, dname); if (new == NULL) goto out; - copy_verf(new, &clverifier); - new->cl_addr = sin->sin_addr.s_addr; - copy_cred(&new->cl_cred,&rqstp->rq_cred); gen_clid(new); - gen_confirm(new); - gen_callback(new, setclid); - add_to_unconfirmed(new, strhashval); - } else if (cmp_verf(&conf->cl_verifier, &clverifier)) { + } else if (same_verf(&conf->cl_verifier, &clverifier)) { /* * CASE 1: * cl_name match, confirmed, principal match @@ -804,13 +799,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, new = create_client(clname, dname); if (new == NULL) goto out; - copy_verf(new,&conf->cl_verifier); - new->cl_addr = sin->sin_addr.s_addr; - copy_cred(&new->cl_cred,&rqstp->rq_cred); copy_clid(new, conf); - gen_confirm(new); - gen_callback(new, setclid); - add_to_unconfirmed(new,strhashval); } else if (!unconf) { /* * CASE 2: @@ -823,14 +812,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, new = create_client(clname, dname); if (new == NULL) goto out; - copy_verf(new,&clverifier); - new->cl_addr = sin->sin_addr.s_addr; - copy_cred(&new->cl_cred,&rqstp->rq_cred); gen_clid(new); - gen_confirm(new); - gen_callback(new, setclid); - add_to_unconfirmed(new, strhashval); - } else if (!cmp_verf(&conf->cl_confirm, &unconf->cl_confirm)) { + } else if (!same_verf(&conf->cl_confirm, &unconf->cl_confirm)) { /* * CASE3: * confirmed found (name, principal match) @@ -850,19 +833,19 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, new = create_client(clname, dname); if (new == NULL) goto out; - copy_verf(new,&clverifier); - new->cl_addr = sin->sin_addr.s_addr; - copy_cred(&new->cl_cred,&rqstp->rq_cred); gen_clid(new); - gen_confirm(new); - gen_callback(new, setclid); - add_to_unconfirmed(new, strhashval); } else { /* No cases hit !!! */ status = nfserr_inval; goto out; } + copy_verf(new, &clverifier); + new->cl_addr = sin->sin_addr.s_addr; + copy_cred(&new->cl_cred, &rqstp->rq_cred); + gen_confirm(new); + gen_callback(new, setclid); + add_to_unconfirmed(new, strhashval); setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; setclid->se_clientid.cl_id = new->cl_clientid.cl_id; memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); @@ -910,16 +893,16 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, goto out; if ((conf && unconf) && - (cmp_verf(&unconf->cl_confirm, &confirm)) && - (cmp_verf(&conf->cl_verifier, &unconf->cl_verifier)) && + (same_verf(&unconf->cl_confirm, &confirm)) && + (same_verf(&conf->cl_verifier, &unconf->cl_verifier)) && (same_name(conf->cl_recdir,unconf->cl_recdir)) && - (!cmp_verf(&conf->cl_confirm, &unconf->cl_confirm))) { + (!same_verf(&conf->cl_confirm, &unconf->cl_confirm))) { /* CASE 1: * unconf record that matches input clientid and input confirm. * conf record that matches input clientid. * conf and unconf records match names, verifiers */ - if (!cmp_creds(&conf->cl_cred, &unconf->cl_cred)) + if (!same_creds(&conf->cl_cred, &unconf->cl_cred)) status = nfserr_clid_inuse; else { /* XXX: We just turn off callbacks until we can handle @@ -933,7 +916,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, } } else if ((conf && !unconf) || ((conf && unconf) && - (!cmp_verf(&conf->cl_verifier, &unconf->cl_verifier) || + (!same_verf(&conf->cl_verifier, &unconf->cl_verifier) || !same_name(conf->cl_recdir, unconf->cl_recdir)))) { /* CASE 2: * conf record that matches input clientid. @@ -941,18 +924,18 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, * unconf->cl_name or unconf->cl_verifier don't match the * conf record. */ - if (!cmp_creds(&conf->cl_cred,&rqstp->rq_cred)) + if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) status = nfserr_clid_inuse; else status = nfs_ok; } else if (!conf && unconf - && cmp_verf(&unconf->cl_confirm, &confirm)) { + && same_verf(&unconf->cl_confirm, &confirm)) { /* CASE 3: * conf record not found. * unconf record found. * unconf->cl_confirm matches input confirm */ - if (!cmp_creds(&unconf->cl_cred, &rqstp->rq_cred)) { + if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) { status = nfserr_clid_inuse; } else { unsigned int hash = @@ -967,8 +950,8 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, conf = unconf; status = nfs_ok; } - } else if ((!conf || (conf && !cmp_verf(&conf->cl_confirm, &confirm))) - && (!unconf || (unconf && !cmp_verf(&unconf->cl_confirm, + } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm))) + && (!unconf || (unconf && !same_verf(&unconf->cl_confirm, &confirm)))) { /* CASE 4: * conf record not found, or if conf, conf->cl_confirm does not @@ -1019,7 +1002,7 @@ nfsd4_free_slab(struct kmem_cache **slab) *slab = NULL; } -static void +void nfsd4_free_slabs(void) { nfsd4_free_slab(&stateowner_slab); @@ -1207,10 +1190,12 @@ move_to_close_lru(struct nfs4_stateowner *sop) } static int -cmp_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, clientid_t *clid) { - return ((sop->so_owner.len == owner->len) && - !memcmp(sop->so_owner.data, owner->data, owner->len) && - (sop->so_client->cl_clientid.cl_id == clid->cl_id)); +same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, + clientid_t *clid) +{ + return (sop->so_owner.len == owner->len) && + 0 == memcmp(sop->so_owner.data, owner->data, owner->len) && + (sop->so_client->cl_clientid.cl_id == clid->cl_id); } static struct nfs4_stateowner * @@ -1219,7 +1204,7 @@ find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open) struct nfs4_stateowner *so = NULL; list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) { - if (cmp_owner_str(so, &open->op_owner, &open->op_clientid)) + if (same_owner_str(so, &open->op_owner, &open->op_clientid)) return so; } return NULL; @@ -1360,6 +1345,7 @@ void nfsd_break_deleg_cb(struct file_lock *fl) * lock) we know the server hasn't removed the lease yet, we know * it's safe to take a reference: */ atomic_inc(&dp->dl_count); + atomic_inc(&dp->dl_client->cl_count); spin_lock(&recall_lock); list_add_tail(&dp->dl_recall_lru, &del_recall_lru); @@ -1368,8 +1354,12 @@ void nfsd_break_deleg_cb(struct file_lock *fl) /* only place dl_time is set. protected by lock_kernel*/ dp->dl_time = get_seconds(); - /* XXX need to merge NFSD_LEASE_TIME with fs/locks.c:lease_break_time */ - fl->fl_break_time = jiffies + NFSD_LEASE_TIME * HZ; + /* + * We don't want the locks code to timeout the lease for us; + * we'll remove it ourself if the delegation isn't returned + * in time. + */ + fl->fl_break_time = 0; t = kthread_run(do_recall, dp, "%s", "nfs4_cb_recall"); if (IS_ERR(t)) { @@ -1378,6 +1368,7 @@ void nfsd_break_deleg_cb(struct file_lock *fl) printk(KERN_INFO "NFSD: Callback thread failed for " "for client (clientid %08x/%08x)\n", clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); + put_nfs4_client(dp->dl_client); nfs4_put_delegation(dp); } } @@ -1738,7 +1729,7 @@ out: if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && flag == NFS4_OPEN_DELEGATE_NONE && open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) - printk("NFSD: WARNING: refusing delegation reclaim\n"); + dprintk("NFSD: WARNING: refusing delegation reclaim\n"); open->op_delegate_type = flag; } @@ -2044,7 +2035,7 @@ static inline int io_during_grace_disallowed(struct inode *inode, int flags) { return nfs4_in_grace() && (flags & (RD_STATE | WR_STATE)) - && MANDATORY_LOCK(inode); + && mandatory_lock(inode); } /* @@ -2147,7 +2138,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei *sopp = NULL; if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) { - printk("NFSD: preprocess_seqid_op: magic stateid!\n"); + dprintk("NFSD: preprocess_seqid_op: magic stateid!\n"); return nfserr_bad_stateid; } @@ -2181,25 +2172,24 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei lkflg = setlkflg(lock->lk_type); if (lock->lk_is_new) { - if (!sop->so_is_open_owner) - return nfserr_bad_stateid; - if (!cmp_clid(&clp->cl_clientid, lockclid)) + if (!sop->so_is_open_owner) + return nfserr_bad_stateid; + if (!same_clid(&clp->cl_clientid, lockclid)) return nfserr_bad_stateid; - /* stp is the open stateid */ - status = nfs4_check_openmode(stp, lkflg); - if (status) - return status; - } else { - /* stp is the lock stateid */ - status = nfs4_check_openmode(stp->st_openstp, lkflg); - if (status) - return status; + /* stp is the open stateid */ + status = nfs4_check_openmode(stp, lkflg); + if (status) + return status; + } else { + /* stp is the lock stateid */ + status = nfs4_check_openmode(stp->st_openstp, lkflg); + if (status) + return status; } - } if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) { - printk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n"); + dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n"); return nfserr_bad_stateid; } @@ -2215,22 +2205,22 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei goto check_replay; if (sop->so_confirmed && flags & CONFIRM) { - printk("NFSD: preprocess_seqid_op: expected" + dprintk("NFSD: preprocess_seqid_op: expected" " unconfirmed stateowner!\n"); return nfserr_bad_stateid; } if (!sop->so_confirmed && !(flags & CONFIRM)) { - printk("NFSD: preprocess_seqid_op: stateowner not" + dprintk("NFSD: preprocess_seqid_op: stateowner not" " confirmed yet!\n"); return nfserr_bad_stateid; } if (stateid->si_generation > stp->st_stateid.si_generation) { - printk("NFSD: preprocess_seqid_op: future stateid?!\n"); + dprintk("NFSD: preprocess_seqid_op: future stateid?!\n"); return nfserr_bad_stateid; } if (stateid->si_generation < stp->st_stateid.si_generation) { - printk("NFSD: preprocess_seqid_op: old stateid!\n"); + dprintk("NFSD: preprocess_seqid_op: old stateid!\n"); return nfserr_old_stateid; } renew_client(sop->so_client); @@ -2242,7 +2232,7 @@ check_replay: /* indicate replay to calling function */ return nfserr_replay_me; } - printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n", + dprintk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n", sop->so_seqid, seqid); *sopp = NULL; return nfserr_bad_seqid; @@ -2561,7 +2551,7 @@ find_lockstateowner_str(struct inode *inode, clientid_t *clid, struct nfs4_stateowner *op; list_for_each_entry(op, &lock_ownerstr_hashtbl[hashval], so_strhash) { - if (cmp_owner_str(op, owner, clid)) + if (same_owner_str(op, owner, clid)) return op; } return NULL; @@ -2855,7 +2845,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, file_lock.fl_type = F_WRLCK; break; default: - printk("NFSD: nfs4_lockt: bad lock type!\n"); + dprintk("NFSD: nfs4_lockt: bad lock type!\n"); status = nfserr_inval; goto out; } @@ -3025,7 +3015,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, INIT_LIST_HEAD(&matches); for (i = 0; i < LOCK_HASH_SIZE; i++) { list_for_each_entry(sop, &lock_ownerid_hashtbl[i], so_idhash) { - if (!cmp_owner_str(sop, owner, clid)) + if (!same_owner_str(sop, owner, clid)) continue; list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) { @@ -3149,11 +3139,14 @@ nfs4_check_open_reclaim(clientid_t *clid) /* initialization to perform at module load time: */ -void +int nfs4_state_init(void) { - int i; + int i, status; + status = nfsd4_init_slabs(); + if (status) + return status; for (i = 0; i < CLIENT_HASH_SIZE; i++) { INIT_LIST_HEAD(&conf_id_hashtbl[i]); INIT_LIST_HEAD(&conf_str_hashtbl[i]); @@ -3182,6 +3175,7 @@ nfs4_state_init(void) for (i = 0; i < CLIENT_HASH_SIZE; i++) INIT_LIST_HEAD(&reclaim_str_hashtbl[i]); reclaim_str_hashtbl_size = 0; + return 0; } static void @@ -3242,20 +3236,15 @@ __nfs4_state_start(void) set_max_delegations(); } -int +void nfs4_state_start(void) { - int status; - if (nfs4_init) - return 0; - status = nfsd4_init_slabs(); - if (status) - return status; + return; nfsd4_load_reboot_recovery_data(); __nfs4_state_start(); nfs4_init = 1; - return 0; + return; } int @@ -3313,7 +3302,6 @@ nfs4_state_shutdown(void) nfs4_lock_state(); nfs4_release_reclaim(); __nfs4_state_shutdown(); - nfsd4_free_slabs(); nfs4_unlock_state(); } diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 8ef0964179bc..57333944af7f 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -102,7 +102,8 @@ check_filename(char *str, int len, __be32 err) out: \ return status; \ xdr_error: \ - printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); \ + dprintk("NFSD: xdr error (%s:%d)\n", \ + __FILE__, __LINE__); \ status = nfserr_bad_xdr; \ goto out @@ -124,7 +125,8 @@ xdr_error: \ if (!(x = (p==argp->tmp || p == argp->tmpp) ? \ savemem(argp, p, nbytes) : \ (char *)p)) { \ - printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); \ + dprintk("NFSD: xdr error (%s:%d)\n", \ + __FILE__, __LINE__); \ goto xdr_error; \ } \ p += XDR_QUADLEN(nbytes); \ @@ -140,7 +142,8 @@ xdr_error: \ p = argp->p; \ argp->p += XDR_QUADLEN(nbytes); \ } else if (!(p = read_buf(argp, nbytes))) { \ - printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); \ + dprintk("NFSD: xdr error (%s:%d)\n", \ + __FILE__, __LINE__); \ goto xdr_error; \ } \ } while (0) @@ -948,7 +951,8 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) */ avail = (char*)argp->end - (char*)argp->p; if (avail + argp->pagelen < write->wr_buflen) { - printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); + dprintk("NFSD: xdr error (%s:%d)\n", + __FILE__, __LINE__); goto xdr_error; } argp->rqstp->rq_vec[0].iov_base = p; @@ -1019,7 +1023,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) argp->ops = kmalloc(argp->opcnt * sizeof(*argp->ops), GFP_KERNEL); if (!argp->ops) { argp->ops = argp->iops; - printk(KERN_INFO "nfsd: couldn't allocate room for COMPOUND\n"); + dprintk("nfsd: couldn't allocate room for COMPOUND\n"); goto xdr_error; } } @@ -1326,7 +1330,7 @@ static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 * path = exp->ex_path; if (strncmp(path, rootpath, strlen(rootpath))) { - printk("nfsd: fs_locations failed;" + dprintk("nfsd: fs_locations failed;" "%s is not contained in %s\n", path, rootpath); *stat = nfserr_notsupp; return NULL; @@ -1475,7 +1479,8 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, err = vfs_getattr(exp->ex_mnt, dentry, &stat); if (err) goto out_nfserr; - if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL)) || + if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | + FATTR4_WORD0_MAXNAME)) || (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | FATTR4_WORD1_SPACE_TOTAL))) { err = vfs_statfs(dentry, &statfs); @@ -1679,7 +1684,7 @@ out_acl: if (bmval0 & FATTR4_WORD0_FILEID) { if ((buflen -= 8) < 0) goto out_resource; - WRITE64((u64) stat.ino); + WRITE64(stat.ino); } if (bmval0 & FATTR4_WORD0_FILES_AVAIL) { if ((buflen -= 8) < 0) @@ -1721,7 +1726,7 @@ out_acl: if (bmval0 & FATTR4_WORD0_MAXNAME) { if ((buflen -= 4) < 0) goto out_resource; - WRITE32(~(u32) 0); + WRITE32(statfs.f_namelen); } if (bmval0 & FATTR4_WORD0_MAXREAD) { if ((buflen -= 8) < 0) @@ -1821,16 +1826,15 @@ out_acl: WRITE32(stat.mtime.tv_nsec); } if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) { - struct dentry *mnt_pnt, *mnt_root; - if ((buflen -= 8) < 0) goto out_resource; - mnt_root = exp->ex_mnt->mnt_root; - if (mnt_root->d_inode == dentry->d_inode) { - mnt_pnt = exp->ex_mnt->mnt_mountpoint; - WRITE64((u64) mnt_pnt->d_inode->i_ino); - } else - WRITE64((u64) stat.ino); + if (exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) { + err = vfs_getattr(exp->ex_mnt->mnt_parent, + exp->ex_mnt->mnt_mountpoint, &stat); + if (err) + goto out_nfserr; + } + WRITE64(stat.ino); } *attrlenp = htonl((char *)p - (char *)attrlenp - 4); *countp = p - buffer; diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index baac89d917ca..77dc9893b7ba 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -298,7 +298,7 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size) * qword quoting is used, so filehandle will be \x.... */ char *dname, *path; - int maxsize; + int uninitialized_var(maxsize); char *mesg = buf; int len; struct auth_domain *dom; @@ -679,11 +679,13 @@ static int __init init_nfsd(void) int retval; printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n"); + retval = nfs4_state_init(); /* nfs4 locking state */ + if (retval) + return retval; nfsd_stat_init(); /* Statistics */ nfsd_cache_init(); /* RPC reply cache */ nfsd_export_init(); /* Exports table */ nfsd_lockd_init(); /* lockd->nfsd callbacks */ - nfs4_state_init(); /* NFSv4 locking state */ nfsd_idmap_init(); /* Name to ID mapping */ if (proc_mkdir("fs/nfs", NULL)) { struct proc_dir_entry *entry; @@ -712,6 +714,7 @@ static void __exit exit_nfsd(void) nfsd_stat_shutdown(); nfsd_lockd_shutdown(); nfsd_idmap_shutdown(); + nfsd4_free_slabs(); unregister_filesystem(&nfsd_fs_type); } diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index a8c89ae4c743..1190aeaa92be 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -349,9 +349,7 @@ nfsd_svc(unsigned short port, int nrservs) error = nfsd_racache_init(2*nrservs); if (error<0) goto out; - error = nfs4_state_start(); - if (error<0) - goto out; + nfs4_state_start(); nfsd_reset_versions(); @@ -546,10 +544,8 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) /* Now call the procedure handler, and encode NFS status. */ nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); nfserr = map_new_errors(rqstp->rq_vers, nfserr); - if (nfserr == nfserr_jukebox && rqstp->rq_vers == 2) - nfserr = nfserr_dropit; if (nfserr == nfserr_dropit) { - dprintk("nfsd: Dropping request due to malloc failure!\n"); + dprintk("nfsd: Dropping request; may be revisited later\n"); nfsd_cache_update(rqstp, RC_NOCACHE, NULL); return 0; } diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index cb3e7fadb772..986f9b32083c 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -523,6 +523,10 @@ nfssvc_encode_entry(void *ccdv, const char *name, cd->common.err = nfserr_toosmall; return -EINVAL; } + if (ino > ~((u32) 0)) { + cd->common.err = nfserr_fbig; + return -EINVAL; + } *p++ = xdr_one; /* mark entry present */ *p++ = htonl((u32) ino); /* file id */ p = xdr_encode_array(p, name, namlen);/* name length & name */ diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 7867151ebb83..d0199189924c 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -61,12 +61,6 @@ #define NFSDDBG_FACILITY NFSDDBG_FILEOP -/* We must ignore files (but only files) which might have mandatory - * locks on them because there is no way to know if the accesser has - * the lock. - */ -#define IS_ISMNDLK(i) (S_ISREG((i)->i_mode) && MANDATORY_LOCK(i)) - /* * This is a cache of readahead params that help us choose the proper * readahead strategy. Initially, we set all readahead parameters to 0 @@ -295,7 +289,8 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, if (!iap->ia_valid) goto out; - /* NFSv2 does not differentiate between "set-[ac]time-to-now" + /* + * NFSv2 does not differentiate between "set-[ac]time-to-now" * which only requires access, and "set-[ac]time-to-X" which * requires ownership. * So if it looks like it might be "set both to the same time which @@ -308,25 +303,33 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, */ #define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET) #define MAX_TOUCH_TIME_ERROR (30*60) - if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET - && iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec - ) { - /* Looks probable. Now just make sure time is in the right ballpark. - * Solaris, at least, doesn't seem to care what the time request is. - * We require it be within 30 minutes of now. - */ - time_t delta = iap->ia_atime.tv_sec - get_seconds(); - if (delta<0) delta = -delta; - if (delta < MAX_TOUCH_TIME_ERROR && - inode_change_ok(inode, iap) != 0) { - /* turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME - * this will cause notify_change to set these times to "now" + if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET && + iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec) { + /* + * Looks probable. + * + * Now just make sure time is in the right ballpark. + * Solaris, at least, doesn't seem to care what the time + * request is. We require it be within 30 minutes of now. */ - iap->ia_valid &= ~BOTH_TIME_SET; - } + time_t delta = iap->ia_atime.tv_sec - get_seconds(); + if (delta < 0) + delta = -delta; + if (delta < MAX_TOUCH_TIME_ERROR && + inode_change_ok(inode, iap) != 0) { + /* + * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME. + * This will cause notify_change to set these times + * to "now" + */ + iap->ia_valid &= ~BOTH_TIME_SET; + } } - /* The size case is special. It changes the file as well as the attributes. */ + /* + * The size case is special. + * It changes the file as well as the attributes. + */ if (iap->ia_valid & ATTR_SIZE) { if (iap->ia_size < inode->i_size) { err = nfsd_permission(rqstp, fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE); @@ -361,14 +364,23 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, if (iap->ia_valid & ATTR_MODE) { iap->ia_mode &= S_IALLUGO; imode = iap->ia_mode |= (imode & ~S_IALLUGO); + /* if changing uid/gid revoke setuid/setgid in mode */ + if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) { + iap->ia_valid |= ATTR_KILL_PRIV; + iap->ia_mode &= ~S_ISUID; + } + if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid) + iap->ia_mode &= ~S_ISGID; + } else { + /* + * Revoke setuid/setgid bit on chown/chgrp + */ + if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) + iap->ia_valid |= ATTR_KILL_SUID | ATTR_KILL_PRIV; + if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid) + iap->ia_valid |= ATTR_KILL_SGID; } - /* Revoke setuid/setgid bit on chown/chgrp */ - if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) - iap->ia_valid |= ATTR_KILL_SUID; - if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid) - iap->ia_valid |= ATTR_KILL_SGID; - /* Change the attributes. */ iap->ia_valid |= ATTR_CTIME; @@ -680,7 +692,12 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, err = nfserr_perm; if (IS_APPEND(inode) && (access & MAY_WRITE)) goto out; - if (IS_ISMNDLK(inode)) + /* + * We must ignore files (but only files) which might have mandatory + * locks on them because there is no way to know if the accesser has + * the lock. + */ + if (S_ISREG((inode)->i_mode) && mandatory_lock(inode)) goto out; if (!inode->i_fop) @@ -857,6 +874,15 @@ static int nfsd_direct_splice_actor(struct pipe_inode_info *pipe, return __splice_from_pipe(pipe, sd, nfsd_splice_actor); } +static inline int svc_msnfs(struct svc_fh *ffhp) +{ +#ifdef MSNFS + return (ffhp->fh_export->ex_flags & NFSEXP_MSNFS); +#else + return 0; +#endif +} + static __be32 nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, loff_t offset, struct kvec *vec, int vlen, unsigned long *count) @@ -869,11 +895,9 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, err = nfserr_perm; inode = file->f_path.dentry->d_inode; -#ifdef MSNFS - if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && - (!lock_may_read(inode, offset, *count))) + + if (svc_msnfs(fhp) && !lock_may_read(inode, offset, *count)) goto out; -#endif /* Get readahead parameters */ ra = nfsd_get_raparms(inode->i_sb->s_dev, inode->i_ino); @@ -922,7 +946,7 @@ out: static void kill_suid(struct dentry *dentry) { struct iattr ia; - ia.ia_valid = ATTR_KILL_SUID | ATTR_KILL_SGID; + ia.ia_valid = ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV; mutex_lock(&dentry->d_inode->i_mutex); notify_change(dentry, &ia); @@ -1005,13 +1029,13 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, if (EX_WGATHER(exp)) { if (atomic_read(&inode->i_writecount) > 1 || (last_ino == inode->i_ino && last_dev == inode->i_sb->s_dev)) { - dprintk("nfsd: write defer %d\n", current->pid); + dprintk("nfsd: write defer %d\n", task_pid_nr(current)); msleep(10); - dprintk("nfsd: write resume %d\n", current->pid); + dprintk("nfsd: write resume %d\n", task_pid_nr(current)); } if (inode->i_state & I_DIRTY) { - dprintk("nfsd: write sync %d\n", current->pid); + dprintk("nfsd: write sync %d\n", task_pid_nr(current)); host_err=nfsd_sync(file); } #if 0 diff --git a/fs/nls/Kconfig b/fs/nls/Kconfig index 976ecccd6f56..a39edc41becc 100644 --- a/fs/nls/Kconfig +++ b/fs/nls/Kconfig @@ -2,10 +2,8 @@ # Native language support configuration # -menu "Native Language Support" - -config NLS - tristate "Base native language support" +menuconfig NLS + tristate "Native language support" ---help--- The base Native Language Support. A number of filesystems depend on it (e.g. FAT, JOLIET, NT, BEOS filesystems), as well @@ -17,9 +15,10 @@ config NLS To compile this code as a module, choose M here: the module will be called nls_base. +if NLS + config NLS_DEFAULT string "Default NLS Option" - depends on NLS default "iso8859-1" ---help--- The default NLS used when mounting file system. Note, that this is @@ -39,7 +38,6 @@ config NLS_DEFAULT config NLS_CODEPAGE_437 tristate "Codepage 437 (United States, Canada)" - depends on NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored @@ -52,7 +50,6 @@ config NLS_CODEPAGE_437 config NLS_CODEPAGE_737 tristate "Codepage 737 (Greek)" - depends on NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored @@ -65,7 +62,6 @@ config NLS_CODEPAGE_737 config NLS_CODEPAGE_775 tristate "Codepage 775 (Baltic Rim)" - depends on NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored @@ -79,7 +75,6 @@ config NLS_CODEPAGE_775 config NLS_CODEPAGE_850 tristate "Codepage 850 (Europe)" - depends on NLS ---help--- The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -96,7 +91,6 @@ config NLS_CODEPAGE_850 config NLS_CODEPAGE_852 tristate "Codepage 852 (Central/Eastern Europe)" - depends on NLS ---help--- The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -112,7 +106,6 @@ config NLS_CODEPAGE_852 config NLS_CODEPAGE_855 tristate "Codepage 855 (Cyrillic)" - depends on NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -124,7 +117,6 @@ config NLS_CODEPAGE_855 config NLS_CODEPAGE_857 tristate "Codepage 857 (Turkish)" - depends on NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -136,7 +128,6 @@ config NLS_CODEPAGE_857 config NLS_CODEPAGE_860 tristate "Codepage 860 (Portuguese)" - depends on NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -148,7 +139,6 @@ config NLS_CODEPAGE_860 config NLS_CODEPAGE_861 tristate "Codepage 861 (Icelandic)" - depends on NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -160,7 +150,6 @@ config NLS_CODEPAGE_861 config NLS_CODEPAGE_862 tristate "Codepage 862 (Hebrew)" - depends on NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -172,7 +161,6 @@ config NLS_CODEPAGE_862 config NLS_CODEPAGE_863 tristate "Codepage 863 (Canadian French)" - depends on NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -185,7 +173,6 @@ config NLS_CODEPAGE_863 config NLS_CODEPAGE_864 tristate "Codepage 864 (Arabic)" - depends on NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -197,7 +184,6 @@ config NLS_CODEPAGE_864 config NLS_CODEPAGE_865 tristate "Codepage 865 (Norwegian, Danish)" - depends on NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -210,7 +196,6 @@ config NLS_CODEPAGE_865 config NLS_CODEPAGE_866 tristate "Codepage 866 (Cyrillic/Russian)" - depends on NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -223,7 +208,6 @@ config NLS_CODEPAGE_866 config NLS_CODEPAGE_869 tristate "Codepage 869 (Greek)" - depends on NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -235,7 +219,6 @@ config NLS_CODEPAGE_869 config NLS_CODEPAGE_936 tristate "Simplified Chinese charset (CP936, GB2312)" - depends on NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -248,7 +231,6 @@ config NLS_CODEPAGE_936 config NLS_CODEPAGE_950 tristate "Traditional Chinese charset (Big5)" - depends on NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -261,7 +243,6 @@ config NLS_CODEPAGE_950 config NLS_CODEPAGE_932 tristate "Japanese charsets (Shift-JIS, EUC-JP)" - depends on NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -275,7 +256,6 @@ config NLS_CODEPAGE_932 config NLS_CODEPAGE_949 tristate "Korean charset (CP949, EUC-KR)" - depends on NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -287,7 +267,6 @@ config NLS_CODEPAGE_949 config NLS_CODEPAGE_874 tristate "Thai charset (CP874, TIS-620)" - depends on NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -299,7 +278,6 @@ config NLS_CODEPAGE_874 config NLS_ISO8859_8 tristate "Hebrew charsets (ISO-8859-8, CP1255)" - depends on NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -309,7 +287,6 @@ config NLS_ISO8859_8 config NLS_CODEPAGE_1250 tristate "Windows CP1250 (Slavic/Central European Languages)" - depends on NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CDROMs @@ -321,7 +298,6 @@ config NLS_CODEPAGE_1250 config NLS_CODEPAGE_1251 tristate "Windows CP1251 (Bulgarian, Belarusian)" - depends on NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -334,7 +310,6 @@ config NLS_CODEPAGE_1251 config NLS_ASCII tristate "ASCII (United States)" - depends on NLS help An ASCII NLS module is needed if you want to override the DEFAULT NLS with this very basic charset and don't want any @@ -342,7 +317,6 @@ config NLS_ASCII config NLS_ISO8859_1 tristate "NLS ISO 8859-1 (Latin 1; Western European Languages)" - depends on NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -355,7 +329,6 @@ config NLS_ISO8859_1 config NLS_ISO8859_2 tristate "NLS ISO 8859-2 (Latin 2; Slavic/Central European Languages)" - depends on NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -367,7 +340,6 @@ config NLS_ISO8859_2 config NLS_ISO8859_3 tristate "NLS ISO 8859-3 (Latin 3; Esperanto, Galician, Maltese, Turkish)" - depends on NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -378,7 +350,6 @@ config NLS_ISO8859_3 config NLS_ISO8859_4 tristate "NLS ISO 8859-4 (Latin 4; old Baltic charset)" - depends on NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -389,7 +360,6 @@ config NLS_ISO8859_4 config NLS_ISO8859_5 tristate "NLS ISO 8859-5 (Cyrillic)" - depends on NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -401,7 +371,6 @@ config NLS_ISO8859_5 config NLS_ISO8859_6 tristate "NLS ISO 8859-6 (Arabic)" - depends on NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -411,7 +380,6 @@ config NLS_ISO8859_6 config NLS_ISO8859_7 tristate "NLS ISO 8859-7 (Modern Greek)" - depends on NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -421,7 +389,6 @@ config NLS_ISO8859_7 config NLS_ISO8859_9 tristate "NLS ISO 8859-9 (Latin 5; Turkish)" - depends on NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -432,7 +399,6 @@ config NLS_ISO8859_9 config NLS_ISO8859_13 tristate "NLS ISO 8859-13 (Latin 7; Baltic)" - depends on NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -443,7 +409,6 @@ config NLS_ISO8859_13 config NLS_ISO8859_14 tristate "NLS ISO 8859-14 (Latin 8; Celtic)" - depends on NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -455,7 +420,6 @@ config NLS_ISO8859_14 config NLS_ISO8859_15 tristate "NLS ISO 8859-15 (Latin 9; Western European Languages with Euro)" - depends on NLS ---help--- If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -472,7 +436,6 @@ config NLS_ISO8859_15 config NLS_KOI8_R tristate "NLS KOI8-R (Russian)" - depends on NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -482,7 +445,6 @@ config NLS_KOI8_R config NLS_KOI8_U tristate "NLS KOI8-U/RU (Ukrainian, Belarusian)" - depends on NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -492,7 +454,6 @@ config NLS_KOI8_U config NLS_UTF8 tristate "NLS UTF-8" - depends on NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -500,5 +461,4 @@ config NLS_UTF8 input/output character sets. Say Y here for the UTF-8 encoding of the Unicode/ISO9646 universal character set. -endmenu - +endif # NLS diff --git a/fs/nls/nls_ascii.c b/fs/nls/nls_ascii.c index 6993faea28ac..7020e940f74e 100644 --- a/fs/nls/nls_ascii.c +++ b/fs/nls/nls_ascii.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -56,7 +56,7 @@ static wchar_t charset2uni[256] = { 0x007c, 0x007d, 0x007e, 0x007f, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -75,11 +75,11 @@ static unsigned char page00[256] = { 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -98,7 +98,7 @@ static unsigned char charset2lower[256] = { 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -119,7 +119,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c index 7dfdab98729b..64965e1c21c4 100644 --- a/fs/nls/nls_base.c +++ b/fs/nls/nls_base.c @@ -34,7 +34,7 @@ struct utf8_table { long lval; }; -static struct utf8_table utf8_table[] = +static const struct utf8_table utf8_table[] = { {0x80, 0x00, 0*6, 0x7F, 0, /* 1 byte sequence */}, {0xE0, 0xC0, 1*6, 0x7FF, 0x80, /* 2 byte sequence */}, @@ -50,7 +50,7 @@ utf8_mbtowc(wchar_t *p, const __u8 *s, int n) { long l; int c0, c, nc; - struct utf8_table *t; + const struct utf8_table *t; nc = 0; c0 = *s; @@ -109,9 +109,9 @@ utf8_wctomb(__u8 *s, wchar_t wc, int maxlen) { long l; int c, nc; - struct utf8_table *t; + const struct utf8_table *t; - if (s == 0) + if (!s) return 0; l = wc; @@ -240,7 +240,7 @@ void unload_nls(struct nls_table *nls) module_put(nls->owner); } -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -323,7 +323,7 @@ static wchar_t charset2uni[256] = { 0x00fc, 0x00fd, 0x00fe, 0x00ff, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -359,11 +359,11 @@ static unsigned char page00[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00 }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -399,7 +399,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -438,7 +438,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_cp1250.c b/fs/nls/nls_cp1250.c index 570aa69846a0..c8471fe78e4e 100644 --- a/fs/nls/nls_cp1250.c +++ b/fs/nls/nls_cp1250.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x00fc, 0x00fd, 0x0163, 0x02d9, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -132,7 +132,7 @@ static unsigned char page00[256] = { 0x00, 0x00, 0xfa, 0x00, 0xfc, 0xfd, 0x00, 0x00, /* 0xf8-0xff */ }; -static unsigned char page01[256] = { +static const unsigned char page01[256] = { 0x00, 0x00, 0xc3, 0xe3, 0xa5, 0xb9, 0xc6, 0xe6, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0xcf, 0xef, /* 0x08-0x0f */ 0xd0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -152,7 +152,7 @@ static unsigned char page01[256] = { }; -static unsigned char page02[256] = { +static const unsigned char page02[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -184,7 +184,7 @@ static unsigned char page02[256] = { 0xa2, 0xff, 0x00, 0xb2, 0x00, 0xbd, 0x00, 0x00, /* 0xd8-0xdf */ }; -static unsigned char page20[256] = { +static const unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x96, 0x97, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -210,7 +210,7 @@ static unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ }; -static unsigned char page21[256] = { +static const unsigned char page21[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -218,7 +218,7 @@ static unsigned char page21[256] = { 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, page01, page02, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -226,7 +226,7 @@ static unsigned char *page_uni2charset[256] = { page20, page21, NULL, NULL, NULL, NULL, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -262,7 +262,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -300,7 +300,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_cp1251.c b/fs/nls/nls_cp1251.c index f114afa069db..1939b46e772f 100644 --- a/fs/nls/nls_cp1251.c +++ b/fs/nls/nls_cp1251.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x044c, 0x044d, 0x044e, 0x044f, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -132,7 +132,7 @@ static unsigned char page00[256] = { 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ }; -static unsigned char page04[256] = { +static const unsigned char page04[256] = { 0x00, 0xa8, 0x80, 0x81, 0xaa, 0xbd, 0xb2, 0xaf, /* 0x00-0x07 */ 0xa3, 0x8a, 0x8c, 0x8e, 0x8d, 0x00, 0xa1, 0x8f, /* 0x08-0x0f */ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0x10-0x17 */ @@ -155,7 +155,7 @@ static unsigned char page04[256] = { 0x00, 0xa5, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ }; -static unsigned char page20[256] = { +static const unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x96, 0x97, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -166,7 +166,7 @@ static unsigned char page20[256] = { 0x00, 0x8b, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ }; -static unsigned char page21[256] = { +static const unsigned char page21[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x00, /* 0x10-0x17 */ @@ -174,7 +174,7 @@ static unsigned char page21[256] = { 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, NULL, NULL, NULL, page04, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -182,7 +182,7 @@ static unsigned char *page_uni2charset[256] = { page20, page21, NULL, NULL, NULL, NULL, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -217,7 +217,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -254,7 +254,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_cp1255.c b/fs/nls/nls_cp1255.c index e57f2cbf5bc0..8120ae2e091a 100644 --- a/fs/nls/nls_cp1255.c +++ b/fs/nls/nls_cp1255.c @@ -11,7 +11,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -94,7 +94,7 @@ static wchar_t charset2uni[256] = { 0x0000, 0x0000, 0x0000, 0x0000, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -129,7 +129,7 @@ static unsigned char page00[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, /* 0xf0-0xf7 */ }; -static unsigned char page01[256] = { +static const unsigned char page01[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -152,7 +152,7 @@ static unsigned char page01[256] = { 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ }; -static unsigned char page02[256] = { +static const unsigned char page02[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -184,7 +184,7 @@ static unsigned char page02[256] = { 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ }; -static unsigned char page05[256] = { +static const unsigned char page05[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -219,7 +219,7 @@ static unsigned char page05[256] = { 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ }; -static unsigned char page20[256] = { +static const unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xfe, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x96, 0x97, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -245,7 +245,7 @@ static unsigned char page20[256] = { 0x00, 0x00, 0xa4, 0x00, 0x80, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ }; -static unsigned char page21[256] = { +static const unsigned char page21[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x00, /* 0x10-0x17 */ @@ -253,7 +253,7 @@ static unsigned char page21[256] = { 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, page01, page02, NULL, NULL, page05, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -261,7 +261,7 @@ static unsigned char *page_uni2charset[256] = { page20, page21, NULL, NULL, NULL, NULL, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -297,7 +297,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -335,7 +335,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_cp437.c b/fs/nls/nls_cp437.c index d41930ce4a44..ff37a4628ce4 100644 --- a/fs/nls/nls_cp437.c +++ b/fs/nls/nls_cp437.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x207f, 0x00b2, 0x25a0, 0x00a0, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -132,7 +132,7 @@ static unsigned char page00[256] = { 0x00, 0x97, 0xa3, 0x96, 0x81, 0x00, 0x00, 0x98, /* 0xf8-0xff */ }; -static unsigned char page01[256] = { +static const unsigned char page01[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -155,7 +155,7 @@ static unsigned char page01[256] = { 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ }; -static unsigned char page03[256] = { +static const unsigned char page03[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -184,7 +184,7 @@ static unsigned char page03[256] = { 0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */ }; -static unsigned char page20[256] = { +static const unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -209,7 +209,7 @@ static unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */ }; -static unsigned char page22[256] = { +static const unsigned char page22[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -225,7 +225,7 @@ static unsigned char page22[256] = { 0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */ }; -static unsigned char page23[256] = { +static const unsigned char page23[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -233,7 +233,7 @@ static unsigned char page23[256] = { 0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ }; -static unsigned char page25[256] = { +static const unsigned char page25[256] = { 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -258,7 +258,7 @@ static unsigned char page25[256] = { 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, page01, NULL, page03, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -266,7 +266,7 @@ static unsigned char *page_uni2charset[256] = { page20, NULL, page22, page23, NULL, page25, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -302,7 +302,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -340,7 +340,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_cp737.c b/fs/nls/nls_cp737.c index d21f8790aa19..f5576b8be1b9 100644 --- a/fs/nls/nls_cp737.c +++ b/fs/nls/nls_cp737.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x207f, 0x00b2, 0x25a0, 0x00a0, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -131,7 +131,7 @@ static unsigned char page00[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, /* 0xf0-0xf7 */ }; -static unsigned char page03[256] = { +static const unsigned char page03[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -161,7 +161,7 @@ static unsigned char page03[256] = { 0xaf, 0xe0, 0xe4, 0xe8, 0xe6, 0xe7, 0xe9, 0x00, /* 0xc8-0xcf */ }; -static unsigned char page20[256] = { +static const unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -180,7 +180,7 @@ static unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */ }; -static unsigned char page22[256] = { +static const unsigned char page22[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -196,7 +196,7 @@ static unsigned char page22[256] = { 0x00, 0x00, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */ }; -static unsigned char page25[256] = { +static const unsigned char page25[256] = { 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -221,7 +221,7 @@ static unsigned char page25[256] = { 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, NULL, NULL, page03, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -229,7 +229,7 @@ static unsigned char *page_uni2charset[256] = { page20, NULL, page22, NULL, NULL, page25, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -265,7 +265,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -303,7 +303,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_cp775.c b/fs/nls/nls_cp775.c index c97714c38a90..4905635d1c00 100644 --- a/fs/nls/nls_cp775.c +++ b/fs/nls/nls_cp775.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x00b3, 0x00b2, 0x25a0, 0x00a0, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -132,7 +132,7 @@ static unsigned char page00[256] = { 0x9b, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, /* 0xf8-0xff */ }; -static unsigned char page01[256] = { +static const unsigned char page01[256] = { 0xa0, 0x83, 0x00, 0x00, 0xb5, 0xd0, 0x80, 0x87, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xb6, 0xd1, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0xed, 0x89, 0x00, 0x00, 0xb8, 0xd3, /* 0x10-0x17 */ @@ -151,21 +151,21 @@ static unsigned char page01[256] = { 0x00, 0x8d, 0xa5, 0xa3, 0xa4, 0xcf, 0xd8, 0x00, /* 0x78-0x7f */ }; -static unsigned char page20[256] = { +static const unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ 0x00, 0xef, 0x00, 0x00, 0xf2, 0xa6, 0xf7, 0x00, /* 0x18-0x1f */ }; -static unsigned char page22[256] = { +static const unsigned char page22[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ 0x00, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ }; -static unsigned char page25[256] = { +static const unsigned char page25[256] = { 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -190,7 +190,7 @@ static unsigned char page25[256] = { 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, page01, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -198,7 +198,7 @@ static unsigned char *page_uni2charset[256] = { page20, NULL, page22, NULL, NULL, page25, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -234,7 +234,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -272,7 +272,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_cp850.c b/fs/nls/nls_cp850.c index 843b7d975ba2..fe5bdad50e2b 100644 --- a/fs/nls/nls_cp850.c +++ b/fs/nls/nls_cp850.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x00b3, 0x00b2, 0x25a0, 0x00a0, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -132,7 +132,7 @@ static unsigned char page00[256] = { 0x9b, 0x97, 0xa3, 0x96, 0x81, 0xec, 0xe7, 0x98, /* 0xf8-0xff */ }; -static unsigned char page01[256] = { +static const unsigned char page01[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -155,13 +155,13 @@ static unsigned char page01[256] = { 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ }; -static unsigned char page20[256] = { +static const unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, /* 0x10-0x17 */ }; -static unsigned char page25[256] = { +static const unsigned char page25[256] = { 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -186,7 +186,7 @@ static unsigned char page25[256] = { 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, page01, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -194,7 +194,7 @@ static unsigned char *page_uni2charset[256] = { page20, NULL, NULL, NULL, NULL, page25, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -230,7 +230,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -268,7 +268,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_cp852.c b/fs/nls/nls_cp852.c index 83cfd844d5ca..ceb1c0166dd8 100644 --- a/fs/nls/nls_cp852.c +++ b/fs/nls/nls_cp852.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x0158, 0x0159, 0x25a0, 0x00a0, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -132,7 +132,7 @@ static unsigned char page00[256] = { 0x00, 0x00, 0xa3, 0x00, 0x81, 0xec, 0x00, 0x00, /* 0xf8-0xff */ }; -static unsigned char page01[256] = { +static const unsigned char page01[256] = { 0x00, 0x00, 0xc6, 0xc7, 0xa4, 0xa5, 0x8f, 0x86, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xac, 0x9f, 0xd2, 0xd4, /* 0x08-0x0f */ 0xd1, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -151,7 +151,7 @@ static unsigned char page01[256] = { 0x00, 0x8d, 0xab, 0xbd, 0xbe, 0xa6, 0xa7, 0x00, /* 0x78-0x7f */ }; -static unsigned char page02[256] = { +static const unsigned char page02[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -183,7 +183,7 @@ static unsigned char page02[256] = { 0xf4, 0xfa, 0x00, 0xf2, 0x00, 0xf1, 0x00, 0x00, /* 0xd8-0xdf */ }; -static unsigned char page25[256] = { +static const unsigned char page25[256] = { 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -208,7 +208,7 @@ static unsigned char page25[256] = { 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, page01, page02, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -216,7 +216,7 @@ static unsigned char *page_uni2charset[256] = { NULL, NULL, NULL, NULL, NULL, page25, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -252,7 +252,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfd, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -290,7 +290,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_cp855.c b/fs/nls/nls_cp855.c index 9190b7b574ff..cc7f5fb2e0c2 100644 --- a/fs/nls/nls_cp855.c +++ b/fs/nls/nls_cp855.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x0427, 0x00a7, 0x25a0, 0x00a0, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -124,7 +124,7 @@ static unsigned char page00[256] = { 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ }; -static unsigned char page04[256] = { +static const unsigned char page04[256] = { 0x00, 0x85, 0x81, 0x83, 0x87, 0x89, 0x8b, 0x8d, /* 0x00-0x07 */ 0x8f, 0x91, 0x93, 0x95, 0x97, 0x00, 0x99, 0x9b, /* 0x08-0x0f */ 0xa1, 0xa3, 0xec, 0xad, 0xa7, 0xa9, 0xea, 0xf4, /* 0x10-0x17 */ @@ -139,13 +139,13 @@ static unsigned char page04[256] = { 0x8e, 0x90, 0x92, 0x94, 0x96, 0x00, 0x98, 0x9a, /* 0x58-0x5f */ }; -static unsigned char page21[256] = { +static const unsigned char page21[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0x00, /* 0x10-0x17 */ }; -static unsigned char page25[256] = { +static const unsigned char page25[256] = { 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -170,7 +170,7 @@ static unsigned char page25[256] = { 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, NULL, NULL, NULL, page04, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -178,7 +178,7 @@ static unsigned char *page_uni2charset[256] = { NULL, page21, NULL, NULL, NULL, page25, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -214,7 +214,7 @@ static unsigned char charset2lower[256] = { 0xf7, 0xf9, 0xf9, 0xfb, 0xfb, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -252,7 +252,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_cp857.c b/fs/nls/nls_cp857.c index ef3d36db8082..e418e198e8d8 100644 --- a/fs/nls/nls_cp857.c +++ b/fs/nls/nls_cp857.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x00b3, 0x00b2, 0x25a0, 0x00a0, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -132,7 +132,7 @@ static unsigned char page00[256] = { 0x9b, 0x97, 0xa3, 0x96, 0x81, 0x00, 0x00, 0xed, /* 0xf8-0xff */ }; -static unsigned char page01[256] = { +static const unsigned char page01[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -147,7 +147,7 @@ static unsigned char page01[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x9f, /* 0x58-0x5f */ }; -static unsigned char page25[256] = { +static const unsigned char page25[256] = { 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -172,7 +172,7 @@ static unsigned char page25[256] = { 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, page01, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -180,7 +180,7 @@ static unsigned char *page_uni2charset[256] = { NULL, NULL, NULL, NULL, NULL, page25, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -216,7 +216,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -254,7 +254,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_cp860.c b/fs/nls/nls_cp860.c index 7e2fb6645893..a86c97d1aa34 100644 --- a/fs/nls/nls_cp860.c +++ b/fs/nls/nls_cp860.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x207f, 0x00b2, 0x25a0, 0x00a0, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -132,7 +132,7 @@ static unsigned char page00[256] = { 0x00, 0x97, 0xa3, 0x00, 0x81, 0x00, 0x00, 0x00, /* 0xf8-0xff */ }; -static unsigned char page03[256] = { +static const unsigned char page03[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -161,7 +161,7 @@ static unsigned char page03[256] = { 0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */ }; -static unsigned char page20[256] = { +static const unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -186,7 +186,7 @@ static unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */ }; -static unsigned char page22[256] = { +static const unsigned char page22[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -202,7 +202,7 @@ static unsigned char page22[256] = { 0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */ }; -static unsigned char page23[256] = { +static const unsigned char page23[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -210,7 +210,7 @@ static unsigned char page23[256] = { 0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ }; -static unsigned char page25[256] = { +static const unsigned char page25[256] = { 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -235,7 +235,7 @@ static unsigned char page25[256] = { 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, NULL, NULL, page03, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -243,7 +243,7 @@ static unsigned char *page_uni2charset[256] = { page20, NULL, page22, page23, NULL, page25, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -279,7 +279,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -317,7 +317,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_cp861.c b/fs/nls/nls_cp861.c index 66d8d808ccf1..bd920227acdf 100644 --- a/fs/nls/nls_cp861.c +++ b/fs/nls/nls_cp861.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x207f, 0x00b2, 0x25a0, 0x00a0, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -132,7 +132,7 @@ static unsigned char page00[256] = { 0x9b, 0x00, 0xa3, 0x96, 0x81, 0x98, 0x95, 0x00, /* 0xf8-0xff */ }; -static unsigned char page01[256] = { +static const unsigned char page01[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -155,7 +155,7 @@ static unsigned char page01[256] = { 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ }; -static unsigned char page03[256] = { +static const unsigned char page03[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -184,7 +184,7 @@ static unsigned char page03[256] = { 0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */ }; -static unsigned char page20[256] = { +static const unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -209,7 +209,7 @@ static unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */ }; -static unsigned char page22[256] = { +static const unsigned char page22[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -225,7 +225,7 @@ static unsigned char page22[256] = { 0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */ }; -static unsigned char page23[256] = { +static const unsigned char page23[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -233,7 +233,7 @@ static unsigned char page23[256] = { 0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ }; -static unsigned char page25[256] = { +static const unsigned char page25[256] = { 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -258,7 +258,7 @@ static unsigned char page25[256] = { 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, page01, NULL, page03, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -266,7 +266,7 @@ static unsigned char *page_uni2charset[256] = { page20, NULL, page22, page23, NULL, page25, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -302,7 +302,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -340,7 +340,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_cp862.c b/fs/nls/nls_cp862.c index 360ba388485f..e9b68eb3daf0 100644 --- a/fs/nls/nls_cp862.c +++ b/fs/nls/nls_cp862.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x207f, 0x00b2, 0x25a0, 0x00a0, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -132,7 +132,7 @@ static unsigned char page00[256] = { 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ }; -static unsigned char page01[256] = { +static const unsigned char page01[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -155,7 +155,7 @@ static unsigned char page01[256] = { 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ }; -static unsigned char page03[256] = { +static const unsigned char page03[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -184,7 +184,7 @@ static unsigned char page03[256] = { 0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */ }; -static unsigned char page05[256] = { +static const unsigned char page05[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -218,7 +218,7 @@ static unsigned char page05[256] = { 0x98, 0x99, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ }; -static unsigned char page20[256] = { +static const unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -243,7 +243,7 @@ static unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */ }; -static unsigned char page22[256] = { +static const unsigned char page22[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -259,7 +259,7 @@ static unsigned char page22[256] = { 0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */ }; -static unsigned char page23[256] = { +static const unsigned char page23[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -267,7 +267,7 @@ static unsigned char page23[256] = { 0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ }; -static unsigned char page25[256] = { +static const unsigned char page25[256] = { 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -292,7 +292,7 @@ static unsigned char page25[256] = { 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, page01, NULL, page03, NULL, page05, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -300,7 +300,7 @@ static unsigned char *page_uni2charset[256] = { page20, NULL, page22, page23, NULL, page25, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -336,7 +336,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -374,7 +374,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_cp863.c b/fs/nls/nls_cp863.c index 656a93113e37..f8a9b07ab4e2 100644 --- a/fs/nls/nls_cp863.c +++ b/fs/nls/nls_cp863.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x207f, 0x00b2, 0x25a0, 0x00a0, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -132,7 +132,7 @@ static unsigned char page00[256] = { 0x00, 0x97, 0xa3, 0x96, 0x81, 0x00, 0x00, 0x00, /* 0xf8-0xff */ }; -static unsigned char page01[256] = { +static const unsigned char page01[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -155,7 +155,7 @@ static unsigned char page01[256] = { 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ }; -static unsigned char page03[256] = { +static const unsigned char page03[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -184,7 +184,7 @@ static unsigned char page03[256] = { 0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */ }; -static unsigned char page20[256] = { +static const unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8d, /* 0x10-0x17 */ @@ -203,7 +203,7 @@ static unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */ }; -static unsigned char page22[256] = { +static const unsigned char page22[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -219,7 +219,7 @@ static unsigned char page22[256] = { 0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */ }; -static unsigned char page23[256] = { +static const unsigned char page23[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -227,7 +227,7 @@ static unsigned char page23[256] = { 0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ }; -static unsigned char page25[256] = { +static const unsigned char page25[256] = { 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -252,7 +252,7 @@ static unsigned char page25[256] = { 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, page01, NULL, page03, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -260,7 +260,7 @@ static unsigned char *page_uni2charset[256] = { page20, NULL, page22, page23, NULL, page25, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -296,7 +296,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -334,7 +334,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_cp864.c b/fs/nls/nls_cp864.c index 01ca7309753e..8d31f435fc6f 100644 --- a/fs/nls/nls_cp864.c +++ b/fs/nls/nls_cp864.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0xfed9, 0xfef1, 0x25a0, 0x0000, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -131,7 +131,7 @@ static unsigned char page00[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, /* 0xf0-0xf7 */ }; -static unsigned char page03[256] = { +static const unsigned char page03[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -160,7 +160,7 @@ static unsigned char page03[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, /* 0xc0-0xc7 */ }; -static unsigned char page06[256] = { +static const unsigned char page06[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -177,7 +177,7 @@ static unsigned char page06[256] = { 0xb8, 0xb9, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ }; -static unsigned char page22[256] = { +static const unsigned char page22[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -190,7 +190,7 @@ static unsigned char page22[256] = { 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ }; -static unsigned char page25[256] = { +static const unsigned char page25[256] = { 0x85, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x8c, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -215,7 +215,7 @@ static unsigned char page25[256] = { 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ }; -static unsigned char pagefe[256] = { +static const unsigned char pagefe[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -251,7 +251,7 @@ static unsigned char pagefe[256] = { 0x9a, 0x00, 0x00, 0x9d, 0x9e, 0x00, 0x00, 0x00, /* 0xf8-0xff */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, NULL, NULL, page03, NULL, NULL, page06, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -286,7 +286,7 @@ static unsigned char *page_uni2charset[256] = { NULL, NULL, NULL, NULL, NULL, NULL, pagefe, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -322,7 +322,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0x00, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -360,7 +360,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_cp865.c b/fs/nls/nls_cp865.c index 5ba6ee13e109..4bd902fe3ec9 100644 --- a/fs/nls/nls_cp865.c +++ b/fs/nls/nls_cp865.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x207f, 0x00b2, 0x25a0, 0x00a0, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -132,7 +132,7 @@ static unsigned char page00[256] = { 0x9b, 0x97, 0xa3, 0x96, 0x81, 0x00, 0x00, 0x98, /* 0xf8-0xff */ }; -static unsigned char page01[256] = { +static const unsigned char page01[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -155,7 +155,7 @@ static unsigned char page01[256] = { 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ }; -static unsigned char page03[256] = { +static const unsigned char page03[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -184,7 +184,7 @@ static unsigned char page03[256] = { 0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */ }; -static unsigned char page20[256] = { +static const unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -209,7 +209,7 @@ static unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */ }; -static unsigned char page22[256] = { +static const unsigned char page22[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -225,7 +225,7 @@ static unsigned char page22[256] = { 0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */ }; -static unsigned char page23[256] = { +static const unsigned char page23[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -233,7 +233,7 @@ static unsigned char page23[256] = { 0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ }; -static unsigned char page25[256] = { +static const unsigned char page25[256] = { 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -258,7 +258,7 @@ static unsigned char page25[256] = { 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, page01, NULL, page03, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -266,7 +266,7 @@ static unsigned char *page_uni2charset[256] = { page20, NULL, page22, page23, NULL, page25, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -302,7 +302,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -340,7 +340,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_cp866.c b/fs/nls/nls_cp866.c index c5f82221c9fe..bdc7cb391398 100644 --- a/fs/nls/nls_cp866.c +++ b/fs/nls/nls_cp866.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x2116, 0x00a4, 0x25a0, 0x00a0, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -123,7 +123,7 @@ static unsigned char page00[256] = { 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, /* 0xb0-0xb7 */ }; -static unsigned char page04[256] = { +static const unsigned char page04[256] = { 0x00, 0xf0, 0x00, 0x00, 0xf2, 0x00, 0x00, 0xf4, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x00, /* 0x08-0x0f */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x10-0x17 */ @@ -138,20 +138,20 @@ static unsigned char page04[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x00, /* 0x58-0x5f */ }; -static unsigned char page21[256] = { +static const unsigned char page21[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, /* 0x10-0x17 */ }; -static unsigned char page22[256] = { +static const unsigned char page22[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ 0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ }; -static unsigned char page25[256] = { +static const unsigned char page25[256] = { 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -176,7 +176,7 @@ static unsigned char page25[256] = { 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, NULL, NULL, NULL, page04, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -184,7 +184,7 @@ static unsigned char *page_uni2charset[256] = { NULL, page21, page22, NULL, NULL, page25, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -220,7 +220,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -258,7 +258,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_cp869.c b/fs/nls/nls_cp869.c index 8d4015124d11..9f283a2b151a 100644 --- a/fs/nls/nls_cp869.c +++ b/fs/nls/nls_cp869.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x03b0, 0x03ce, 0x25a0, 0x00a0, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -124,7 +124,7 @@ static unsigned char page00[256] = { 0x00, 0x00, 0x00, 0xaf, 0x00, 0xab, 0x00, 0x00, /* 0xb8-0xbf */ }; -static unsigned char page03[256] = { +static const unsigned char page03[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -154,14 +154,14 @@ static unsigned char page03[256] = { 0xf6, 0xfa, 0xa0, 0xfb, 0xa2, 0xa3, 0xfd, 0x00, /* 0xc8-0xcf */ }; -static unsigned char page20[256] = { +static const unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, /* 0x10-0x17 */ 0x8b, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ }; -static unsigned char page25[256] = { +static const unsigned char page25[256] = { 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -186,7 +186,7 @@ static unsigned char page25[256] = { 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, NULL, NULL, page03, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -194,7 +194,7 @@ static unsigned char *page_uni2charset[256] = { page20, NULL, NULL, NULL, NULL, page25, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -230,7 +230,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -268,7 +268,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_cp874.c b/fs/nls/nls_cp874.c index df042052c2db..0b3c4886f8c0 100644 --- a/fs/nls/nls_cp874.c +++ b/fs/nls/nls_cp874.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x0000, 0x0000, 0x0000, 0x0000, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -121,7 +121,7 @@ static unsigned char page00[256] = { 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ }; -static unsigned char page0e[256] = { +static const unsigned char page0e[256] = { 0x00, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0x00-0x07 */ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0x08-0x0f */ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0x10-0x17 */ @@ -136,7 +136,7 @@ static unsigned char page0e[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ }; -static unsigned char page20[256] = { +static const unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x96, 0x97, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -144,7 +144,7 @@ static unsigned char page20[256] = { 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x85, 0x00, /* 0x20-0x27 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, page0e, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -152,7 +152,7 @@ static unsigned char *page_uni2charset[256] = { page20, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -188,7 +188,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -226,7 +226,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_cp932.c b/fs/nls/nls_cp932.c index 2a9ccf3bc7ef..0ffed6f1cebb 100644 --- a/fs/nls/nls_cp932.c +++ b/fs/nls/nls_cp932.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t c2u_81[256] = { +static const wchar_t c2u_81[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -49,7 +49,7 @@ static wchar_t c2u_81[256] = { 0x0000,0x0000,0x0000,0x0000,0x25EF,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_82[256] = { +static const wchar_t c2u_82[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -84,7 +84,7 @@ static wchar_t c2u_82[256] = { 0x3092,0x3093,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xF0-0xF7 */ }; -static wchar_t c2u_83[256] = { +static const wchar_t c2u_83[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -115,7 +115,7 @@ static wchar_t c2u_83[256] = { 0x03C3,0x03C4,0x03C5,0x03C6,0x03C7,0x03C8,0x03C9,0x0000,/* 0xD0-0xD7 */ }; -static wchar_t c2u_84[256] = { +static const wchar_t c2u_84[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -143,7 +143,7 @@ static wchar_t c2u_84[256] = { 0x2537,0x253F,0x251D,0x2530,0x2525,0x2538,0x2542,0x0000,/* 0xB8-0xBF */ }; -static wchar_t c2u_87[256] = { +static const wchar_t c2u_87[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -167,7 +167,7 @@ static wchar_t c2u_87[256] = { 0x221F,0x22BF,0x2235,0x2229,0x222A,0x0000,0x0000,0x0000,/* 0x98-0x9F */ }; -static wchar_t c2u_88[256] = { +static const wchar_t c2u_88[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -203,7 +203,7 @@ static wchar_t c2u_88[256] = { 0x5F15,0x98F2,0x6DEB,0x80E4,0x852D,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_89[256] = { +static const wchar_t c2u_89[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -239,7 +239,7 @@ static wchar_t c2u_89[256] = { 0x6062,0x61D0,0x6212,0x62D0,0x6539,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_8A[256] = { +static const wchar_t c2u_8A[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -275,7 +275,7 @@ static wchar_t c2u_8A[256] = { 0x65D7,0x65E2,0x671F,0x68CB,0x68C4,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_8B[256] = { +static const wchar_t c2u_8B[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -311,7 +311,7 @@ static wchar_t c2u_8B[256] = { 0x4E32,0x6ADB,0x91E7,0x5C51,0x5C48,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_8C[256] = { +static const wchar_t c2u_8C[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -347,7 +347,7 @@ static wchar_t c2u_8C[256] = { 0x52B9,0x52FE,0x539A,0x53E3,0x5411,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_8D[256] = { +static const wchar_t c2u_8D[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -383,7 +383,7 @@ static wchar_t c2u_8D[256] = { 0x9BAD,0x7B39,0x5319,0x518A,0x5237,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_8E[256] = { +static const wchar_t c2u_8E[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -419,7 +419,7 @@ static wchar_t c2u_8E[256] = { 0x7DAC,0x9700,0x56DA,0x53CE,0x5468,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_8F[256] = { +static const wchar_t c2u_8F[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -455,7 +455,7 @@ static wchar_t c2u_8F[256] = { 0x91B8,0x9320,0x5631,0x57F4,0x98FE,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_90[256] = { +static const wchar_t c2u_90[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -491,7 +491,7 @@ static wchar_t c2u_90[256] = { 0x717D,0x65CB,0x7A7F,0x7BAD,0x7DDA,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_91[256] = { +static const wchar_t c2u_91[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -527,7 +527,7 @@ static wchar_t c2u_91[256] = { 0x8AFE,0x8338,0x51E7,0x86F8,0x53EA,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_92[256] = { +static const wchar_t c2u_92[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -563,7 +563,7 @@ static wchar_t c2u_92[256] = { 0x8247,0x8A02,0x8AE6,0x8E44,0x9013,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_93[256] = { +static const wchar_t c2u_93[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -599,7 +599,7 @@ static wchar_t c2u_93[256] = { 0x8679,0x5EFF,0x65E5,0x4E73,0x5165,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_94[256] = { +static const wchar_t c2u_94[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -635,7 +635,7 @@ static wchar_t c2u_94[256] = { 0x6787,0x6BD8,0x7435,0x7709,0x7F8E,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_95[256] = { +static const wchar_t c2u_95[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -671,7 +671,7 @@ static wchar_t c2u_95[256] = { 0x62B1,0x6367,0x653E,0x65B9,0x670B,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_96[256] = { +static const wchar_t c2u_96[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -707,7 +707,7 @@ static wchar_t c2u_96[256] = { 0x9453,0x6109,0x6108,0x6CB9,0x7652,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_97[256] = { +static const wchar_t c2u_97[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -743,7 +743,7 @@ static wchar_t c2u_97[256] = { 0x6F23,0x7149,0x7C3E,0x7DF4,0x806F,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_98[256] = { +static const wchar_t c2u_98[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -779,7 +779,7 @@ static wchar_t c2u_98[256] = { 0x5080,0x509A,0x5085,0x50B4,0x50B2,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_99[256] = { +static const wchar_t c2u_99[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -815,7 +815,7 @@ static wchar_t c2u_99[256] = { 0x54A5,0x54AC,0x54C4,0x54C8,0x54A8,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_9A[256] = { +static const wchar_t c2u_9A[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -851,7 +851,7 @@ static wchar_t c2u_9A[256] = { 0x5962,0x5960,0x5967,0x596C,0x5969,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_9B[256] = { +static const wchar_t c2u_9B[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -887,7 +887,7 @@ static wchar_t c2u_9B[256] = { 0x5EC1,0x5EC2,0x5EC8,0x5ED0,0x5ECF,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_9C[256] = { +static const wchar_t c2u_9C[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -923,7 +923,7 @@ static wchar_t c2u_9C[256] = { 0x6209,0x620D,0x620C,0x6214,0x621B,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_9D[256] = { +static const wchar_t c2u_9D[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -959,7 +959,7 @@ static wchar_t c2u_9D[256] = { 0x66C1,0x66B9,0x66C9,0x66BE,0x66BC,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_9E[256] = { +static const wchar_t c2u_9E[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -995,7 +995,7 @@ static wchar_t c2u_9E[256] = { 0x6A8D,0x6AA0,0x6A84,0x6AA2,0x6AA3,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_9F[256] = { +static const wchar_t c2u_9F[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1031,7 +1031,7 @@ static wchar_t c2u_9F[256] = { 0x6EF2,0x6F31,0x6EEF,0x6F32,0x6ECC,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E0[256] = { +static const wchar_t c2u_E0[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1067,7 +1067,7 @@ static wchar_t c2u_E0[256] = { 0x74A7,0x74CA,0x74CF,0x74D4,0x73F1,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E1[256] = { +static const wchar_t c2u_E1[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1103,7 +1103,7 @@ static wchar_t c2u_E1[256] = { 0x78BE,0x78BC,0x78C5,0x78CA,0x78EC,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E2[256] = { +static const wchar_t c2u_E2[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1139,7 +1139,7 @@ static wchar_t c2u_E2[256] = { 0x7CF2,0x7CF4,0x7CF6,0x7CFA,0x7D06,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E3[256] = { +static const wchar_t c2u_E3[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1175,7 +1175,7 @@ static wchar_t c2u_E3[256] = { 0x811B,0x8129,0x8123,0x812F,0x814B,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E4[256] = { +static const wchar_t c2u_E4[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1211,7 +1211,7 @@ static wchar_t c2u_E4[256] = { 0x84FC,0x8540,0x8563,0x8558,0x8548,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E5[256] = { +static const wchar_t c2u_E5[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1247,7 +1247,7 @@ static wchar_t c2u_E5[256] = { 0x8938,0x894C,0x891D,0x8960,0x895E,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E6[256] = { +static const wchar_t c2u_E6[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1283,7 +1283,7 @@ static wchar_t c2u_E6[256] = { 0x8E42,0x8E35,0x8E30,0x8E34,0x8E4A,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E7[256] = { +static const wchar_t c2u_E7[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1319,7 +1319,7 @@ static wchar_t c2u_E7[256] = { 0x92E9,0x930F,0x92FA,0x9344,0x932E,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E8[256] = { +static const wchar_t c2u_E8[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1355,7 +1355,7 @@ static wchar_t c2u_E8[256] = { 0x984F,0x984B,0x986B,0x986F,0x9870,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E9[256] = { +static const wchar_t c2u_E9[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1391,7 +1391,7 @@ static wchar_t c2u_E9[256] = { 0x9D41,0x9D3F,0x9D3E,0x9D46,0x9D48,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_EA[256] = { +static const wchar_t c2u_EA[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1416,7 +1416,7 @@ static wchar_t c2u_EA[256] = { 0x69C7,0x9059,0x7464,0x51DC,0x7199,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ }; -static wchar_t c2u_ED[256] = { +static const wchar_t c2u_ED[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1452,7 +1452,7 @@ static wchar_t c2u_ED[256] = { 0x7147,0xFA15,0x71C1,0x71FE,0x72B1,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_EE[256] = { +static const wchar_t c2u_EE[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1488,7 +1488,7 @@ static wchar_t c2u_EE[256] = { 0x2179,0xFFE2,0xFFE4,0xFF07,0xFF02,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_FA[256] = { +static const wchar_t c2u_FA[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1524,7 +1524,7 @@ static wchar_t c2u_FA[256] = { 0x6C6F,0x6CDA,0x6D04,0x6D87,0x6D6F,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_FB[256] = { +static const wchar_t c2u_FB[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1560,7 +1560,7 @@ static wchar_t c2u_FB[256] = { 0x9927,0xFA2C,0x999E,0x9A4E,0x9AD9,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_FC[256] = { +static const wchar_t c2u_FC[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1573,7 +1573,7 @@ static wchar_t c2u_FC[256] = { 0x9D6B,0xFA2D,0x9E19,0x9ED1,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ }; -static wchar_t *page_charset2uni[256] = { +static const wchar_t *page_charset2uni[256] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -1608,7 +1608,7 @@ static wchar_t *page_charset2uni[256] = { NULL, NULL, c2u_FA, c2u_FB, c2u_FC, NULL, NULL, NULL, }; -static unsigned char u2c_00hi[256 - 0xA0][2] = { +static const unsigned char u2c_00hi[256 - 0xA0][2] = { {0x00, 0x00}, {0x00, 0x00}, {0x81, 0x91}, {0x81, 0x92},/* 0xA0-0xA3 */ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x81, 0x98},/* 0xA4-0xA7 */ {0x81, 0x4E}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},/* 0xA8-0xAB */ @@ -1635,7 +1635,7 @@ static unsigned char u2c_00hi[256 - 0xA0][2] = { {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},/* 0xFC-0xFF */ }; -static unsigned char u2c_03[512] = { +static const unsigned char u2c_03[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -1690,7 +1690,7 @@ static unsigned char u2c_03[512] = { 0x83, 0xD5, 0x83, 0xD6, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ }; -static unsigned char u2c_04[512] = { +static const unsigned char u2c_04[512] = { 0x00, 0x00, 0x84, 0x46, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -1714,7 +1714,7 @@ static unsigned char u2c_04[512] = { 0x00, 0x00, 0x84, 0x76, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ }; -static unsigned char u2c_20[512] = { +static const unsigned char u2c_20[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -1732,7 +1732,7 @@ static unsigned char u2c_20[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0xA6, /* 0x38-0x3B */ }; -static unsigned char u2c_21[512] = { +static const unsigned char u2c_21[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x8E, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -1790,7 +1790,7 @@ static unsigned char u2c_21[512] = { 0x81, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ }; -static unsigned char u2c_22[512] = { +static const unsigned char u2c_22[512] = { 0x81, 0xCD, 0x00, 0x00, 0x81, 0xDD, 0x81, 0xCE, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0xDE, /* 0x04-0x07 */ 0x81, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x81, 0xB9, /* 0x08-0x0B */ @@ -1842,7 +1842,7 @@ static unsigned char u2c_22[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x99, /* 0xBC-0xBF */ }; -static unsigned char u2c_23[512] = { +static const unsigned char u2c_23[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -1850,7 +1850,7 @@ static unsigned char u2c_23[512] = { 0x00, 0x00, 0x00, 0x00, 0x81, 0xDC, 0x00, 0x00, /* 0x10-0x13 */ }; -static unsigned char u2c_24[512] = { +static const unsigned char u2c_24[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -1882,7 +1882,7 @@ static unsigned char u2c_24[512] = { 0x87, 0x50, 0x87, 0x51, 0x87, 0x52, 0x87, 0x53, /* 0x70-0x73 */ }; -static unsigned char u2c_25[512] = { +static const unsigned char u2c_25[512] = { 0x84, 0x9F, 0x84, 0xAA, 0x84, 0xA0, 0x84, 0xAB, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -1946,7 +1946,7 @@ static unsigned char u2c_25[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0xFC, /* 0xEC-0xEF */ }; -static unsigned char u2c_26[512] = { +static const unsigned char u2c_26[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x81, 0x9A, 0x81, 0x99, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -1977,7 +1977,7 @@ static unsigned char u2c_26[512] = { 0x00, 0x00, 0x81, 0xF3, 0x00, 0x00, 0x81, 0xF2, /* 0x6C-0x6F */ }; -static unsigned char u2c_30[512] = { +static const unsigned char u2c_30[512] = { 0x81, 0x40, 0x81, 0x41, 0x81, 0x42, 0x81, 0x56, /* 0x00-0x03 */ 0x00, 0x00, 0x81, 0x58, 0x81, 0x59, 0x81, 0x5A, /* 0x04-0x07 */ 0x81, 0x71, 0x81, 0x72, 0x81, 0x73, 0x81, 0x74, /* 0x08-0x0B */ @@ -2045,7 +2045,7 @@ static unsigned char u2c_30[512] = { 0x81, 0x5B, 0x81, 0x52, 0x81, 0x53, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_32[512] = { +static const unsigned char u2c_32[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -2092,7 +2092,7 @@ static unsigned char u2c_32[512] = { 0x87, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ }; -static unsigned char u2c_33[512] = { +static const unsigned char u2c_33[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x65, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -2148,7 +2148,7 @@ static unsigned char u2c_33[512] = { 0x00, 0x00, 0x87, 0x83, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ }; -static unsigned char u2c_4E[512] = { +static const unsigned char u2c_4E[512] = { 0x88, 0xEA, 0x92, 0x9A, 0x00, 0x00, 0x8E, 0xB5, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x9C, /* 0x04-0x07 */ 0x8F, 0xE4, 0x8E, 0x4F, 0x8F, 0xE3, 0x89, 0xBA, /* 0x08-0x0B */ @@ -2216,7 +2216,7 @@ static unsigned char u2c_4E[512] = { 0xED, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_4F[512] = { +static const unsigned char u2c_4F[512] = { 0xED, 0x4F, 0x8A, 0xE9, 0x00, 0x00, 0xED, 0x50, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x98, 0xC2, 0x88, 0xC9, 0x00, 0x00, /* 0x08-0x0B */ @@ -2284,7 +2284,7 @@ static unsigned char u2c_4F[512] = { 0x00, 0x00, 0x00, 0x00, 0x98, 0xEA, 0xED, 0x5A, /* 0xFC-0xFF */ }; -static unsigned char u2c_50[512] = { +static const unsigned char u2c_50[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x98, 0xE4, 0x98, 0xED, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x91, 0x71, 0x00, 0x00, 0x8C, 0xC2, /* 0x08-0x0B */ @@ -2351,7 +2351,7 @@ static unsigned char u2c_50[512] = { 0x00, 0x00, 0x99, 0x4A, 0x00, 0x00, 0x95, 0xC6, /* 0xF8-0xFB */ }; -static unsigned char u2c_51[512] = { +static const unsigned char u2c_51[512] = { 0x8B, 0x56, 0x99, 0x4D, 0x99, 0x4E, 0x00, 0x00, /* 0x00-0x03 */ 0x89, 0xAD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x99, 0x4C, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -2419,7 +2419,7 @@ static unsigned char u2c_51[512] = { 0x00, 0x00, 0x94, 0x9F, 0x99, 0x82, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_52[512] = { +static const unsigned char u2c_52[512] = { 0x93, 0x81, 0x00, 0x00, 0x00, 0x00, 0x90, 0x6E, /* 0x00-0x03 */ 0x99, 0x83, 0x00, 0x00, 0x95, 0xAA, 0x90, 0xD8, /* 0x04-0x07 */ 0x8A, 0xA0, 0x00, 0x00, 0x8A, 0xA7, 0x99, 0x84, /* 0x08-0x0B */ @@ -2487,7 +2487,7 @@ static unsigned char u2c_52[512] = { 0x00, 0x00, 0x00, 0x00, 0x8C, 0xF9, 0x96, 0xDC, /* 0xFC-0xFF */ }; -static unsigned char u2c_53[512] = { +static const unsigned char u2c_53[512] = { 0xED, 0x6C, 0x96, 0xE6, 0x93, 0xF5, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x95, 0xEF, 0x99, 0xB0, 0xED, 0x6D, /* 0x04-0x07 */ 0x99, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -2554,7 +2554,7 @@ static unsigned char u2c_53[512] = { 0x8E, 0x69, 0x00, 0x00, 0x99, 0xDB, 0x00, 0x00, /* 0xF8-0xFB */ }; -static unsigned char u2c_54[512] = { +static const unsigned char u2c_54[512] = { 0x00, 0x00, 0x99, 0xDC, 0x00, 0x00, 0x8B, 0x68, /* 0x00-0x03 */ 0x8A, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x8D, 0x87, 0x8B, 0x67, 0x92, 0xDD, 0x89, 0x44, /* 0x08-0x0B */ @@ -2622,7 +2622,7 @@ static unsigned char u2c_54[512] = { 0x00, 0x00, 0x9A, 0x4A, 0x00, 0x00, 0xED, 0x77, /* 0xFC-0xFF */ }; -static unsigned char u2c_55[512] = { +static const unsigned char u2c_55[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x89, 0x53, 0x00, 0x00, 0x8D, 0xB4, 0x90, 0x4F, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -2690,7 +2690,7 @@ static unsigned char u2c_55[512] = { 0x00, 0x00, 0x9A, 0x75, 0x9A, 0x74, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_56[512] = { +static const unsigned char u2c_56[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x92, 0x51, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x89, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -2758,7 +2758,7 @@ static unsigned char u2c_56[512] = { 0x00, 0x00, 0x8D, 0x91, 0x00, 0x00, 0x9A, 0x9C, /* 0xFC-0xFF */ }; -static unsigned char u2c_57[512] = { +static const unsigned char u2c_57[512] = { 0x9A, 0x9B, 0x00, 0x00, 0x00, 0x00, 0x95, 0xDE, /* 0x00-0x03 */ 0x9A, 0x9D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x9A, 0x9F, 0x9A, 0x9E, 0x00, 0x00, 0x9A, 0xA0, /* 0x08-0x0B */ @@ -2826,7 +2826,7 @@ static unsigned char u2c_57[512] = { 0x8D, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_58[512] = { +static const unsigned char u2c_58[512] = { 0x96, 0x78, 0x00, 0x00, 0x93, 0xB0, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x8C, 0x98, 0x91, 0xCD, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x9A, 0xBF, 0x9A, 0xC2, /* 0x08-0x0B */ @@ -2894,7 +2894,7 @@ static unsigned char u2c_58[512] = { 0x9A, 0xE5, 0x9A, 0xE6, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_59[512] = { +static const unsigned char u2c_59[512] = { 0x00, 0x00, 0x00, 0x00, 0x9A, 0xE7, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x95, 0xCF, 0x9A, 0xE8, 0xED, 0x83, /* 0x08-0x0B */ @@ -2962,7 +2962,7 @@ static unsigned char u2c_59[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x70, /* 0xFC-0xFF */ }; -static unsigned char u2c_5A[512] = { +static const unsigned char u2c_5A[512] = { 0x00, 0x00, 0x88, 0xD0, 0x00, 0x00, 0x88, 0xA1, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x9B, 0x51, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -3029,7 +3029,7 @@ static unsigned char u2c_5A[512] = { 0x00, 0x00, 0x00, 0x00, 0x9B, 0x65, 0x9B, 0x66, /* 0xF8-0xFB */ }; -static unsigned char u2c_5B[512] = { +static const unsigned char u2c_5B[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x8A, 0xF0, 0x00, 0x00, 0x9B, 0x68, /* 0x08-0x0B */ @@ -3097,7 +3097,7 @@ static unsigned char u2c_5B[512] = { 0x00, 0x00, 0x00, 0x00, 0x91, 0xCE, 0x8E, 0xF5, /* 0xFC-0xFF */ }; -static unsigned char u2c_5C[512] = { +static const unsigned char u2c_5C[512] = { 0x00, 0x00, 0x95, 0x95, 0x90, 0xEA, 0x00, 0x00, /* 0x00-0x03 */ 0x8E, 0xCB, 0x9B, 0x91, 0x8F, 0xAB, 0x9B, 0x92, /* 0x04-0x07 */ 0x9B, 0x93, 0x88, 0xD1, 0x91, 0xB8, 0x90, 0x71, /* 0x08-0x0B */ @@ -3165,7 +3165,7 @@ static unsigned char u2c_5C[512] = { 0x00, 0x00, 0x9B, 0xB5, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_5D[512] = { +static const unsigned char u2c_5D[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x92, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0xBA, /* 0x08-0x0B */ @@ -3233,7 +3233,7 @@ static unsigned char u2c_5D[512] = { 0x00, 0x00, 0x92, 0x46, 0x8B, 0xD0, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_5E[512] = { +static const unsigned char u2c_5E[512] = { 0x00, 0x00, 0x00, 0x00, 0x8E, 0x73, 0x95, 0x7A, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x94, 0xBF, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0xE1, /* 0x08-0x0B */ @@ -3301,7 +3301,7 @@ static unsigned char u2c_5E[512] = { 0x94, 0x55, 0x00, 0x00, 0x9C, 0x4F, 0x93, 0xF9, /* 0xFC-0xFF */ }; -static unsigned char u2c_5F[512] = { +static const unsigned char u2c_5F[512] = { 0x00, 0x00, 0x95, 0xD9, 0x00, 0x00, 0x9C, 0x50, /* 0x00-0x03 */ 0x98, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x9C, 0x51, 0x95, 0xBE, 0x9C, 0x54, /* 0x08-0x0B */ @@ -3369,7 +3369,7 @@ static unsigned char u2c_5F[512] = { 0x00, 0x00, 0x8D, 0x9A, 0x00, 0x00, 0x9C, 0x7C, /* 0xFC-0xFF */ }; -static unsigned char u2c_60[512] = { +static const unsigned char u2c_60[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -3436,7 +3436,7 @@ static unsigned char u2c_60[512] = { 0x00, 0x00, 0x8E, 0xE4, 0x9C, 0xB7, 0x9C, 0xBA, /* 0xF8-0xFB */ }; -static unsigned char u2c_61[512] = { +static const unsigned char u2c_61[512] = { 0x9C, 0xB5, 0x8F, 0x44, 0x00, 0x00, 0x9C, 0xB8, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x9C, 0xB2, 0x00, 0x00, /* 0x04-0x07 */ 0x96, 0xFA, 0x96, 0xF9, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -3504,7 +3504,7 @@ static unsigned char u2c_61[512] = { 0x9C, 0xF4, 0x9C, 0xF3, 0x9C, 0xF5, 0x9C, 0xF2, /* 0xFC-0xFF */ }; -static unsigned char u2c_62[512] = { +static const unsigned char u2c_62[512] = { 0x9C, 0xF6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x9C, 0xF7, 0x9C, 0xF8, 0x95, 0xE8, 0x00, 0x00, /* 0x08-0x0B */ @@ -3572,7 +3572,7 @@ static unsigned char u2c_62[512] = { 0x00, 0x00, 0x00, 0x00, 0x8F, 0x45, 0x9D, 0x5C, /* 0xFC-0xFF */ }; -static unsigned char u2c_63[512] = { +static const unsigned char u2c_63[512] = { 0x00, 0x00, 0x8E, 0x9D, 0x9D, 0x6B, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x77, /* 0x04-0x07 */ 0x9D, 0x6C, 0x88, 0xC2, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -3639,7 +3639,7 @@ static unsigned char u2c_63[512] = { 0x00, 0x00, 0x00, 0x00, 0x97, 0x68, 0x00, 0x00, /* 0xF8-0xFB */ }; -static unsigned char u2c_64[512] = { +static const unsigned char u2c_64[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x9D, 0x8C, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -3707,7 +3707,7 @@ static unsigned char u2c_64[512] = { 0x00, 0x00, 0x9D, 0xB4, 0x8F, 0xEF, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_65[512] = { +static const unsigned char u2c_65[512] = { 0x9D, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x9D, 0xB7, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -3774,7 +3774,7 @@ static unsigned char u2c_65[512] = { 0x00, 0x00, 0x00, 0x00, 0x89, 0xA0, 0x9D, 0xDF, /* 0xF8-0xFB */ }; -static unsigned char u2c_66[512] = { +static const unsigned char u2c_66[512] = { 0xED, 0xB2, 0x00, 0x00, 0x8D, 0x56, 0x9D, 0xDE, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x8D, 0xA9, 0x8F, 0xB8, /* 0x04-0x07 */ 0x00, 0x00, 0xED, 0xB5, 0x9D, 0xDD, 0x00, 0x00, /* 0x08-0x0B */ @@ -3842,7 +3842,7 @@ static unsigned char u2c_66[512] = { 0x99, 0xD6, 0x91, 0x5D, 0x91, 0x5C, 0x91, 0xD6, /* 0xFC-0xFF */ }; -static unsigned char u2c_67[512] = { +static const unsigned char u2c_67[512] = { 0x8D, 0xC5, 0x00, 0x00, 0x00, 0x00, 0x98, 0xF0, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x8C, 0x8E, 0x97, 0x4C, 0x00, 0x00, 0x95, 0xFC, /* 0x08-0x0B */ @@ -3910,7 +3910,7 @@ static unsigned char u2c_67[512] = { 0x00, 0x00, 0x00, 0x00, 0x96, 0x8F, 0x8A, 0x60, /* 0xFC-0xFF */ }; -static unsigned char u2c_68[512] = { +static const unsigned char u2c_68[512] = { 0x00, 0x00, 0xED, 0xC9, 0x92, 0xCC, 0x93, 0xC8, /* 0x00-0x03 */ 0x89, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -3977,7 +3977,7 @@ static unsigned char u2c_68[512] = { 0x00, 0x00, 0x9E, 0xA8, 0x8A, 0xBB, 0x00, 0x00, /* 0xF8-0xFB */ }; -static unsigned char u2c_69[512] = { +static const unsigned char u2c_69[512] = { 0x98, 0x6F, 0x9E, 0x96, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x9E, 0xA4, 0x88, 0xD6, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x9E, 0x98, 0x00, 0x00, 0x00, 0x00, 0x96, 0xB8, /* 0x08-0x0B */ @@ -4045,7 +4045,7 @@ static unsigned char u2c_69[512] = { 0x00, 0x00, 0x91, 0x85, 0x00, 0x00, 0x9E, 0xDB, /* 0xFC-0xFF */ }; -static unsigned char u2c_6A[512] = { +static const unsigned char u2c_6A[512] = { 0x00, 0x00, 0x00, 0x00, 0x9E, 0xD9, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x9E, 0xE0, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x9E, 0xE6, 0x94, 0xF3, /* 0x08-0x0B */ @@ -4112,7 +4112,7 @@ static unsigned char u2c_6A[512] = { 0x00, 0x00, 0x00, 0x00, 0x9F, 0x51, 0x9F, 0x4E, /* 0xF8-0xFB */ }; -static unsigned char u2c_6B[512] = { +static const unsigned char u2c_6B[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x97, 0x93, 0x9F, 0x4F, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x9E, 0xDC, 0x00, 0x00, /* 0x08-0x0B */ @@ -4177,7 +4177,7 @@ static unsigned char u2c_6B[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x7D, /* 0xF0-0xF3 */ }; -static unsigned char u2c_6C[512] = { +static const unsigned char u2c_6C[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x9F, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4242,7 +4242,7 @@ static unsigned char u2c_6C[512] = { 0x91, 0xD7, 0x9F, 0x96, 0x00, 0x00, 0x89, 0x6A, /* 0xF0-0xF3 */ }; -static unsigned char u2c_6D[512] = { +static const unsigned char u2c_6D[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0xED, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x6D, /* 0x08-0x0B */ @@ -4310,7 +4310,7 @@ static unsigned char u2c_6D[512] = { 0xED, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_6E[512] = { +static const unsigned char u2c_6E[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x90, 0xB4, 0x00, 0x00, 0x8A, 0x89, /* 0x04-0x07 */ 0x8D, 0xCF, 0x8F, 0xC2, 0x9F, 0xBB, 0x8F, 0x61, /* 0x08-0x0B */ @@ -4378,7 +4378,7 @@ static unsigned char u2c_6E[512] = { 0x00, 0x00, 0x00, 0x00, 0x9F, 0xF6, 0x9F, 0xDE, /* 0xFC-0xFF */ }; -static unsigned char u2c_6F[512] = { +static const unsigned char u2c_6F[512] = { 0x00, 0x00, 0x8B, 0x99, 0x95, 0x59, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x8E, 0xBD, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x8D, 0x97, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4446,7 +4446,7 @@ static unsigned char u2c_6F[512] = { 0x00, 0x00, 0x00, 0x00, 0xE0, 0x68, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_70[512] = { +static const unsigned char u2c_70[512] = { 0x00, 0x00, 0xE0, 0x66, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xED, 0xEF, 0x00, 0x00, 0xED, 0xF0, /* 0x04-0x07 */ 0x00, 0x00, 0xE0, 0x62, 0x00, 0x00, 0xE0, 0x63, /* 0x08-0x0B */ @@ -4514,7 +4514,7 @@ static unsigned char u2c_70[512] = { 0x00, 0x00, 0xE0, 0x82, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_71[512] = { +static const unsigned char u2c_71[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0xED, 0xF5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xE0, 0x81, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4582,7 +4582,7 @@ static unsigned char u2c_71[512] = { 0xE0, 0x9E, 0x00, 0x00, 0xED, 0xFB, 0xE0, 0xA0, /* 0xFC-0xFF */ }; -static unsigned char u2c_72[512] = { +static const unsigned char u2c_72[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x94, 0x9A, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4650,7 +4650,7 @@ static unsigned char u2c_72[512] = { 0x98, 0x54, 0x94, 0x82, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_73[512] = { +static const unsigned char u2c_73[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xE0, 0xC7, 0x00, 0x00, /* 0x08-0x0B */ @@ -4718,7 +4718,7 @@ static unsigned char u2c_73[512] = { 0x00, 0x00, 0x00, 0x00, 0x8C, 0xBB, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_74[512] = { +static const unsigned char u2c_74[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x85, /* 0x00-0x03 */ 0x00, 0x00, 0xE0, 0xE4, 0x97, 0x9D, 0xEE, 0x49, /* 0x04-0x07 */ 0x00, 0x00, 0x97, 0xAE, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4785,7 +4785,7 @@ static unsigned char u2c_74[512] = { 0xE1, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ }; -static unsigned char u2c_75[512] = { +static const unsigned char u2c_75[512] = { 0x00, 0x00, 0xEE, 0x52, 0x00, 0x00, 0xE1, 0x4B, /* 0x00-0x03 */ 0xE1, 0x4A, 0xE1, 0x4C, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4853,7 +4853,7 @@ static unsigned char u2c_75[512] = { 0xE1, 0x80, 0x00, 0x00, 0xE1, 0x7D, 0xE1, 0x7E, /* 0xFC-0xFF */ }; -static unsigned char u2c_76[512] = { +static const unsigned char u2c_76[512] = { 0x00, 0x00, 0xE1, 0x81, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xE1, 0x88, 0x00, 0x00, 0xE1, 0x86, /* 0x08-0x0B */ @@ -4921,7 +4921,7 @@ static unsigned char u2c_76[512] = { 0x00, 0x00, 0x00, 0x00, 0x8F, 0x82, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_77[512] = { +static const unsigned char u2c_77[512] = { 0x00, 0x00, 0x8F, 0xC8, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0xE1, 0xBE, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xBD, /* 0x04-0x07 */ 0xE1, 0xBC, 0x94, 0xFB, 0x00, 0x00, 0x8A, 0xC5, /* 0x08-0x0B */ @@ -4989,7 +4989,7 @@ static unsigned char u2c_77[512] = { 0xE1, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_78[512] = { +static const unsigned char u2c_78[512] = { 0x00, 0x00, 0x00, 0x00, 0x8D, 0xBB, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -5057,7 +5057,7 @@ static unsigned char u2c_78[512] = { 0x00, 0x00, 0xE2, 0x42, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_79[512] = { +static const unsigned char u2c_79[512] = { 0x00, 0x00, 0x8F, 0xCA, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0x44, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -5124,7 +5124,7 @@ static unsigned char u2c_79[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xDA, /* 0xF8-0xFB */ }; -static unsigned char u2c_7A[512] = { +static const unsigned char u2c_7A[512] = { 0x8B, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0xE2, 0x62, 0x00, 0x00, 0x00, 0x00, 0x92, 0xF6, /* 0x08-0x0B */ @@ -5192,7 +5192,7 @@ static unsigned char u2c_7A[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xC6, /* 0xFC-0xFF */ }; -static unsigned char u2c_7B[512] = { +static const unsigned char u2c_7B[512] = { 0x00, 0x00, 0x00, 0x00, 0xE2, 0x93, 0x00, 0x00, /* 0x00-0x03 */ 0xE2, 0xA0, 0x00, 0x00, 0xE2, 0x96, 0x00, 0x00, /* 0x04-0x07 */ 0x8B, 0x88, 0x00, 0x00, 0xE2, 0x95, 0xE2, 0xA2, /* 0x08-0x0B */ @@ -5258,7 +5258,7 @@ static unsigned char u2c_7B[512] = { 0x00, 0x00, 0x00, 0x00, 0xE2, 0xCC, 0xE2, 0xC9, /* 0xF4-0xF7 */ }; -static unsigned char u2c_7C[512] = { +static const unsigned char u2c_7C[512] = { 0xE2, 0xC5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xC6, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -5326,7 +5326,7 @@ static unsigned char u2c_7C[512] = { 0x00, 0x00, 0x00, 0x00, 0x8B, 0x8A, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_7D[512] = { +static const unsigned char u2c_7D[512] = { 0x8B, 0x49, 0x00, 0x00, 0xE3, 0x40, 0x00, 0x00, /* 0x00-0x03 */ 0x96, 0xF1, 0x8D, 0x67, 0xE2, 0xFC, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xE3, 0x43, 0x96, 0xE4, /* 0x08-0x0B */ @@ -5393,7 +5393,7 @@ static unsigned char u2c_7D[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0x6B, /* 0xF8-0xFB */ }; -static unsigned char u2c_7E[512] = { +static const unsigned char u2c_7E[512] = { 0x00, 0x00, 0x89, 0x8F, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x93, 0xEA, 0xE3, 0x6E, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xE3, 0x75, 0xE3, 0x6F, 0xE3, 0x76, /* 0x08-0x0B */ @@ -5437,7 +5437,7 @@ static unsigned char u2c_7E[512] = { 0xE3, 0x9C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ }; -static unsigned char u2c_7F[512] = { +static const unsigned char u2c_7F[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -5505,7 +5505,7 @@ static unsigned char u2c_7F[512] = { 0x97, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_80[512] = { +static const unsigned char u2c_80[512] = { 0x97, 0x73, 0x98, 0x56, 0x00, 0x00, 0x8D, 0x6C, /* 0x00-0x03 */ 0xE3, 0xCC, 0x8E, 0xD2, 0xE3, 0xCB, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xCD, /* 0x08-0x0B */ @@ -5573,7 +5573,7 @@ static unsigned char u2c_80[512] = { 0xE4, 0x45, 0x94, 0x5C, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_81[512] = { +static const unsigned char u2c_81[512] = { 0x00, 0x00, 0x00, 0x00, 0x8E, 0x89, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x8B, 0xBA, 0x90, 0xC6, 0x98, 0x65, /* 0x04-0x07 */ 0x96, 0xAC, 0xE3, 0xF5, 0x90, 0xD2, 0x00, 0x00, /* 0x08-0x0B */ @@ -5641,7 +5641,7 @@ static unsigned char u2c_81[512] = { 0x89, 0x50, 0x00, 0x00, 0xE4, 0x6B, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_82[512] = { +static const unsigned char u2c_82[512] = { 0x00, 0x00, 0xE4, 0x6C, 0xE4, 0x6D, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xE4, 0x6E, 0x00, 0x00, 0xE4, 0x6F, /* 0x04-0x07 */ 0x8B, 0xBB, 0x9D, 0xA8, 0xE4, 0x70, 0x00, 0x00, /* 0x08-0x0B */ @@ -5708,7 +5708,7 @@ static unsigned char u2c_82[512] = { 0x00, 0x00, 0xE4, 0x99, 0xE4, 0x95, 0xE4, 0x98, /* 0xF8-0xFB */ }; -static unsigned char u2c_83[512] = { +static const unsigned char u2c_83[512] = { 0x00, 0x00, 0xEE, 0x76, 0x96, 0xCE, 0xE4, 0x97, /* 0x00-0x03 */ 0x89, 0xD6, 0x8A, 0x9D, 0xE4, 0x9B, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xE4, 0x9D, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -5776,7 +5776,7 @@ static unsigned char u2c_83[512] = { 0x00, 0x00, 0xE4, 0xC1, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_84[512] = { +static const unsigned char u2c_84[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xC2, /* 0x00-0x03 */ 0x93, 0xB8, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xC7, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xC4, /* 0x08-0x0B */ @@ -5844,7 +5844,7 @@ static unsigned char u2c_84[512] = { 0xE4, 0xF8, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xF0, /* 0xFC-0xFF */ }; -static unsigned char u2c_85[512] = { +static const unsigned char u2c_85[512] = { 0x8E, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0xE4, 0xCF, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -5912,7 +5912,7 @@ static unsigned char u2c_85[512] = { 0x00, 0x00, 0x00, 0x00, 0xE5, 0x60, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_86[512] = { +static const unsigned char u2c_86[512] = { 0x00, 0x00, 0x00, 0x00, 0xE5, 0x41, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0xE5, 0x62, 0x91, 0x68, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xE5, 0x5D, 0xE5, 0x5F, /* 0x08-0x0B */ @@ -5980,7 +5980,7 @@ static unsigned char u2c_86[512] = { 0x00, 0x00, 0x00, 0x00, 0x89, 0xE9, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_87[512] = { +static const unsigned char u2c_87[512] = { 0xE5, 0x86, 0x00, 0x00, 0x96, 0x49, 0xE5, 0x87, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0xE5, 0x84, 0x00, 0x00, /* 0x04-0x07 */ 0xE5, 0x85, 0xE5, 0x8A, 0xE5, 0x8D, 0x00, 0x00, /* 0x08-0x0B */ @@ -6048,7 +6048,7 @@ static unsigned char u2c_87[512] = { 0x00, 0x00, 0x00, 0x00, 0xE5, 0xB7, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_88[512] = { +static const unsigned char u2c_88[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xE5, 0xA2, 0x00, 0x00, 0xEE, 0x85, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -6116,7 +6116,7 @@ static unsigned char u2c_88[512] = { 0xE5, 0xE7, 0x90, 0xBB, 0x90, 0x9E, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_89[512] = { +static const unsigned char u2c_89[512] = { 0x00, 0x00, 0x00, 0x00, 0xE5, 0xE6, 0x00, 0x00, /* 0x00-0x03 */ 0xE5, 0xEB, 0x00, 0x00, 0x00, 0x00, 0x95, 0xA1, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xE5, 0xED, 0x00, 0x00, /* 0x08-0x0B */ @@ -6183,7 +6183,7 @@ static unsigned char u2c_89[512] = { 0xE6, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ }; -static unsigned char u2c_8A[512] = { +static const unsigned char u2c_8A[512] = { 0x8C, 0xBE, 0x00, 0x00, 0x92, 0xF9, 0xE6, 0x5D, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x8C, 0x76, 0x00, 0x00, 0x90, 0x75, 0x00, 0x00, /* 0x08-0x0B */ @@ -6251,7 +6251,7 @@ static unsigned char u2c_8A[512] = { 0x00, 0x00, 0x00, 0x00, 0x91, 0xF8, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_8B[512] = { +static const unsigned char u2c_8B[512] = { 0x96, 0x64, 0x89, 0x79, 0x88, 0xE0, 0x00, 0x00, /* 0x00-0x03 */ 0x93, 0xA3, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x89, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -6294,7 +6294,7 @@ static unsigned char u2c_8B[512] = { 0x00, 0x00, 0xE6, 0xAA, 0xE6, 0xAB, 0x00, 0x00, /* 0x98-0x9B */ }; -static unsigned char u2c_8C[512] = { +static const unsigned char u2c_8C[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -6362,7 +6362,7 @@ static unsigned char u2c_8C[512] = { 0x8D, 0x77, 0xE6, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_8D[512] = { +static const unsigned char u2c_8D[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0xE6, 0xD1, 0xE6, 0xD2, 0x00, 0x00, 0xE6, 0xD4, /* 0x04-0x07 */ 0x91, 0xA1, 0x00, 0x00, 0xE6, 0xD3, 0x8A, 0xE4, /* 0x08-0x0B */ @@ -6430,7 +6430,7 @@ static unsigned char u2c_8D[512] = { 0xE6, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xF3, /* 0xFC-0xFF */ }; -static unsigned char u2c_8E[512] = { +static const unsigned char u2c_8E[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0xE6, 0xF1, 0xE6, 0xF2, 0x97, 0x78, 0x00, 0x00, /* 0x08-0x0B */ @@ -6498,7 +6498,7 @@ static unsigned char u2c_8E[512] = { 0xE7, 0x64, 0x8C, 0x79, 0xE7, 0x67, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_8F[512] = { +static const unsigned char u2c_8F[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x72, /* 0x00-0x03 */ 0x00, 0x00, 0xE7, 0x69, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x8D, 0xDA, 0xE7, 0x68, 0x00, 0x00, /* 0x08-0x0B */ @@ -6566,7 +6566,7 @@ static unsigned char u2c_8F[512] = { 0x00, 0x00, 0x92, 0xC7, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_90[512] = { +static const unsigned char u2c_90[512] = { 0x91, 0xDE, 0x91, 0x97, 0x00, 0x00, 0x93, 0xA6, /* 0x00-0x03 */ 0x00, 0x00, 0xE7, 0x90, 0x8B, 0x74, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x99, /* 0x08-0x0B */ @@ -6634,7 +6634,7 @@ static unsigned char u2c_90[512] = { 0x00, 0x00, 0x93, 0x73, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_91[512] = { +static const unsigned char u2c_91[512] = { 0x00, 0x00, 0x00, 0x00, 0xE7, 0xBD, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -6702,7 +6702,7 @@ static unsigned char u2c_91[512] = { 0xE7, 0xDD, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xE1, /* 0xFC-0xFF */ }; -static unsigned char u2c_92[512] = { +static const unsigned char u2c_92[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0xEE, 0xA5, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xEE, 0xA7, 0x00, 0x00, /* 0x08-0x0B */ @@ -6770,7 +6770,7 @@ static unsigned char u2c_92[512] = { 0x8D, 0x7C, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xC0, /* 0xFC-0xFF */ }; -static unsigned char u2c_93[512] = { +static const unsigned char u2c_93[512] = { 0x00, 0x00, 0x00, 0x00, 0xEE, 0xC2, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x8E, 0x4B, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -6837,7 +6837,7 @@ static unsigned char u2c_93[512] = { 0xEE, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ }; -static unsigned char u2c_94[512] = { +static const unsigned char u2c_94[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x5E, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x5F, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -6874,7 +6874,7 @@ static unsigned char u2c_94[512] = { 0x00, 0x00, 0xE8, 0x76, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ }; -static unsigned char u2c_95[512] = { +static const unsigned char u2c_95[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -6936,7 +6936,7 @@ static unsigned char u2c_95[512] = { 0x00, 0x00, 0xE8, 0x92, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ }; -static unsigned char u2c_96[512] = { +static const unsigned char u2c_96[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -7003,7 +7003,7 @@ static unsigned char u2c_96[512] = { 0x00, 0x00, 0xE8, 0xB9, 0x00, 0x00, 0x93, 0x64, /* 0xF8-0xFB */ }; -static unsigned char u2c_97[512] = { +static const unsigned char u2c_97[512] = { 0x8E, 0xF9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0xE8, 0xBA, 0x00, 0x00, 0xE8, 0xBB, 0x90, 0x6B, /* 0x04-0x07 */ 0xE8, 0xBC, 0x00, 0x00, 0x97, 0xEC, 0x00, 0x00, /* 0x08-0x0B */ @@ -7071,7 +7071,7 @@ static unsigned char u2c_97[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0xBF, /* 0xFC-0xFF */ }; -static unsigned char u2c_98[512] = { +static const unsigned char u2c_98[512] = { 0x00, 0x00, 0x95, 0xC5, 0x92, 0xB8, 0x8D, 0xA0, /* 0x00-0x03 */ 0x00, 0x00, 0x8D, 0x80, 0x8F, 0x87, 0x00, 0x00, /* 0x04-0x07 */ 0x90, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -7139,7 +7139,7 @@ static unsigned char u2c_98[512] = { 0x8E, 0x94, 0x96, 0x4F, 0x8F, 0xFC, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_99[512] = { +static const unsigned char u2c_99[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x4C, /* 0x00-0x03 */ 0x00, 0x00, 0x96, 0xDD, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xE9, 0x4D, 0x97, 0x7B, 0x00, 0x00, /* 0x08-0x0B */ @@ -7207,7 +7207,7 @@ static unsigned char u2c_99[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x78, /* 0xFC-0xFF */ }; -static unsigned char u2c_9A[512] = { +static const unsigned char u2c_9A[512] = { 0x00, 0x00, 0xE9, 0x74, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xE9, 0x76, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -7274,7 +7274,7 @@ static unsigned char u2c_9A[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x9F, /* 0xF8-0xFB */ }; -static unsigned char u2c_9B[512] = { +static const unsigned char u2c_9B[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0xE9, 0xA0, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -7340,7 +7340,7 @@ static unsigned char u2c_9B[512] = { 0x00, 0x00, 0x88, 0xB1, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ }; -static unsigned char u2c_9C[512] = { +static const unsigned char u2c_9C[512] = { 0xEE, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0xE9, 0xD8, 0x00, 0x00, 0xE9, 0xD4, 0x00, 0x00, /* 0x04-0x07 */ 0xE9, 0xD5, 0xE9, 0xD1, 0xE9, 0xD7, 0x00, 0x00, /* 0x08-0x0B */ @@ -7406,7 +7406,7 @@ static unsigned char u2c_9C[512] = { 0x96, 0xC2, 0x00, 0x00, 0x93, 0xCE, 0x00, 0x00, /* 0xF4-0xF7 */ }; -static unsigned char u2c_9D[512] = { +static const unsigned char u2c_9D[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0xEE, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0xE9, 0xEF, 0x93, 0xBC, /* 0x04-0x07 */ 0xE9, 0xEC, 0xE9, 0xEB, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -7474,7 +7474,7 @@ static unsigned char u2c_9D[512] = { 0x00, 0x00, 0xEA, 0x5E, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_9E[512] = { +static const unsigned char u2c_9E[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -7542,7 +7542,7 @@ static unsigned char u2c_9E[512] = { 0xEA, 0x85, 0xEA, 0x86, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_9F[512] = { +static const unsigned char u2c_9F[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x87, /* 0x04-0x07 */ 0xEA, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -7587,11 +7587,11 @@ static unsigned char u2c_9F[512] = { 0xEA, 0x9E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ }; -static unsigned char u2c_DC[512] = { +static const unsigned char u2c_DC[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ }; -static unsigned char u2c_F9[512] = { +static const unsigned char u2c_F9[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -7651,7 +7651,7 @@ static unsigned char u2c_F9[512] = { 0xEE, 0xCD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ }; -static unsigned char u2c_FA[512] = { +static const unsigned char u2c_FA[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -7666,7 +7666,7 @@ static unsigned char u2c_FA[512] = { 0xEE, 0xDD, 0xEE, 0xEA, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ }; -static unsigned char u2c_FF[512] = { +static const unsigned char u2c_FF[512] = { 0x00, 0x00, 0x81, 0x49, 0xEE, 0xFC, 0x81, 0x94, /* 0x00-0x03 */ 0x81, 0x90, 0x81, 0x93, 0x81, 0x95, 0xEE, 0xFB, /* 0x04-0x07 */ 0x81, 0x69, 0x81, 0x6A, 0x81, 0x96, 0x81, 0x7B, /* 0x08-0x0B */ @@ -7728,7 +7728,7 @@ static unsigned char u2c_FF[512] = { 0xEE, 0xFA, 0x81, 0x8F, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { NULL, NULL, NULL, u2c_03, u2c_04, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -7762,7 +7762,7 @@ static unsigned char *page_uni2charset[256] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, u2c_F9, u2c_FA, NULL, NULL, NULL, NULL, u2c_FF, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -7798,7 +7798,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -7837,7 +7837,7 @@ static unsigned char charset2upper[256] = { static int uni2char(const wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni&0xFF; unsigned char ch = (uni>>8)&0xFF; @@ -7878,7 +7878,7 @@ static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) { unsigned char ch, cl; - wchar_t *charset2uni; + const wchar_t *charset2uni; if (boundlen <= 0) return -ENAMETOOLONG; diff --git a/fs/nls/nls_cp936.c b/fs/nls/nls_cp936.c index 65e640c61c8b..82770301bc3d 100644 --- a/fs/nls/nls_cp936.c +++ b/fs/nls/nls_cp936.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t c2u_81[256] = { +static const wchar_t c2u_81[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -49,7 +49,7 @@ static wchar_t c2u_81[256] = { 0x4F99,0x4F9A,0x4F9C,0x4F9E,0x4F9F,0x4FA1,0x4FA2,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_82[256] = { +static const wchar_t c2u_82[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -85,7 +85,7 @@ static wchar_t c2u_82[256] = { 0x50B4,0x50B5,0x50B6,0x50B7,0x50B8,0x50B9,0x50BC,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_83[256] = { +static const wchar_t c2u_83[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -121,7 +121,7 @@ static wchar_t c2u_83[256] = { 0x51D0,0x51D2,0x51D3,0x51D4,0x51D5,0x51D6,0x51D7,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_84[256] = { +static const wchar_t c2u_84[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -157,7 +157,7 @@ static wchar_t c2u_84[256] = { 0x5304,0x5307,0x5309,0x530A,0x530B,0x530C,0x530E,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_85[256] = { +static const wchar_t c2u_85[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -193,7 +193,7 @@ static wchar_t c2u_85[256] = { 0x5497,0x5498,0x549C,0x549E,0x549F,0x54A0,0x54A1,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_86[256] = { +static const wchar_t c2u_86[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -229,7 +229,7 @@ static wchar_t c2u_86[256] = { 0x55FB,0x55FC,0x55FF,0x5602,0x5603,0x5604,0x5605,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_87[256] = { +static const wchar_t c2u_87[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -265,7 +265,7 @@ static wchar_t c2u_87[256] = { 0x570B,0x570C,0x570D,0x570E,0x570F,0x5710,0x5711,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_88[256] = { +static const wchar_t c2u_88[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -301,7 +301,7 @@ static wchar_t c2u_88[256] = { 0x5837,0x5838,0x5839,0x583A,0x583B,0x583C,0x583D,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_89[256] = { +static const wchar_t c2u_89[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -337,7 +337,7 @@ static wchar_t c2u_89[256] = { 0x592C,0x5930,0x5932,0x5933,0x5935,0x5936,0x593B,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_8A[256] = { +static const wchar_t c2u_8A[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -373,7 +373,7 @@ static wchar_t c2u_8A[256] = { 0x5A59,0x5A5B,0x5A5C,0x5A5D,0x5A5E,0x5A5F,0x5A60,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_8B[256] = { +static const wchar_t c2u_8B[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -409,7 +409,7 @@ static wchar_t c2u_8B[256] = { 0x5B41,0x5B42,0x5B43,0x5B44,0x5B45,0x5B46,0x5B47,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_8C[256] = { +static const wchar_t c2u_8C[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -445,7 +445,7 @@ static wchar_t c2u_8C[256] = { 0x5CA0,0x5CA1,0x5CA4,0x5CA5,0x5CA6,0x5CA7,0x5CA8,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_8D[256] = { +static const wchar_t c2u_8D[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -481,7 +481,7 @@ static wchar_t c2u_8D[256] = { 0x5D98,0x5D9A,0x5D9B,0x5D9C,0x5D9E,0x5D9F,0x5DA0,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_8E[256] = { +static const wchar_t c2u_8E[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -517,7 +517,7 @@ static wchar_t c2u_8E[256] = { 0x5EBF,0x5EC0,0x5EC1,0x5EC2,0x5EC3,0x5EC4,0x5EC5,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_8F[256] = { +static const wchar_t c2u_8F[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -553,7 +553,7 @@ static wchar_t c2u_8F[256] = { 0x5FF4,0x5FF6,0x5FF7,0x5FF9,0x5FFA,0x5FFC,0x6007,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_90[256] = { +static const wchar_t c2u_90[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -589,7 +589,7 @@ static wchar_t c2u_90[256] = { 0x6140,0x6141,0x6142,0x6143,0x6144,0x6145,0x6146,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_91[256] = { +static const wchar_t c2u_91[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -625,7 +625,7 @@ static wchar_t c2u_91[256] = { 0x623B,0x623C,0x6242,0x6244,0x6245,0x6246,0x624A,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_92[256] = { +static const wchar_t c2u_92[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -661,7 +661,7 @@ static wchar_t c2u_92[256] = { 0x63B5,0x63B6,0x63B9,0x63BB,0x63BD,0x63BF,0x63C0,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_93[256] = { +static const wchar_t c2u_93[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -697,7 +697,7 @@ static wchar_t c2u_93[256] = { 0x64D1,0x64D3,0x64D4,0x64D5,0x64D6,0x64D9,0x64DA,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_94[256] = { +static const wchar_t c2u_94[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -733,7 +733,7 @@ static wchar_t c2u_94[256] = { 0x65DE,0x65DF,0x65E1,0x65E3,0x65E4,0x65EA,0x65EB,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_95[256] = { +static const wchar_t c2u_95[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -769,7 +769,7 @@ static wchar_t c2u_95[256] = { 0x66F8,0x66FA,0x66FB,0x66FD,0x6701,0x6702,0x6703,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_96[256] = { +static const wchar_t c2u_96[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -805,7 +805,7 @@ static wchar_t c2u_96[256] = { 0x6852,0x6856,0x6857,0x6858,0x6859,0x685A,0x685B,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_97[256] = { +static const wchar_t c2u_97[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -841,7 +841,7 @@ static wchar_t c2u_97[256] = { 0x6955,0x6956,0x6958,0x6959,0x695B,0x695C,0x695F,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_98[256] = { +static const wchar_t c2u_98[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -877,7 +877,7 @@ static wchar_t c2u_98[256] = { 0x6A52,0x6A53,0x6A54,0x6A55,0x6A56,0x6A57,0x6A5A,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_99[256] = { +static const wchar_t c2u_99[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -913,7 +913,7 @@ static wchar_t c2u_99[256] = { 0x6B28,0x6B29,0x6B2A,0x6B2B,0x6B2C,0x6B2D,0x6B2E,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_9A[256] = { +static const wchar_t c2u_9A[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -949,7 +949,7 @@ static wchar_t c2u_9A[256] = { 0x6C4E,0x6C4F,0x6C51,0x6C52,0x6C53,0x6C56,0x6C58,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_9B[256] = { +static const wchar_t c2u_9B[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -985,7 +985,7 @@ static wchar_t c2u_9B[256] = { 0x6DBE,0x6DC1,0x6DC2,0x6DC3,0x6DC8,0x6DC9,0x6DCA,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_9C[256] = { +static const wchar_t c2u_9C[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1021,7 +1021,7 @@ static wchar_t c2u_9C[256] = { 0x6EE7,0x6EEA,0x6EEB,0x6EEC,0x6EED,0x6EEE,0x6EEF,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_9D[256] = { +static const wchar_t c2u_9D[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1057,7 +1057,7 @@ static wchar_t c2u_9D[256] = { 0x6FDC,0x6FDD,0x6FDF,0x6FE2,0x6FE3,0x6FE4,0x6FE5,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_9E[256] = { +static const wchar_t c2u_9E[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1093,7 +1093,7 @@ static wchar_t c2u_9E[256] = { 0x70D2,0x70D3,0x70D4,0x70D5,0x70D6,0x70D7,0x70DA,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_9F[256] = { +static const wchar_t c2u_9F[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1129,7 +1129,7 @@ static wchar_t c2u_9F[256] = { 0x71CC,0x71CD,0x71CF,0x71D0,0x71D1,0x71D2,0x71D3,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_A0[256] = { +static const wchar_t c2u_A0[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1165,7 +1165,7 @@ static wchar_t c2u_A0[256] = { 0x72D3,0x72D4,0x72D5,0x72D6,0x72D8,0x72DA,0x72DB,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_A1[256] = { +static const wchar_t c2u_A1[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1201,7 +1201,7 @@ static wchar_t c2u_A1[256] = { 0x25B2,0x203B,0x2192,0x2190,0x2191,0x2193,0x3013,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_A2[256] = { +static const wchar_t c2u_A2[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1237,7 +1237,7 @@ static wchar_t c2u_A2[256] = { 0x2167,0x2168,0x2169,0x216A,0x216B,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_A3[256] = { +static const wchar_t c2u_A3[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1273,7 +1273,7 @@ static wchar_t c2u_A3[256] = { 0xFF58,0xFF59,0xFF5A,0xFF5B,0xFF5C,0xFF5D,0xFFE3,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_A4[256] = { +static const wchar_t c2u_A4[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1308,7 +1308,7 @@ static wchar_t c2u_A4[256] = { 0x3090,0x3091,0x3092,0x3093,0x0000,0x0000,0x0000,0x0000,/* 0xF0-0xF7 */ }; -static wchar_t c2u_A5[256] = { +static const wchar_t c2u_A5[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1343,7 +1343,7 @@ static wchar_t c2u_A5[256] = { 0x30F0,0x30F1,0x30F2,0x30F3,0x30F4,0x30F5,0x30F6,0x0000,/* 0xF0-0xF7 */ }; -static wchar_t c2u_A6[256] = { +static const wchar_t c2u_A6[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1378,7 +1378,7 @@ static wchar_t c2u_A6[256] = { 0xFE37,0xFE38,0xFE31,0x0000,0xFE33,0xFE34,0x0000,0x0000,/* 0xF0-0xF7 */ }; -static wchar_t c2u_A7[256] = { +static const wchar_t c2u_A7[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1413,7 +1413,7 @@ static wchar_t c2u_A7[256] = { 0x044E,0x044F,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xF0-0xF7 */ }; -static wchar_t c2u_A8[256] = { +static const wchar_t c2u_A8[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1447,7 +1447,7 @@ static wchar_t c2u_A8[256] = { 0x3128,0x3129,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xE8-0xEF */ }; -static wchar_t c2u_A9[256] = { +static const wchar_t c2u_A9[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1481,7 +1481,7 @@ static wchar_t c2u_A9[256] = { 0x2544,0x2545,0x2546,0x2547,0x2548,0x2549,0x254A,0x254B,/* 0xE8-0xEF */ }; -static wchar_t c2u_AA[256] = { +static const wchar_t c2u_AA[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1506,7 +1506,7 @@ static wchar_t c2u_AA[256] = { 0x7371,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ }; -static wchar_t c2u_AB[256] = { +static const wchar_t c2u_AB[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1531,7 +1531,7 @@ static wchar_t c2u_AB[256] = { 0x73F7,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ }; -static wchar_t c2u_AC[256] = { +static const wchar_t c2u_AC[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1556,7 +1556,7 @@ static wchar_t c2u_AC[256] = { 0x747A,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ }; -static wchar_t c2u_AD[256] = { +static const wchar_t c2u_AD[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1581,7 +1581,7 @@ static wchar_t c2u_AD[256] = { 0x74F2,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ }; -static wchar_t c2u_AE[256] = { +static const wchar_t c2u_AE[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1606,7 +1606,7 @@ static wchar_t c2u_AE[256] = { 0x7587,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ }; -static wchar_t c2u_AF[256] = { +static const wchar_t c2u_AF[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1631,7 +1631,7 @@ static wchar_t c2u_AF[256] = { 0x7644,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ }; -static wchar_t c2u_B0[256] = { +static const wchar_t c2u_B0[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1667,7 +1667,7 @@ static wchar_t c2u_B0[256] = { 0x508D,0x8C24,0x82DE,0x80DE,0x5305,0x8912,0x5265,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B1[256] = { +static const wchar_t c2u_B1[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1703,7 +1703,7 @@ static wchar_t c2u_B1[256] = { 0x5175,0x51B0,0x67C4,0x4E19,0x79C9,0x997C,0x70B3,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B2[256] = { +static const wchar_t c2u_B2[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1739,7 +1739,7 @@ static wchar_t c2u_B2[256] = { 0x7F20,0x94F2,0x4EA7,0x9610,0x98A4,0x660C,0x7316,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B3[256] = { +static const wchar_t c2u_B3[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1775,7 +1775,7 @@ static wchar_t c2u_B3[256] = { 0x53A8,0x8E87,0x9504,0x96CF,0x6EC1,0x9664,0x695A,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B4[256] = { +static const wchar_t c2u_B4[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1811,7 +1811,7 @@ static wchar_t c2u_B4[256] = { 0x5E26,0x6B86,0x4EE3,0x8D37,0x888B,0x5F85,0x902E,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B5[256] = { +static const wchar_t c2u_B5[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1847,7 +1847,7 @@ static wchar_t c2u_B5[256] = { 0x8DCC,0x7239,0x789F,0x8776,0x8FED,0x8C0D,0x53E0,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B6[256] = { +static const wchar_t c2u_B6[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1883,7 +1883,7 @@ static wchar_t c2u_B6[256] = { 0x800C,0x513F,0x8033,0x5C14,0x9975,0x6D31,0x4E8C,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B7[256] = { +static const wchar_t c2u_B7[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1919,7 +1919,7 @@ static wchar_t c2u_B7[256] = { 0x8F90,0x5E45,0x6C1F,0x7B26,0x4F0F,0x4FD8,0x670D,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B8[256] = { +static const wchar_t c2u_B8[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1955,7 +1955,7 @@ static wchar_t c2u_B8[256] = { 0x7ED9,0x6839,0x8DDF,0x8015,0x66F4,0x5E9A,0x7FB9,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B9[256] = { +static const wchar_t c2u_B9[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1991,7 +1991,7 @@ static wchar_t c2u_B9[256] = { 0x9505,0x90ED,0x56FD,0x679C,0x88F9,0x8FC7,0x54C8,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_BA[256] = { +static const wchar_t c2u_BA[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2027,7 +2027,7 @@ static wchar_t c2u_BA[256] = { 0x58F6,0x846B,0x80E1,0x8774,0x72D0,0x7CCA,0x6E56,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_BB[256] = { +static const wchar_t c2u_BB[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2063,7 +2063,7 @@ static wchar_t c2u_BB[256] = { 0x573E,0x57FA,0x673A,0x7578,0x7A3D,0x79EF,0x7B95,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_BC[256] = { +static const wchar_t c2u_BC[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2099,7 +2099,7 @@ static wchar_t c2u_BC[256] = { 0x9274,0x8DF5,0x8D31,0x89C1,0x952E,0x7BAD,0x4EF6,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_BD[256] = { +static const wchar_t c2u_BD[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2135,7 +2135,7 @@ static wchar_t c2u_BD[256] = { 0x8FDB,0x9773,0x664B,0x7981,0x8FD1,0x70EC,0x6D78,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_BE[256] = { +static const wchar_t c2u_BE[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2171,7 +2171,7 @@ static wchar_t c2u_BE[256] = { 0x7EDD,0x5747,0x83CC,0x94A7,0x519B,0x541B,0x5CFB,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_BF[256] = { +static const wchar_t c2u_BF[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2207,7 +2207,7 @@ static wchar_t c2u_BF[256] = { 0x76D4,0x5CBF,0x7AA5,0x8475,0x594E,0x9B41,0x5080,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C0[256] = { +static const wchar_t c2u_C0[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2243,7 +2243,7 @@ static wchar_t c2u_C0[256] = { 0x52B1,0x783E,0x5386,0x5229,0x5088,0x4F8B,0x4FD0,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C1[256] = { +static const wchar_t c2u_C1[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2279,7 +2279,7 @@ static wchar_t c2u_C1[256] = { 0x67F3,0x516D,0x9F99,0x804B,0x5499,0x7B3C,0x7ABF,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C2[256] = { +static const wchar_t c2u_C2[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2315,7 +2315,7 @@ static wchar_t c2u_C2[256] = { 0x9992,0x86EE,0x6EE1,0x8513,0x66FC,0x6162,0x6F2B,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C3[256] = { +static const wchar_t c2u_C3[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2351,7 +2351,7 @@ static wchar_t c2u_C3[256] = { 0x879F,0x9E23,0x94ED,0x540D,0x547D,0x8C2C,0x6478,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C4[256] = { +static const wchar_t c2u_C4[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2387,7 +2387,7 @@ static wchar_t c2u_C4[256] = { 0x954D,0x6D85,0x60A8,0x67E0,0x72DE,0x51DD,0x5B81,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C5[256] = { +static const wchar_t c2u_C5[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2423,7 +2423,7 @@ static wchar_t c2u_C5[256] = { 0x7812,0x9739,0x6279,0x62AB,0x5288,0x7435,0x6BD7,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C6[256] = { +static const wchar_t c2u_C6[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2459,7 +2459,7 @@ static wchar_t c2u_C6[256] = { 0x6C14,0x8FC4,0x5F03,0x6C7D,0x6CE3,0x8BAB,0x6390,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C7[256] = { +static const wchar_t c2u_C7[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2495,7 +2495,7 @@ static wchar_t c2u_C7[256] = { 0x533A,0x86C6,0x66F2,0x8EAF,0x5C48,0x9A71,0x6E20,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C8[256] = { +static const wchar_t c2u_C8[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2531,7 +2531,7 @@ static wchar_t c2u_C8[256] = { 0x8428,0x816E,0x9CC3,0x585E,0x8D5B,0x4E09,0x53C1,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C9[256] = { +static const wchar_t c2u_C9[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2567,7 +2567,7 @@ static wchar_t c2u_C9[256] = { 0x6E17,0x58F0,0x751F,0x7525,0x7272,0x5347,0x7EF3,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_CA[256] = { +static const wchar_t c2u_CA[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2603,7 +2603,7 @@ static wchar_t c2u_CA[256] = { 0x675F,0x620D,0x7AD6,0x5885,0x5EB6,0x6570,0x6F31,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_CB[256] = { +static const wchar_t c2u_CB[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2639,7 +2639,7 @@ static wchar_t c2u_CB[256] = { 0x9501,0x6240,0x584C,0x4ED6,0x5B83,0x5979,0x5854,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_CC[256] = { +static const wchar_t c2u_CC[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2675,7 +2675,7 @@ static wchar_t c2u_CC[256] = { 0x8DF3,0x8D34,0x94C1,0x5E16,0x5385,0x542C,0x70C3,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_CD[256] = { +static const wchar_t c2u_CD[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2711,7 +2711,7 @@ static wchar_t c2u_CD[256] = { 0x7F51,0x5F80,0x65FA,0x671B,0x5FD8,0x5984,0x5A01,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_CE[256] = { +static const wchar_t c2u_CE[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2747,7 +2747,7 @@ static wchar_t c2u_CE[256] = { 0x7852,0x77FD,0x6670,0x563B,0x5438,0x9521,0x727A,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_CF[256] = { +static const wchar_t c2u_CF[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2783,7 +2783,7 @@ static wchar_t c2u_CF[256] = { 0x54EE,0x56A3,0x9500,0x6D88,0x5BB5,0x6DC6,0x6653,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D0[256] = { +static const wchar_t c2u_D0[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2819,7 +2819,7 @@ static wchar_t c2u_D0[256] = { 0x7EED,0x8F69,0x55A7,0x5BA3,0x60AC,0x65CB,0x7384,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D1[256] = { +static const wchar_t c2u_D1[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2855,7 +2855,7 @@ static wchar_t c2u_D1[256] = { 0x517B,0x6837,0x6F3E,0x9080,0x8170,0x5996,0x7476,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D2[256] = { +static const wchar_t c2u_D2[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2891,7 +2891,7 @@ static wchar_t c2u_D2[256] = { 0x94F6,0x6DEB,0x5BC5,0x996E,0x5C39,0x5F15,0x9690,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D3[256] = { +static const wchar_t c2u_D3[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2927,7 +2927,7 @@ static wchar_t c2u_D3[256] = { 0x5CEA,0x5FA1,0x6108,0x6B32,0x72F1,0x80B2,0x8A89,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D4[256] = { +static const wchar_t c2u_D4[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2963,7 +2963,7 @@ static wchar_t c2u_D4[256] = { 0x66FE,0x8D60,0x624E,0x55B3,0x6E23,0x672D,0x8F67,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D5[256] = { +static const wchar_t c2u_D5[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2999,7 +2999,7 @@ static wchar_t c2u_D5[256] = { 0x72F0,0x4E89,0x6014,0x6574,0x62EF,0x6B63,0x653F,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D6[256] = { +static const wchar_t c2u_D6[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3035,7 +3035,7 @@ static wchar_t c2u_D6[256] = { 0x8457,0x67F1,0x52A9,0x86C0,0x8D2E,0x94F8,0x7B51,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D7[256] = { +static const wchar_t c2u_D7[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3071,7 +3071,7 @@ static wchar_t c2u_D7[256] = { 0x5750,0x5EA7,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D8[256] = { +static const wchar_t c2u_D8[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3107,7 +3107,7 @@ static wchar_t c2u_D8[256] = { 0x4F09,0x4F2B,0x4F5E,0x4F67,0x6538,0x4F5A,0x4F5D,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D9[256] = { +static const wchar_t c2u_D9[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3143,7 +3143,7 @@ static wchar_t c2u_D9[256] = { 0x5B34,0x8803,0x7FB8,0x51AB,0x51B1,0x51BD,0x51BC,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_DA[256] = { +static const wchar_t c2u_DA[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3179,7 +3179,7 @@ static wchar_t c2u_DA[256] = { 0x9099,0x90AC,0x90A1,0x90B4,0x90B3,0x90B6,0x90BA,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_DB[256] = { +static const wchar_t c2u_DB[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3215,7 +3215,7 @@ static wchar_t c2u_DB[256] = { 0x57D2,0x57B8,0x57F4,0x57EF,0x57F8,0x57E4,0x57DD,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_DC[256] = { +static const wchar_t c2u_DC[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3251,7 +3251,7 @@ static wchar_t c2u_DC[256] = { 0x8317,0x8360,0x832D,0x833A,0x8333,0x8366,0x8365,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_DD[256] = { +static const wchar_t c2u_DD[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3287,7 +3287,7 @@ static wchar_t c2u_DD[256] = { 0x850C,0x750D,0x8538,0x84F0,0x8539,0x851F,0x853A,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_DE[256] = { +static const wchar_t c2u_DE[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3323,7 +3323,7 @@ static wchar_t c2u_DE[256] = { 0x640C,0x6426,0x6421,0x645E,0x6484,0x646D,0x6496,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_DF[256] = { +static const wchar_t c2u_DF[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3359,7 +3359,7 @@ static wchar_t c2u_DF[256] = { 0x5549,0x556D,0x5541,0x5555,0x553F,0x5550,0x553C,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E0[256] = { +static const wchar_t c2u_E0[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3395,7 +3395,7 @@ static wchar_t c2u_E0[256] = { 0x5E0F,0x5E19,0x5E14,0x5E11,0x5E31,0x5E3B,0x5E3C,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E1[256] = { +static const wchar_t c2u_E1[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3431,7 +3431,7 @@ static wchar_t c2u_E1[256] = { 0x72F2,0x72F4,0x72F7,0x7301,0x72F3,0x7303,0x72FA,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E2[256] = { +static const wchar_t c2u_E2[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3467,7 +3467,7 @@ static wchar_t c2u_E2[256] = { 0x603F,0x6021,0x6078,0x6079,0x607B,0x607A,0x6042,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E3[256] = { +static const wchar_t c2u_E3[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3503,7 +3503,7 @@ static wchar_t c2u_E3[256] = { 0x6CFA,0x6CEB,0x6CEE,0x6CB1,0x6CD3,0x6CEF,0x6CFE,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E4[256] = { +static const wchar_t c2u_E4[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3539,7 +3539,7 @@ static wchar_t c2u_E4[256] = { 0x6F8D,0x6F8C,0x6F78,0x6F72,0x6F7C,0x6F7A,0x6FD1,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E5[256] = { +static const wchar_t c2u_E5[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3575,7 +3575,7 @@ static wchar_t c2u_E5[256] = { 0x5C6E,0x5981,0x5983,0x598D,0x59A9,0x59AA,0x59A3,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E6[256] = { +static const wchar_t c2u_E6[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3611,7 +3611,7 @@ static wchar_t c2u_E6[256] = { 0x9AA7,0x7E9F,0x7EA1,0x7EA3,0x7EA5,0x7EA8,0x7EA9,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E7[256] = { +static const wchar_t c2u_E7[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3647,7 +3647,7 @@ static wchar_t c2u_E7[256] = { 0x745B,0x7426,0x7425,0x7428,0x7430,0x742E,0x742C,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E8[256] = { +static const wchar_t c2u_E8[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3683,7 +3683,7 @@ static wchar_t c2u_E8[256] = { 0x686B,0x68C2,0x696E,0x68FC,0x691F,0x6920,0x68F9,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E9[256] = { +static const wchar_t c2u_E9[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3719,7 +3719,7 @@ static wchar_t c2u_E9[256] = { 0x8F7C,0x8F7E,0x8F81,0x8F82,0x8F84,0x8F87,0x8F8B,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_EA[256] = { +static const wchar_t c2u_EA[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3755,7 +3755,7 @@ static wchar_t c2u_EA[256] = { 0x728B,0x728D,0x728F,0x7292,0x6308,0x6332,0x63B0,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_EB[256] = { +static const wchar_t c2u_EB[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3791,7 +3791,7 @@ static wchar_t c2u_EB[256] = { 0x6ED5,0x81A3,0x81AA,0x81CC,0x6726,0x81CA,0x81BB,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_EC[256] = { +static const wchar_t c2u_EC[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3827,7 +3827,7 @@ static wchar_t c2u_EC[256] = { 0x7985,0x798A,0x799A,0x79A7,0x79B3,0x5FD1,0x5FD0,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_ED[256] = { +static const wchar_t c2u_ED[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3863,7 +3863,7 @@ static wchar_t c2u_ED[256] = { 0x7738,0x7750,0x7751,0x7747,0x7743,0x775A,0x7768,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_EE[256] = { +static const wchar_t c2u_EE[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3899,7 +3899,7 @@ static wchar_t c2u_EE[256] = { 0x94E0,0x94E2,0x94E4,0x94E5,0x94E7,0x94E8,0x94EA,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_EF[256] = { +static const wchar_t c2u_EF[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3935,7 +3935,7 @@ static wchar_t c2u_EF[256] = { 0x79EB,0x7A06,0x5D47,0x7A03,0x7A02,0x7A1E,0x7A14,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F0[256] = { +static const wchar_t c2u_F0[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3971,7 +3971,7 @@ static wchar_t c2u_F0[256] = { 0x760C,0x7617,0x760A,0x7625,0x7618,0x7615,0x7619,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F1[256] = { +static const wchar_t c2u_F1[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4007,7 +4007,7 @@ static wchar_t c2u_F1[256] = { 0x8052,0x8069,0x8071,0x8983,0x9878,0x9880,0x9883,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F2[256] = { +static const wchar_t c2u_F2[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4043,7 +4043,7 @@ static wchar_t c2u_F2[256] = { 0x8764,0x8759,0x8765,0x8793,0x87AF,0x87A8,0x87D2,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F3[256] = { +static const wchar_t c2u_F3[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4079,7 +4079,7 @@ static wchar_t c2u_F3[256] = { 0x7BEA,0x7C0C,0x7BFE,0x7BFC,0x7C0F,0x7C16,0x7C0B,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F4[256] = { +static const wchar_t c2u_F4[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4115,7 +4115,7 @@ static wchar_t c2u_F4[256] = { 0x8C47,0x8C49,0x914A,0x9150,0x914E,0x914F,0x9164,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F5[256] = { +static const wchar_t c2u_F5[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4151,7 +4151,7 @@ static wchar_t c2u_F5[256] = { 0x8C98,0x8C94,0x659B,0x89D6,0x89DE,0x89DA,0x89DC,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F6[256] = { +static const wchar_t c2u_F6[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4187,7 +4187,7 @@ static wchar_t c2u_F6[256] = { 0x9CBD,0x9CC4,0x9CC5,0x9CC6,0x9CC7,0x9CCA,0x9CCB,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F7[256] = { +static const wchar_t c2u_F7[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4223,7 +4223,7 @@ static wchar_t c2u_F7[256] = { 0x9F2C,0x9F2F,0x9F39,0x9F37,0x9F3D,0x9F3E,0x9F44,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F8[256] = { +static const wchar_t c2u_F8[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4248,7 +4248,7 @@ static wchar_t c2u_F8[256] = { 0x9D42,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ }; -static wchar_t c2u_F9[256] = { +static const wchar_t c2u_F9[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4273,7 +4273,7 @@ static wchar_t c2u_F9[256] = { 0x9DA2,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ }; -static wchar_t c2u_FA[256] = { +static const wchar_t c2u_FA[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4298,7 +4298,7 @@ static wchar_t c2u_FA[256] = { 0x9E02,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ }; -static wchar_t c2u_FB[256] = { +static const wchar_t c2u_FB[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4323,7 +4323,7 @@ static wchar_t c2u_FB[256] = { 0x9EAA,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ }; -static wchar_t c2u_FC[256] = { +static const wchar_t c2u_FC[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4348,7 +4348,7 @@ static wchar_t c2u_FC[256] = { 0x9F31,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ }; -static wchar_t c2u_FD[256] = { +static const wchar_t c2u_FD[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4373,7 +4373,7 @@ static wchar_t c2u_FD[256] = { 0xF9F1,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ }; -static wchar_t c2u_FE[256] = { +static const wchar_t c2u_FE[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4386,7 +4386,7 @@ static wchar_t c2u_FE[256] = { 0xFA1F,0xFA20,0xFA21,0xFA23,0xFA24,0xFA27,0xFA28,0xFA29,/* 0x48-0x4F */ }; -static wchar_t *page_charset2uni[256] = { +static const wchar_t *page_charset2uni[256] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -4421,7 +4421,7 @@ static wchar_t *page_charset2uni[256] = { c2u_F8, c2u_F9, c2u_FA, c2u_FB, c2u_FC, c2u_FD, c2u_FE, NULL, }; -static unsigned char u2c_00[512] = { +static const unsigned char u2c_00[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4488,7 +4488,7 @@ static unsigned char u2c_00[512] = { 0xA8, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_01[512] = { +static const unsigned char u2c_01[512] = { 0xA8, 0xA1, 0xA8, 0xA1, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4548,7 +4548,7 @@ static unsigned char u2c_01[512] = { 0xA8, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ }; -static unsigned char u2c_02[512] = { +static const unsigned char u2c_02[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4607,7 +4607,7 @@ static unsigned char u2c_02[512] = { 0x00, 0x00, 0xA8, 0x42, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ }; -static unsigned char u2c_03[512] = { +static const unsigned char u2c_03[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4662,7 +4662,7 @@ static unsigned char u2c_03[512] = { 0xA6, 0xD7, 0xA6, 0xD8, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ }; -static unsigned char u2c_04[512] = { +static const unsigned char u2c_04[512] = { 0x00, 0x00, 0xA7, 0xA7, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4686,7 +4686,7 @@ static unsigned char u2c_04[512] = { 0x00, 0x00, 0xA7, 0xD7, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ }; -static unsigned char u2c_20[512] = { +static const unsigned char u2c_20[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4705,7 +4705,7 @@ static unsigned char u2c_20[512] = { 0x00, 0x00, 0x00, 0x00, 0xA3, 0xFE, 0x00, 0x00, /* 0x3C-0x3F */ }; -static unsigned char u2c_21[512] = { +static const unsigned char u2c_21[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xE6, /* 0x00-0x03 */ 0x00, 0x00, 0xA8, 0x47, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xA8, 0x48, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4748,7 +4748,7 @@ static unsigned char u2c_21[512] = { 0xA8, 0x4B, 0xA8, 0x4C, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ }; -static unsigned char u2c_22[512] = { +static const unsigned char u2c_22[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0xA1, 0xCA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4800,7 +4800,7 @@ static unsigned char u2c_22[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x53, /* 0xBC-0xBF */ }; -static unsigned char u2c_23[512] = { +static const unsigned char u2c_23[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4808,7 +4808,7 @@ static unsigned char u2c_23[512] = { 0x00, 0x00, 0x00, 0x00, 0xA1, 0xD0, 0x00, 0x00, /* 0x10-0x13 */ }; -static unsigned char u2c_24[512] = { +static const unsigned char u2c_24[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4851,7 +4851,7 @@ static unsigned char u2c_24[512] = { 0xA2, 0xC1, 0xA2, 0xC2, 0xA2, 0xC3, 0xA2, 0xC4, /* 0x98-0x9B */ }; -static unsigned char u2c_25[512] = { +static const unsigned char u2c_25[512] = { 0xA9, 0xA4, 0xA9, 0xA5, 0xA9, 0xA6, 0xA9, 0xA7, /* 0x00-0x03 */ 0xA9, 0xA8, 0xA9, 0xA9, 0xA9, 0xAA, 0xA9, 0xAB, /* 0x04-0x07 */ 0xA9, 0xAC, 0xA9, 0xAD, 0xA9, 0xAE, 0xA9, 0xAF, /* 0x08-0x0B */ @@ -4919,7 +4919,7 @@ static unsigned char u2c_25[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_26[512] = { +static const unsigned char u2c_26[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xA1, 0xEF, 0xA1, 0xEE, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xA8, 0x91, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4939,7 +4939,7 @@ static unsigned char u2c_26[512] = { 0xA1, 0xE2, 0x00, 0x00, 0xA1, 0xE1, 0x00, 0x00, /* 0x40-0x43 */ }; -static unsigned char u2c_30[512] = { +static const unsigned char u2c_30[512] = { 0xA1, 0xA1, 0xA1, 0xA2, 0xA1, 0xA3, 0xA1, 0xA8, /* 0x00-0x03 */ 0x00, 0x00, 0xA1, 0xA9, 0xA9, 0x65, 0xA9, 0x96, /* 0x04-0x07 */ 0xA1, 0xB4, 0xA1, 0xB5, 0xA1, 0xB6, 0xA1, 0xB7, /* 0x08-0x0B */ @@ -5007,7 +5007,7 @@ static unsigned char u2c_30[512] = { 0xA9, 0x60, 0xA9, 0x63, 0xA9, 0x64, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_31[512] = { +static const unsigned char u2c_31[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xA8, 0xC5, 0xA8, 0xC6, 0xA8, 0xC7, /* 0x04-0x07 */ 0xA8, 0xC8, 0xA8, 0xC9, 0xA8, 0xCA, 0xA8, 0xCB, /* 0x08-0x0B */ @@ -5051,7 +5051,7 @@ static unsigned char u2c_31[512] = { 0xB6, 0xA1, 0xCC, 0xEC, 0xB5, 0xD8, 0xC8, 0xCB, /* 0x9C-0x9F */ }; -static unsigned char u2c_32[512] = { +static const unsigned char u2c_32[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -5100,7 +5100,7 @@ static unsigned char u2c_32[512] = { 0xD2, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ }; -static unsigned char u2c_33[512] = { +static const unsigned char u2c_33[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -5158,7 +5158,7 @@ static unsigned char u2c_33[512] = { 0x00, 0x00, 0xA9, 0x54, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ }; -static unsigned char u2c_4E[512] = { +static const unsigned char u2c_4E[512] = { 0xD2, 0xBB, 0xB6, 0xA1, 0x81, 0x40, 0xC6, 0xDF, /* 0x00-0x03 */ 0x81, 0x41, 0x81, 0x42, 0x81, 0x43, 0xCD, 0xF2, /* 0x04-0x07 */ 0xD5, 0xC9, 0xC8, 0xFD, 0xC9, 0xCF, 0xCF, 0xC2, /* 0x08-0x0B */ @@ -5226,7 +5226,7 @@ static unsigned char u2c_4E[512] = { 0x81, 0xA9, 0xB7, 0xDD, 0x81, 0xAA, 0xB7, 0xC2, /* 0xFC-0xFF */ }; -static unsigned char u2c_4F[512] = { +static const unsigned char u2c_4F[512] = { 0x81, 0xAB, 0xC6, 0xF3, 0x81, 0xAC, 0x81, 0xAD, /* 0x00-0x03 */ 0x81, 0xAE, 0x81, 0xAF, 0x81, 0xB0, 0x81, 0xB1, /* 0x04-0x07 */ 0x81, 0xB2, 0xD8, 0xF8, 0xD2, 0xC1, 0x81, 0xB3, /* 0x08-0x0B */ @@ -5294,7 +5294,7 @@ static unsigned char u2c_4F[512] = { 0x82, 0x71, 0x82, 0x72, 0xD9, 0xC2, 0x82, 0x73, /* 0xFC-0xFF */ }; -static unsigned char u2c_50[512] = { +static const unsigned char u2c_50[512] = { 0x82, 0x74, 0x82, 0x75, 0x82, 0x76, 0x82, 0x77, /* 0x00-0x03 */ 0x82, 0x78, 0x82, 0x79, 0x82, 0x7A, 0x82, 0x7B, /* 0x04-0x07 */ 0x82, 0x7C, 0x82, 0x7D, 0x82, 0x7E, 0x82, 0x80, /* 0x08-0x0B */ @@ -5362,7 +5362,7 @@ static unsigned char u2c_50[512] = { 0x83, 0x74, 0x83, 0x75, 0x83, 0x76, 0x83, 0x77, /* 0xFC-0xFF */ }; -static unsigned char u2c_51[512] = { +static const unsigned char u2c_51[512] = { 0x83, 0x78, 0x83, 0x79, 0x83, 0x7A, 0x83, 0x7B, /* 0x00-0x03 */ 0x83, 0x7C, 0x83, 0x7D, 0xD9, 0xD3, 0xD9, 0xD8, /* 0x04-0x07 */ 0x83, 0x7E, 0x83, 0x80, 0x83, 0x81, 0xD9, 0xD9, /* 0x08-0x0B */ @@ -5430,7 +5430,7 @@ static unsigned char u2c_51[512] = { 0xDB, 0xCA, 0xBA, 0xAF, 0x84, 0x54, 0xD4, 0xE4, /* 0xFC-0xFF */ }; -static unsigned char u2c_52[512] = { +static const unsigned char u2c_52[512] = { 0xB5, 0xB6, 0xB5, 0xF3, 0xD8, 0xD6, 0xC8, 0xD0, /* 0x00-0x03 */ 0x84, 0x55, 0x84, 0x56, 0xB7, 0xD6, 0xC7, 0xD0, /* 0x04-0x07 */ 0xD8, 0xD7, 0x84, 0x57, 0xBF, 0xAF, 0x84, 0x58, /* 0x08-0x0B */ @@ -5498,7 +5498,7 @@ static unsigned char u2c_52[512] = { 0x84, 0xF3, 0x84, 0xF4, 0xB9, 0xB4, 0xCE, 0xF0, /* 0xFC-0xFF */ }; -static unsigned char u2c_53[512] = { +static const unsigned char u2c_53[512] = { 0xD4, 0xC8, 0x84, 0xF5, 0x84, 0xF6, 0x84, 0xF7, /* 0x00-0x03 */ 0x84, 0xF8, 0xB0, 0xFC, 0xB4, 0xD2, 0x84, 0xF9, /* 0x04-0x07 */ 0xD0, 0xD9, 0x84, 0xFA, 0x84, 0xFB, 0x84, 0xFC, /* 0x08-0x0B */ @@ -5566,7 +5566,7 @@ static unsigned char u2c_53[512] = { 0xB5, 0xF0, 0xDF, 0xB4, 0x85, 0xB6, 0x85, 0xB7, /* 0xFC-0xFF */ }; -static unsigned char u2c_54[512] = { +static const unsigned char u2c_54[512] = { 0x85, 0xB8, 0xD3, 0xF5, 0x85, 0xB9, 0xB3, 0xD4, /* 0x00-0x03 */ 0xB8, 0xF7, 0x85, 0xBA, 0xDF, 0xBA, 0x85, 0xBB, /* 0x04-0x07 */ 0xBA, 0xCF, 0xBC, 0xAA, 0xB5, 0xF5, 0x85, 0xBC, /* 0x08-0x0B */ @@ -5634,7 +5634,7 @@ static unsigned char u2c_54[512] = { 0xBA, 0xDF, 0xDF, 0xEC, 0x86, 0x64, 0xDB, 0xC1, /* 0xFC-0xFF */ }; -static unsigned char u2c_55[512] = { +static const unsigned char u2c_55[512] = { 0x86, 0x65, 0xD1, 0xE4, 0x86, 0x66, 0x86, 0x67, /* 0x00-0x03 */ 0x86, 0x68, 0x86, 0x69, 0xCB, 0xF4, 0xB4, 0xBD, /* 0x04-0x07 */ 0x86, 0x6A, 0xB0, 0xA6, 0x86, 0x6B, 0x86, 0x6C, /* 0x08-0x0B */ @@ -5702,7 +5702,7 @@ static unsigned char u2c_55[512] = { 0x86, 0xF9, 0xCB, 0xD4, 0xE0, 0xD5, 0x86, 0xFA, /* 0xFC-0xFF */ }; -static unsigned char u2c_56[512] = { +static const unsigned char u2c_56[512] = { 0xE0, 0xD6, 0xE0, 0xD2, 0x86, 0xFB, 0x86, 0xFC, /* 0x00-0x03 */ 0x86, 0xFD, 0x86, 0xFE, 0x87, 0x40, 0x87, 0x41, /* 0x04-0x07 */ 0xE0, 0xD0, 0xBC, 0xCE, 0x87, 0x42, 0x87, 0x43, /* 0x08-0x0B */ @@ -5770,7 +5770,7 @@ static unsigned char u2c_56[512] = { 0x87, 0xF2, 0xB9, 0xFA, 0xCD, 0xBC, 0xE0, 0xF3, /* 0xFC-0xFF */ }; -static unsigned char u2c_57[512] = { +static const unsigned char u2c_57[512] = { 0x87, 0xF3, 0x87, 0xF4, 0x87, 0xF5, 0xC6, 0xD4, /* 0x00-0x03 */ 0xE0, 0xF4, 0x87, 0xF6, 0xD4, 0xB2, 0x87, 0xF7, /* 0x04-0x07 */ 0xC8, 0xA6, 0xE0, 0xF6, 0xE0, 0xF5, 0x87, 0xF8, /* 0x08-0x0B */ @@ -5838,7 +5838,7 @@ static unsigned char u2c_57[512] = { 0x88, 0xCE, 0xDC, 0xA3, 0x88, 0xCF, 0x88, 0xD0, /* 0xFC-0xFF */ }; -static unsigned char u2c_58[512] = { +static const unsigned char u2c_58[512] = { 0xDC, 0xA5, 0x88, 0xD1, 0xCC, 0xC3, 0x88, 0xD2, /* 0x00-0x03 */ 0x88, 0xD3, 0x88, 0xD4, 0xB6, 0xD1, 0xDD, 0xC0, /* 0x04-0x07 */ 0x88, 0xD5, 0x88, 0xD6, 0x88, 0xD7, 0xDC, 0xA1, /* 0x08-0x0B */ @@ -5906,7 +5906,7 @@ static unsigned char u2c_58[512] = { 0x89, 0xDA, 0x89, 0xDB, 0x89, 0xDC, 0x89, 0xDD, /* 0xFC-0xFF */ }; -static unsigned char u2c_59[512] = { +static const unsigned char u2c_59[512] = { 0x89, 0xDE, 0x89, 0xDF, 0xE2, 0xBA, 0x89, 0xE0, /* 0x00-0x03 */ 0xB4, 0xA6, 0x89, 0xE1, 0x89, 0xE2, 0xB1, 0xB8, /* 0x04-0x07 */ 0x89, 0xE3, 0x89, 0xE4, 0x89, 0xE5, 0x89, 0xE6, /* 0x08-0x0B */ @@ -5974,7 +5974,7 @@ static unsigned char u2c_59[512] = { 0x8A, 0xB8, 0x8A, 0xB9, 0x8A, 0xBA, 0xD7, 0xCB, /* 0xFC-0xFF */ }; -static unsigned char u2c_5A[512] = { +static const unsigned char u2c_5A[512] = { 0x8A, 0xBB, 0xCD, 0xFE, 0x8A, 0xBC, 0xCD, 0xDE, /* 0x00-0x03 */ 0xC2, 0xA6, 0xE6, 0xAB, 0xE6, 0xAC, 0xBD, 0xBF, /* 0x04-0x07 */ 0xE6, 0xAE, 0xE6, 0xB3, 0x8A, 0xBD, 0x8A, 0xBE, /* 0x08-0x0B */ @@ -6042,7 +6042,7 @@ static unsigned char u2c_5A[512] = { 0x8B, 0xBA, 0x8B, 0xBB, 0x8B, 0xBC, 0x8B, 0xBD, /* 0xFC-0xFF */ }; -static unsigned char u2c_5B[512] = { +static const unsigned char u2c_5B[512] = { 0x8B, 0xBE, 0x8B, 0xBF, 0x8B, 0xC0, 0x8B, 0xC1, /* 0x00-0x03 */ 0x8B, 0xC2, 0x8B, 0xC3, 0x8B, 0xC4, 0x8B, 0xC5, /* 0x04-0x07 */ 0x8B, 0xC6, 0xE6, 0xD2, 0x8B, 0xC7, 0x8B, 0xC8, /* 0x08-0x0B */ @@ -6110,7 +6110,7 @@ static unsigned char u2c_5B[512] = { 0xB5, 0xBC, 0x8C, 0x9C, 0x8C, 0x9D, 0xCA, 0xD9, /* 0xFC-0xFF */ }; -static unsigned char u2c_5C[512] = { +static const unsigned char u2c_5C[512] = { 0x8C, 0x9E, 0xB7, 0xE2, 0x8C, 0x9F, 0x8C, 0xA0, /* 0x00-0x03 */ 0xC9, 0xE4, 0x8C, 0xA1, 0xBD, 0xAB, 0x8C, 0xA2, /* 0x04-0x07 */ 0x8C, 0xA3, 0xCE, 0xBE, 0xD7, 0xF0, 0x8C, 0xA4, /* 0x08-0x0B */ @@ -6178,7 +6178,7 @@ static unsigned char u2c_5C[512] = { 0x8D, 0x7A, 0x8D, 0x7B, 0x8D, 0x7C, 0x8D, 0x7D, /* 0xFC-0xFF */ }; -static unsigned char u2c_5D[512] = { +static const unsigned char u2c_5D[512] = { 0x8D, 0x7E, 0x8D, 0x80, 0xE1, 0xC0, 0xE1, 0xC1, /* 0x00-0x03 */ 0x8D, 0x81, 0x8D, 0x82, 0xE1, 0xC7, 0xB3, 0xE7, /* 0x04-0x07 */ 0x8D, 0x83, 0x8D, 0x84, 0x8D, 0x85, 0x8D, 0x86, /* 0x08-0x0B */ @@ -6246,7 +6246,7 @@ static unsigned char u2c_5D[512] = { 0x8E, 0x87, 0xD9, 0xE3, 0xBD, 0xED, 0x8E, 0x88, /* 0xFC-0xFF */ }; -static unsigned char u2c_5E[512] = { +static const unsigned char u2c_5E[512] = { 0x8E, 0x89, 0xB1, 0xD2, 0xCA, 0xD0, 0xB2, 0xBC, /* 0x00-0x03 */ 0x8E, 0x8A, 0xCB, 0xA7, 0xB7, 0xAB, 0x8E, 0x8B, /* 0x04-0x07 */ 0xCA, 0xA6, 0x8E, 0x8C, 0x8E, 0x8D, 0x8E, 0x8E, /* 0x08-0x0B */ @@ -6314,7 +6314,7 @@ static unsigned char u2c_5E[512] = { 0x8F, 0x69, 0x8F, 0x6A, 0xDE, 0xC3, 0xD8, 0xA5, /* 0xFC-0xFF */ }; -static unsigned char u2c_5F[512] = { +static const unsigned char u2c_5F[512] = { 0xBF, 0xAA, 0xDB, 0xCD, 0xD2, 0xEC, 0xC6, 0xFA, /* 0x00-0x03 */ 0xC5, 0xAA, 0x8F, 0x6B, 0x8F, 0x6C, 0x8F, 0x6D, /* 0x04-0x07 */ 0xDE, 0xC4, 0x8F, 0x6E, 0xB1, 0xD7, 0xDF, 0xAE, /* 0x08-0x0B */ @@ -6382,7 +6382,7 @@ static unsigned char u2c_5F[512] = { 0x8F, 0xFD, 0xBA, 0xF6, 0xE2, 0xE9, 0xB7, 0xDE, /* 0xFC-0xFF */ }; -static unsigned char u2c_60[512] = { +static const unsigned char u2c_60[512] = { 0xBB, 0xB3, 0xCC, 0xAC, 0xCB, 0xCB, 0xE2, 0xE4, /* 0x00-0x03 */ 0xE2, 0xE6, 0xE2, 0xEA, 0xE2, 0xEB, 0x8F, 0xFE, /* 0x04-0x07 */ 0x90, 0x40, 0x90, 0x41, 0xE2, 0xF7, 0x90, 0x42, /* 0x08-0x0B */ @@ -6450,7 +6450,7 @@ static unsigned char u2c_60[512] = { 0x90, 0xC6, 0x90, 0xC7, 0x90, 0xC8, 0x90, 0xC9, /* 0xFC-0xFF */ }; -static unsigned char u2c_61[512] = { +static const unsigned char u2c_61[512] = { 0xE3, 0xB8, 0xB3, 0xEE, 0x90, 0xCA, 0x90, 0xCB, /* 0x00-0x03 */ 0x90, 0xCC, 0x90, 0xCD, 0xED, 0xA9, 0x90, 0xCE, /* 0x04-0x07 */ 0xD3, 0xFA, 0xD3, 0xE4, 0x90, 0xCF, 0x90, 0xD0, /* 0x08-0x0B */ @@ -6518,7 +6518,7 @@ static unsigned char u2c_61[512] = { 0x91, 0xD6, 0x91, 0xD7, 0x91, 0xD8, 0xDC, 0xB2, /* 0xFC-0xFF */ }; -static unsigned char u2c_62[512] = { +static const unsigned char u2c_62[512] = { 0x91, 0xD9, 0x91, 0xDA, 0x91, 0xDB, 0x91, 0xDC, /* 0x00-0x03 */ 0x91, 0xDD, 0x91, 0xDE, 0xED, 0xB0, 0x91, 0xDF, /* 0x04-0x07 */ 0xB8, 0xEA, 0x91, 0xE0, 0xCE, 0xEC, 0xEA, 0xA7, /* 0x08-0x0B */ @@ -6586,7 +6586,7 @@ static unsigned char u2c_62[512] = { 0xC6, 0xB4, 0xD7, 0xA7, 0xCA, 0xB0, 0xC4, 0xC3, /* 0xFC-0xFF */ }; -static unsigned char u2c_63[512] = { +static const unsigned char u2c_63[512] = { 0x92, 0x93, 0xB3, 0xD6, 0xB9, 0xD2, 0x92, 0x94, /* 0x00-0x03 */ 0x92, 0x95, 0x92, 0x96, 0x92, 0x97, 0xD6, 0xB8, /* 0x04-0x07 */ 0xEA, 0xFC, 0xB0, 0xB4, 0x92, 0x98, 0x92, 0x99, /* 0x08-0x0B */ @@ -6654,7 +6654,7 @@ static unsigned char u2c_63[512] = { 0x93, 0x67, 0xC0, 0xBF, 0x93, 0x68, 0xDE, 0xEC, /* 0xFC-0xFF */ }; -static unsigned char u2c_64[512] = { +static const unsigned char u2c_64[512] = { 0xB2, 0xF3, 0xB8, 0xE9, 0xC2, 0xA7, 0x93, 0x69, /* 0x00-0x03 */ 0x93, 0x6A, 0xBD, 0xC1, 0x93, 0x6B, 0x93, 0x6C, /* 0x04-0x07 */ 0x93, 0x6D, 0x93, 0x6E, 0x93, 0x6F, 0xDE, 0xF5, /* 0x08-0x0B */ @@ -6722,7 +6722,7 @@ static unsigned char u2c_64[512] = { 0x94, 0x5D, 0x94, 0x5E, 0x94, 0x5F, 0x94, 0x60, /* 0xFC-0xFF */ }; -static unsigned char u2c_65[512] = { +static const unsigned char u2c_65[512] = { 0xC5, 0xCA, 0x94, 0x61, 0x94, 0x62, 0x94, 0x63, /* 0x00-0x03 */ 0x94, 0x64, 0x94, 0x65, 0x94, 0x66, 0x94, 0x67, /* 0x04-0x07 */ 0x94, 0x68, 0xDF, 0xAB, 0x94, 0x69, 0x94, 0x6A, /* 0x08-0x0B */ @@ -6790,7 +6790,7 @@ static unsigned char u2c_65[512] = { 0x95, 0x47, 0x95, 0x48, 0x95, 0x49, 0x95, 0x4A, /* 0xFC-0xFF */ }; -static unsigned char u2c_66[512] = { +static const unsigned char u2c_66[512] = { 0xEA, 0xC0, 0x95, 0x4B, 0xB0, 0xBA, 0xEA, 0xBE, /* 0x00-0x03 */ 0x95, 0x4C, 0x95, 0x4D, 0xC0, 0xA5, 0x95, 0x4E, /* 0x04-0x07 */ 0x95, 0x4F, 0x95, 0x50, 0xEA, 0xBB, 0x95, 0x51, /* 0x08-0x0B */ @@ -6858,7 +6858,7 @@ static unsigned char u2c_66[512] = { 0xC2, 0xFC, 0x95, 0xFB, 0xD4, 0xF8, 0xCC, 0xE6, /* 0xFC-0xFF */ }; -static unsigned char u2c_67[512] = { +static const unsigned char u2c_67[512] = { 0xD7, 0xEE, 0x95, 0xFC, 0x95, 0xFD, 0x95, 0xFE, /* 0x00-0x03 */ 0x96, 0x40, 0x96, 0x41, 0x96, 0x42, 0x96, 0x43, /* 0x04-0x07 */ 0xD4, 0xC2, 0xD3, 0xD0, 0xEB, 0xC3, 0xC5, 0xF3, /* 0x08-0x0B */ @@ -6926,7 +6926,7 @@ static unsigned char u2c_67[512] = { 0x96, 0xCC, 0xE8, 0xDF, 0x96, 0xCD, 0xCA, 0xC1, /* 0xFC-0xFF */ }; -static unsigned char u2c_68[512] = { +static const unsigned char u2c_68[512] = { 0xE8, 0xD9, 0x96, 0xCE, 0x96, 0xCF, 0x96, 0xD0, /* 0x00-0x03 */ 0x96, 0xD1, 0xD5, 0xA4, 0x96, 0xD2, 0xB1, 0xEA, /* 0x04-0x07 */ 0xD5, 0xBB, 0xE8, 0xCE, 0xE8, 0xD0, 0xB6, 0xB0, /* 0x08-0x0B */ @@ -6994,7 +6994,7 @@ static unsigned char u2c_68[512] = { 0xE8, 0xFB, 0x97, 0xB2, 0x97, 0xB3, 0x97, 0xB4, /* 0xFC-0xFF */ }; -static unsigned char u2c_69[512] = { +static const unsigned char u2c_69[512] = { 0x97, 0xB5, 0xE9, 0xA4, 0x97, 0xB6, 0x97, 0xB7, /* 0x00-0x03 */ 0x97, 0xB8, 0xD2, 0xCE, 0x97, 0xB9, 0x97, 0xBA, /* 0x04-0x07 */ 0x97, 0xBB, 0x97, 0xBC, 0x97, 0xBD, 0xE9, 0xA3, /* 0x08-0x0B */ @@ -7062,7 +7062,7 @@ static unsigned char u2c_69[512] = { 0x98, 0xB3, 0xB2, 0xDB, 0x98, 0xB4, 0xE9, 0xC8, /* 0xFC-0xFF */ }; -static unsigned char u2c_6A[512] = { +static const unsigned char u2c_6A[512] = { 0x98, 0xB5, 0x98, 0xB6, 0x98, 0xB7, 0x98, 0xB8, /* 0x00-0x03 */ 0x98, 0xB9, 0x98, 0xBA, 0x98, 0xBB, 0x98, 0xBC, /* 0x04-0x07 */ 0x98, 0xBD, 0x98, 0xBE, 0xB7, 0xAE, 0x98, 0xBF, /* 0x08-0x0B */ @@ -7130,7 +7130,7 @@ static unsigned char u2c_6A[512] = { 0x99, 0xD2, 0x99, 0xD3, 0x99, 0xD4, 0x99, 0xD5, /* 0xFC-0xFF */ }; -static unsigned char u2c_6B[512] = { +static const unsigned char u2c_6B[512] = { 0x99, 0xD6, 0x99, 0xD7, 0x99, 0xD8, 0x99, 0xD9, /* 0x00-0x03 */ 0x99, 0xDA, 0x99, 0xDB, 0x99, 0xDC, 0x99, 0xDD, /* 0x04-0x07 */ 0x99, 0xDE, 0x99, 0xDF, 0x99, 0xE0, 0x99, 0xE1, /* 0x08-0x0B */ @@ -7198,7 +7198,7 @@ static unsigned char u2c_6B[512] = { 0x9A, 0xCE, 0xEB, 0xA6, 0x9A, 0xCF, 0x9A, 0xD0, /* 0xFC-0xFF */ }; -static unsigned char u2c_6C[512] = { +static const unsigned char u2c_6C[512] = { 0x9A, 0xD1, 0x9A, 0xD2, 0x9A, 0xD3, 0x9A, 0xD4, /* 0x00-0x03 */ 0x9A, 0xD5, 0xEB, 0xA9, 0xEB, 0xAB, 0xEB, 0xAA, /* 0x04-0x07 */ 0x9A, 0xD6, 0x9A, 0xD7, 0x9A, 0xD8, 0x9A, 0xD9, /* 0x08-0x0B */ @@ -7266,7 +7266,7 @@ static unsigned char u2c_6C[512] = { 0xC6, 0xC3, 0xD4, 0xF3, 0xE3, 0xFE, 0x9B, 0x8E, /* 0xFC-0xFF */ }; -static unsigned char u2c_6D[512] = { +static const unsigned char u2c_6D[512] = { 0x9B, 0x8F, 0xBD, 0xE0, 0x9B, 0x90, 0x9B, 0x91, /* 0x00-0x03 */ 0xE4, 0xA7, 0x9B, 0x92, 0x9B, 0x93, 0xE4, 0xA6, /* 0x04-0x07 */ 0x9B, 0x94, 0x9B, 0x95, 0x9B, 0x96, 0xD1, 0xF3, /* 0x08-0x0B */ @@ -7334,7 +7334,7 @@ static unsigned char u2c_6D[512] = { 0xED, 0xB5, 0x9C, 0x5D, 0x9C, 0x5E, 0x9C, 0x5F, /* 0xFC-0xFF */ }; -static unsigned char u2c_6E[512] = { +static const unsigned char u2c_6E[512] = { 0x9C, 0x60, 0x9C, 0x61, 0x9C, 0x62, 0x9C, 0x63, /* 0x00-0x03 */ 0x9C, 0x64, 0xC7, 0xE5, 0x9C, 0x65, 0x9C, 0x66, /* 0x04-0x07 */ 0x9C, 0x67, 0x9C, 0x68, 0xD4, 0xA8, 0x9C, 0x69, /* 0x08-0x0B */ @@ -7402,7 +7402,7 @@ static unsigned char u2c_6E[512] = { 0x9D, 0x4A, 0x9D, 0x4B, 0x9D, 0x4C, 0x9D, 0x4D, /* 0xFC-0xFF */ }; -static unsigned char u2c_6F[512] = { +static const unsigned char u2c_6F[512] = { 0x9D, 0x4E, 0x9D, 0x4F, 0xC6, 0xAF, 0x9D, 0x50, /* 0x00-0x03 */ 0x9D, 0x51, 0x9D, 0x52, 0xC6, 0xE1, 0x9D, 0x53, /* 0x04-0x07 */ 0x9D, 0x54, 0xE4, 0xF5, 0x9D, 0x55, 0x9D, 0x56, /* 0x08-0x0B */ @@ -7470,7 +7470,7 @@ static unsigned char u2c_6F[512] = { 0x9E, 0x54, 0x9E, 0x55, 0x9E, 0x56, 0x9E, 0x57, /* 0xFC-0xFF */ }; -static unsigned char u2c_70[512] = { +static const unsigned char u2c_70[512] = { 0x9E, 0x58, 0x9E, 0x59, 0x9E, 0x5A, 0x9E, 0x5B, /* 0x00-0x03 */ 0x9E, 0x5C, 0x9E, 0x5D, 0x9E, 0x5E, 0x9E, 0x5F, /* 0x04-0x07 */ 0x9E, 0x60, 0x9E, 0x61, 0x9E, 0x62, 0x9E, 0x63, /* 0x08-0x0B */ @@ -7538,7 +7538,7 @@ static unsigned char u2c_70[512] = { 0x9F, 0x54, 0xB7, 0xE9, 0x9F, 0x55, 0x9F, 0x56, /* 0xFC-0xFF */ }; -static unsigned char u2c_71[512] = { +static const unsigned char u2c_71[512] = { 0x9F, 0x57, 0x9F, 0x58, 0x9F, 0x59, 0x9F, 0x5A, /* 0x00-0x03 */ 0x9F, 0x5B, 0x9F, 0x5C, 0x9F, 0x5D, 0x9F, 0x5E, /* 0x04-0x07 */ 0x9F, 0x5F, 0xD1, 0xC9, 0xBA, 0xB8, 0x9F, 0x60, /* 0x08-0x0B */ @@ -7606,7 +7606,7 @@ static unsigned char u2c_71[512] = { 0xA0, 0x61, 0xA0, 0x62, 0xA0, 0x63, 0xA0, 0x64, /* 0xFC-0xFF */ }; -static unsigned char u2c_72[512] = { +static const unsigned char u2c_72[512] = { 0xA0, 0x65, 0xA0, 0x66, 0xA0, 0x67, 0xA0, 0x68, /* 0x00-0x03 */ 0xA0, 0x69, 0xA0, 0x6A, 0xB1, 0xAC, 0xA0, 0x6B, /* 0x04-0x07 */ 0xA0, 0x6C, 0xA0, 0x6D, 0xA0, 0x6E, 0xA0, 0x6F, /* 0x08-0x0B */ @@ -7674,7 +7674,7 @@ static unsigned char u2c_72[512] = { 0xC0, 0xC7, 0xAA, 0x4E, 0xAA, 0x4F, 0xAA, 0x50, /* 0xFC-0xFF */ }; -static unsigned char u2c_73[512] = { +static const unsigned char u2c_73[512] = { 0xAA, 0x51, 0xE1, 0xFB, 0xAA, 0x52, 0xE1, 0xFD, /* 0x00-0x03 */ 0xAA, 0x53, 0xAA, 0x54, 0xAA, 0x55, 0xAA, 0x56, /* 0x04-0x07 */ 0xAA, 0x57, 0xAA, 0x58, 0xE2, 0xA5, 0xAA, 0x59, /* 0x08-0x0B */ @@ -7742,7 +7742,7 @@ static unsigned char u2c_73[512] = { 0xAC, 0x44, 0xAC, 0x45, 0xAC, 0x46, 0xAC, 0x47, /* 0xFC-0xFF */ }; -static unsigned char u2c_74[512] = { +static const unsigned char u2c_74[512] = { 0xAC, 0x48, 0xAC, 0x49, 0xAC, 0x4A, 0xC7, 0xF2, /* 0x00-0x03 */ 0xAC, 0x4B, 0xC0, 0xC5, 0xC0, 0xED, 0xAC, 0x4C, /* 0x04-0x07 */ 0xAC, 0x4D, 0xC1, 0xF0, 0xE7, 0xF0, 0xAC, 0x4E, /* 0x08-0x0B */ @@ -7810,7 +7810,7 @@ static unsigned char u2c_74[512] = { 0xAE, 0x46, 0xAE, 0x47, 0xAE, 0x48, 0xEA, 0xB3, /* 0xFC-0xFF */ }; -static unsigned char u2c_75[512] = { +static const unsigned char u2c_75[512] = { 0xAE, 0x49, 0xAE, 0x4A, 0xAE, 0x4B, 0xAE, 0x4C, /* 0x00-0x03 */ 0xD5, 0xE7, 0xAE, 0x4D, 0xAE, 0x4E, 0xAE, 0x4F, /* 0x04-0x07 */ 0xAE, 0x50, 0xAE, 0x51, 0xAE, 0x52, 0xAE, 0x53, /* 0x08-0x0B */ @@ -7878,7 +7878,7 @@ static unsigned char u2c_75[512] = { 0xF0, 0xF3, 0xAF, 0x79, 0xAF, 0x7A, 0xF0, 0xF4, /* 0xFC-0xFF */ }; -static unsigned char u2c_76[512] = { +static const unsigned char u2c_76[512] = { 0xF0, 0xF6, 0xB4, 0xE1, 0xAF, 0x7B, 0xF0, 0xF1, /* 0x00-0x03 */ 0xAF, 0x7C, 0xF0, 0xF7, 0xAF, 0x7D, 0xAF, 0x7E, /* 0x04-0x07 */ 0xAF, 0x80, 0xAF, 0x81, 0xF0, 0xFA, 0xAF, 0x82, /* 0x08-0x0B */ @@ -7946,7 +7946,7 @@ static unsigned char u2c_76[512] = { 0xC5, 0xCE, 0xB1, 0x60, 0xB6, 0xDC, 0xB1, 0x61, /* 0xFC-0xFF */ }; -static unsigned char u2c_77[512] = { +static const unsigned char u2c_77[512] = { 0xB1, 0x62, 0xCA, 0xA1, 0xB1, 0x63, 0xB1, 0x64, /* 0x00-0x03 */ 0xED, 0xED, 0xB1, 0x65, 0xB1, 0x66, 0xED, 0xF0, /* 0x04-0x07 */ 0xED, 0xF1, 0xC3, 0xBC, 0xB1, 0x67, 0xBF, 0xB4, /* 0x08-0x0B */ @@ -8014,7 +8014,7 @@ static unsigned char u2c_77[512] = { 0xB3, 0x4D, 0xCE, 0xF9, 0xB7, 0xAF, 0xBF, 0xF3, /* 0xFC-0xFF */ }; -static unsigned char u2c_78[512] = { +static const unsigned char u2c_78[512] = { 0xED, 0xB8, 0xC2, 0xEB, 0xC9, 0xB0, 0xB3, 0x4E, /* 0x00-0x03 */ 0xB3, 0x4F, 0xB3, 0x50, 0xB3, 0x51, 0xB3, 0x52, /* 0x04-0x07 */ 0xB3, 0x53, 0xED, 0xB9, 0xB3, 0x54, 0xB3, 0x55, /* 0x08-0x0B */ @@ -8082,7 +8082,7 @@ static unsigned char u2c_78[512] = { 0xB4, 0x92, 0xB4, 0x93, 0xB4, 0x94, 0xB4, 0x95, /* 0xFC-0xFF */ }; -static unsigned char u2c_79[512] = { +static const unsigned char u2c_79[512] = { 0xB4, 0x96, 0xBD, 0xB8, 0xB4, 0x97, 0xB4, 0x98, /* 0x00-0x03 */ 0xB4, 0x99, 0xED, 0xE2, 0xB4, 0x9A, 0xB4, 0x9B, /* 0x04-0x07 */ 0xB4, 0x9C, 0xB4, 0x9D, 0xB4, 0x9E, 0xB4, 0x9F, /* 0x08-0x0B */ @@ -8150,7 +8150,7 @@ static unsigned char u2c_79[512] = { 0xB6, 0x8B, 0xBB, 0xE0, 0xB6, 0x8C, 0xB6, 0x8D, /* 0xFC-0xFF */ }; -static unsigned char u2c_7A[512] = { +static const unsigned char u2c_7A[512] = { 0xCF, 0xA1, 0xB6, 0x8E, 0xEF, 0xFC, 0xEF, 0xFB, /* 0x00-0x03 */ 0xB6, 0x8F, 0xB6, 0x90, 0xEF, 0xF9, 0xB6, 0x91, /* 0x04-0x07 */ 0xB6, 0x92, 0xB6, 0x93, 0xB6, 0x94, 0xB3, 0xCC, /* 0x08-0x0B */ @@ -8218,7 +8218,7 @@ static unsigned char u2c_7A[512] = { 0xB8, 0x86, 0xF3, 0xC4, 0xB8, 0x87, 0xB8, 0xCD, /* 0xFC-0xFF */ }; -static unsigned char u2c_7B[512] = { +static const unsigned char u2c_7B[512] = { 0xB8, 0x88, 0xB8, 0x89, 0xB8, 0x8A, 0xF3, 0xC6, /* 0x00-0x03 */ 0xF3, 0xC7, 0xB8, 0x8B, 0xB0, 0xCA, 0xB8, 0x8C, /* 0x04-0x07 */ 0xF3, 0xC5, 0xB8, 0x8D, 0xF3, 0xC9, 0xCB, 0xF1, /* 0x08-0x0B */ @@ -8286,7 +8286,7 @@ static unsigned char u2c_7B[512] = { 0xF3, 0xFB, 0xBA, 0x68, 0xF3, 0xFA, 0xBA, 0x69, /* 0xFC-0xFF */ }; -static unsigned char u2c_7C[512] = { +static const unsigned char u2c_7C[512] = { 0xBA, 0x6A, 0xBA, 0x6B, 0xBA, 0x6C, 0xBA, 0x6D, /* 0x00-0x03 */ 0xBA, 0x6E, 0xBA, 0x6F, 0xBA, 0x70, 0xB4, 0xD8, /* 0x04-0x07 */ 0xBA, 0x71, 0xBA, 0x72, 0xBA, 0x73, 0xF3, 0xFE, /* 0x08-0x0B */ @@ -8354,7 +8354,7 @@ static unsigned char u2c_7C[512] = { 0xBC, 0x6B, 0xBC, 0x6C, 0xBC, 0x6D, 0xBC, 0x6E, /* 0xFC-0xFF */ }; -static unsigned char u2c_7D[512] = { +static const unsigned char u2c_7D[512] = { 0xBC, 0x6F, 0xBC, 0x70, 0xBC, 0x71, 0xBC, 0x72, /* 0x00-0x03 */ 0xBC, 0x73, 0xBC, 0x74, 0xBC, 0x75, 0xBC, 0x76, /* 0x04-0x07 */ 0xBC, 0x77, 0xBC, 0x78, 0xCE, 0xC9, 0xBC, 0x79, /* 0x08-0x0B */ @@ -8422,7 +8422,7 @@ static unsigned char u2c_7D[512] = { 0xBF, 0x41, 0xBF, 0x42, 0xBF, 0x43, 0xBF, 0x44, /* 0xFC-0xFF */ }; -static unsigned char u2c_7E[512] = { +static const unsigned char u2c_7E[512] = { 0xBF, 0x45, 0xBF, 0x46, 0xBF, 0x47, 0xBF, 0x48, /* 0x00-0x03 */ 0xBF, 0x49, 0xBF, 0x4A, 0xBF, 0x4B, 0xBF, 0x4C, /* 0x04-0x07 */ 0xBF, 0x4D, 0xBF, 0x4E, 0xBF, 0x4F, 0xBF, 0x50, /* 0x08-0x0B */ @@ -8490,7 +8490,7 @@ static unsigned char u2c_7E[512] = { 0xD7, 0xDB, 0xD5, 0xC0, 0xE7, 0xBA, 0xC2, 0xCC, /* 0xFC-0xFF */ }; -static unsigned char u2c_7F[512] = { +static const unsigned char u2c_7F[512] = { 0xD7, 0xBA, 0xE7, 0xBB, 0xE7, 0xBC, 0xE7, 0xBD, /* 0x00-0x03 */ 0xBC, 0xEA, 0xC3, 0xE5, 0xC0, 0xC2, 0xE7, 0xBE, /* 0x04-0x07 */ 0xE7, 0xBF, 0xBC, 0xA9, 0xC0, 0x88, 0xE7, 0xC0, /* 0x08-0x0B */ @@ -8558,7 +8558,7 @@ static unsigned char u2c_7F[512] = { 0xD2, 0xED, 0xC2, 0x50, 0xC2, 0x51, 0xC2, 0x52, /* 0xFC-0xFF */ }; -static unsigned char u2c_80[512] = { +static const unsigned char u2c_80[512] = { 0xD2, 0xAB, 0xC0, 0xCF, 0xC2, 0x53, 0xBF, 0xBC, /* 0x00-0x03 */ 0xEB, 0xA3, 0xD5, 0xDF, 0xEA, 0xC8, 0xC2, 0x54, /* 0x04-0x07 */ 0xC2, 0x55, 0xC2, 0x56, 0xC2, 0x57, 0xF1, 0xF3, /* 0x08-0x0B */ @@ -8626,7 +8626,7 @@ static unsigned char u2c_80[512] = { 0xEB, 0xDD, 0xC4, 0xDC, 0xC3, 0x75, 0xC3, 0x76, /* 0xFC-0xFF */ }; -static unsigned char u2c_81[512] = { +static const unsigned char u2c_81[512] = { 0xC3, 0x77, 0xC3, 0x78, 0xD6, 0xAC, 0xC3, 0x79, /* 0x00-0x03 */ 0xC3, 0x7A, 0xC3, 0x7B, 0xB4, 0xE0, 0xC3, 0x7C, /* 0x04-0x07 */ 0xC3, 0x7D, 0xC2, 0xF6, 0xBC, 0xB9, 0xC3, 0x7E, /* 0x08-0x0B */ @@ -8694,7 +8694,7 @@ static unsigned char u2c_81[512] = { 0xBE, 0xCA, 0xC5, 0x60, 0xF4, 0xA7, 0xC5, 0x61, /* 0xFC-0xFF */ }; -static unsigned char u2c_82[512] = { +static const unsigned char u2c_82[512] = { 0xD2, 0xA8, 0xF4, 0xA8, 0xF4, 0xA9, 0xC5, 0x62, /* 0x00-0x03 */ 0xF4, 0xAA, 0xBE, 0xCB, 0xD3, 0xDF, 0xC5, 0x63, /* 0x04-0x07 */ 0xC5, 0x64, 0xC5, 0x65, 0xC5, 0x66, 0xC5, 0x67, /* 0x08-0x0B */ @@ -8762,7 +8762,7 @@ static unsigned char u2c_82[512] = { 0xC6, 0x81, 0xC6, 0x82, 0xC6, 0x83, 0xC6, 0x84, /* 0xFC-0xFF */ }; -static unsigned char u2c_83[512] = { +static const unsigned char u2c_83[512] = { 0xC6, 0x85, 0xD7, 0xC2, 0xC3, 0xAF, 0xB7, 0xB6, /* 0x00-0x03 */ 0xC7, 0xD1, 0xC3, 0xA9, 0xDC, 0xE2, 0xDC, 0xD8, /* 0x04-0x07 */ 0xDC, 0xEB, 0xDC, 0xD4, 0xC6, 0x86, 0xC6, 0x87, /* 0x08-0x0B */ @@ -8830,7 +8830,7 @@ static unsigned char u2c_83[512] = { 0xC8, 0x49, 0xDD, 0xC4, 0xC8, 0x4A, 0xC8, 0x4B, /* 0xFC-0xFF */ }; -static unsigned char u2c_84[512] = { +static const unsigned char u2c_84[512] = { 0xC8, 0x4C, 0xDD, 0xBD, 0xC8, 0x4D, 0xDD, 0xCD, /* 0x00-0x03 */ 0xCC, 0xD1, 0xC8, 0x4E, 0xDD, 0xC9, 0xC8, 0x4F, /* 0x04-0x07 */ 0xC8, 0x50, 0xC8, 0x51, 0xC8, 0x52, 0xDD, 0xC2, /* 0x08-0x0B */ @@ -8898,7 +8898,7 @@ static unsigned char u2c_84[512] = { 0xDE, 0xA4, 0xC9, 0x9C, 0xC9, 0x9D, 0xDE, 0xA3, /* 0xFC-0xFF */ }; -static unsigned char u2c_85[512] = { +static const unsigned char u2c_85[512] = { 0xC9, 0x9E, 0xC9, 0x9F, 0xC9, 0xA0, 0xCA, 0x40, /* 0x00-0x03 */ 0xCA, 0x41, 0xCA, 0x42, 0xCA, 0x43, 0xCA, 0x44, /* 0x04-0x07 */ 0xCA, 0x45, 0xCA, 0x46, 0xCA, 0x47, 0xCA, 0x48, /* 0x08-0x0B */ @@ -8966,7 +8966,7 @@ static unsigned char u2c_85[512] = { 0xCC, 0x42, 0xCC, 0x43, 0xCC, 0x44, 0xDE, 0xBD, /* 0xFC-0xFF */ }; -static unsigned char u2c_86[512] = { +static const unsigned char u2c_86[512] = { 0xCC, 0x45, 0xCC, 0x46, 0xCC, 0x47, 0xCC, 0x48, /* 0x00-0x03 */ 0xCC, 0x49, 0xDE, 0xBF, 0xCC, 0x4A, 0xCC, 0x4B, /* 0x04-0x07 */ 0xCC, 0x4C, 0xCC, 0x4D, 0xCC, 0x4E, 0xCC, 0x4F, /* 0x08-0x0B */ @@ -9034,7 +9034,7 @@ static unsigned char u2c_86[512] = { 0xCD, 0x92, 0xCD, 0x93, 0xB6, 0xEA, 0xCD, 0x94, /* 0xFC-0xFF */ }; -static unsigned char u2c_87[512] = { +static const unsigned char u2c_87[512] = { 0xCA, 0xF1, 0xCD, 0x95, 0xB7, 0xE4, 0xF2, 0xD7, /* 0x00-0x03 */ 0xCD, 0x96, 0xCD, 0x97, 0xCD, 0x98, 0xF2, 0xD8, /* 0x04-0x07 */ 0xF2, 0xDA, 0xF2, 0xDD, 0xF2, 0xDB, 0xCD, 0x99, /* 0x08-0x0B */ @@ -9102,7 +9102,7 @@ static unsigned char u2c_87[512] = { 0xCF, 0x82, 0xCF, 0x83, 0xF3, 0xB8, 0xCF, 0x84, /* 0xFC-0xFF */ }; -static unsigned char u2c_88[512] = { +static const unsigned char u2c_88[512] = { 0xCF, 0x85, 0xCF, 0x86, 0xCF, 0x87, 0xD9, 0xF9, /* 0x00-0x03 */ 0xCF, 0x88, 0xCF, 0x89, 0xCF, 0x8A, 0xCF, 0x8B, /* 0x04-0x07 */ 0xCF, 0x8C, 0xCF, 0x8D, 0xF3, 0xB9, 0xCF, 0x8E, /* 0x08-0x0B */ @@ -9170,7 +9170,7 @@ static unsigned char u2c_88[512] = { 0xF1, 0xD3, 0xD1, 0x75, 0xF1, 0xD5, 0xD1, 0x76, /* 0xFC-0xFF */ }; -static unsigned char u2c_89[512] = { +static const unsigned char u2c_89[512] = { 0xD1, 0x77, 0xD1, 0x78, 0xB9, 0xD3, 0xD1, 0x79, /* 0x00-0x03 */ 0xD1, 0x7A, 0xD1, 0x7B, 0xD1, 0x7C, 0xD1, 0x7D, /* 0x04-0x07 */ 0xD1, 0x7E, 0xD1, 0x80, 0xF1, 0xDB, 0xD1, 0x81, /* 0x08-0x0B */ @@ -9238,7 +9238,7 @@ static unsigned char u2c_89[512] = { 0xD3, 0x81, 0xD3, 0x82, 0xD3, 0x83, 0xD3, 0x84, /* 0xFC-0xFF */ }; -static unsigned char u2c_8A[512] = { +static const unsigned char u2c_8A[512] = { 0xD1, 0xD4, 0xD3, 0x85, 0xD3, 0x86, 0xD3, 0x87, /* 0x00-0x03 */ 0xD3, 0x88, 0xD3, 0x89, 0xD3, 0x8A, 0xD9, 0xEA, /* 0x04-0x07 */ 0xD3, 0x8B, 0xD3, 0x8C, 0xD3, 0x8D, 0xD3, 0x8E, /* 0x08-0x0B */ @@ -9306,7 +9306,7 @@ static unsigned char u2c_8A[512] = { 0xD6, 0x58, 0xD6, 0x59, 0xD6, 0x5A, 0xD6, 0x5B, /* 0xFC-0xFF */ }; -static unsigned char u2c_8B[512] = { +static const unsigned char u2c_8B[512] = { 0xD6, 0x5C, 0xD6, 0x5D, 0xD6, 0x5E, 0xD6, 0x5F, /* 0x00-0x03 */ 0xD6, 0x60, 0xD6, 0x61, 0xD6, 0x62, 0xE5, 0xC0, /* 0x04-0x07 */ 0xD6, 0x63, 0xD6, 0x64, 0xD6, 0x65, 0xD6, 0x66, /* 0x08-0x0B */ @@ -9374,7 +9374,7 @@ static unsigned char u2c_8B[512] = { 0xDA, 0xC2, 0xB7, 0xCC, 0xBF, 0xCE, 0xDA, 0xC3, /* 0xFC-0xFF */ }; -static unsigned char u2c_8C[512] = { +static const unsigned char u2c_8C[512] = { 0xDA, 0xC4, 0xCB, 0xAD, 0xDA, 0xC5, 0xB5, 0xF7, /* 0x00-0x03 */ 0xDA, 0xC6, 0xC1, 0xC2, 0xD7, 0xBB, 0xDA, 0xC7, /* 0x04-0x07 */ 0xCC, 0xB8, 0xD7, 0x9F, 0xD2, 0xEA, 0xC4, 0xB1, /* 0x08-0x0B */ @@ -9442,7 +9442,7 @@ static unsigned char u2c_8C[512] = { 0xD9, 0x8F, 0xD9, 0x90, 0xD9, 0x91, 0xD9, 0x92, /* 0xFC-0xFF */ }; -static unsigned char u2c_8D[512] = { +static const unsigned char u2c_8D[512] = { 0xD9, 0x93, 0xD9, 0x94, 0xD9, 0x95, 0xD9, 0x96, /* 0x00-0x03 */ 0xD9, 0x97, 0xD9, 0x98, 0xD9, 0x99, 0xD9, 0x9A, /* 0x04-0x07 */ 0xD9, 0x9B, 0xD9, 0x9C, 0xD9, 0x9D, 0xD9, 0x9E, /* 0x08-0x0B */ @@ -9510,7 +9510,7 @@ static unsigned char u2c_8D[512] = { 0xDB, 0x52, 0xF5, 0xD5, 0xDB, 0x53, 0xDB, 0x54, /* 0xFC-0xFF */ }; -static unsigned char u2c_8E[512] = { +static const unsigned char u2c_8E[512] = { 0xDB, 0x55, 0xDB, 0x56, 0xDB, 0x57, 0xDB, 0x58, /* 0x00-0x03 */ 0xDB, 0x59, 0xF5, 0xBD, 0xDB, 0x5A, 0xDB, 0x5B, /* 0x04-0x07 */ 0xDB, 0x5C, 0xF5, 0xD4, 0xD3, 0xBB, 0xDB, 0x5D, /* 0x08-0x0B */ @@ -9578,7 +9578,7 @@ static unsigned char u2c_8E[512] = { 0xDD, 0x57, 0xDD, 0x58, 0xDD, 0x59, 0xDD, 0x5A, /* 0xFC-0xFF */ }; -static unsigned char u2c_8F[512] = { +static const unsigned char u2c_8F[512] = { 0xDD, 0x5B, 0xDD, 0x5C, 0xDD, 0x5D, 0xDD, 0x5E, /* 0x00-0x03 */ 0xDD, 0x5F, 0xDD, 0x60, 0xDD, 0x61, 0xDD, 0x62, /* 0x04-0x07 */ 0xDD, 0x63, 0xDD, 0x64, 0xDD, 0x65, 0xDD, 0x66, /* 0x08-0x0B */ @@ -9646,7 +9646,7 @@ static unsigned char u2c_8F[512] = { 0xDE, 0x97, 0xD7, 0xB7, 0xDE, 0x98, 0xDE, 0x99, /* 0xFC-0xFF */ }; -static unsigned char u2c_90[512] = { +static const unsigned char u2c_90[512] = { 0xCD, 0xCB, 0xCB, 0xCD, 0xCA, 0xCA, 0xCC, 0xD3, /* 0x00-0x03 */ 0xE5, 0xCC, 0xE5, 0xCB, 0xC4, 0xE6, 0xDE, 0x9A, /* 0x04-0x07 */ 0xDE, 0x9B, 0xD1, 0xA1, 0xD1, 0xB7, 0xE5, 0xCD, /* 0x08-0x0B */ @@ -9714,7 +9714,7 @@ static unsigned char u2c_90[512] = { 0xE0, 0x63, 0xB6, 0xBC, 0xDB, 0xB1, 0xE0, 0x64, /* 0xFC-0xFF */ }; -static unsigned char u2c_91[512] = { +static const unsigned char u2c_91[512] = { 0xE0, 0x65, 0xE0, 0x66, 0xB6, 0xF5, 0xE0, 0x67, /* 0x00-0x03 */ 0xDB, 0xB2, 0xE0, 0x68, 0xE0, 0x69, 0xE0, 0x6A, /* 0x04-0x07 */ 0xE0, 0x6B, 0xE0, 0x6C, 0xE0, 0x6D, 0xE0, 0x6E, /* 0x08-0x0B */ @@ -9782,7 +9782,7 @@ static unsigned char u2c_91[512] = { 0xE2, 0x56, 0xE2, 0x57, 0xE2, 0x58, 0xE2, 0x59, /* 0xFC-0xFF */ }; -static unsigned char u2c_92[512] = { +static const unsigned char u2c_92[512] = { 0xE2, 0x5A, 0xE2, 0x5B, 0xE2, 0x5C, 0xE2, 0x5D, /* 0x00-0x03 */ 0xE2, 0x5E, 0xE2, 0x5F, 0xE2, 0x60, 0xE2, 0x61, /* 0x04-0x07 */ 0xE2, 0x62, 0xE2, 0x63, 0xE2, 0x64, 0xE2, 0x65, /* 0x08-0x0B */ @@ -9850,7 +9850,7 @@ static unsigned char u2c_92[512] = { 0xE4, 0x93, 0xE4, 0x94, 0xE4, 0x95, 0xE4, 0x96, /* 0xFC-0xFF */ }; -static unsigned char u2c_93[512] = { +static const unsigned char u2c_93[512] = { 0xE4, 0x97, 0xE4, 0x98, 0xE4, 0x99, 0xE4, 0x9A, /* 0x00-0x03 */ 0xE4, 0x9B, 0xE4, 0x9C, 0xE4, 0x9D, 0xE4, 0x9E, /* 0x04-0x07 */ 0xE4, 0x9F, 0xE4, 0xA0, 0xE5, 0x40, 0xE5, 0x41, /* 0x08-0x0B */ @@ -9918,7 +9918,7 @@ static unsigned char u2c_93[512] = { 0xE7, 0x6D, 0xE7, 0x6E, 0xE7, 0x6F, 0xE7, 0x70, /* 0xFC-0xFF */ }; -static unsigned char u2c_94[512] = { +static const unsigned char u2c_94[512] = { 0xE7, 0x71, 0xE7, 0x72, 0xE7, 0x73, 0xE7, 0x74, /* 0x00-0x03 */ 0xE7, 0x75, 0xE7, 0x76, 0xE7, 0x77, 0xE7, 0x78, /* 0x04-0x07 */ 0xE7, 0x79, 0xE7, 0x7A, 0xE7, 0x7B, 0xE7, 0x7C, /* 0x08-0x0B */ @@ -9986,7 +9986,7 @@ static unsigned char u2c_94[512] = { 0xEF, 0xAA, 0xEF, 0xAB, 0xC1, 0xB4, 0xEF, 0xAC, /* 0xFC-0xFF */ }; -static unsigned char u2c_95[512] = { +static const unsigned char u2c_95[512] = { 0xCF, 0xFA, 0xCB, 0xF8, 0xEF, 0xAE, 0xEF, 0xAD, /* 0x00-0x03 */ 0xB3, 0xFA, 0xB9, 0xF8, 0xEF, 0xAF, 0xEF, 0xB0, /* 0x04-0x07 */ 0xD0, 0xE2, 0xEF, 0xB1, 0xEF, 0xB2, 0xB7, 0xE6, /* 0x08-0x0B */ @@ -10054,7 +10054,7 @@ static unsigned char u2c_95[512] = { 0xE3, 0xCB, 0xC3, 0xF6, 0xE3, 0xCC, 0xEA, 0x5D, /* 0xFC-0xFF */ }; -static unsigned char u2c_96[512] = { +static const unsigned char u2c_96[512] = { 0xB7, 0xA7, 0xB8, 0xF3, 0xBA, 0xD2, 0xE3, 0xCD, /* 0x00-0x03 */ 0xE3, 0xCE, 0xD4, 0xC4, 0xE3, 0xCF, 0xEA, 0x5E, /* 0x04-0x07 */ 0xE3, 0xD0, 0xD1, 0xCB, 0xE3, 0xD1, 0xE3, 0xD2, /* 0x08-0x0B */ @@ -10122,7 +10122,7 @@ static unsigned char u2c_96[512] = { 0xEB, 0x8B, 0xEB, 0x8C, 0xCE, 0xED, 0xEB, 0x8D, /* 0xFC-0xFF */ }; -static unsigned char u2c_97[512] = { +static const unsigned char u2c_97[512] = { 0xD0, 0xE8, 0xF6, 0xAB, 0xEB, 0x8E, 0xEB, 0x8F, /* 0x00-0x03 */ 0xCF, 0xF6, 0xEB, 0x90, 0xF6, 0xAA, 0xD5, 0xF0, /* 0x04-0x07 */ 0xF6, 0xAC, 0xC3, 0xB9, 0xEB, 0x91, 0xEB, 0x92, /* 0x08-0x0B */ @@ -10190,7 +10190,7 @@ static unsigned char u2c_97[512] = { 0xED, 0x8E, 0xED, 0x8F, 0xED, 0x90, 0xED, 0x91, /* 0xFC-0xFF */ }; -static unsigned char u2c_98[512] = { +static const unsigned char u2c_98[512] = { 0xED, 0x92, 0xED, 0x93, 0xED, 0x94, 0xED, 0x95, /* 0x00-0x03 */ 0xED, 0x96, 0xED, 0x97, 0xED, 0x98, 0xED, 0x99, /* 0x04-0x07 */ 0xED, 0x9A, 0xED, 0x9B, 0xED, 0x9C, 0xED, 0x9D, /* 0x08-0x0B */ @@ -10258,7 +10258,7 @@ static unsigned char u2c_98[512] = { 0xEF, 0x95, 0xEF, 0x96, 0xEF, 0x97, 0xEF, 0x98, /* 0xFC-0xFF */ }; -static unsigned char u2c_99[512] = { +static const unsigned char u2c_99[512] = { 0xEF, 0x99, 0xEF, 0x9A, 0xEF, 0x9B, 0xEF, 0x9C, /* 0x00-0x03 */ 0xEF, 0x9D, 0xEF, 0x9E, 0xEF, 0x9F, 0xEF, 0xA0, /* 0x04-0x07 */ 0xF0, 0x40, 0xF0, 0x41, 0xF0, 0x42, 0xF0, 0x43, /* 0x08-0x0B */ @@ -10326,7 +10326,7 @@ static unsigned char u2c_99[512] = { 0xF2, 0x42, 0xF2, 0x43, 0xF2, 0x44, 0xF2, 0x45, /* 0xFC-0xFF */ }; -static unsigned char u2c_9A[512] = { +static const unsigned char u2c_9A[512] = { 0xF2, 0x46, 0xF2, 0x47, 0xF2, 0x48, 0xF2, 0x49, /* 0x00-0x03 */ 0xF2, 0x4A, 0xF2, 0x4B, 0xF2, 0x4C, 0xF2, 0x4D, /* 0x04-0x07 */ 0xF2, 0x4E, 0xF2, 0x4F, 0xF2, 0x50, 0xF2, 0x51, /* 0x08-0x0B */ @@ -10394,7 +10394,7 @@ static unsigned char u2c_9A[512] = { 0xF3, 0x97, 0xF3, 0x98, 0xF3, 0x99, 0xF3, 0x9A, /* 0xFC-0xFF */ }; -static unsigned char u2c_9B[512] = { +static const unsigned char u2c_9B[512] = { 0xF3, 0x9B, 0xF3, 0x9C, 0xF3, 0x9D, 0xD7, 0xD7, /* 0x00-0x03 */ 0xF3, 0x9E, 0xF3, 0x9F, 0xF3, 0xA0, 0xF4, 0x40, /* 0x04-0x07 */ 0xF7, 0xDC, 0xF4, 0x41, 0xF4, 0x42, 0xF4, 0x43, /* 0x08-0x0B */ @@ -10462,7 +10462,7 @@ static unsigned char u2c_9B[512] = { 0xF6, 0x60, 0xF6, 0x61, 0xF6, 0x62, 0xF6, 0x63, /* 0xFC-0xFF */ }; -static unsigned char u2c_9C[512] = { +static const unsigned char u2c_9C[512] = { 0xF6, 0x64, 0xF6, 0x65, 0xF6, 0x66, 0xF6, 0x67, /* 0x00-0x03 */ 0xF6, 0x68, 0xF6, 0x69, 0xF6, 0x6A, 0xF6, 0x6B, /* 0x04-0x07 */ 0xF6, 0x6C, 0xF6, 0x6D, 0xF6, 0x6E, 0xF6, 0x6F, /* 0x08-0x0B */ @@ -10530,7 +10530,7 @@ static unsigned char u2c_9C[512] = { 0xF8, 0x59, 0xF8, 0x5A, 0xF8, 0x5B, 0xF8, 0x5C, /* 0xFC-0xFF */ }; -static unsigned char u2c_9D[512] = { +static const unsigned char u2c_9D[512] = { 0xF8, 0x5D, 0xF8, 0x5E, 0xF8, 0x5F, 0xF8, 0x60, /* 0x00-0x03 */ 0xF8, 0x61, 0xF8, 0x62, 0xF8, 0x63, 0xF8, 0x64, /* 0x04-0x07 */ 0xF8, 0x65, 0xF8, 0x66, 0xF8, 0x67, 0xF8, 0x68, /* 0x08-0x0B */ @@ -10598,7 +10598,7 @@ static unsigned char u2c_9D[512] = { 0xFA, 0x9A, 0xFA, 0x9B, 0xFA, 0x9C, 0xFA, 0x9D, /* 0xFC-0xFF */ }; -static unsigned char u2c_9E[512] = { +static const unsigned char u2c_9E[512] = { 0xFA, 0x9E, 0xFA, 0x9F, 0xFA, 0xA0, 0xFB, 0x40, /* 0x00-0x03 */ 0xFB, 0x41, 0xFB, 0x42, 0xFB, 0x43, 0xFB, 0x44, /* 0x04-0x07 */ 0xFB, 0x45, 0xFB, 0x46, 0xFB, 0x47, 0xFB, 0x48, /* 0x08-0x0B */ @@ -10666,7 +10666,7 @@ static unsigned char u2c_9E[512] = { 0xED, 0xEB, 0xFC, 0x77, 0xF6, 0xBC, 0xFC, 0x78, /* 0xFC-0xFF */ }; -static unsigned char u2c_9F[512] = { +static const unsigned char u2c_9F[512] = { 0xFC, 0x79, 0xFC, 0x7A, 0xFC, 0x7B, 0xFC, 0x7C, /* 0x00-0x03 */ 0xFC, 0x7D, 0xFC, 0x7E, 0xFC, 0x80, 0xFC, 0x81, /* 0x04-0x07 */ 0xFC, 0x82, 0xFC, 0x83, 0xFC, 0x84, 0xF6, 0xBD, /* 0x08-0x0B */ @@ -10712,11 +10712,11 @@ static unsigned char u2c_9F[512] = { 0xFD, 0x9A, 0xFD, 0x9B, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ }; -static unsigned char u2c_DC[512] = { +static const unsigned char u2c_DC[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ }; -static unsigned char u2c_F9[512] = { +static const unsigned char u2c_F9[512] = { 0xD8, 0x4D, 0xB8, 0xFC, 0xDC, 0x87, 0xD9, 0x5A, /* 0x00-0x03 */ 0xBB, 0xAC, 0xB4, 0xAE, 0xBE, 0xE4, 0xFD, 0x94, /* 0x04-0x07 */ 0xFD, 0x94, 0xC6, 0xF5, 0xBD, 0xF0, 0xC0, 0xAE, /* 0x08-0x0B */ @@ -10784,7 +10784,7 @@ static unsigned char u2c_F9[512] = { 0xD7, 0x52, 0xCA, 0xB2, 0xB2, 0xE8, 0xB4, 0xCC, /* 0xFC-0xFF */ }; -static unsigned char u2c_FA[512] = { +static const unsigned char u2c_FA[512] = { 0xC7, 0xD0, 0xB6, 0xC8, 0xCD, 0xD8, 0xCC, 0xC7, /* 0x00-0x03 */ 0xD5, 0xAC, 0xB6, 0xB4, 0xB1, 0xA9, 0xDD, 0x97, /* 0x04-0x07 */ 0xD0, 0xD0, 0xBD, 0xB5, 0xD2, 0x8A, 0xC0, 0xAA, /* 0x08-0x0B */ @@ -10799,7 +10799,7 @@ static unsigned char u2c_FA[512] = { 0xF0, 0x5E, 0xFA, 0x51, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ }; -static unsigned char u2c_FE[512] = { +static const unsigned char u2c_FE[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -10829,7 +10829,7 @@ static unsigned char u2c_FE[512] = { 0xA9, 0x85, 0xA9, 0x86, 0xA9, 0x87, 0xA9, 0x88, /* 0x68-0x6B */ }; -static unsigned char u2c_FF[512] = { +static const unsigned char u2c_FF[512] = { 0x00, 0x00, 0xA3, 0xA1, 0xA3, 0xA2, 0xA3, 0xA3, /* 0x00-0x03 */ 0xA1, 0xE7, 0xA3, 0xA5, 0xA3, 0xA6, 0xA3, 0xA7, /* 0x04-0x07 */ 0xA3, 0xA8, 0xA3, 0xA9, 0xA3, 0xAA, 0xA3, 0xAB, /* 0x08-0x0B */ @@ -10891,7 +10891,7 @@ static unsigned char u2c_FF[512] = { 0xA9, 0x57, 0xA3, 0xA4, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { u2c_00, u2c_01, u2c_02, u2c_03, u2c_04, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -10925,7 +10925,7 @@ static unsigned char *page_uni2charset[256] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, u2c_F9, u2c_FA, NULL, NULL, NULL, u2c_FE, u2c_FF, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -10961,7 +10961,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -11000,7 +11000,7 @@ static unsigned char charset2upper[256] = { static int uni2char(const wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni&0xFF; unsigned char ch = (uni>>8)&0xFF; unsigned char out0,out1; @@ -11050,7 +11050,7 @@ static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) { unsigned char ch, cl; - wchar_t *charset2uni; + const wchar_t *charset2uni; int n; if (boundlen <= 0) diff --git a/fs/nls/nls_cp949.c b/fs/nls/nls_cp949.c index 92ae19372f0f..8a7a2fe85c65 100644 --- a/fs/nls/nls_cp949.c +++ b/fs/nls/nls_cp949.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t c2u_81[256] = { +static const wchar_t c2u_81[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -49,7 +49,7 @@ static wchar_t c2u_81[256] = { 0xAD09,0xAD0A,0xAD0B,0xAD0E,0xAD10,0xAD12,0xAD13,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_82[256] = { +static const wchar_t c2u_82[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -85,7 +85,7 @@ static wchar_t c2u_82[256] = { 0xADF1,0xADF2,0xADF3,0xADF4,0xADF5,0xADF6,0xADF7,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_83[256] = { +static const wchar_t c2u_83[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -121,7 +121,7 @@ static wchar_t c2u_83[256] = { 0xAEDF,0xAEE0,0xAEE1,0xAEE2,0xAEE3,0xAEE4,0xAEE5,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_84[256] = { +static const wchar_t c2u_84[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -157,7 +157,7 @@ static wchar_t c2u_84[256] = { 0xAFB5,0xAFB6,0xAFB7,0xAFBA,0xAFBB,0xAFBD,0xAFBE,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_85[256] = { +static const wchar_t c2u_85[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -193,7 +193,7 @@ static wchar_t c2u_85[256] = { 0xB096,0xB097,0xB09B,0xB09D,0xB09E,0xB0A3,0xB0A4,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_86[256] = { +static const wchar_t c2u_86[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -229,7 +229,7 @@ static wchar_t c2u_86[256] = { 0xB195,0xB196,0xB197,0xB199,0xB19A,0xB19B,0xB19D,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_87[256] = { +static const wchar_t c2u_87[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -265,7 +265,7 @@ static wchar_t c2u_87[256] = { 0xB266,0xB267,0xB26A,0xB26B,0xB26C,0xB26D,0xB26E,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_88[256] = { +static const wchar_t c2u_88[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -301,7 +301,7 @@ static wchar_t c2u_88[256] = { 0xB359,0xB35A,0xB35D,0xB360,0xB361,0xB362,0xB363,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_89[256] = { +static const wchar_t c2u_89[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -337,7 +337,7 @@ static wchar_t c2u_89[256] = { 0xB43E,0xB43F,0xB440,0xB441,0xB442,0xB443,0xB444,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_8A[256] = { +static const wchar_t c2u_8A[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -373,7 +373,7 @@ static wchar_t c2u_8A[256] = { 0xB512,0xB513,0xB516,0xB517,0xB519,0xB51A,0xB51D,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_8B[256] = { +static const wchar_t c2u_8B[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -409,7 +409,7 @@ static wchar_t c2u_8B[256] = { 0xB5F9,0xB5FA,0xB5FB,0xB5FC,0xB5FD,0xB5FE,0xB5FF,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_8C[256] = { +static const wchar_t c2u_8C[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -445,7 +445,7 @@ static wchar_t c2u_8C[256] = { 0xB6BC,0xB6BD,0xB6BE,0xB6BF,0xB6C0,0xB6C1,0xB6C2,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_8D[256] = { +static const wchar_t c2u_8D[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -481,7 +481,7 @@ static wchar_t c2u_8D[256] = { 0xB793,0xB794,0xB795,0xB79A,0xB79B,0xB79D,0xB79E,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_8E[256] = { +static const wchar_t c2u_8E[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -517,7 +517,7 @@ static wchar_t c2u_8E[256] = { 0xB87E,0xB87F,0xB880,0xB881,0xB882,0xB883,0xB884,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_8F[256] = { +static const wchar_t c2u_8F[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -553,7 +553,7 @@ static wchar_t c2u_8F[256] = { 0xB950,0xB952,0xB953,0xB954,0xB955,0xB956,0xB957,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_90[256] = { +static const wchar_t c2u_90[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -589,7 +589,7 @@ static wchar_t c2u_90[256] = { 0xBA3E,0xBA3F,0xBA41,0xBA43,0xBA44,0xBA45,0xBA46,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_91[256] = { +static const wchar_t c2u_91[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -625,7 +625,7 @@ static wchar_t c2u_91[256] = { 0xBB21,0xBB22,0xBB23,0xBB24,0xBB25,0xBB26,0xBB27,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_92[256] = { +static const wchar_t c2u_92[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -661,7 +661,7 @@ static wchar_t c2u_92[256] = { 0xBBF6,0xBBF7,0xBBFA,0xBBFB,0xBBFD,0xBBFE,0xBC01,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_93[256] = { +static const wchar_t c2u_93[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -697,7 +697,7 @@ static wchar_t c2u_93[256] = { 0xBCF2,0xBCF3,0xBCF7,0xBCF9,0xBCFA,0xBCFB,0xBCFD,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_94[256] = { +static const wchar_t c2u_94[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -733,7 +733,7 @@ static wchar_t c2u_94[256] = { 0xBDCB,0xBDCC,0xBDCD,0xBDCE,0xBDCF,0xBDD0,0xBDD1,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_95[256] = { +static const wchar_t c2u_95[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -769,7 +769,7 @@ static wchar_t c2u_95[256] = { 0xBEB1,0xBEB2,0xBEB3,0xBEB4,0xBEB5,0xBEB6,0xBEB7,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_96[256] = { +static const wchar_t c2u_96[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -805,7 +805,7 @@ static wchar_t c2u_96[256] = { 0xBF7C,0xBF7D,0xBF7E,0xBF7F,0xBF80,0xBF81,0xBF82,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_97[256] = { +static const wchar_t c2u_97[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -841,7 +841,7 @@ static wchar_t c2u_97[256] = { 0xC038,0xC039,0xC03A,0xC03B,0xC03D,0xC03E,0xC03F,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_98[256] = { +static const wchar_t c2u_98[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -877,7 +877,7 @@ static wchar_t c2u_98[256] = { 0xC122,0xC125,0xC128,0xC129,0xC12A,0xC12B,0xC12E,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_99[256] = { +static const wchar_t c2u_99[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -913,7 +913,7 @@ static wchar_t c2u_99[256] = { 0xC21A,0xC21B,0xC21D,0xC21E,0xC221,0xC222,0xC223,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_9A[256] = { +static const wchar_t c2u_9A[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -949,7 +949,7 @@ static wchar_t c2u_9A[256] = { 0xC305,0xC306,0xC307,0xC30A,0xC30B,0xC30E,0xC30F,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_9B[256] = { +static const wchar_t c2u_9B[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -985,7 +985,7 @@ static wchar_t c2u_9B[256] = { 0xC3D2,0xC3D3,0xC3D4,0xC3D5,0xC3D6,0xC3D7,0xC3DA,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_9C[256] = { +static const wchar_t c2u_9C[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1021,7 +1021,7 @@ static wchar_t c2u_9C[256] = { 0xC4A3,0xC4A4,0xC4A5,0xC4A6,0xC4A7,0xC4A8,0xC4A9,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_9D[256] = { +static const wchar_t c2u_9D[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1057,7 +1057,7 @@ static wchar_t c2u_9D[256] = { 0xC58A,0xC58B,0xC58E,0xC590,0xC592,0xC593,0xC594,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_9E[256] = { +static const wchar_t c2u_9E[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1093,7 +1093,7 @@ static wchar_t c2u_9E[256] = { 0xC69E,0xC69F,0xC6A0,0xC6A1,0xC6A2,0xC6A3,0xC6A6,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_9F[256] = { +static const wchar_t c2u_9F[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1129,7 +1129,7 @@ static wchar_t c2u_9F[256] = { 0xC7AF,0xC7B1,0xC7B2,0xC7B3,0xC7B5,0xC7B6,0xC7B7,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_A0[256] = { +static const wchar_t c2u_A0[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1165,7 +1165,7 @@ static wchar_t c2u_A0[256] = { 0xC89B,0xC89C,0xC89E,0xC8A0,0xC8A2,0xC8A3,0xC8A4,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_A1[256] = { +static const wchar_t c2u_A1[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1201,7 +1201,7 @@ static wchar_t c2u_A1[256] = { 0x2282,0x2283,0x222A,0x2229,0x2227,0x2228,0xFFE2,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_A2[256] = { +static const wchar_t c2u_A2[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1234,7 +1234,7 @@ static wchar_t c2u_A2[256] = { 0x2116,0x33C7,0x2122,0x33C2,0x33D8,0x2121,0x20AC,0x00AE,/* 0xE0-0xE7 */ }; -static wchar_t c2u_A3[256] = { +static const wchar_t c2u_A3[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1270,7 +1270,7 @@ static wchar_t c2u_A3[256] = { 0xFF58,0xFF59,0xFF5A,0xFF5B,0xFF5C,0xFF5D,0xFFE3,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_A4[256] = { +static const wchar_t c2u_A4[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1306,7 +1306,7 @@ static wchar_t c2u_A4[256] = { 0x3188,0x3189,0x318A,0x318B,0x318C,0x318D,0x318E,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_A5[256] = { +static const wchar_t c2u_A5[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1342,7 +1342,7 @@ static wchar_t c2u_A5[256] = { 0x03C9,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_A6[256] = { +static const wchar_t c2u_A6[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1375,7 +1375,7 @@ static wchar_t c2u_A6[256] = { 0x2546,0x2547,0x2548,0x2549,0x254A,0x0000,0x0000,0x0000,/* 0xE0-0xE7 */ }; -static wchar_t c2u_A7[256] = { +static const wchar_t c2u_A7[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1409,7 +1409,7 @@ static wchar_t c2u_A7[256] = { 0x33AC,0x33DD,0x33D0,0x33D3,0x33C3,0x33C9,0x33DC,0x33C6,/* 0xE8-0xEF */ }; -static wchar_t c2u_A8[256] = { +static const wchar_t c2u_A8[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1445,7 +1445,7 @@ static wchar_t c2u_A8[256] = { 0x2154,0x00BC,0x00BE,0x215B,0x215C,0x215D,0x215E,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_A9[256] = { +static const wchar_t c2u_A9[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1481,7 +1481,7 @@ static wchar_t c2u_A9[256] = { 0x00B3,0x2074,0x207F,0x2081,0x2082,0x2083,0x2084,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_AA[256] = { +static const wchar_t c2u_AA[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1516,7 +1516,7 @@ static wchar_t c2u_AA[256] = { 0x3090,0x3091,0x3092,0x3093,0x0000,0x0000,0x0000,0x0000,/* 0xF0-0xF7 */ }; -static wchar_t c2u_AB[256] = { +static const wchar_t c2u_AB[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1551,7 +1551,7 @@ static wchar_t c2u_AB[256] = { 0x30F0,0x30F1,0x30F2,0x30F3,0x30F4,0x30F5,0x30F6,0x0000,/* 0xF0-0xF7 */ }; -static wchar_t c2u_AC[256] = { +static const wchar_t c2u_AC[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1586,7 +1586,7 @@ static wchar_t c2u_AC[256] = { 0x044E,0x044F,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xF0-0xF7 */ }; -static wchar_t c2u_AD[256] = { +static const wchar_t c2u_AD[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1611,7 +1611,7 @@ static wchar_t c2u_AD[256] = { 0xCDC5,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ }; -static wchar_t c2u_AE[256] = { +static const wchar_t c2u_AE[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1636,7 +1636,7 @@ static wchar_t c2u_AE[256] = { 0xCE2B,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ }; -static wchar_t c2u_AF[256] = { +static const wchar_t c2u_AF[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1661,7 +1661,7 @@ static wchar_t c2u_AF[256] = { 0xCE99,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ }; -static wchar_t c2u_B0[256] = { +static const wchar_t c2u_B0[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1697,7 +1697,7 @@ static wchar_t c2u_B0[256] = { 0xACF5,0xACF6,0xACFC,0xACFD,0xAD00,0xAD04,0xAD06,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B1[256] = { +static const wchar_t c2u_B1[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1733,7 +1733,7 @@ static wchar_t c2u_B1[256] = { 0xAE61,0xAE65,0xAE68,0xAE69,0xAE6C,0xAE70,0xAE78,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B2[256] = { +static const wchar_t c2u_B2[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1769,7 +1769,7 @@ static wchar_t c2u_B2[256] = { 0xB04C,0xB04E,0xB053,0xB054,0xB055,0xB057,0xB059,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B3[256] = { +static const wchar_t c2u_B3[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1805,7 +1805,7 @@ static wchar_t c2u_B3[256] = { 0xB19C,0xB1A8,0xB1CC,0xB1D0,0xB1D4,0xB1DC,0xB1DD,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B4[256] = { +static const wchar_t c2u_B4[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1841,7 +1841,7 @@ static wchar_t c2u_B4[256] = { 0xB358,0xB35B,0xB35C,0xB35E,0xB35F,0xB364,0xB365,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B5[256] = { +static const wchar_t c2u_B5[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1877,7 +1877,7 @@ static wchar_t c2u_B5[256] = { 0xB528,0xB529,0xB52A,0xB530,0xB531,0xB534,0xB538,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B6[256] = { +static const wchar_t c2u_B6[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1913,7 +1913,7 @@ static wchar_t c2u_B6[256] = { 0xB78D,0xB78F,0xB790,0xB791,0xB792,0xB796,0xB797,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B7[256] = { +static const wchar_t c2u_B7[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1949,7 +1949,7 @@ static wchar_t c2u_B7[256] = { 0xB951,0xB958,0xB959,0xB95C,0xB960,0xB968,0xB969,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B8[256] = { +static const wchar_t c2u_B8[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1985,7 +1985,7 @@ static wchar_t c2u_B8[256] = { 0xBABB,0xBABD,0xBAC4,0xBAC8,0xBAD8,0xBAD9,0xBAFC,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B9[256] = { +static const wchar_t c2u_B9[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2021,7 +2021,7 @@ static wchar_t c2u_B9[256] = { 0xBC88,0xBC8B,0xBC8C,0xBC8E,0xBC94,0xBC95,0xBC97,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_BA[256] = { +static const wchar_t c2u_BA[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2057,7 +2057,7 @@ static wchar_t c2u_BA[256] = { 0xBE57,0xBE59,0xBE5A,0xBE5B,0xBE60,0xBE61,0xBE64,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_BB[256] = { +static const wchar_t c2u_BB[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2093,7 +2093,7 @@ static wchar_t c2u_BB[256] = { 0xC0D0,0xC0D8,0xC0D9,0xC0DB,0xC0DC,0xC0DD,0xC0E4,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_BC[256] = { +static const wchar_t c2u_BC[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2129,7 +2129,7 @@ static wchar_t c2u_BC[256] = { 0xC21C,0xC21F,0xC220,0xC228,0xC229,0xC22B,0xC22D,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_BD[256] = { +static const wchar_t c2u_BD[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2165,7 +2165,7 @@ static wchar_t c2u_BD[256] = { 0xC3F5,0xC3F8,0xC408,0xC410,0xC424,0xC42C,0xC430,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_BE[256] = { +static const wchar_t c2u_BE[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2201,7 +2201,7 @@ static wchar_t c2u_BE[256] = { 0xC5C6,0xC5C7,0xC5C8,0xC5C9,0xC5CA,0xC5CC,0xC5CE,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_BF[256] = { +static const wchar_t c2u_BF[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2237,7 +2237,7 @@ static wchar_t c2u_BF[256] = { 0xC6D0,0xC6D4,0xC6DC,0xC6DD,0xC6E0,0xC6E1,0xC6E8,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C0[256] = { +static const wchar_t c2u_C0[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2273,7 +2273,7 @@ static wchar_t c2u_C0[256] = { 0xC7E8,0xC7EC,0xC800,0xC801,0xC804,0xC808,0xC80A,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C1[256] = { +static const wchar_t c2u_C1[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2309,7 +2309,7 @@ static wchar_t c2u_C1[256] = { 0xC9C4,0xC9C7,0xC9C8,0xC9CA,0xC9D0,0xC9D1,0xC9D3,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C2[256] = { +static const wchar_t c2u_C2[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2345,7 +2345,7 @@ static wchar_t c2u_C2[256] = { 0xCC29,0xCC2C,0xCC2E,0xCC30,0xCC38,0xCC39,0xCC3B,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C3[256] = { +static const wchar_t c2u_C3[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2381,7 +2381,7 @@ static wchar_t c2u_C3[256] = { 0xCE21,0xCE24,0xCE28,0xCE30,0xCE31,0xCE33,0xCE35,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C4[256] = { +static const wchar_t c2u_C4[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2417,7 +2417,7 @@ static wchar_t c2u_C4[256] = { 0xD011,0xD018,0xD02D,0xD034,0xD035,0xD038,0xD03C,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C5[256] = { +static const wchar_t c2u_C5[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2453,7 +2453,7 @@ static wchar_t c2u_C5[256] = { 0xD234,0xD23C,0xD23D,0xD23F,0xD241,0xD248,0xD25C,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C6[256] = { +static const wchar_t c2u_C6[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2489,7 +2489,7 @@ static wchar_t c2u_C6[256] = { 0xD3ED,0xD3F0,0xD3F4,0xD3FC,0xD3FD,0xD3FF,0xD401,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C7[256] = { +static const wchar_t c2u_C7[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2525,7 +2525,7 @@ static wchar_t c2u_C7[256] = { 0xD610,0xD611,0xD613,0xD614,0xD615,0xD61C,0xD620,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C8[256] = { +static const wchar_t c2u_C8[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2561,7 +2561,7 @@ static wchar_t c2u_C8[256] = { 0xD789,0xD78C,0xD790,0xD798,0xD799,0xD79B,0xD79D,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_CA[256] = { +static const wchar_t c2u_CA[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2597,7 +2597,7 @@ static wchar_t c2u_CA[256] = { 0x76E3,0x77B0,0x7D3A,0x90AF,0x9451,0x9452,0x9F95,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_CB[256] = { +static const wchar_t c2u_CB[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2633,7 +2633,7 @@ static wchar_t c2u_CB[256] = { 0x5091,0x6770,0x6840,0x5109,0x528D,0x5292,0x6AA2,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_CC[256] = { +static const wchar_t c2u_CC[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2669,7 +2669,7 @@ static wchar_t c2u_CC[256] = { 0x5951,0x5B63,0x5C46,0x60B8,0x6212,0x6842,0x68B0,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_CD[256] = { +static const wchar_t c2u_CD[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2705,7 +2705,7 @@ static wchar_t c2u_CD[256] = { 0x8CA2,0x978F,0x4E32,0x5BE1,0x6208,0x679C,0x74DC,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_CE[256] = { +static const wchar_t c2u_CE[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2741,7 +2741,7 @@ static wchar_t c2u_CE[256] = { 0x4E18,0x4E45,0x4E5D,0x4EC7,0x4FF1,0x5177,0x52FE,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_CF[256] = { +static const wchar_t c2u_CF[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2777,7 +2777,7 @@ static wchar_t c2u_CF[256] = { 0x8A6D,0x8ECC,0x994B,0xF906,0x6677,0x6B78,0x8CB4,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D0[256] = { +static const wchar_t c2u_D0[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2813,7 +2813,7 @@ static wchar_t c2u_D0[256] = { 0x5D0E,0x5DF1,0x5E7E,0x5FCC,0x6280,0x65D7,0x65E3,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D1[256] = { +static const wchar_t c2u_D1[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2849,7 +2849,7 @@ static wchar_t c2u_D1[256] = { 0x6960,0x6E73,0xF922,0x7537,0xF923,0xF924,0xF925,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D2[256] = { +static const wchar_t c2u_D2[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2885,7 +2885,7 @@ static wchar_t c2u_D2[256] = { 0xF959,0x5C3C,0x6CE5,0x533F,0x6EBA,0x591A,0x8336,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D3[256] = { +static const wchar_t c2u_D3[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2921,7 +2921,7 @@ static wchar_t c2u_D3[256] = { 0x5EA6,0x5F92,0x60BC,0x6311,0x6389,0x6417,0x6843,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D4[256] = { +static const wchar_t c2u_D4[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2957,7 +2957,7 @@ static wchar_t c2u_D4[256] = { 0x9127,0x9A30,0x5587,0x61F6,0xF95B,0x7669,0x7F85,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D5[256] = { +static const wchar_t c2u_D5[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2993,7 +2993,7 @@ static wchar_t c2u_D5[256] = { 0x792B,0x8F62,0x9742,0x6190,0x6200,0x6523,0x6F23,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D6[256] = { +static const wchar_t c2u_D6[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3029,7 +3029,7 @@ static wchar_t c2u_D6[256] = { 0x5ED6,0x6599,0x71CE,0x7642,0x77AD,0x804A,0x84FC,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D7[256] = { +static const wchar_t c2u_D7[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3065,7 +3065,7 @@ static wchar_t c2u_D7[256] = { 0x9E9F,0x6797,0x6DCB,0x7433,0x81E8,0x9716,0x782C,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D8[256] = { +static const wchar_t c2u_D8[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3101,7 +3101,7 @@ static wchar_t c2u_D8[256] = { 0x7704,0x7720,0x7DBF,0x7DEC,0x9762,0x9EB5,0x6EC5,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D9[256] = { +static const wchar_t c2u_D9[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3137,7 +3137,7 @@ static wchar_t c2u_D9[256] = { 0x58A8,0x9ED8,0x5011,0x520E,0x543B,0x554F,0x6587,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_DA[256] = { +static const wchar_t c2u_DA[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3173,7 +3173,7 @@ static wchar_t c2u_DA[256] = { 0x9812,0x98EF,0x52C3,0x62D4,0x64A5,0x6E24,0x6F51,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_DB[256] = { +static const wchar_t c2u_DB[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3209,7 +3209,7 @@ static wchar_t c2u_DB[256] = { 0x50FB,0x5288,0x58C1,0x64D8,0x6A97,0x74A7,0x7656,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_DC[256] = { +static const wchar_t c2u_DC[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3245,7 +3245,7 @@ static wchar_t c2u_DC[256] = { 0x5256,0x526F,0x5426,0x5490,0x57E0,0x592B,0x5A66,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_DD[256] = { +static const wchar_t c2u_DD[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3281,7 +3281,7 @@ static wchar_t c2u_DD[256] = { 0x7891,0x79D5,0x79D8,0x7C83,0x7DCB,0x7FE1,0x80A5,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_DE[256] = { +static const wchar_t c2u_DE[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3317,7 +3317,7 @@ static wchar_t c2u_DE[256] = { 0x98FC,0x99DF,0x9E9D,0x524A,0xF969,0x6714,0xF96A,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_DF[256] = { +static const wchar_t c2u_DF[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3353,7 +3353,7 @@ static wchar_t c2u_DF[256] = { 0x68F2,0x7280,0x745E,0x7B6E,0x7D6E,0x7DD6,0x7F72,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E0[256] = { +static const wchar_t c2u_E0[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3389,7 +3389,7 @@ static wchar_t c2u_E0[256] = { 0x661F,0x665F,0x7329,0x73F9,0x76DB,0x7701,0x7B6C,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E1[256] = { +static const wchar_t c2u_E1[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3425,7 +3425,7 @@ static wchar_t c2u_E1[256] = { 0x58FD,0x5AC2,0x5B88,0x5CAB,0x5CC0,0x5E25,0x6101,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E2[256] = { +static const wchar_t c2u_E2[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3461,7 +3461,7 @@ static wchar_t c2u_E2[256] = { 0x99B4,0x620C,0x8853,0x8FF0,0x9265,0x5D07,0x5D27,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E3[256] = { +static const wchar_t c2u_E3[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3497,7 +3497,7 @@ static wchar_t c2u_E3[256] = { 0x5BA4,0x5BE6,0x6089,0x5BE9,0x5C0B,0x5FC3,0x6C81,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E4[256] = { +static const wchar_t c2u_E4[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3533,7 +3533,7 @@ static wchar_t c2u_E4[256] = { 0x5384,0x627C,0x6396,0x6DB2,0x7E0A,0x814B,0x984D,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E5[256] = { +static const wchar_t c2u_E5[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3569,7 +3569,7 @@ static wchar_t c2u_E5[256] = { 0x4E88,0x4F59,0xF97F,0xF980,0xF981,0x5982,0xF982,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E6[256] = { +static const wchar_t c2u_E6[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3605,7 +3605,7 @@ static wchar_t c2u_E6[256] = { 0x67D3,0xF9A5,0x708E,0x7130,0x7430,0x8276,0x82D2,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E7[256] = { +static const wchar_t c2u_E7[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3641,7 +3641,7 @@ static wchar_t c2u_E7[256] = { 0x61CA,0x6556,0x65FF,0x6664,0x68A7,0x6C5A,0x6FB3,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E8[256] = { +static const wchar_t c2u_E8[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3677,7 +3677,7 @@ static wchar_t c2u_E8[256] = { 0x66DC,0xF9BF,0x6A48,0xF9C0,0x71FF,0x7464,0xF9C1,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E9[256] = { +static const wchar_t c2u_E9[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3713,7 +3713,7 @@ static wchar_t c2u_E9[256] = { 0x6A52,0x6B9E,0x6F90,0x7189,0x8018,0x82B8,0x8553,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_EA[256] = { +static const wchar_t c2u_EA[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3749,7 +3749,7 @@ static wchar_t c2u_EA[256] = { 0x6961,0x6962,0x6CB9,0x6D27,0xF9CA,0x6E38,0xF9CB,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_EB[256] = { +static const wchar_t c2u_EB[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3785,7 +3785,7 @@ static wchar_t c2u_EB[256] = { 0x77E3,0x7FA9,0x8264,0x858F,0x87FB,0x8863,0x8ABC,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_EC[256] = { +static const wchar_t c2u_EC[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3821,7 +3821,7 @@ static wchar_t c2u_EC[256] = { 0xF9F5,0x7A14,0xF9F6,0x834F,0x8CC3,0x5165,0x5344,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_ED[256] = { +static const wchar_t c2u_ED[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3857,7 +3857,7 @@ static wchar_t c2u_ED[256] = { 0x8523,0x8594,0x85CF,0x88DD,0x8D13,0x91AC,0x9577,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_EE[256] = { +static const wchar_t c2u_EE[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3893,7 +3893,7 @@ static wchar_t c2u_EE[256] = { 0x5EDB,0x609B,0x6230,0x6813,0x6BBF,0x6C08,0x6FB1,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_EF[256] = { +static const wchar_t c2u_EF[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3929,7 +3929,7 @@ static wchar_t c2u_EF[256] = { 0x914A,0x91D8,0x9266,0x92CC,0x9320,0x9706,0x9756,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F0[256] = { +static const wchar_t c2u_F0[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3965,7 +3965,7 @@ static wchar_t c2u_F0[256] = { 0x6DD9,0x742E,0x7A2E,0x7D42,0x7D9C,0x7E31,0x816B,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F1[256] = { +static const wchar_t c2u_F1[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4001,7 +4001,7 @@ static wchar_t c2u_F1[256] = { 0x75C7,0x7E52,0x84B8,0x8B49,0x8D08,0x4E4B,0x53EA,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F2[256] = { +static const wchar_t c2u_F2[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4037,7 +4037,7 @@ static wchar_t c2u_F2[256] = { 0x659F,0x6715,0xF9FD,0x57F7,0x6F57,0x7DDD,0x8F2F,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F3[256] = { +static const wchar_t c2u_F3[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4073,7 +4073,7 @@ static wchar_t c2u_F3[256] = { 0x83DC,0x8521,0x91C7,0x91F5,0x518A,0x67F5,0x7B56,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F4[256] = { +static const wchar_t c2u_F4[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4109,7 +4109,7 @@ static wchar_t c2u_F4[256] = { 0x521D,0x527F,0x54E8,0x6194,0x6284,0x62DB,0x68A2,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F5[256] = { +static const wchar_t c2u_F5[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4145,7 +4145,7 @@ static wchar_t c2u_F5[256] = { 0x6C96,0x87F2,0x885D,0x8877,0x60B4,0x81B5,0x8403,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F6[256] = { +static const wchar_t c2u_F6[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4181,7 +4181,7 @@ static wchar_t c2u_F6[256] = { 0x666B,0x67DD,0x6FC1,0x6FEF,0x7422,0x7438,0x8A17,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F7[256] = { +static const wchar_t c2u_F7[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4217,7 +4217,7 @@ static wchar_t c2u_F7[256] = { 0x5742,0x677F,0x7248,0x74E3,0x8CA9,0x8FA6,0x9211,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F8[256] = { +static const wchar_t c2u_F8[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4253,7 +4253,7 @@ static wchar_t c2u_F8[256] = { 0x74E2,0x7968,0x8868,0x8C79,0x98C7,0x98C4,0x9A43,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F9[256] = { +static const wchar_t c2u_F9[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4289,7 +4289,7 @@ static wchar_t c2u_F9[256] = { 0x676D,0x6841,0x6C86,0x6E2F,0x7F38,0x809B,0x822A,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_FA[256] = { +static const wchar_t c2u_FA[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4325,7 +4325,7 @@ static wchar_t c2u_FA[256] = { 0x83A2,0x92CF,0x9830,0x4EA8,0x5144,0x5211,0x578B,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_FB[256] = { +static const wchar_t c2u_FB[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4361,7 +4361,7 @@ static wchar_t c2u_FB[256] = { 0x9D3B,0x5316,0x548C,0x5B05,0x6A3A,0x706B,0x7575,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_FC[256] = { +static const wchar_t c2u_FC[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4397,7 +4397,7 @@ static wchar_t c2u_FC[256] = { 0x5B5D,0x6548,0x6585,0x66C9,0x689F,0x6D8D,0x6DC6,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_FD[256] = { +static const wchar_t c2u_FD[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -4433,7 +4433,7 @@ static wchar_t c2u_FD[256] = { 0x71B9,0x71BA,0x72A7,0x79A7,0x7A00,0x7FB2,0x8A70,0x0000,/* 0xF8-0xFF */ }; -static wchar_t *page_charset2uni[256] = { +static const wchar_t *page_charset2uni[256] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -4468,7 +4468,7 @@ static wchar_t *page_charset2uni[256] = { c2u_F8, c2u_F9, c2u_FA, c2u_FB, c2u_FC, c2u_FD, NULL, NULL, }; -static unsigned char u2c_01[512] = { +static const unsigned char u2c_01[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4497,7 +4497,7 @@ static unsigned char u2c_01[512] = { 0x00, 0x00, 0x00, 0x00, 0xA8, 0xAE, 0xA9, 0xAE, /* 0x64-0x67 */ }; -static unsigned char u2c_02[512] = { +static const unsigned char u2c_02[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4557,7 +4557,7 @@ static unsigned char u2c_02[512] = { 0x00, 0x00, 0xA2, 0xA9, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ }; -static unsigned char u2c_03[512] = { +static const unsigned char u2c_03[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4612,7 +4612,7 @@ static unsigned char u2c_03[512] = { 0xA5, 0xF7, 0xA5, 0xF8, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ }; -static unsigned char u2c_04[512] = { +static const unsigned char u2c_04[512] = { 0x00, 0x00, 0xAC, 0xA7, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4636,7 +4636,7 @@ static unsigned char u2c_04[512] = { 0x00, 0x00, 0xAC, 0xD7, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ }; -static unsigned char u2c_11[512] = { +static const unsigned char u2c_11[512] = { 0xA4, 0xA1, 0xA4, 0xA2, 0xA4, 0xA4, 0xA4, 0xA7, /* 0x00-0x03 */ 0xA4, 0xA8, 0xA4, 0xA9, 0xA4, 0xB1, 0xA4, 0xB2, /* 0x04-0x07 */ 0xA4, 0xB3, 0xA4, 0xB5, 0xA4, 0xB6, 0xA4, 0xB7, /* 0x08-0x0B */ @@ -4703,7 +4703,7 @@ static unsigned char u2c_11[512] = { 0x00, 0x00, 0xA4, 0xF6, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ }; -static unsigned char u2c_20[512] = { +static const unsigned char u2c_20[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4750,7 +4750,7 @@ static unsigned char u2c_20[512] = { 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ }; -static unsigned char u2c_21[512] = { +static const unsigned char u2c_21[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xC9, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xA2, 0xB5, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4808,7 +4808,7 @@ static unsigned char u2c_21[512] = { 0xA2, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ }; -static unsigned char u2c_22[512] = { +static const unsigned char u2c_22[512] = { 0xA2, 0xA3, 0x00, 0x00, 0xA1, 0xD3, 0xA2, 0xA4, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xD4, /* 0x04-0x07 */ 0xA1, 0xF4, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xF5, /* 0x08-0x0B */ @@ -4854,7 +4854,7 @@ static unsigned char u2c_22[512] = { 0x00, 0x00, 0xA1, 0xD1, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ }; -static unsigned char u2c_23[512] = { +static const unsigned char u2c_23[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4862,7 +4862,7 @@ static unsigned char u2c_23[512] = { 0x00, 0x00, 0x00, 0x00, 0xA1, 0xD2, 0x00, 0x00, /* 0x10-0x13 */ }; -static unsigned char u2c_24[512] = { +static const unsigned char u2c_24[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4925,7 +4925,7 @@ static unsigned char u2c_24[512] = { 0xA8, 0xE5, 0xA8, 0xE6, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ }; -static unsigned char u2c_25[512] = { +static const unsigned char u2c_25[512] = { 0xA6, 0xA1, 0xA6, 0xAC, 0xA6, 0xA2, 0xA6, 0xAD, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4982,7 +4982,7 @@ static unsigned char u2c_25[512] = { 0xA2, 0xC4, 0xA2, 0xC5, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ }; -static unsigned char u2c_26[512] = { +static const unsigned char u2c_26[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xA1, 0xDA, 0xA1, 0xD9, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -5013,7 +5013,7 @@ static unsigned char u2c_26[512] = { 0xA2, 0xDD, 0xA2, 0xDA, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ }; -static unsigned char u2c_30[512] = { +static const unsigned char u2c_30[512] = { 0xA1, 0xA1, 0xA1, 0xA2, 0xA1, 0xA3, 0xA1, 0xA8, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0xA1, 0xB4, 0xA1, 0xB5, 0xA1, 0xB6, 0xA1, 0xB7, /* 0x08-0x0B */ @@ -5079,7 +5079,7 @@ static unsigned char u2c_30[512] = { 0xAB, 0xF4, 0xAB, 0xF5, 0xAB, 0xF6, 0x00, 0x00, /* 0xF4-0xF7 */ }; -static unsigned char u2c_31[512] = { +static const unsigned char u2c_31[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -5123,7 +5123,7 @@ static unsigned char u2c_31[512] = { 0xEF, 0xCB, 0xF4, 0xB8, 0xF2, 0xA2, 0xEC, 0xD1, /* 0x9C-0x9F */ }; -static unsigned char u2c_32[512] = { +static const unsigned char u2c_32[512] = { 0xA9, 0xB1, 0xA9, 0xB2, 0xA9, 0xB3, 0xA9, 0xB4, /* 0x00-0x03 */ 0xA9, 0xB5, 0xA9, 0xB6, 0xA9, 0xB7, 0xA9, 0xB8, /* 0x04-0x07 */ 0xA9, 0xB9, 0xA9, 0xBA, 0xA9, 0xBB, 0xA9, 0xBC, /* 0x08-0x0B */ @@ -5172,7 +5172,7 @@ static unsigned char u2c_32[512] = { 0xE5, 0xA8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ }; -static unsigned char u2c_33[512] = { +static const unsigned char u2c_33[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -5232,7 +5232,7 @@ static unsigned char u2c_33[512] = { 0xA7, 0xEE, 0xA7, 0xE9, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ }; -static unsigned char u2c_4E[512] = { +static const unsigned char u2c_4E[512] = { 0xEC, 0xE9, 0xEF, 0xCB, 0x00, 0x00, 0xF6, 0xD2, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xB2, /* 0x04-0x07 */ 0xED, 0xDB, 0xDF, 0xB2, 0xDF, 0xBE, 0xF9, 0xBB, /* 0x08-0x0B */ @@ -5299,7 +5299,7 @@ static unsigned char u2c_4E[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xF2, /* 0xF8-0xFB */ }; -static unsigned char u2c_4F[512] = { +static const unsigned char u2c_4F[512] = { 0x00, 0x00, 0xD0, 0xEA, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xF9, 0xF2, 0xEC, 0xA5, 0xD0, 0xDF, /* 0x08-0x0B */ @@ -5366,7 +5366,7 @@ static unsigned char u2c_4F[512] = { 0xDC, 0xE4, 0x00, 0x00, 0xE5, 0xEF, 0x00, 0x00, /* 0xF8-0xFB */ }; -static unsigned char u2c_50[512] = { +static const unsigned char u2c_50[512] = { 0x00, 0x00, 0x00, 0x00, 0xDC, 0xB1, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0xD5, 0xD6, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xF3, 0xDA, 0x00, 0x00, 0xCB, 0xC1, /* 0x08-0x0B */ @@ -5434,7 +5434,7 @@ static unsigned char u2c_50[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xC7, /* 0xFC-0xFF */ }; -static unsigned char u2c_51[512] = { +static const unsigned char u2c_51[512] = { 0xEB, 0xF0, 0xF1, 0xD6, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0xE5, 0xE2, 0x00, 0x00, 0xCC, 0xCC, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xCB, 0xFB, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -5502,7 +5502,7 @@ static unsigned char u2c_51[512] = { 0x00, 0x00, 0xF9, 0xDE, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_52[512] = { +static const unsigned char u2c_52[512] = { 0xD3, 0xEF, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xD3, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0xDD, 0xC2, 0xEF, 0xB7, /* 0x04-0x07 */ 0xE7, 0xD4, 0x00, 0x00, 0xCA, 0xCA, 0x00, 0x00, /* 0x08-0x0B */ @@ -5570,7 +5570,7 @@ static unsigned char u2c_52[512] = { 0x00, 0x00, 0x00, 0x00, 0xCE, 0xFE, 0xDA, 0xA8, /* 0xFC-0xFF */ }; -static unsigned char u2c_53[512] = { +static const unsigned char u2c_53[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xF8, 0xD0, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0xFD, 0xD6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -5637,7 +5637,7 @@ static unsigned char u2c_53[512] = { 0xDE, 0xC9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ }; -static unsigned char u2c_54[512] = { +static const unsigned char u2c_54[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xDE, /* 0x00-0x03 */ 0xCA, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0xF9, 0xEA, 0xD1, 0xCE, 0xEE, 0xD4, 0x00, 0x00, /* 0x08-0x0B */ @@ -5704,7 +5704,7 @@ static unsigned char u2c_54[512] = { 0x00, 0x00, 0x00, 0x00, 0xF8, 0xD4, 0x00, 0x00, /* 0xF8-0xFB */ }; -static unsigned char u2c_55[512] = { +static const unsigned char u2c_55[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0xF8, 0xA6, 0x00, 0x00, 0xDE, 0xCA, 0xF2, 0xC6, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -5772,7 +5772,7 @@ static unsigned char u2c_55[512] = { 0x00, 0x00, 0xE1, 0xF5, 0xF1, 0xB3, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_56[512] = { +static const unsigned char u2c_56[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0xF7, 0xA3, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xCA, 0xA9, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -5839,7 +5839,7 @@ static unsigned char u2c_56[512] = { 0x00, 0x00, 0xD6, 0xB7, 0xCD, 0xB3, 0x00, 0x00, /* 0xF8-0xFB */ }; -static unsigned char u2c_57[512] = { +static const unsigned char u2c_57[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xD5, /* 0x00-0x03 */ 0xE5, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0xCF, 0xEA, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xD0, /* 0x08-0x0B */ @@ -5907,7 +5907,7 @@ static unsigned char u2c_57[512] = { 0xD0, 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_58[512] = { +static const unsigned char u2c_58[512] = { 0xCF, 0xDC, 0x00, 0x00, 0xD3, 0xD1, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xCC, 0xB1, 0xF7, 0xD8, 0x00, 0x00, /* 0x04-0x07 */ 0xCB, 0xA8, 0xEB, 0xBC, 0xE4, 0xBE, 0x00, 0x00, /* 0x08-0x0B */ @@ -5975,7 +5975,7 @@ static unsigned char u2c_58[512] = { 0x00, 0x00, 0xE1, 0xF8, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_59[512] = { +static const unsigned char u2c_59[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -6043,7 +6043,7 @@ static unsigned char u2c_59[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0xAC, /* 0xFC-0xFF */ }; -static unsigned char u2c_5A[512] = { +static const unsigned char u2c_5A[512] = { 0x00, 0x00, 0xEA, 0xCE, 0x00, 0x00, 0xE8, 0xDF, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -6106,7 +6106,7 @@ static unsigned char u2c_5A[512] = { 0x00, 0x00, 0xD2, 0xEC, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ }; -static unsigned char u2c_5B[512] = { +static const unsigned char u2c_5B[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xFB, 0xFB, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xFD, 0xF0, 0x00, 0x00, 0xE0, 0xBD, /* 0x08-0x0B */ @@ -6173,7 +6173,7 @@ static unsigned char u2c_5B[512] = { 0xF5, 0xBB, 0x00, 0x00, 0xDE, 0xD1, 0x00, 0x00, /* 0xF8-0xFB */ }; -static unsigned char u2c_5C[512] = { +static const unsigned char u2c_5C[512] = { 0x00, 0x00, 0xDC, 0xE6, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0xDE, 0xD2, 0x00, 0x00, 0x00, 0x00, 0xED, 0xE2, /* 0x04-0x07 */ 0xEE, 0xF6, 0xEA, 0xCF, 0xF0, 0xEE, 0xE3, 0xFC, /* 0x08-0x0B */ @@ -6241,7 +6241,7 @@ static unsigned char u2c_5C[512] = { 0x00, 0x00, 0xFA, 0xF2, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_5D[512] = { +static const unsigned char u2c_5D[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xFD, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -6309,7 +6309,7 @@ static unsigned char u2c_5D[512] = { 0x00, 0x00, 0xE1, 0xDE, 0xCB, 0xEE, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_5E[512] = { +static const unsigned char u2c_5E[512] = { 0x00, 0x00, 0x00, 0x00, 0xE3, 0xBC, 0xF8, 0xD6, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0xDB, 0xEE, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -6376,7 +6376,7 @@ static unsigned char u2c_5E[512] = { 0x00, 0x00, 0x00, 0x00, 0xCB, 0xEF, 0xFC, 0xDF, /* 0xF8-0xFB */ }; -static unsigned char u2c_5F[512] = { +static const unsigned char u2c_5F[512] = { 0x00, 0x00, 0xDC, 0xA7, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0xD6, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xF8, 0xC9, 0x00, 0x00, /* 0x08-0x0B */ @@ -6444,7 +6444,7 @@ static unsigned char u2c_5F[512] = { 0x00, 0x00, 0xFB, 0xEC, 0x00, 0x00, 0xDD, 0xC8, /* 0xFC-0xFF */ }; -static unsigned char u2c_60[512] = { +static const unsigned char u2c_60[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -6511,7 +6511,7 @@ static unsigned char u2c_60[512] = { 0x00, 0x00, 0xE5, 0xA9, 0xE0, 0xF6, 0xF6, 0xB3, /* 0xF8-0xFB */ }; -static unsigned char u2c_61[512] = { +static const unsigned char u2c_61[512] = { 0x00, 0x00, 0xE1, 0xFE, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0xCB, 0xF0, 0x00, 0x00, /* 0x04-0x07 */ 0xEA, 0xEF, 0xEA, 0xF0, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -6579,7 +6579,7 @@ static unsigned char u2c_61[512] = { 0xCF, 0xAB, 0x00, 0x00, 0x00, 0x00, 0xEB, 0xF3, /* 0xFC-0xFF */ }; -static unsigned char u2c_62[512] = { +static const unsigned char u2c_62[512] = { 0xD5, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD3, 0xD4, /* 0x04-0x07 */ 0xCD, 0xFC, 0x00, 0x00, 0xD9, 0xE6, 0x00, 0x00, /* 0x08-0x0B */ @@ -6647,7 +6647,7 @@ static unsigned char u2c_62[512] = { 0x00, 0x00, 0x00, 0x00, 0xE3, 0xA6, 0xD1, 0xDA, /* 0xFC-0xFF */ }; -static unsigned char u2c_63[512] = { +static const unsigned char u2c_63[512] = { 0x00, 0x00, 0xF2, 0xA5, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xA6, /* 0x04-0x07 */ 0x00, 0x00, 0xE4, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -6713,7 +6713,7 @@ static unsigned char u2c_63[512] = { 0xEA, 0xB5, 0x00, 0x00, 0xE5, 0xAA, 0xDF, 0xBA, /* 0xF4-0xF7 */ }; -static unsigned char u2c_64[512] = { +static const unsigned char u2c_64[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -6781,7 +6781,7 @@ static unsigned char u2c_64[512] = { 0x00, 0x00, 0x00, 0x00, 0xE8, 0xF6, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_65[512] = { +static const unsigned char u2c_65[512] = { 0xDA, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0xF7, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -6849,7 +6849,7 @@ static unsigned char u2c_65[512] = { 0xDA, 0xC4, 0xD4, 0xC5, 0x00, 0x00, 0xE7, 0xFA, /* 0xFC-0xFF */ }; -static unsigned char u2c_66[512] = { +static const unsigned char u2c_66[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0xCD, 0xE0, 0xE3, 0xB0, /* 0x04-0x07 */ 0x00, 0x00, 0xDB, 0xB2, 0xFB, 0xC4, 0x00, 0x00, /* 0x08-0x0B */ @@ -6917,7 +6917,7 @@ static unsigned char u2c_66[512] = { 0xD8, 0xBA, 0x00, 0x00, 0xF1, 0xF4, 0xF4, 0xF0, /* 0xFC-0xFF */ }; -static unsigned char u2c_67[512] = { +static const unsigned char u2c_67[512] = { 0xF5, 0xCC, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xE5, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0xEA, 0xC5, 0xEA, 0xF3, 0x00, 0x00, 0xDD, 0xDB, /* 0x08-0x0B */ @@ -6985,7 +6985,7 @@ static unsigned char u2c_67[512] = { 0x00, 0x00, 0x00, 0x00, 0xEF, 0xDE, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_68[512] = { +static const unsigned char u2c_68[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -7052,7 +7052,7 @@ static unsigned char u2c_68[512] = { 0x00, 0x00, 0xD4, 0xA1, 0xCE, 0xB2, 0x00, 0x00, /* 0xF8-0xFB */ }; -static unsigned char u2c_69[512] = { +static const unsigned char u2c_69[512] = { 0xE8, 0xCA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xEB, 0xF5, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -7120,7 +7120,7 @@ static unsigned char u2c_69[512] = { 0x00, 0x00, 0xF0, 0xCB, 0x00, 0x00, 0xD0, 0xC7, /* 0xFC-0xFF */ }; -static unsigned char u2c_6A[512] = { +static const unsigned char u2c_6A[512] = { 0x00, 0x00, 0x00, 0x00, 0xE4, 0xC5, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xDB, 0xE0, 0x00, 0x00, /* 0x08-0x0B */ @@ -7187,7 +7187,7 @@ static unsigned char u2c_6A[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xA1, /* 0xF8-0xFB */ }; -static unsigned char u2c_6B[512] = { +static const unsigned char u2c_6B[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0xD5, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xCF, 0xED, 0x00, 0x00, /* 0x08-0x0B */ @@ -7251,7 +7251,7 @@ static unsigned char u2c_6B[512] = { 0xCF, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ }; -static unsigned char u2c_6C[512] = { +static const unsigned char u2c_6C[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0xEE, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -7316,7 +7316,7 @@ static unsigned char u2c_6C[512] = { 0xF7, 0xC1, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xB6, /* 0xF0-0xF3 */ }; -static unsigned char u2c_6D[512] = { +static const unsigned char u2c_6D[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xC7, /* 0x08-0x0B */ @@ -7383,7 +7383,7 @@ static unsigned char u2c_6D[512] = { 0xF4, 0xE8, 0xE5, 0xF4, 0xF4, 0xBC, 0xF4, 0xD5, /* 0xF8-0xFB */ }; -static unsigned char u2c_6E[512] = { +static const unsigned char u2c_6E[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -7451,7 +7451,7 @@ static unsigned char u2c_6E[512] = { 0x00, 0x00, 0x00, 0x00, 0xCD, 0xE3, 0xD8, 0xBB, /* 0xFC-0xFF */ }; -static unsigned char u2c_6F[512] = { +static const unsigned char u2c_6F[512] = { 0x00, 0x00, 0xE5, 0xDB, 0xF8, 0xF7, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0xF6, 0xD4, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -7519,7 +7519,7 @@ static unsigned char u2c_6F[512] = { 0x00, 0x00, 0x00, 0x00, 0xD5, 0xEB, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_70[512] = { +static const unsigned char u2c_70[512] = { 0x00, 0x00, 0xE5, 0xC8, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xFB, 0xA4, 0xD4, 0xB9, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xDE, 0xE1, 0x00, 0x00, 0xE4, 0xA3, /* 0x08-0x0B */ @@ -7587,7 +7587,7 @@ static unsigned char u2c_70[512] = { 0x00, 0x00, 0xDC, 0xEB, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_71[512] = { +static const unsigned char u2c_71[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0xFD, 0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xE5, 0xEA, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -7655,7 +7655,7 @@ static unsigned char u2c_71[512] = { 0xE3, 0xE8, 0x00, 0x00, 0xD4, 0xA7, 0xE8, 0xFC, /* 0xFC-0xFF */ }; -static unsigned char u2c_72[512] = { +static const unsigned char u2c_72[512] = { 0xFA, 0xD2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0xF8, 0xEF, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -7723,7 +7723,7 @@ static unsigned char u2c_72[512] = { 0xD5, 0xC9, 0xF8, 0xAC, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_73[512] = { +static const unsigned char u2c_73[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xE7, 0xD9, 0x00, 0x00, /* 0x08-0x0B */ @@ -7791,7 +7791,7 @@ static unsigned char u2c_73[512] = { 0x00, 0x00, 0xEF, 0xEA, 0xFA, 0xDE, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_74[512] = { +static const unsigned char u2c_74[512] = { 0x00, 0x00, 0xE0, 0xC4, 0x00, 0x00, 0xCF, 0xB9, /* 0x00-0x03 */ 0x00, 0x00, 0xD5, 0xCA, 0xD7, 0xE2, 0xE2, 0xAF, /* 0x04-0x07 */ 0x00, 0x00, 0xD7, 0xB8, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -7857,7 +7857,7 @@ static unsigned char u2c_74[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0xB6, /* 0xF4-0xF7 */ }; -static unsigned char u2c_75[512] = { +static const unsigned char u2c_75[512] = { 0x00, 0x00, 0xDC, 0xBA, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0xCC, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -7925,7 +7925,7 @@ static unsigned char u2c_75[512] = { 0xCD, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_76[512] = { +static const unsigned char u2c_76[512] = { 0xE5, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -7993,7 +7993,7 @@ static unsigned char u2c_76[512] = { 0xDA, 0xF0, 0x00, 0x00, 0xE2, 0xEA, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_77[512] = { +static const unsigned char u2c_77[512] = { 0x00, 0x00, 0xE0, 0xFD, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0xD8, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0xF7, 0xAF, 0xDA, 0xB6, 0x00, 0x00, 0xCA, 0xD7, /* 0x08-0x0B */ @@ -8058,7 +8058,7 @@ static unsigned char u2c_77[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xB4, /* 0xF0-0xF3 */ }; -static unsigned char u2c_78[512] = { +static const unsigned char u2c_78[512] = { 0x00, 0x00, 0x00, 0x00, 0xDE, 0xE3, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -8125,7 +8125,7 @@ static unsigned char u2c_78[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xF2, /* 0xF8-0xFB */ }; -static unsigned char u2c_79[512] = { +static const unsigned char u2c_79[512] = { 0x00, 0x00, 0xF5, 0xA7, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -8192,7 +8192,7 @@ static unsigned char u2c_79[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xB9, /* 0xF8-0xFB */ }; -static unsigned char u2c_7A[512] = { +static const unsigned char u2c_7A[512] = { 0xFD, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xE1, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0xCA, 0xD9, 0x00, 0x00, 0x00, 0x00, 0xEF, 0xEF, /* 0x08-0x0B */ @@ -8260,7 +8260,7 @@ static unsigned char u2c_7A[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xDA, /* 0xFC-0xFF */ }; -static unsigned char u2c_7B[512] = { +static const unsigned char u2c_7B[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -8323,7 +8323,7 @@ static unsigned char u2c_7B[512] = { 0x00, 0x00, 0xDE, 0xE8, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ }; -static unsigned char u2c_7C[512] = { +static const unsigned char u2c_7C[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xEA, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -8391,7 +8391,7 @@ static unsigned char u2c_7C[512] = { 0x00, 0x00, 0x00, 0x00, 0xD0, 0xAC, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_7D[512] = { +static const unsigned char u2c_7D[512] = { 0xD1, 0xBA, 0x00, 0x00, 0xF1, 0xC4, 0x00, 0x00, /* 0x00-0x03 */ 0xE5, 0xB3, 0xFB, 0xF5, 0xE9, 0xE1, 0xFD, 0xE0, /* 0x04-0x07 */ 0xFC, 0xBC, 0x00, 0x00, 0xDA, 0xA2, 0xDA, 0xA3, /* 0x08-0x0B */ @@ -8458,7 +8458,7 @@ static unsigned char u2c_7D[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xC6, /* 0xF8-0xFB */ }; -static unsigned char u2c_7E[512] = { +static const unsigned char u2c_7E[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xF2, 0xDB, 0xE4, 0xFC, 0x00, 0x00, /* 0x08-0x0B */ @@ -8502,7 +8502,7 @@ static unsigned char u2c_7E[512] = { 0xD5, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ }; -static unsigned char u2c_7F[512] = { +static const unsigned char u2c_7F[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -8570,7 +8570,7 @@ static unsigned char u2c_7F[512] = { 0xEC, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_80[512] = { +static const unsigned char u2c_80[512] = { 0xE9, 0xA5, 0xD6, 0xD5, 0x00, 0x00, 0xCD, 0xC5, /* 0x00-0x03 */ 0x00, 0x00, 0xED, 0xBA, 0xD1, 0xBD, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xCF, 0xBE, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -8638,7 +8638,7 @@ static unsigned char u2c_80[512] = { 0x00, 0x00, 0xD2, 0xF6, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_81[512] = { +static const unsigned char u2c_81[512] = { 0x00, 0x00, 0x00, 0x00, 0xF2, 0xB7, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xFA, 0xF6, 0xF6, 0xAA, 0xFA, 0xF7, /* 0x04-0x07 */ 0xD8, 0xE6, 0x00, 0x00, 0xF4, 0xB1, 0x00, 0x00, /* 0x08-0x0B */ @@ -8706,7 +8706,7 @@ static unsigned char u2c_81[512] = { 0xCF, 0xBF, 0x00, 0x00, 0xEB, 0xAC, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_82[512] = { +static const unsigned char u2c_82[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xCF, 0xC0, 0x00, 0x00, 0xE6, 0xA8, /* 0x04-0x07 */ 0xFD, 0xE9, 0x00, 0x00, 0xCF, 0xC1, 0x00, 0x00, /* 0x08-0x0B */ @@ -8774,7 +8774,7 @@ static unsigned char u2c_82[512] = { 0x00, 0x00, 0xCD, 0xC9, 0xF9, 0xB7, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_83[512] = { +static const unsigned char u2c_83[512] = { 0x00, 0x00, 0xF1, 0xE8, 0xD9, 0xF2, 0xDB, 0xF5, /* 0x00-0x03 */ 0xCA, 0xB5, 0xD9, 0xC6, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xD8, 0xC9, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -8842,7 +8842,7 @@ static unsigned char u2c_83[512] = { 0x00, 0x00, 0xE2, 0xDD, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_84[512] = { +static const unsigned char u2c_84[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF5, 0xFE, /* 0x00-0x03 */ 0xD4, 0xAC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xD5, 0xD1, 0x00, 0x00, /* 0x08-0x0B */ @@ -8910,7 +8910,7 @@ static unsigned char u2c_84[512] = { 0xD6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_85[512] = { +static const unsigned char u2c_85[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -8978,7 +8978,7 @@ static unsigned char u2c_85[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xAB, /* 0xFC-0xFF */ }; -static unsigned char u2c_86[512] = { +static const unsigned char u2c_86[512] = { 0x00, 0x00, 0x00, 0x00, 0xE7, 0xDE, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0xD6, 0xD6, 0xE1, 0xCC, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xE8, 0xB3, 0x00, 0x00, /* 0x08-0x0B */ @@ -9046,7 +9046,7 @@ static unsigned char u2c_86[512] = { 0x00, 0x00, 0x00, 0x00, 0xE4, 0xB6, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_87[512] = { +static const unsigned char u2c_87[512] = { 0xF5, 0xB9, 0x00, 0x00, 0xDC, 0xF0, 0xE3, 0xF1, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0xE8, 0xA5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -9114,7 +9114,7 @@ static unsigned char u2c_87[512] = { 0x00, 0x00, 0x00, 0x00, 0xE0, 0xEA, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_88[512] = { +static const unsigned char u2c_88[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xE3, 0xB2, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -9182,7 +9182,7 @@ static unsigned char u2c_88[512] = { 0x00, 0x00, 0xF0, 0xB2, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_89[512] = { +static const unsigned char u2c_89[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -9249,7 +9249,7 @@ static unsigned char u2c_89[512] = { 0xF5, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ }; -static unsigned char u2c_8A[512] = { +static const unsigned char u2c_8A[512] = { 0xE5, 0xEB, 0x00, 0x00, 0xEF, 0xF4, 0xDD, 0xB5, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0xCD, 0xAA, 0x00, 0x00, 0xE3, 0xF2, 0x00, 0x00, /* 0x08-0x0B */ @@ -9317,7 +9317,7 @@ static unsigned char u2c_8A[512] = { 0x00, 0x00, 0x00, 0x00, 0xD1, 0xE7, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_8B[512] = { +static const unsigned char u2c_8B[512] = { 0xD9, 0xC7, 0xE4, 0xD7, 0xEA, 0xDD, 0x00, 0x00, /* 0x00-0x03 */ 0xD4, 0xF7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -9360,7 +9360,7 @@ static unsigned char u2c_8B[512] = { 0x00, 0x00, 0x00, 0x00, 0xF3, 0xC6, 0x00, 0x00, /* 0x98-0x9B */ }; -static unsigned char u2c_8C[512] = { +static const unsigned char u2c_8C[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -9428,7 +9428,7 @@ static unsigned char u2c_8C[512] = { 0xCF, 0xC5, 0xDF, 0xDF, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_8D[512] = { +static const unsigned char u2c_8D[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0xF2, 0xBE, 0xF6, 0xA1, 0x00, 0x00, 0xEB, 0xCB, /* 0x04-0x07 */ 0xF1, 0xFC, 0x00, 0x00, 0xF3, 0xC7, 0x00, 0x00, /* 0x08-0x0B */ @@ -9493,7 +9493,7 @@ static unsigned char u2c_8D[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 0xAF, /* 0xF0-0xF3 */ }; -static unsigned char u2c_8E[512] = { +static const unsigned char u2c_8E[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xE9, 0xC9, 0x00, 0x00, /* 0x08-0x0B */ @@ -9561,7 +9561,7 @@ static unsigned char u2c_8E[512] = { 0x00, 0x00, 0x00, 0x00, 0xE3, 0xDC, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_8F[512] = { +static const unsigned char u2c_8F[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xF2, /* 0x00-0x03 */ 0x00, 0x00, 0xD6, 0xD9, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xEE, 0xB0, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -9629,7 +9629,7 @@ static unsigned char u2c_8F[512] = { 0x00, 0x00, 0xF5, 0xDA, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_90[512] = { +static const unsigned char u2c_90[512] = { 0xF7, 0xDC, 0xE1, 0xEA, 0xCE, 0xC1, 0xD4, 0xB1, /* 0x00-0x03 */ 0x00, 0x00, 0xFD, 0xB1, 0xE6, 0xBD, 0x00, 0x00, /* 0x04-0x07 */ 0xFB, 0xAD, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xE7, /* 0x08-0x0B */ @@ -9697,7 +9697,7 @@ static unsigned char u2c_90[512] = { 0x00, 0x00, 0xD4, 0xB4, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_91[512] = { +static const unsigned char u2c_91[512] = { 0x00, 0x00, 0x00, 0x00, 0xE4, 0xC7, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -9763,7 +9763,7 @@ static unsigned char u2c_91[512] = { 0x00, 0x00, 0xF3, 0xFB, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ }; -static unsigned char u2c_92[512] = { +static const unsigned char u2c_92[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -9831,7 +9831,7 @@ static unsigned char u2c_92[512] = { 0xCB, 0xBC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_93[512] = { +static const unsigned char u2c_93[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0xD6, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -9897,7 +9897,7 @@ static unsigned char u2c_93[512] = { 0x00, 0x00, 0x00, 0x00, 0xF3, 0xA1, 0x00, 0x00, /* 0xF4-0xF7 */ }; -static unsigned char u2c_94[512] = { +static const unsigned char u2c_94[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0xFC, 0xF5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -9932,7 +9932,7 @@ static unsigned char u2c_94[512] = { 0x00, 0x00, 0xF3, 0xC8, 0x00, 0x00, 0xF3, 0xBA, /* 0x7C-0x7F */ }; -static unsigned char u2c_95[512] = { +static const unsigned char u2c_95[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -9993,7 +9993,7 @@ static unsigned char u2c_95[512] = { 0x00, 0x00, 0xF4, 0xC5, 0xDC, 0xA3, 0x00, 0x00, /* 0xE0-0xE3 */ }; -static unsigned char u2c_96[512] = { +static const unsigned char u2c_96[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -10060,7 +10060,7 @@ static unsigned char u2c_96[512] = { 0x00, 0x00, 0xDA, 0xDF, 0x00, 0x00, 0xEF, 0xB3, /* 0xF8-0xFB */ }; -static unsigned char u2c_97[512] = { +static const unsigned char u2c_97[512] = { 0xE2, 0xCD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0xEF, 0xFD, 0xF2, 0xE8, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -10128,7 +10128,7 @@ static unsigned char u2c_97[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xC2, /* 0xFC-0xFF */ }; -static unsigned char u2c_98[512] = { +static const unsigned char u2c_98[512] = { 0xFB, 0xE1, 0xFA, 0xED, 0xF0, 0xA2, 0xCC, 0xF1, /* 0x00-0x03 */ 0x00, 0x00, 0xFA, 0xA3, 0xE2, 0xF7, 0x00, 0x00, /* 0x04-0x07 */ 0xE2, 0xCE, 0x00, 0x00, 0xE9, 0xF5, 0x00, 0x00, /* 0x08-0x0B */ @@ -10196,7 +10196,7 @@ static unsigned char u2c_98[512] = { 0xDE, 0xF8, 0xF8, 0xE9, 0xE3, 0xDE, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_99[512] = { +static const unsigned char u2c_99[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xF5, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xFA, 0xC3, 0xE5, 0xD7, 0x00, 0x00, /* 0x08-0x0B */ @@ -10264,7 +10264,7 @@ static unsigned char u2c_99[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xE7, /* 0xFC-0xFF */ }; -static unsigned char u2c_9A[512] = { +static const unsigned char u2c_9A[512] = { 0x00, 0x00, 0xDE, 0xBE, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0xDC, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -10328,7 +10328,7 @@ static unsigned char u2c_9A[512] = { 0x00, 0x00, 0x00, 0x00, 0xDB, 0xA5, 0x00, 0x00, /* 0xEC-0xEF */ }; -static unsigned char u2c_9B[512] = { +static const unsigned char u2c_9B[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -10391,7 +10391,7 @@ static unsigned char u2c_9B[512] = { 0xCC, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ }; -static unsigned char u2c_9C[512] = { +static const unsigned char u2c_9C[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -10457,7 +10457,7 @@ static unsigned char u2c_9C[512] = { 0xD9, 0xB0, 0x00, 0x00, 0xE6, 0xE9, 0x00, 0x00, /* 0xF4-0xF7 */ }; -static unsigned char u2c_9D[512] = { +static const unsigned char u2c_9D[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xE4, 0xBC, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -10524,7 +10524,7 @@ static unsigned char u2c_9D[512] = { 0xFD, 0xD3, 0xEB, 0xED, 0xD6, 0xDC, 0x00, 0x00, /* 0xF8-0xFB */ }; -static unsigned char u2c_9E[512] = { +static const unsigned char u2c_9E[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -10590,7 +10590,7 @@ static unsigned char u2c_9E[512] = { 0xDA, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ }; -static unsigned char u2c_9F[512] = { +static const unsigned char u2c_9F[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xA8, /* 0x04-0x07 */ 0xDC, 0xAF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -10634,7 +10634,7 @@ static unsigned char u2c_9F[512] = { 0xCF, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ }; -static unsigned char u2c_AC[512] = { +static const unsigned char u2c_AC[512] = { 0xB0, 0xA1, 0xB0, 0xA2, 0x81, 0x41, 0x81, 0x42, /* 0x00-0x03 */ 0xB0, 0xA3, 0x81, 0x43, 0x81, 0x44, 0xB0, 0xA4, /* 0x04-0x07 */ 0xB0, 0xA5, 0xB0, 0xA6, 0xB0, 0xA7, 0x81, 0x45, /* 0x08-0x0B */ @@ -10702,7 +10702,7 @@ static unsigned char u2c_AC[512] = { 0xB0, 0xFA, 0xB0, 0xFB, 0x81, 0xF0, 0x81, 0xF1, /* 0xFC-0xFF */ }; -static unsigned char u2c_AD[512] = { +static const unsigned char u2c_AD[512] = { 0xB0, 0xFC, 0x81, 0xF2, 0x81, 0xF3, 0x81, 0xF4, /* 0x00-0x03 */ 0xB0, 0xFD, 0x81, 0xF5, 0xB0, 0xFE, 0x81, 0xF6, /* 0x04-0x07 */ 0x81, 0xF7, 0x81, 0xF8, 0x81, 0xF9, 0x81, 0xFA, /* 0x08-0x0B */ @@ -10770,7 +10770,7 @@ static unsigned char u2c_AD[512] = { 0xB1, 0xD9, 0x83, 0x43, 0x83, 0x44, 0xB1, 0xDA, /* 0xFC-0xFF */ }; -static unsigned char u2c_AE[512] = { +static const unsigned char u2c_AE[512] = { 0xB1, 0xDB, 0xB1, 0xDC, 0x83, 0x45, 0x83, 0x46, /* 0x00-0x03 */ 0x83, 0x47, 0x83, 0x48, 0x83, 0x49, 0x83, 0x4A, /* 0x04-0x07 */ 0xB1, 0xDD, 0xB1, 0xDE, 0x83, 0x4B, 0xB1, 0xDF, /* 0x08-0x0B */ @@ -10838,7 +10838,7 @@ static unsigned char u2c_AE[512] = { 0xB2, 0xBA, 0x84, 0x52, 0x84, 0x53, 0x84, 0x54, /* 0xFC-0xFF */ }; -static unsigned char u2c_AF[512] = { +static const unsigned char u2c_AF[512] = { 0x84, 0x55, 0x84, 0x56, 0x84, 0x57, 0x84, 0x58, /* 0x00-0x03 */ 0x84, 0x59, 0x84, 0x5A, 0x84, 0x61, 0xB2, 0xBB, /* 0x04-0x07 */ 0xB2, 0xBC, 0x84, 0x62, 0x84, 0x63, 0x84, 0x64, /* 0x08-0x0B */ @@ -10906,7 +10906,7 @@ static unsigned char u2c_AF[512] = { 0x85, 0x75, 0x85, 0x76, 0x85, 0x77, 0x85, 0x78, /* 0xFC-0xFF */ }; -static unsigned char u2c_B0[512] = { +static const unsigned char u2c_B0[512] = { 0xB2, 0xEB, 0xB2, 0xEC, 0x85, 0x79, 0x85, 0x7A, /* 0x00-0x03 */ 0xB2, 0xED, 0x85, 0x81, 0x85, 0x82, 0x85, 0x83, /* 0x04-0x07 */ 0x85, 0x84, 0x85, 0x85, 0x85, 0x86, 0x85, 0x87, /* 0x08-0x0B */ @@ -10974,7 +10974,7 @@ static unsigned char u2c_B0[512] = { 0x86, 0x8C, 0x86, 0x8D, 0x86, 0x8E, 0x86, 0x8F, /* 0xFC-0xFF */ }; -static unsigned char u2c_B1[512] = { +static const unsigned char u2c_B1[512] = { 0x86, 0x90, 0x86, 0x91, 0x86, 0x92, 0x86, 0x93, /* 0x00-0x03 */ 0x86, 0x94, 0x86, 0x95, 0x86, 0x96, 0x86, 0x97, /* 0x04-0x07 */ 0xB3, 0xCA, 0xB3, 0xCB, 0x86, 0x98, 0xB3, 0xCC, /* 0x08-0x0B */ @@ -11042,7 +11042,7 @@ static unsigned char u2c_B1[512] = { 0x87, 0x9E, 0xB4, 0xA8, 0x87, 0x9F, 0x87, 0xA0, /* 0xFC-0xFF */ }; -static unsigned char u2c_B2[512] = { +static const unsigned char u2c_B2[512] = { 0x87, 0xA1, 0x87, 0xA2, 0x87, 0xA3, 0x87, 0xA4, /* 0x00-0x03 */ 0xB4, 0xA9, 0xB4, 0xAA, 0x87, 0xA5, 0x87, 0xA6, /* 0x04-0x07 */ 0xB4, 0xAB, 0x87, 0xA7, 0x87, 0xA8, 0xB4, 0xAC, /* 0x08-0x0B */ @@ -11110,7 +11110,7 @@ static unsigned char u2c_B2[512] = { 0x88, 0xAA, 0x88, 0xAB, 0x88, 0xAC, 0xB4, 0xEA, /* 0xFC-0xFF */ }; -static unsigned char u2c_B3[512] = { +static const unsigned char u2c_B3[512] = { 0xB4, 0xEB, 0xB4, 0xEC, 0x88, 0xAD, 0x88, 0xAE, /* 0x00-0x03 */ 0xB4, 0xED, 0x88, 0xAF, 0x88, 0xB0, 0x88, 0xB1, /* 0x04-0x07 */ 0xB4, 0xEE, 0x88, 0xB2, 0x88, 0xB3, 0x88, 0xB4, /* 0x08-0x0B */ @@ -11178,7 +11178,7 @@ static unsigned char u2c_B3[512] = { 0xB5, 0xC5, 0x89, 0xBF, 0x89, 0xC0, 0x89, 0xC1, /* 0xFC-0xFF */ }; -static unsigned char u2c_B4[512] = { +static const unsigned char u2c_B4[512] = { 0x89, 0xC2, 0x89, 0xC3, 0x89, 0xC4, 0x89, 0xC5, /* 0x00-0x03 */ 0x89, 0xC6, 0x89, 0xC7, 0x89, 0xC8, 0x89, 0xC9, /* 0x04-0x07 */ 0x89, 0xCA, 0x89, 0xCB, 0x89, 0xCC, 0x89, 0xCD, /* 0x08-0x0B */ @@ -11246,7 +11246,7 @@ static unsigned char u2c_B4[512] = { 0x8A, 0xE2, 0x8A, 0xE3, 0x8A, 0xE4, 0x8A, 0xE5, /* 0xFC-0xFF */ }; -static unsigned char u2c_B5[512] = { +static const unsigned char u2c_B5[512] = { 0x8A, 0xE6, 0x8A, 0xE7, 0x8A, 0xE8, 0x8A, 0xE9, /* 0x00-0x03 */ 0x8A, 0xEA, 0x8A, 0xEB, 0x8A, 0xEC, 0x8A, 0xED, /* 0x04-0x07 */ 0x8A, 0xEE, 0x8A, 0xEF, 0x8A, 0xF0, 0x8A, 0xF1, /* 0x08-0x0B */ @@ -11314,7 +11314,7 @@ static unsigned char u2c_B5[512] = { 0x8B, 0xFB, 0x8B, 0xFC, 0x8B, 0xFD, 0x8B, 0xFE, /* 0xFC-0xFF */ }; -static unsigned char u2c_B6[512] = { +static const unsigned char u2c_B6[512] = { 0x8C, 0x41, 0x8C, 0x42, 0x8C, 0x43, 0x8C, 0x44, /* 0x00-0x03 */ 0x8C, 0x45, 0x8C, 0x46, 0x8C, 0x47, 0x8C, 0x48, /* 0x04-0x07 */ 0x8C, 0x49, 0x8C, 0x4A, 0x8C, 0x4B, 0x8C, 0x4C, /* 0x08-0x0B */ @@ -11382,7 +11382,7 @@ static unsigned char u2c_B6[512] = { 0x8D, 0x82, 0x8D, 0x83, 0x8D, 0x84, 0x8D, 0x85, /* 0xFC-0xFF */ }; -static unsigned char u2c_B7[512] = { +static const unsigned char u2c_B7[512] = { 0xB6, 0xDC, 0xB6, 0xDD, 0x8D, 0x86, 0x8D, 0x87, /* 0x00-0x03 */ 0x8D, 0x88, 0xB6, 0xDE, 0x8D, 0x89, 0x8D, 0x8A, /* 0x04-0x07 */ 0x8D, 0x8B, 0x8D, 0x8C, 0x8D, 0x8D, 0x8D, 0x8E, /* 0x08-0x0B */ @@ -11450,7 +11450,7 @@ static unsigned char u2c_B7[512] = { 0xB7, 0xB3, 0xB7, 0xB4, 0x8E, 0x9B, 0xB7, 0xB5, /* 0xFC-0xFF */ }; -static unsigned char u2c_B8[512] = { +static const unsigned char u2c_B8[512] = { 0xB7, 0xB6, 0xB7, 0xB7, 0x8E, 0x9C, 0x8E, 0x9D, /* 0x00-0x03 */ 0x8E, 0x9E, 0x8E, 0x9F, 0x8E, 0xA0, 0xB7, 0xB8, /* 0x04-0x07 */ 0xB7, 0xB9, 0xB7, 0xBA, 0x8E, 0xA1, 0x8E, 0xA2, /* 0x08-0x0B */ @@ -11518,7 +11518,7 @@ static unsigned char u2c_B8[512] = { 0x8F, 0xAE, 0xB7, 0xEE, 0x8F, 0xAF, 0x8F, 0xB0, /* 0xFC-0xFF */ }; -static unsigned char u2c_B9[512] = { +static const unsigned char u2c_B9[512] = { 0x8F, 0xB1, 0x8F, 0xB2, 0x8F, 0xB3, 0x8F, 0xB4, /* 0x00-0x03 */ 0xB7, 0xEF, 0x8F, 0xB5, 0x8F, 0xB6, 0x8F, 0xB7, /* 0x04-0x07 */ 0x8F, 0xB8, 0x8F, 0xB9, 0x8F, 0xBA, 0x8F, 0xBB, /* 0x08-0x0B */ @@ -11586,7 +11586,7 @@ static unsigned char u2c_B9[512] = { 0x90, 0xBD, 0x90, 0xBE, 0x90, 0xBF, 0x90, 0xC0, /* 0xFC-0xFF */ }; -static unsigned char u2c_BA[512] = { +static const unsigned char u2c_BA[512] = { 0xB8, 0xCF, 0xB8, 0xD0, 0x90, 0xC1, 0x90, 0xC2, /* 0x00-0x03 */ 0x90, 0xC3, 0x90, 0xC4, 0x90, 0xC5, 0x90, 0xC6, /* 0x04-0x07 */ 0xB8, 0xD1, 0x90, 0xC7, 0x90, 0xC8, 0x90, 0xC9, /* 0x08-0x0B */ @@ -11654,7 +11654,7 @@ static unsigned char u2c_BA[512] = { 0xB8, 0xFE, 0x91, 0xDC, 0x91, 0xDD, 0x91, 0xDE, /* 0xFC-0xFF */ }; -static unsigned char u2c_BB[512] = { +static const unsigned char u2c_BB[512] = { 0xB9, 0xA1, 0x91, 0xDF, 0x91, 0xE0, 0x91, 0xE1, /* 0x00-0x03 */ 0xB9, 0xA2, 0x91, 0xE2, 0x91, 0xE3, 0x91, 0xE4, /* 0x04-0x07 */ 0x91, 0xE5, 0x91, 0xE6, 0x91, 0xE7, 0x91, 0xE8, /* 0x08-0x0B */ @@ -11722,7 +11722,7 @@ static unsigned char u2c_BB[512] = { 0xB9, 0xCE, 0x92, 0xFC, 0x92, 0xFD, 0xB9, 0xCF, /* 0xFC-0xFF */ }; -static unsigned char u2c_BC[512] = { +static const unsigned char u2c_BC[512] = { 0xB9, 0xD0, 0x92, 0xFE, 0xB9, 0xD1, 0x93, 0x41, /* 0x00-0x03 */ 0x93, 0x42, 0x93, 0x43, 0x93, 0x44, 0x93, 0x45, /* 0x04-0x07 */ 0xB9, 0xD2, 0xB9, 0xD3, 0x93, 0x46, 0xB9, 0xD4, /* 0x08-0x0B */ @@ -11790,7 +11790,7 @@ static unsigned char u2c_BC[512] = { 0xBA, 0xBC, 0x93, 0xFE, 0x94, 0x41, 0x94, 0x42, /* 0xFC-0xFF */ }; -static unsigned char u2c_BD[512] = { +static const unsigned char u2c_BD[512] = { 0x94, 0x43, 0x94, 0x44, 0x94, 0x45, 0x94, 0x46, /* 0x00-0x03 */ 0xBA, 0xBD, 0xBA, 0xBE, 0x94, 0x47, 0xBA, 0xBF, /* 0x04-0x07 */ 0x94, 0x48, 0xBA, 0xC0, 0x94, 0x49, 0x94, 0x4A, /* 0x08-0x0B */ @@ -11858,7 +11858,7 @@ static unsigned char u2c_BD[512] = { 0x95, 0x69, 0x95, 0x6A, 0x95, 0x6B, 0x95, 0x6C, /* 0xFC-0xFF */ }; -static unsigned char u2c_BE[512] = { +static const unsigned char u2c_BE[512] = { 0xBA, 0xE7, 0x95, 0x6D, 0x95, 0x6E, 0xBA, 0xE8, /* 0x00-0x03 */ 0x95, 0x6F, 0xBA, 0xE9, 0x95, 0x70, 0x95, 0x71, /* 0x04-0x07 */ 0x95, 0x72, 0x95, 0x73, 0x95, 0x74, 0x95, 0x75, /* 0x08-0x0B */ @@ -11926,7 +11926,7 @@ static unsigned char u2c_BE[512] = { 0x96, 0x87, 0x96, 0x88, 0x96, 0x89, 0x96, 0x8A, /* 0xFC-0xFF */ }; -static unsigned char u2c_BF[512] = { +static const unsigned char u2c_BF[512] = { 0x96, 0x8B, 0xBB, 0xBF, 0x96, 0x8C, 0x96, 0x8D, /* 0x00-0x03 */ 0x96, 0x8E, 0x96, 0x8F, 0x96, 0x90, 0x96, 0x91, /* 0x04-0x07 */ 0xBB, 0xC0, 0xBB, 0xC1, 0x96, 0x92, 0x96, 0x93, /* 0x08-0x0B */ @@ -11994,7 +11994,7 @@ static unsigned char u2c_BF[512] = { 0x97, 0xBC, 0x97, 0xBD, 0x97, 0xBE, 0x97, 0xBF, /* 0xFC-0xFF */ }; -static unsigned char u2c_C0[512] = { +static const unsigned char u2c_C0[512] = { 0x97, 0xC0, 0x97, 0xC1, 0x97, 0xC2, 0x97, 0xC3, /* 0x00-0x03 */ 0x97, 0xC4, 0x97, 0xC5, 0x97, 0xC6, 0x97, 0xC7, /* 0x04-0x07 */ 0x97, 0xC8, 0x97, 0xC9, 0x97, 0xCA, 0x97, 0xCB, /* 0x08-0x0B */ @@ -12062,7 +12062,7 @@ static unsigned char u2c_C0[512] = { 0x98, 0xDC, 0x98, 0xDD, 0x98, 0xDE, 0x98, 0xDF, /* 0xFC-0xFF */ }; -static unsigned char u2c_C1[512] = { +static const unsigned char u2c_C1[512] = { 0xBC, 0xA8, 0x98, 0xE0, 0x98, 0xE1, 0x98, 0xE2, /* 0x00-0x03 */ 0xBC, 0xA9, 0x98, 0xE3, 0x98, 0xE4, 0x98, 0xE5, /* 0x04-0x07 */ 0xBC, 0xAA, 0x98, 0xE6, 0x98, 0xE7, 0x98, 0xE8, /* 0x08-0x0B */ @@ -12130,7 +12130,7 @@ static unsigned char u2c_C1[512] = { 0xBC, 0xEE, 0xBC, 0xEF, 0x99, 0xE4, 0x99, 0xE5, /* 0xFC-0xFF */ }; -static unsigned char u2c_C2[512] = { +static const unsigned char u2c_C2[512] = { 0xBC, 0xF0, 0x99, 0xE6, 0x99, 0xE7, 0x99, 0xE8, /* 0x00-0x03 */ 0xBC, 0xF1, 0x99, 0xE9, 0x99, 0xEA, 0x99, 0xEB, /* 0x04-0x07 */ 0x99, 0xEC, 0x99, 0xED, 0x99, 0xEE, 0x99, 0xEF, /* 0x08-0x0B */ @@ -12198,7 +12198,7 @@ static unsigned char u2c_C2[512] = { 0xBD, 0xD1, 0x9A, 0xF1, 0x9A, 0xF2, 0x9A, 0xF3, /* 0xFC-0xFF */ }; -static unsigned char u2c_C3[512] = { +static const unsigned char u2c_C3[512] = { 0xBD, 0xD2, 0x9A, 0xF4, 0x9A, 0xF5, 0x9A, 0xF6, /* 0x00-0x03 */ 0x9A, 0xF7, 0x9A, 0xF8, 0x9A, 0xF9, 0x9A, 0xFA, /* 0x04-0x07 */ 0xBD, 0xD3, 0xBD, 0xD4, 0x9A, 0xFB, 0x9A, 0xFC, /* 0x08-0x0B */ @@ -12266,7 +12266,7 @@ static unsigned char u2c_C3[512] = { 0x9C, 0x58, 0x9C, 0x59, 0x9C, 0x5A, 0x9C, 0x61, /* 0xFC-0xFF */ }; -static unsigned char u2c_C4[512] = { +static const unsigned char u2c_C4[512] = { 0x9C, 0x62, 0x9C, 0x63, 0x9C, 0x64, 0x9C, 0x65, /* 0x00-0x03 */ 0x9C, 0x66, 0x9C, 0x67, 0x9C, 0x68, 0x9C, 0x69, /* 0x04-0x07 */ 0xBD, 0xFA, 0x9C, 0x6A, 0x9C, 0x6B, 0x9C, 0x6C, /* 0x08-0x0B */ @@ -12334,7 +12334,7 @@ static unsigned char u2c_C4[512] = { 0x9D, 0x97, 0x9D, 0x98, 0x9D, 0x99, 0xBE, 0xB7, /* 0xFC-0xFF */ }; -static unsigned char u2c_C5[512] = { +static const unsigned char u2c_C5[512] = { 0xBE, 0xB8, 0xBE, 0xB9, 0x9D, 0x9A, 0x9D, 0x9B, /* 0x00-0x03 */ 0x9D, 0x9C, 0x9D, 0x9D, 0x9D, 0x9E, 0x9D, 0x9F, /* 0x04-0x07 */ 0x9D, 0xA0, 0x9D, 0xA1, 0x9D, 0xA2, 0x9D, 0xA3, /* 0x08-0x0B */ @@ -12402,7 +12402,7 @@ static unsigned char u2c_C5[512] = { 0xBF, 0xB0, 0xBF, 0xB1, 0xBF, 0xB2, 0xBF, 0xB3, /* 0xFC-0xFF */ }; -static unsigned char u2c_C6[512] = { +static const unsigned char u2c_C6[512] = { 0xBF, 0xB4, 0xBF, 0xB5, 0x9E, 0x8E, 0x9E, 0x8F, /* 0x00-0x03 */ 0x9E, 0x90, 0xBF, 0xB6, 0xBF, 0xB7, 0xBF, 0xB8, /* 0x04-0x07 */ 0xBF, 0xB9, 0x9E, 0x91, 0x9E, 0x92, 0x9E, 0x93, /* 0x08-0x0B */ @@ -12470,7 +12470,7 @@ static unsigned char u2c_C6[512] = { 0x9F, 0x88, 0xC0, 0xA6, 0x9F, 0x89, 0x9F, 0x8A, /* 0xFC-0xFF */ }; -static unsigned char u2c_C7[512] = { +static const unsigned char u2c_C7[512] = { 0x9F, 0x8B, 0x9F, 0x8C, 0x9F, 0x8D, 0x9F, 0x8E, /* 0x00-0x03 */ 0xC0, 0xA7, 0xC0, 0xA8, 0x9F, 0x8F, 0x9F, 0x90, /* 0x04-0x07 */ 0xC0, 0xA9, 0x9F, 0x91, 0x9F, 0x92, 0x9F, 0x93, /* 0x08-0x0B */ @@ -12538,7 +12538,7 @@ static unsigned char u2c_C7[512] = { 0xA0, 0x82, 0xA0, 0x83, 0xA0, 0x84, 0xA0, 0x85, /* 0xFC-0xFF */ }; -static unsigned char u2c_C8[512] = { +static const unsigned char u2c_C8[512] = { 0xC0, 0xFA, 0xC0, 0xFB, 0xA0, 0x86, 0xA0, 0x87, /* 0x00-0x03 */ 0xC0, 0xFC, 0xA0, 0x88, 0xA0, 0x89, 0xA0, 0x8A, /* 0x04-0x07 */ 0xC0, 0xFD, 0xA0, 0x8B, 0xC0, 0xFE, 0xA0, 0x8C, /* 0x08-0x0B */ @@ -12606,7 +12606,7 @@ static unsigned char u2c_C8[512] = { 0xC1, 0xD6, 0xC1, 0xD7, 0xA1, 0x96, 0xA1, 0x97, /* 0xFC-0xFF */ }; -static unsigned char u2c_C9[512] = { +static const unsigned char u2c_C9[512] = { 0xC1, 0xD8, 0xA1, 0x98, 0xA1, 0x99, 0xA1, 0x9A, /* 0x00-0x03 */ 0xC1, 0xD9, 0xC1, 0xDA, 0xC1, 0xDB, 0xA1, 0x9B, /* 0x04-0x07 */ 0xA1, 0x9C, 0xA1, 0x9D, 0xA1, 0x9E, 0xA1, 0x9F, /* 0x08-0x0B */ @@ -12674,7 +12674,7 @@ static unsigned char u2c_C9[512] = { 0xC2, 0xB2, 0xA4, 0x54, 0xA4, 0x55, 0xA4, 0x56, /* 0xFC-0xFF */ }; -static unsigned char u2c_CA[512] = { +static const unsigned char u2c_CA[512] = { 0xC2, 0xB3, 0xA4, 0x57, 0xA4, 0x58, 0xA4, 0x59, /* 0x00-0x03 */ 0xA4, 0x5A, 0xA4, 0x61, 0xA4, 0x62, 0xA4, 0x63, /* 0x04-0x07 */ 0xC2, 0xB4, 0xC2, 0xB5, 0xA4, 0x64, 0xC2, 0xB6, /* 0x08-0x0B */ @@ -12742,7 +12742,7 @@ static unsigned char u2c_CA[512] = { 0xA6, 0x93, 0xA6, 0x94, 0xA6, 0x95, 0xA6, 0x96, /* 0xFC-0xFF */ }; -static unsigned char u2c_CB[512] = { +static const unsigned char u2c_CB[512] = { 0xA6, 0x97, 0xA6, 0x98, 0xA6, 0x99, 0xA6, 0x9A, /* 0x00-0x03 */ 0xA6, 0x9B, 0xA6, 0x9C, 0xA6, 0x9D, 0xA6, 0x9E, /* 0x04-0x07 */ 0xC2, 0xD7, 0xA6, 0x9F, 0xA6, 0xA0, 0xA7, 0x41, /* 0x08-0x0B */ @@ -12810,7 +12810,7 @@ static unsigned char u2c_CB[512] = { 0xA9, 0x7A, 0xA9, 0x81, 0xA9, 0x82, 0xA9, 0x83, /* 0xFC-0xFF */ }; -static unsigned char u2c_CC[512] = { +static const unsigned char u2c_CC[512] = { 0xA9, 0x84, 0xA9, 0x85, 0xA9, 0x86, 0xA9, 0x87, /* 0x00-0x03 */ 0xA9, 0x88, 0xA9, 0x89, 0xA9, 0x8A, 0xA9, 0x8B, /* 0x04-0x07 */ 0xA9, 0x8C, 0xA9, 0x8D, 0xA9, 0x8E, 0xA9, 0x8F, /* 0x08-0x0B */ @@ -12878,7 +12878,7 @@ static unsigned char u2c_CC[512] = { 0xAB, 0x9F, 0xAB, 0xA0, 0xAC, 0x41, 0xAC, 0x42, /* 0xFC-0xFF */ }; -static unsigned char u2c_CD[512] = { +static const unsigned char u2c_CD[512] = { 0xAC, 0x43, 0xC3, 0xC9, 0xAC, 0x44, 0xAC, 0x45, /* 0x00-0x03 */ 0xAC, 0x46, 0xAC, 0x47, 0xAC, 0x48, 0xAC, 0x49, /* 0x04-0x07 */ 0xC3, 0xCA, 0xC3, 0xCB, 0xAC, 0x4A, 0xAC, 0x4B, /* 0x08-0x0B */ @@ -12946,7 +12946,7 @@ static unsigned char u2c_CD[512] = { 0xAE, 0x75, 0xC3, 0xF1, 0xAE, 0x76, 0xAE, 0x77, /* 0xFC-0xFF */ }; -static unsigned char u2c_CE[512] = { +static const unsigned char u2c_CE[512] = { 0xAE, 0x78, 0xAE, 0x79, 0xAE, 0x7A, 0xAE, 0x81, /* 0x00-0x03 */ 0xC3, 0xF2, 0xAE, 0x82, 0xAE, 0x83, 0xAE, 0x84, /* 0x04-0x07 */ 0xC3, 0xF3, 0xAE, 0x85, 0xAE, 0x86, 0xAE, 0x87, /* 0x08-0x0B */ @@ -13014,7 +13014,7 @@ static unsigned char u2c_CE[512] = { 0xB0, 0x9D, 0xB0, 0x9E, 0xB0, 0x9F, 0xB0, 0xA0, /* 0xFC-0xFF */ }; -static unsigned char u2c_CF[512] = { +static const unsigned char u2c_CF[512] = { 0xC4, 0xC9, 0xC4, 0xCA, 0xB1, 0x41, 0xB1, 0x42, /* 0x00-0x03 */ 0xC4, 0xCB, 0xB1, 0x43, 0xB1, 0x44, 0xB1, 0x45, /* 0x04-0x07 */ 0xC4, 0xCC, 0xB1, 0x46, 0xB1, 0x47, 0xB1, 0x48, /* 0x08-0x0B */ @@ -13082,7 +13082,7 @@ static unsigned char u2c_CF[512] = { 0xC4, 0xF5, 0xB3, 0x6F, 0xB3, 0x70, 0xB3, 0x71, /* 0xFC-0xFF */ }; -static unsigned char u2c_D0[512] = { +static const unsigned char u2c_D0[512] = { 0xC4, 0xF6, 0xB3, 0x72, 0xB3, 0x73, 0xB3, 0x74, /* 0x00-0x03 */ 0xC4, 0xF7, 0xB3, 0x75, 0xB3, 0x76, 0xB3, 0x77, /* 0x04-0x07 */ 0xB3, 0x78, 0xB3, 0x79, 0xB3, 0x7A, 0xB3, 0x81, /* 0x08-0x0B */ @@ -13150,7 +13150,7 @@ static unsigned char u2c_D0[512] = { 0xB5, 0x98, 0xB5, 0x99, 0xB5, 0x9A, 0xB5, 0x9B, /* 0xFC-0xFF */ }; -static unsigned char u2c_D1[512] = { +static const unsigned char u2c_D1[512] = { 0xB5, 0x9C, 0xB5, 0x9D, 0xB5, 0x9E, 0xB5, 0x9F, /* 0x00-0x03 */ 0xB5, 0xA0, 0xB6, 0x41, 0xB6, 0x42, 0xB6, 0x43, /* 0x04-0x07 */ 0xB6, 0x44, 0xB6, 0x45, 0xB6, 0x46, 0xB6, 0x47, /* 0x08-0x0B */ @@ -13218,7 +13218,7 @@ static unsigned char u2c_D1[512] = { 0xB8, 0x70, 0xB8, 0x71, 0xB8, 0x72, 0xB8, 0x73, /* 0xFC-0xFF */ }; -static unsigned char u2c_D2[512] = { +static const unsigned char u2c_D2[512] = { 0xB8, 0x74, 0xB8, 0x75, 0xB8, 0x76, 0xB8, 0x77, /* 0x00-0x03 */ 0xB8, 0x78, 0xB8, 0x79, 0xB8, 0x7A, 0xC5, 0xF2, /* 0x04-0x07 */ 0xB8, 0x81, 0xC5, 0xF3, 0xB8, 0x82, 0xB8, 0x83, /* 0x08-0x0B */ @@ -13286,7 +13286,7 @@ static unsigned char u2c_D2[512] = { 0xBB, 0x42, 0xBB, 0x43, 0xBB, 0x44, 0xBB, 0x45, /* 0xFC-0xFF */ }; -static unsigned char u2c_D3[512] = { +static const unsigned char u2c_D3[512] = { 0xC6, 0xC0, 0xC6, 0xC1, 0xBB, 0x46, 0xC6, 0xC2, /* 0x00-0x03 */ 0xBB, 0x47, 0xC6, 0xC3, 0xBB, 0x48, 0xBB, 0x49, /* 0x04-0x07 */ 0xBB, 0x4A, 0xBB, 0x4B, 0xBB, 0x4C, 0xBB, 0x4D, /* 0x08-0x0B */ @@ -13354,7 +13354,7 @@ static unsigned char u2c_D3[512] = { 0xC6, 0xFB, 0xC6, 0xFC, 0xBD, 0x65, 0xC6, 0xFD, /* 0xFC-0xFF */ }; -static unsigned char u2c_D4[512] = { +static const unsigned char u2c_D4[512] = { 0xBD, 0x66, 0xC6, 0xFE, 0xBD, 0x67, 0xBD, 0x68, /* 0x00-0x03 */ 0xBD, 0x69, 0xBD, 0x6A, 0xBD, 0x6B, 0xBD, 0x6C, /* 0x04-0x07 */ 0xC7, 0xA1, 0xBD, 0x6D, 0xBD, 0x6E, 0xBD, 0x6F, /* 0x08-0x0B */ @@ -13422,7 +13422,7 @@ static unsigned char u2c_D4[512] = { 0xBF, 0xA0, 0xC7, 0xC0, 0xC0, 0x41, 0xC0, 0x42, /* 0xFC-0xFF */ }; -static unsigned char u2c_D5[512] = { +static const unsigned char u2c_D5[512] = { 0xC0, 0x43, 0xC0, 0x44, 0xC0, 0x45, 0xC0, 0x46, /* 0x00-0x03 */ 0xC7, 0xC1, 0xC0, 0x47, 0xC0, 0x48, 0xC0, 0x49, /* 0x04-0x07 */ 0xC7, 0xC2, 0xC0, 0x4A, 0xC0, 0x4B, 0xC0, 0x4C, /* 0x08-0x0B */ @@ -13490,7 +13490,7 @@ static unsigned char u2c_D5[512] = { 0xC2, 0x6A, 0xC2, 0x6B, 0xC2, 0x6C, 0xC2, 0x6D, /* 0xFC-0xFF */ }; -static unsigned char u2c_D6[512] = { +static const unsigned char u2c_D6[512] = { 0xC7, 0xF4, 0xC7, 0xF5, 0xC2, 0x6E, 0xC2, 0x6F, /* 0x00-0x03 */ 0xC7, 0xF6, 0xC2, 0x70, 0xC2, 0x71, 0xC2, 0x72, /* 0x04-0x07 */ 0xC7, 0xF7, 0xC2, 0x73, 0xC2, 0x74, 0xC2, 0x75, /* 0x08-0x0B */ @@ -13558,7 +13558,7 @@ static unsigned char u2c_D6[512] = { 0xC8, 0xD1, 0xC8, 0xD2, 0xC4, 0x8D, 0xC4, 0x8E, /* 0xFC-0xFF */ }; -static unsigned char u2c_D7[512] = { +static const unsigned char u2c_D7[512] = { 0xC8, 0xD3, 0xC4, 0x8F, 0xC4, 0x90, 0xC4, 0x91, /* 0x00-0x03 */ 0xC8, 0xD4, 0xC4, 0x92, 0xC4, 0x93, 0xC4, 0x94, /* 0x04-0x07 */ 0xC4, 0x95, 0xC4, 0x96, 0xC4, 0x97, 0xC4, 0x98, /* 0x08-0x0B */ @@ -13603,11 +13603,11 @@ static unsigned char u2c_D7[512] = { 0xC6, 0x4F, 0xC6, 0x50, 0xC6, 0x51, 0xC6, 0x52, /* 0xA0-0xA3 */ }; -static unsigned char u2c_DC[512] = { +static const unsigned char u2c_DC[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ }; -static unsigned char u2c_F9[512] = { +static const unsigned char u2c_F9[512] = { 0xCB, 0xD0, 0xCB, 0xD6, 0xCB, 0xE7, 0xCD, 0xCF, /* 0x00-0x03 */ 0xCD, 0xE8, 0xCE, 0xAD, 0xCF, 0xFB, 0xD0, 0xA2, /* 0x04-0x07 */ 0xD0, 0xB8, 0xD0, 0xD0, 0xD0, 0xDD, 0xD1, 0xD4, /* 0x08-0x0B */ @@ -13675,7 +13675,7 @@ static unsigned char u2c_F9[512] = { 0xF2, 0xBD, 0xF2, 0xFA, 0xF3, 0xB1, 0xF4, 0xA7, /* 0xFC-0xFF */ }; -static unsigned char u2c_FA[512] = { +static const unsigned char u2c_FA[512] = { 0xF4, 0xEE, 0xF6, 0xF4, 0xF6, 0xF6, 0xF7, 0xB8, /* 0x00-0x03 */ 0xF7, 0xC8, 0xF7, 0xD3, 0xF8, 0xDB, 0xF8, 0xF0, /* 0x04-0x07 */ 0xFA, 0xA1, 0xFA, 0xA2, 0xFA, 0xE6, 0xFC, 0xA9, /* 0x08-0x0B */ @@ -13690,7 +13690,7 @@ static unsigned char u2c_FA[512] = { 0xCE, 0xBD, 0xF9, 0xCD, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ }; -static unsigned char u2c_FF[512] = { +static const unsigned char u2c_FF[512] = { 0x00, 0x00, 0xA3, 0xA1, 0xA3, 0xA2, 0xA3, 0xA3, /* 0x00-0x03 */ 0xA3, 0xA4, 0xA3, 0xA5, 0xA3, 0xA6, 0xA3, 0xA7, /* 0x04-0x07 */ 0xA3, 0xA8, 0xA3, 0xA9, 0xA3, 0xAA, 0xA3, 0xAB, /* 0x08-0x0B */ @@ -13752,7 +13752,7 @@ static unsigned char u2c_FF[512] = { 0x00, 0x00, 0xA1, 0xCD, 0xA3, 0xDC, 0x00, 0x00, /* 0xE4-0xE7 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { NULL, u2c_01, u2c_02, u2c_03, u2c_04, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, u2c_11, NULL, NULL, NULL, NULL, NULL, NULL, @@ -13786,7 +13786,7 @@ static unsigned char *page_uni2charset[256] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, u2c_F9, u2c_FA, NULL, NULL, NULL, NULL, u2c_FF, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -13822,7 +13822,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -13861,7 +13861,7 @@ static unsigned char charset2upper[256] = { static int uni2char(const wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni&0xFF; unsigned char ch = (uni>>8)&0xFF; int n; @@ -13893,7 +13893,7 @@ static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) { unsigned char ch, cl; - wchar_t *charset2uni; + const wchar_t *charset2uni; int n; if (boundlen <= 0) diff --git a/fs/nls/nls_cp950.c b/fs/nls/nls_cp950.c index 5665945fb88c..ef2536829aa5 100644 --- a/fs/nls/nls_cp950.c +++ b/fs/nls/nls_cp950.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t c2u_A1[256] = { +static const wchar_t c2u_A1[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -49,7 +49,7 @@ static wchar_t c2u_A1[256] = { 0x2196,0x2197,0x2199,0x2198,0x2225,0x2223,0xFF0F,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_A2[256] = { +static const wchar_t c2u_A2[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -85,7 +85,7 @@ static wchar_t c2u_A2[256] = { 0xFF50,0xFF51,0xFF52,0xFF53,0xFF54,0xFF55,0xFF56,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_A3[256] = { +static const wchar_t c2u_A3[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -118,7 +118,7 @@ static wchar_t c2u_A3[256] = { 0x0000,0x20AC,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xE0-0xE7 */ }; -static wchar_t c2u_A4[256] = { +static const wchar_t c2u_A4[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -154,7 +154,7 @@ static wchar_t c2u_A4[256] = { 0x723B,0x7247,0x7259,0x725B,0x72AC,0x738B,0x4E19,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_A5[256] = { +static const wchar_t c2u_A5[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -190,7 +190,7 @@ static wchar_t c2u_A5[256] = { 0x4F01,0x4F0B,0x5149,0x5147,0x5146,0x5148,0x5168,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_A6[256] = { +static const wchar_t c2u_A6[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -226,7 +226,7 @@ static wchar_t c2u_A6[256] = { 0x4F3A,0x4F38,0x4F43,0x4F54,0x4F3C,0x4F46,0x4F63,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_A7[256] = { +static const wchar_t c2u_A7[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -262,7 +262,7 @@ static wchar_t c2u_A7[256] = { 0x6751,0x675C,0x6756,0x675E,0x6749,0x6746,0x6760,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_A8[256] = { +static const wchar_t c2u_A8[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -298,7 +298,7 @@ static wchar_t c2u_A8[256] = { 0x5378,0x5379,0x53D6,0x53D4,0x53D7,0x5473,0x5475,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_A9[256] = { +static const wchar_t c2u_A9[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -334,7 +334,7 @@ static wchar_t c2u_A9[256] = { 0x6606,0x6602,0x660E,0x6600,0x660F,0x6615,0x660A,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_AA[256] = { +static const wchar_t c2u_AA[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -370,7 +370,7 @@ static wchar_t c2u_AA[256] = { 0x9577,0x9580,0x961C,0x9640,0x963F,0x963B,0x9644,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_AB[256] = { +static const wchar_t c2u_AB[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -406,7 +406,7 @@ static wchar_t c2u_AB[256] = { 0x62ED,0x6301,0x62EE,0x62FD,0x6307,0x62F1,0x62F7,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_AC[256] = { +static const wchar_t c2u_AC[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -442,7 +442,7 @@ static wchar_t c2u_AC[256] = { 0x7D07,0x7D04,0x7D06,0x7F38,0x7F8E,0x7FBF,0x8004,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_AD[256] = { +static const wchar_t c2u_AD[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -478,7 +478,7 @@ static wchar_t c2u_AD[256] = { 0x5514,0x54E9,0x54ED,0x54E1,0x5509,0x54EE,0x54EA,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_AE[256] = { +static const wchar_t c2u_AE[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -514,7 +514,7 @@ static wchar_t c2u_AE[256] = { 0x6D88,0x6D87,0x6D66,0x6D78,0x6D77,0x6D59,0x6D93,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_AF[256] = { +static const wchar_t c2u_AF[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -550,7 +550,7 @@ static wchar_t c2u_AF[256] = { 0x8339,0x8336,0x8317,0x8340,0x8331,0x8328,0x8343,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B0[256] = { +static const wchar_t c2u_B0[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -586,7 +586,7 @@ static wchar_t c2u_B0[256] = { 0x5962,0x5A36,0x5A41,0x5A49,0x5A66,0x5A6A,0x5A40,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B1[256] = { +static const wchar_t c2u_B1[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -622,7 +622,7 @@ static wchar_t c2u_B1[256] = { 0x689D,0x68A8,0x689F,0x68A1,0x6882,0x6B32,0x6BBA,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B2[256] = { +static const wchar_t c2u_B2[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -658,7 +658,7 @@ static wchar_t c2u_B2[256] = { 0x838A,0x8393,0x8389,0x83A0,0x8377,0x837B,0x837C,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B3[256] = { +static const wchar_t c2u_B3[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -694,7 +694,7 @@ static wchar_t c2u_B3[256] = { 0x5831,0x5821,0x581D,0x5820,0x58F9,0x58FA,0x5960,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B4[256] = { +static const wchar_t c2u_B4[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -730,7 +730,7 @@ static wchar_t c2u_B4[256] = { 0x6E4D,0x6E3A,0x6E2C,0x6E43,0x6E1D,0x6E3E,0x6ECB,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B5[256] = { +static const wchar_t c2u_B5[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -766,7 +766,7 @@ static wchar_t c2u_B5[256] = { 0x8996,0x8A3B,0x8A60,0x8A55,0x8A5E,0x8A3C,0x8A41,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B6[256] = { +static const wchar_t c2u_B6[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -802,7 +802,7 @@ static wchar_t c2u_B6[256] = { 0x5967,0x5AC1,0x5AC9,0x5ACC,0x5ABE,0x5ABD,0x5ABC,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B7[256] = { +static const wchar_t c2u_B7[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -838,7 +838,7 @@ static wchar_t c2u_B7[256] = { 0x76DE,0x76DF,0x775B,0x776B,0x7766,0x775E,0x7763,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B8[256] = { +static const wchar_t c2u_B8[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -874,7 +874,7 @@ static wchar_t c2u_B8[256] = { 0x8DE4,0x8DE6,0x8EB2,0x8F03,0x8F09,0x8EFE,0x8F0A,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_B9[256] = { +static const wchar_t c2u_B9[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -910,7 +910,7 @@ static wchar_t c2u_B9[256] = { 0x5ED3,0x5ED6,0x5F0A,0x5F46,0x5F70,0x5FB9,0x6147,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_BA[256] = { +static const wchar_t c2u_BA[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -946,7 +946,7 @@ static wchar_t c2u_BA[256] = { 0x7DBF,0x7DB5,0x7DB8,0x7DAD,0x7DD2,0x7DC7,0x7DAC,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_BB[256] = { +static const wchar_t c2u_BB[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -982,7 +982,7 @@ static wchar_t c2u_BB[256] = { 0x50F5,0x50F9,0x5102,0x5108,0x5109,0x5105,0x51DC,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_BC[256] = { +static const wchar_t c2u_BC[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1018,7 +1018,7 @@ static wchar_t c2u_BC[256] = { 0x7256,0x729B,0x734E,0x7357,0x7469,0x748B,0x7483,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_BD[256] = { +static const wchar_t c2u_BD[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1054,7 +1054,7 @@ static wchar_t c2u_BD[256] = { 0x8F1B,0x8F1F,0x8F29,0x8F26,0x8F2A,0x8F1C,0x8F1E,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_BE[256] = { +static const wchar_t c2u_BE[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1090,7 +1090,7 @@ static wchar_t c2u_BE[256] = { 0x6A48,0x6B59,0x6B77,0x6C05,0x6FC2,0x6FB1,0x6FA1,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_BF[256] = { +static const wchar_t c2u_BF[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1126,7 +1126,7 @@ static wchar_t c2u_BF[256] = { 0x9333,0x932F,0x9322,0x92FC,0x932B,0x9304,0x931A,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C0[256] = { +static const wchar_t c2u_C0[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1162,7 +1162,7 @@ static wchar_t c2u_C0[256] = { 0x7642,0x764C,0x76EA,0x77B3,0x77AA,0x77B0,0x77AC,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C1[256] = { +static const wchar_t c2u_C1[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1198,7 +1198,7 @@ static wchar_t c2u_C1[256] = { 0x971E,0x97A0,0x97D3,0x9846,0x98B6,0x9935,0x9A01,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C2[256] = { +static const wchar_t c2u_C2[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1234,7 +1234,7 @@ static wchar_t c2u_C2[256] = { 0x96DC,0x96D9,0x96DB,0x96DE,0x9724,0x97A3,0x97A6,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C3[256] = { +static const wchar_t c2u_C3[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1270,7 +1270,7 @@ static wchar_t c2u_C3[256] = { 0x96E3,0x972A,0x9727,0x9761,0x97DC,0x97FB,0x985E,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C4[256] = { +static const wchar_t c2u_C4[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1306,7 +1306,7 @@ static wchar_t c2u_C4[256] = { 0x8822,0x8821,0x881F,0x896A,0x896C,0x89BD,0x8B74,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C5[256] = { +static const wchar_t c2u_C5[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1342,7 +1342,7 @@ static wchar_t c2u_C5[256] = { 0x7F50,0x7F88,0x8836,0x8839,0x8862,0x8B93,0x8B92,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_C6[256] = { +static const wchar_t c2u_C6[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1361,7 +1361,7 @@ static wchar_t c2u_C6[256] = { 0x9E1A,0x7228,0x9A6A,0x9B31,0x9E1B,0x9E1E,0x7C72,0x0000,/* 0x78-0x7F */ }; -static wchar_t c2u_C9[256] = { +static const wchar_t c2u_C9[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1397,7 +1397,7 @@ static wchar_t c2u_C9[256] = { 0x6C46,0x6C52,0x6C5C,0x6C4F,0x6C4A,0x6C54,0x6C4B,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_CA[256] = { +static const wchar_t c2u_CA[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1433,7 +1433,7 @@ static wchar_t c2u_CA[256] = { 0x65F0,0x65F4,0x65F3,0x65F2,0x65F5,0x6745,0x6747,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_CB[256] = { +static const wchar_t c2u_CB[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1469,7 +1469,7 @@ static wchar_t c2u_CB[256] = { 0x5776,0x5780,0x5775,0x577B,0x5773,0x5774,0x5762,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_CC[256] = { +static const wchar_t c2u_CC[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1505,7 +1505,7 @@ static wchar_t c2u_CC[256] = { 0x6CD0,0x6CC2,0x6CBA,0x6CC3,0x6CC6,0x6CED,0x6CF2,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_CD[256] = { +static const wchar_t c2u_CD[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1541,7 +1541,7 @@ static wchar_t c2u_CD[256] = { 0x5399,0x5398,0x54BA,0x54A1,0x54AD,0x54A5,0x54CF,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_CE[256] = { +static const wchar_t c2u_CE[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1577,7 +1577,7 @@ static wchar_t c2u_CE[256] = { 0x662E,0x670F,0x6710,0x67C1,0x67F2,0x67C8,0x67BA,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_CF[256] = { +static const wchar_t c2u_CF[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1613,7 +1613,7 @@ static wchar_t c2u_CF[256] = { 0x7944,0x79D5,0x79CD,0x79CF,0x79D6,0x79CE,0x7A80,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D0[256] = { +static const wchar_t c2u_D0[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1649,7 +1649,7 @@ static wchar_t c2u_D0[256] = { 0x54FF,0x5504,0x5508,0x54EB,0x5511,0x5505,0x54F1,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D1[256] = { +static const wchar_t c2u_D1[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1685,7 +1685,7 @@ static wchar_t c2u_D1[256] = { 0x6B31,0x6B34,0x6B6D,0x8082,0x6B88,0x6BE6,0x6BE4,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D2[256] = { +static const wchar_t c2u_D2[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1721,7 +1721,7 @@ static wchar_t c2u_D2[256] = { 0x7A85,0x7A8B,0x7A8C,0x7A8A,0x7A87,0x7AD8,0x7B10,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D3[256] = { +static const wchar_t c2u_D3[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1757,7 +1757,7 @@ static wchar_t c2u_D3[256] = { 0x90E5,0x90D8,0x90DB,0x90D7,0x90DC,0x90E4,0x9150,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D4[256] = { +static const wchar_t c2u_D4[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1793,7 +1793,7 @@ static wchar_t c2u_D4[256] = { 0x5D20,0x5D0C,0x5D28,0x5D0D,0x5D26,0x5D25,0x5D0F,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D5[256] = { +static const wchar_t c2u_D5[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1829,7 +1829,7 @@ static wchar_t c2u_D5[256] = { 0x6DED,0x6DF0,0x6DBA,0x6DD5,0x6DC2,0x6DCF,0x6DC9,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D6[256] = { +static const wchar_t c2u_D6[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1865,7 +1865,7 @@ static wchar_t c2u_D6[256] = { 0x7FCD,0x7FD0,0x7FD1,0x7FC7,0x7FCF,0x7FC9,0x801F,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D7[256] = { +static const wchar_t c2u_D7[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1901,7 +1901,7 @@ static wchar_t c2u_D7[256] = { 0x91F4,0x91F1,0x91F3,0x91F8,0x91E4,0x91F9,0x91EA,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D8[256] = { +static const wchar_t c2u_D8[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1937,7 +1937,7 @@ static wchar_t c2u_D8[256] = { 0x60C9,0x60B9,0x60CC,0x60E2,0x60CE,0x60C4,0x6114,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_D9[256] = { +static const wchar_t c2u_D9[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -1973,7 +1973,7 @@ static wchar_t c2u_D9[256] = { 0x6E4B,0x6E40,0x6E51,0x6E3B,0x6E03,0x6E2E,0x6E5E,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_DA[256] = { +static const wchar_t c2u_DA[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2009,7 +2009,7 @@ static wchar_t c2u_DA[256] = { 0x7D69,0x7D51,0x7D5F,0x7D4E,0x7F3E,0x7F3F,0x7F65,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_DB[256] = { +static const wchar_t c2u_DB[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2045,7 +2045,7 @@ static wchar_t c2u_DB[256] = { 0x8DD9,0x8DC8,0x8DD7,0x8DC5,0x8EEF,0x8EF7,0x8EFA,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_DC[256] = { +static const wchar_t c2u_DC[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2081,7 +2081,7 @@ static wchar_t c2u_DC[256] = { 0x5AB1,0x5AB5,0x5AB0,0x5ABF,0x5AC8,0x5ABB,0x5AC6,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_DD[256] = { +static const wchar_t c2u_DD[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2117,7 +2117,7 @@ static wchar_t c2u_DD[256] = { 0x6B42,0x6B48,0x6B41,0x6B9B,0xFA0D,0x6BFB,0x6BFC,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_DE[256] = { +static const wchar_t c2u_DE[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2153,7 +2153,7 @@ static wchar_t c2u_DE[256] = { 0x7A18,0x7A19,0x7A12,0x7A17,0x7A15,0x7A22,0x7A13,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_DF[256] = { +static const wchar_t c2u_DF[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2189,7 +2189,7 @@ static wchar_t c2u_DF[256] = { 0x88CC,0x88D0,0x8985,0x899B,0x89DF,0x89E5,0x89E4,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E0[256] = { +static const wchar_t c2u_E0[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2225,7 +2225,7 @@ static wchar_t c2u_E0[256] = { 0x50E4,0x50D3,0x50EC,0x50F0,0x50EF,0x50E3,0x50E0,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E1[256] = { +static const wchar_t c2u_E1[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2261,7 +2261,7 @@ static wchar_t c2u_E1[256] = { 0x669F,0x6705,0x6704,0x6722,0x69B1,0x69B6,0x69C9,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E2[256] = { +static const wchar_t c2u_E2[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2297,7 +2297,7 @@ static wchar_t c2u_E2[256] = { 0x7998,0x798A,0x798B,0x7996,0x7995,0x7994,0x7993,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E3[256] = { +static const wchar_t c2u_E3[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2333,7 +2333,7 @@ static wchar_t c2u_E3[256] = { 0x88F2,0x88FA,0x88FE,0x88EE,0x88FC,0x88F6,0x88FB,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E4[256] = { +static const wchar_t c2u_E4[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2369,7 +2369,7 @@ static wchar_t c2u_E4[256] = { 0x564C,0x5635,0x5641,0x564A,0x5649,0x5646,0x5658,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E5[256] = { +static const wchar_t c2u_E5[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2405,7 +2405,7 @@ static wchar_t c2u_E5[256] = { 0x6C02,0x6F41,0x6F26,0x6F7E,0x6F87,0x6FC6,0x6F92,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E6[256] = { +static const wchar_t c2u_E6[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2441,7 +2441,7 @@ static wchar_t c2u_E6[256] = { 0x7FEC,0x7FE6,0x7FE8,0x8064,0x8067,0x81A3,0x819F,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E7[256] = { +static const wchar_t c2u_E7[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2477,7 +2477,7 @@ static wchar_t c2u_E7[256] = { 0x8E15,0x8E1B,0x8E16,0x8E11,0x8E19,0x8E26,0x8E27,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E8[256] = { +static const wchar_t c2u_E8[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2513,7 +2513,7 @@ static wchar_t c2u_E8[256] = { 0x5111,0x51DE,0x5334,0x53E1,0x5670,0x5660,0x566E,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_E9[256] = { +static const wchar_t c2u_E9[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2549,7 +2549,7 @@ static wchar_t c2u_E9[256] = { 0x6FAE,0x6FBA,0x6FAC,0x6FAA,0x6FCF,0x6FBF,0x6FB8,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_EA[256] = { +static const wchar_t c2u_EA[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2585,7 +2585,7 @@ static wchar_t c2u_EA[256] = { 0x8556,0x8545,0x856B,0x854D,0x8553,0x8561,0x8558,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_EB[256] = { +static const wchar_t c2u_EB[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2621,7 +2621,7 @@ static wchar_t c2u_EB[256] = { 0x92FF,0x9329,0x9339,0x9335,0x932A,0x9314,0x930C,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_EC[256] = { +static const wchar_t c2u_EC[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2657,7 +2657,7 @@ static wchar_t c2u_EC[256] = { 0x6A9F,0x6A9B,0x6AA1,0x6A9E,0x6A87,0x6A93,0x6A8E,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_ED[256] = { +static const wchar_t c2u_ED[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2693,7 +2693,7 @@ static wchar_t c2u_ED[256] = { 0x85A0,0x858B,0x85A3,0x857B,0x85A4,0x859A,0x859E,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_EE[256] = { +static const wchar_t c2u_EE[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2729,7 +2729,7 @@ static wchar_t c2u_EE[256] = { 0x971F,0x9718,0x971D,0x9719,0x979A,0x97A1,0x979C,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_EF[256] = { +static const wchar_t c2u_EF[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2765,7 +2765,7 @@ static wchar_t c2u_EF[256] = { 0x700A,0x7201,0x71FF,0x71F9,0x7203,0x71FD,0x7376,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F0[256] = { +static const wchar_t c2u_F0[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2801,7 +2801,7 @@ static wchar_t c2u_F0[256] = { 0x8E62,0x8E60,0x8E57,0x8E56,0x8E5E,0x8E65,0x8E67,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F1[256] = { +static const wchar_t c2u_F1[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2837,7 +2837,7 @@ static wchar_t c2u_F1[256] = { 0x58DB,0x5912,0x5B3D,0x5B3E,0x5B3F,0x5DC3,0x5E70,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F2[256] = { +static const wchar_t c2u_F2[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2873,7 +2873,7 @@ static wchar_t c2u_F2[256] = { 0x8B4A,0x8B40,0x8B53,0x8B56,0x8B54,0x8B4B,0x8B55,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F3[256] = { +static const wchar_t c2u_F3[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2909,7 +2909,7 @@ static wchar_t c2u_F3[256] = { 0x9F41,0x9F4D,0x9F56,0x9F57,0x9F58,0x5337,0x56B2,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F4[256] = { +static const wchar_t c2u_F4[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2945,7 +2945,7 @@ static wchar_t c2u_F4[256] = { 0x9416,0x9412,0x93FA,0x9409,0x93F8,0x940A,0x93FF,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F5[256] = { +static const wchar_t c2u_F5[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -2981,7 +2981,7 @@ static wchar_t c2u_F5[256] = { 0x8627,0x862E,0x8621,0x8620,0x8629,0x861E,0x8625,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F6[256] = { +static const wchar_t c2u_F6[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3017,7 +3017,7 @@ static wchar_t c2u_F6[256] = { 0x7A70,0x7A71,0x7C57,0x7C5C,0x7C59,0x7C5B,0x7C5A,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F7[256] = { +static const wchar_t c2u_F7[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3053,7 +3053,7 @@ static wchar_t c2u_F7[256] = { 0x8832,0x882E,0x8833,0x8976,0x8974,0x8973,0x89FE,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F8[256] = { +static const wchar_t c2u_F8[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3089,7 +3089,7 @@ static wchar_t c2u_F8[256] = { 0x77D8,0x77D9,0x7939,0x7C69,0x7C6B,0x7CF6,0x7E9A,0x0000,/* 0xF8-0xFF */ }; -static wchar_t c2u_F9[256] = { +static const wchar_t c2u_F9[256] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ @@ -3125,7 +3125,7 @@ static wchar_t c2u_F9[256] = { 0x2551,0x2550,0x256D,0x256E,0x2570,0x256F,0x2593,0x0000,/* 0xF8-0xFF */ }; -static wchar_t *page_charset2uni[256] = { +static const wchar_t *page_charset2uni[256] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -3160,7 +3160,7 @@ static wchar_t *page_charset2uni[256] = { c2u_F8, c2u_F9, NULL, NULL, NULL, NULL, NULL, NULL, }; -static unsigned char u2c_02[512] = { +static const unsigned char u2c_02[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -3219,7 +3219,7 @@ static unsigned char u2c_02[512] = { 0x00, 0x00, 0xA3, 0xBB, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ }; -static unsigned char u2c_03[512] = { +static const unsigned char u2c_03[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xA1, 0xC2, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -3274,7 +3274,7 @@ static unsigned char u2c_03[512] = { 0xA3, 0x72, 0xA3, 0x73, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ }; -static unsigned char u2c_20[512] = { +static const unsigned char u2c_20[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -3293,7 +3293,7 @@ static unsigned char u2c_20[512] = { 0x00, 0x00, 0x00, 0x00, 0xA1, 0xC3, 0x00, 0x00, /* 0x3C-0x3F */ }; -static unsigned char u2c_21[512] = { +static const unsigned char u2c_21[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x4A, /* 0x00-0x03 */ 0x00, 0x00, 0xA1, 0xC1, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xA2, 0x4B, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -3336,7 +3336,7 @@ static unsigned char u2c_21[512] = { 0xA1, 0xFB, 0xA1, 0xFA, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ }; -static unsigned char u2c_22[512] = { +static const unsigned char u2c_22[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -3388,12 +3388,12 @@ static unsigned char u2c_22[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xE9, /* 0xBC-0xBF */ }; -static unsigned char u2c_23[512] = { +static const unsigned char u2c_23[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0x5B, /* 0x04-0x07 */ }; -static unsigned char u2c_25[512] = { +static const unsigned char u2c_25[512] = { 0xA2, 0x77, 0x00, 0x00, 0xA2, 0x78, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -3455,7 +3455,7 @@ static unsigned char u2c_25[512] = { 0xA2, 0xAB, 0xA2, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ }; -static unsigned char u2c_26[512] = { +static const unsigned char u2c_26[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xA1, 0xB9, 0xA1, 0xB8, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xA1, 0xF3, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -3475,7 +3475,7 @@ static unsigned char u2c_26[512] = { 0xA1, 0xF0, 0xA1, 0xF2, 0xA1, 0xF1, 0x00, 0x00, /* 0x40-0x43 */ }; -static unsigned char u2c_30[512] = { +static const unsigned char u2c_30[512] = { 0xA1, 0x40, 0xA1, 0x42, 0xA1, 0x43, 0xA1, 0xB2, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0xA1, 0x71, 0xA1, 0x72, 0xA1, 0x6D, 0xA1, 0x6E, /* 0x08-0x0B */ @@ -3491,7 +3491,7 @@ static unsigned char u2c_30[512] = { 0xA1, 0xCA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ }; -static unsigned char u2c_31[512] = { +static const unsigned char u2c_31[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xA3, 0x74, 0xA3, 0x75, 0xA3, 0x76, /* 0x04-0x07 */ 0xA3, 0x77, 0xA3, 0x78, 0xA3, 0x79, 0xA3, 0x7A, /* 0x08-0x0B */ @@ -3535,7 +3535,7 @@ static unsigned char u2c_31[512] = { 0xA4, 0x42, 0xA4, 0xD1, 0xA6, 0x61, 0xA4, 0x48, /* 0x9C-0x9F */ }; -static unsigned char u2c_32[512] = { +static const unsigned char u2c_32[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -3584,7 +3584,7 @@ static unsigned char u2c_32[512] = { 0xA9, 0x5D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ }; -static unsigned char u2c_33[512] = { +static const unsigned char u2c_33[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -3642,7 +3642,7 @@ static unsigned char u2c_33[512] = { 0x00, 0x00, 0xA2, 0x4F, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ }; -static unsigned char u2c_4E[512] = { +static const unsigned char u2c_4E[512] = { 0xA4, 0x40, 0xA4, 0x42, 0x00, 0x00, 0xA4, 0x43, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC9, 0x45, /* 0x04-0x07 */ 0xA4, 0x56, 0xA4, 0x54, 0xA4, 0x57, 0xA4, 0x55, /* 0x08-0x0B */ @@ -3710,7 +3710,7 @@ static unsigned char u2c_4E[512] = { 0x00, 0x00, 0xA5, 0xF7, 0x00, 0x00, 0xA5, 0xE9, /* 0xFC-0xFF */ }; -static unsigned char u2c_4F[512] = { +static const unsigned char u2c_4F[512] = { 0xC9, 0xB1, 0xA5, 0xF8, 0xC9, 0xB5, 0x00, 0x00, /* 0x00-0x03 */ 0xC9, 0xB9, 0xC9, 0xB6, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0xC9, 0xB3, 0xA5, 0xEA, 0xA5, 0xEC, 0xA5, 0xF9, /* 0x08-0x0B */ @@ -3778,7 +3778,7 @@ static unsigned char u2c_4F[512] = { 0x00, 0x00, 0x00, 0x00, 0xAD, 0xDA, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_50[512] = { +static const unsigned char u2c_50[512] = { 0xAD, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xD0, 0xC9, 0xAD, 0xC7, 0xD0, 0xCA, /* 0x04-0x07 */ 0x00, 0x00, 0xAD, 0xDC, 0x00, 0x00, 0xAD, 0xD3, /* 0x08-0x0B */ @@ -3846,7 +3846,7 @@ static unsigned char u2c_50[512] = { 0x00, 0x00, 0xE4, 0xF0, 0xE4, 0xED, 0xE4, 0xE6, /* 0xFC-0xFF */ }; -static unsigned char u2c_51[512] = { +static const unsigned char u2c_51[512] = { 0xBB, 0xF6, 0x00, 0x00, 0xBB, 0xFA, 0xE4, 0xE7, /* 0x00-0x03 */ 0xBB, 0xF5, 0xBB, 0xFD, 0xE4, 0xEA, 0xE4, 0xEB, /* 0x04-0x07 */ 0xBB, 0xFB, 0xBB, 0xFC, 0xE4, 0xF1, 0xE4, 0xEE, /* 0x08-0x0B */ @@ -3914,7 +3914,7 @@ static unsigned char u2c_51[512] = { 0x00, 0x00, 0xA8, 0xE7, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_52[512] = { +static const unsigned char u2c_52[512] = { 0xA4, 0x4D, 0xA4, 0x4E, 0x00, 0x00, 0xA4, 0x62, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0xA4, 0xC0, 0xA4, 0xC1, /* 0x04-0x07 */ 0xA4, 0xC2, 0xC9, 0xBE, 0xA5, 0x5A, 0x00, 0x00, /* 0x08-0x0B */ @@ -3982,7 +3982,7 @@ static unsigned char u2c_52[512] = { 0xC9, 0x56, 0x00, 0x00, 0xA4, 0xC4, 0xA4, 0xC5, /* 0xFC-0xFF */ }; -static unsigned char u2c_53[512] = { +static const unsigned char u2c_53[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xA5, 0x5D, 0xA5, 0x5E, 0x00, 0x00, /* 0x04-0x07 */ 0xA6, 0x49, 0xCA, 0x71, 0xCB, 0xD6, 0xCB, 0xD7, /* 0x08-0x0B */ @@ -4050,7 +4050,7 @@ static unsigned char u2c_53[512] = { 0xA5, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_54[512] = { +static const unsigned char u2c_54[512] = { 0x00, 0x00, 0xA6, 0x53, 0x00, 0x00, 0xA6, 0x59, /* 0x00-0x03 */ 0xA6, 0x55, 0x00, 0x00, 0xA6, 0x5B, 0xC9, 0xC5, /* 0x04-0x07 */ 0xA6, 0x58, 0xA6, 0x4E, 0xA6, 0x51, 0xA6, 0x54, /* 0x08-0x0B */ @@ -4118,7 +4118,7 @@ static unsigned char u2c_54[512] = { 0xAD, 0xF3, 0xAE, 0x43, 0x00, 0x00, 0xD0, 0xF8, /* 0xFC-0xFF */ }; -static unsigned char u2c_55[512] = { +static const unsigned char u2c_55[512] = { 0x00, 0x00, 0xAD, 0xF1, 0x00, 0x00, 0xD1, 0x46, /* 0x00-0x03 */ 0xD0, 0xF9, 0xD0, 0xFD, 0xAD, 0xF6, 0xAE, 0x42, /* 0x04-0x07 */ 0xD0, 0xFA, 0xAD, 0xFC, 0xD1, 0x40, 0xD1, 0x47, /* 0x08-0x0B */ @@ -4186,7 +4186,7 @@ static unsigned char u2c_55[512] = { 0xE1, 0x4B, 0xB9, 0xC2, 0xB9, 0xBE, 0xE1, 0x54, /* 0xFC-0xFF */ }; -static unsigned char u2c_56[512] = { +static const unsigned char u2c_56[512] = { 0xB9, 0xBF, 0xE1, 0x4E, 0xE1, 0x50, 0x00, 0x00, /* 0x00-0x03 */ 0xE1, 0x53, 0x00, 0x00, 0xB9, 0xC4, 0x00, 0x00, /* 0x04-0x07 */ 0xB9, 0xCB, 0xB9, 0xC5, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4254,7 +4254,7 @@ static unsigned char u2c_56[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAB, 0xAA, /* 0xFC-0xFF */ }; -static unsigned char u2c_57[512] = { +static const unsigned char u2c_57[512] = { 0x00, 0x00, 0xD1, 0x48, 0xD1, 0x49, 0xAE, 0x45, /* 0x00-0x03 */ 0xAE, 0x46, 0x00, 0x00, 0x00, 0x00, 0xD4, 0xAC, /* 0x04-0x07 */ 0xB0, 0xE9, 0xB0, 0xEB, 0xD4, 0xAB, 0xB0, 0xEA, /* 0x08-0x0B */ @@ -4322,7 +4322,7 @@ static unsigned char u2c_57[512] = { 0xD4, 0xC3, 0xD4, 0xB5, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_58[512] = { +static const unsigned char u2c_58[512] = { 0xD4, 0xB3, 0xD4, 0xC6, 0xB0, 0xF3, 0x00, 0x00, /* 0x00-0x03 */ 0xD4, 0xCC, 0xB0, 0xED, 0xB0, 0xEF, 0xD4, 0xBB, /* 0x04-0x07 */ 0xD4, 0xB6, 0xAE, 0x4B, 0xB0, 0xEE, 0xD4, 0xB8, /* 0x08-0x0B */ @@ -4390,7 +4390,7 @@ static unsigned char u2c_58[512] = { 0xDC, 0xF2, 0xB9, 0xD8, 0xE1, 0x69, 0xE5, 0x53, /* 0xFC-0xFF */ }; -static unsigned char u2c_59[512] = { +static const unsigned char u2c_59[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC9, 0x5A, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0xCA, 0xB0, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -4458,7 +4458,7 @@ static unsigned char u2c_59[512] = { 0xCE, 0x6A, 0xCE, 0x69, 0xCE, 0x74, 0xAB, 0xBA, /* 0xFC-0xFF */ }; -static unsigned char u2c_5A[512] = { +static const unsigned char u2c_5A[512] = { 0xCE, 0x65, 0xAB, 0xC2, 0x00, 0x00, 0xAB, 0xBD, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xAE, 0x5C, 0xD1, 0x62, 0x00, 0x00, /* 0x08-0x0B */ @@ -4526,7 +4526,7 @@ static unsigned char u2c_5A[512] = { 0x00, 0x00, 0xE5, 0x56, 0x00, 0x00, 0xE5, 0x54, /* 0xFC-0xFF */ }; -static unsigned char u2c_5B[512] = { +static const unsigned char u2c_5B[512] = { 0x00, 0x00, 0xE5, 0x5D, 0xE5, 0x5B, 0xE5, 0x59, /* 0x00-0x03 */ 0x00, 0x00, 0xE5, 0x5F, 0x00, 0x00, 0xE5, 0x5E, /* 0x04-0x07 */ 0xBC, 0x63, 0xBC, 0x5E, 0x00, 0x00, 0xBC, 0x60, /* 0x08-0x0B */ @@ -4594,7 +4594,7 @@ static unsigned char u2c_5B[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_5C[512] = { +static const unsigned char u2c_5C[512] = { 0x00, 0x00, 0xAB, 0xCA, 0x00, 0x00, 0xD1, 0x69, /* 0x00-0x03 */ 0xAE, 0x67, 0x00, 0x00, 0x00, 0x00, 0xB1, 0x4E, /* 0x04-0x07 */ 0xB1, 0x4D, 0xB1, 0x4C, 0xB4, 0x4C, 0xB4, 0x4D, /* 0x08-0x0B */ @@ -4662,7 +4662,7 @@ static unsigned char u2c_5C[512] = { 0x00, 0x00, 0xAE, 0x6C, 0x00, 0x00, 0xD1, 0x6D, /* 0xFC-0xFF */ }; -static unsigned char u2c_5D[512] = { +static const unsigned char u2c_5D[512] = { 0xD1, 0x71, 0xAE, 0x72, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0xB1, 0x53, 0xB1, 0x52, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 0xF5, /* 0x08-0x0B */ @@ -4730,7 +4730,7 @@ static unsigned char u2c_5D[512] = { 0x00, 0x00, 0xB4, 0x53, 0xA4, 0x79, 0xC9, 0x5D, /* 0xFC-0xFF */ }; -static unsigned char u2c_5E[512] = { +static const unsigned char u2c_5E[512] = { 0x00, 0x00, 0x00, 0x00, 0xA5, 0xAB, 0xA5, 0xAC, /* 0x00-0x03 */ 0xC9, 0x78, 0x00, 0x00, 0xA6, 0x7C, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xCA, 0xCB, 0x00, 0x00, /* 0x08-0x0B */ @@ -4798,7 +4798,7 @@ static unsigned char u2c_5E[512] = { 0x00, 0x00, 0x00, 0x00, 0xA4, 0x7B, 0xA4, 0xDC, /* 0xFC-0xFF */ }; -static unsigned char u2c_5F[512] = { +static const unsigned char u2c_5F[512] = { 0x00, 0x00, 0xA5, 0xAF, 0xC9, 0xDD, 0x00, 0x00, /* 0x00-0x03 */ 0xA7, 0xCB, 0xCA, 0xD2, 0x00, 0x00, 0xCE, 0xBB, /* 0x04-0x07 */ 0xAB, 0xD9, 0x00, 0x00, 0xB9, 0xFA, 0xA4, 0x7C, /* 0x08-0x0B */ @@ -4866,7 +4866,7 @@ static unsigned char u2c_5F[512] = { 0x00, 0x00, 0xA9, 0xBF, 0x00, 0x00, 0xA9, 0xC1, /* 0xFC-0xFF */ }; -static unsigned char u2c_60[512] = { +static const unsigned char u2c_60[512] = { 0xCA, 0xE4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xCC, 0xAF, 0xCC, 0xA2, 0xCC, 0x7E, /* 0x08-0x0B */ @@ -4934,7 +4934,7 @@ static unsigned char u2c_60[512] = { 0xD9, 0x47, 0x00, 0x00, 0xD9, 0x48, 0xD9, 0x4E, /* 0xFC-0xFF */ }; -static unsigned char u2c_61[512] = { +static const unsigned char u2c_61[512] = { 0xB4, 0x73, 0xB7, 0x54, 0x00, 0x00, 0xD9, 0x4A, /* 0x00-0x03 */ 0xD9, 0x4F, 0xD9, 0x43, 0xB7, 0x5E, 0x00, 0x00, /* 0x04-0x07 */ 0xB7, 0x55, 0xB4, 0x72, 0xD9, 0x41, 0xD9, 0x50, /* 0x08-0x0B */ @@ -5002,7 +5002,7 @@ static unsigned char u2c_61[512] = { 0xC4, 0xDF, 0xF5, 0xCC, 0xC4, 0xE0, 0xC5, 0x74, /* 0xFC-0xFF */ }; -static unsigned char u2c_62[512] = { +static const unsigned char u2c_62[512] = { 0xC5, 0xCA, 0xF7, 0xD9, 0x00, 0x00, 0xF7, 0xDA, /* 0x00-0x03 */ 0xF7, 0xDB, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xBA, /* 0x04-0x07 */ 0xA4, 0xE0, 0xC9, 0x7C, 0xA5, 0xB3, 0x00, 0x00, /* 0x08-0x0B */ @@ -5070,7 +5070,7 @@ static unsigned char u2c_62[512] = { 0xAB, 0xF7, 0xAB, 0xFB, 0xAC, 0x42, 0xAE, 0xB3, /* 0xFC-0xFF */ }; -static unsigned char u2c_63[512] = { +static const unsigned char u2c_63[512] = { 0xCE, 0xE0, 0xAB, 0xF9, 0xAC, 0x45, 0xCE, 0xD9, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAB, 0xFC, /* 0x04-0x07 */ 0xAE, 0xB2, 0xAB, 0xF6, 0x00, 0x00, 0xCE, 0xD6, /* 0x08-0x0B */ @@ -5138,7 +5138,7 @@ static unsigned char u2c_63[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_64[512] = { +static const unsigned char u2c_64[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0xB7, 0x70, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xDD, 0x7C, 0xDD, 0xB1, 0xDD, 0xB6, /* 0x08-0x0B */ @@ -5206,7 +5206,7 @@ static unsigned char u2c_64[512] = { 0xEF, 0xD7, 0xEF, 0xD3, 0xC2, 0x5A, 0xEF, 0xD1, /* 0xFC-0xFF */ }; -static unsigned char u2c_65[512] = { +static const unsigned char u2c_65[512] = { 0xC3, 0x6B, 0xEF, 0xD5, 0x00, 0x00, 0xEF, 0xD6, /* 0x00-0x03 */ 0xEF, 0xD2, 0x00, 0x00, 0xC2, 0x5B, 0xF2, 0x42, /* 0x04-0x07 */ 0x00, 0x00, 0xF2, 0x45, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -5274,7 +5274,7 @@ static unsigned char u2c_65[512] = { 0xCC, 0xC5, 0xCC, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_66[512] = { +static const unsigned char u2c_66[512] = { 0xA9, 0xFB, 0x00, 0x00, 0xA9, 0xF9, 0xCC, 0xCA, /* 0x00-0x03 */ 0xCC, 0xC6, 0xCC, 0xCD, 0xA9, 0xF8, 0xAA, 0x40, /* 0x04-0x07 */ 0xCC, 0xC8, 0xCC, 0xC4, 0xA9, 0xFE, 0xCC, 0xCB, /* 0x08-0x0B */ @@ -5342,7 +5342,7 @@ static unsigned char u2c_66[512] = { 0xB0, 0xD2, 0x00, 0x00, 0xB4, 0xBF, 0xB4, 0xC0, /* 0xFC-0xFF */ }; -static unsigned char u2c_67[512] = { +static const unsigned char u2c_67[512] = { 0xB3, 0xCC, 0xD9, 0xA9, 0x00, 0x00, 0xB7, 0x7C, /* 0x00-0x03 */ 0xE1, 0xFA, 0xE1, 0xF9, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0xA4, 0xEB, 0xA6, 0xB3, 0xCC, 0xD2, 0xAA, 0x42, /* 0x08-0x0B */ @@ -5410,7 +5410,7 @@ static unsigned char u2c_67[512] = { 0xCF, 0x57, 0x00, 0x00, 0x00, 0x00, 0xAC, 0x55, /* 0xFC-0xFF */ }; -static unsigned char u2c_68[512] = { +static const unsigned char u2c_68[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -5478,7 +5478,7 @@ static unsigned char u2c_68[512] = { 0xD9, 0xC8, 0xD9, 0xC7, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_69[512] = { +static const unsigned char u2c_69[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0xD9, 0xAC, 0xB4, 0xC8, 0xD9, 0xD4, 0xD9, 0xBC, /* 0x04-0x07 */ 0xD9, 0xBE, 0x00, 0x00, 0xD9, 0xCB, 0xD9, 0xCA, /* 0x08-0x0B */ @@ -5546,7 +5546,7 @@ static unsigned char u2c_69[512] = { 0xE5, 0xE4, 0xBC, 0xD1, 0xE5, 0xD8, 0xE5, 0xD3, /* 0xFC-0xFF */ }; -static unsigned char u2c_6A[512] = { +static const unsigned char u2c_6A[512] = { 0xE5, 0xCA, 0xBC, 0xCE, 0xBC, 0xD6, 0x00, 0x00, /* 0x00-0x03 */ 0xE5, 0xE7, 0xBC, 0xD7, 0xE5, 0xCB, 0xE5, 0xED, /* 0x04-0x07 */ 0xE5, 0xE0, 0xE5, 0xE6, 0xBC, 0xD4, 0x00, 0x00, /* 0x08-0x0B */ @@ -5614,7 +5614,7 @@ static unsigned char u2c_6A[512] = { 0xF5, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_6B[512] = { +static const unsigned char u2c_6B[512] = { 0xF5, 0xD2, 0x00, 0x00, 0xF5, 0xCE, 0xF5, 0xD0, /* 0x00-0x03 */ 0xC4, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0xF6, 0xE5, 0xF6, 0xE6, 0xC5, 0x76, 0xF6, 0xE4, /* 0x08-0x0B */ @@ -5682,7 +5682,7 @@ static unsigned char u2c_6B[512] = { 0xDD, 0xFE, 0xB7, 0xB7, 0xE2, 0x6B, 0xE5, 0xF7, /* 0xFC-0xFF */ }; -static unsigned char u2c_6C[512] = { +static const unsigned char u2c_6C[512] = { 0xE5, 0xF6, 0xE5, 0xF5, 0xE5, 0xF8, 0xE9, 0xE7, /* 0x00-0x03 */ 0xE9, 0xE6, 0xBE, 0xFB, 0xE9, 0xE8, 0x00, 0x00, /* 0x04-0x07 */ 0xC0, 0xD6, 0xED, 0x4D, 0x00, 0x00, 0xEF, 0xEA, /* 0x08-0x0B */ @@ -5749,7 +5749,7 @@ static unsigned char u2c_6C[512] = { 0x00, 0x00, 0xCD, 0x4C, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ }; -static unsigned char u2c_6D[512] = { +static const unsigned char u2c_6D[512] = { 0xCF, 0x7C, 0xCF, 0xA1, 0x00, 0x00, 0xCF, 0xA4, /* 0x00-0x03 */ 0xCF, 0x77, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xA7, /* 0x04-0x07 */ 0xCF, 0xAA, 0xCF, 0xAC, 0xCF, 0x74, 0xAC, 0x76, /* 0x08-0x0B */ @@ -5817,7 +5817,7 @@ static unsigned char u2c_6D[512] = { 0xD9, 0xE7, 0xD6, 0x43, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_6E[512] = { +static const unsigned char u2c_6E[512] = { 0xD5, 0xEB, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xFC, /* 0x00-0x03 */ 0x00, 0x00, 0xB2, 0x4D, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -5885,7 +5885,7 @@ static unsigned char u2c_6E[512] = { 0xE2, 0xB3, 0xE2, 0xAF, 0xBA, 0x75, 0xBA, 0xA1, /* 0xFC-0xFF */ }; -static unsigned char u2c_6F[512] = { +static const unsigned char u2c_6F[512] = { 0xE6, 0x53, 0xBA, 0xAE, 0xBA, 0x7D, 0xE2, 0x6F, /* 0x00-0x03 */ 0x00, 0x00, 0xE2, 0xAE, 0xBA, 0xA3, 0xE2, 0xAB, /* 0x04-0x07 */ 0xE2, 0xB8, 0xE2, 0x75, 0xE2, 0x7E, 0x00, 0x00, /* 0x08-0x0B */ @@ -5953,7 +5953,7 @@ static unsigned char u2c_6F[512] = { 0xEF, 0xF6, 0x00, 0x00, 0xC2, 0x6F, 0xEF, 0xF2, /* 0xFC-0xFF */ }; -static unsigned char u2c_70[512] = { +static const unsigned char u2c_70[512] = { 0xEF, 0xF3, 0xEF, 0xEE, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0xE9, 0xF6, 0xEF, 0xEF, 0xC2, 0x70, 0xEF, 0xEB, /* 0x04-0x07 */ 0x00, 0x00, 0xC2, 0x6D, 0xEF, 0xF8, 0xC2, 0x6E, /* 0x08-0x0B */ @@ -6021,7 +6021,7 @@ static unsigned char u2c_70[512] = { 0xD6, 0x52, 0xB2, 0x6C, 0x00, 0x00, 0xD6, 0x53, /* 0xFC-0xFF */ }; -static unsigned char u2c_71[512] = { +static const unsigned char u2c_71[512] = { 0xD6, 0x56, 0x00, 0x00, 0xD6, 0x5A, 0x00, 0x00, /* 0x00-0x03 */ 0xD6, 0x4F, 0x00, 0x00, 0xD6, 0x54, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xB2, 0x6A, 0xB2, 0x6B, 0xD6, 0x59, /* 0x08-0x0B */ @@ -6089,7 +6089,7 @@ static unsigned char u2c_71[512] = { 0xC2, 0x75, 0xEF, 0xFD, 0xC2, 0x76, 0xEF, 0xFA, /* 0xFC-0xFF */ }; -static unsigned char u2c_72[512] = { +static const unsigned char u2c_72[512] = { 0x00, 0x00, 0xEF, 0xF9, 0xF2, 0x6C, 0xEF, 0xFC, /* 0x00-0x03 */ 0x00, 0x00, 0xF2, 0x6D, 0xC3, 0x7A, 0xF2, 0x6B, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xF2, 0x6A, 0x00, 0x00, /* 0x08-0x0B */ @@ -6157,7 +6157,7 @@ static unsigned char u2c_72[512] = { 0xAF, 0x54, 0xAF, 0x56, 0xD2, 0xA6, 0xD6, 0x67, /* 0xFC-0xFF */ }; -static unsigned char u2c_73[512] = { +static const unsigned char u2c_73[512] = { 0xD2, 0xA3, 0xD2, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0x62, /* 0x04-0x07 */ 0xD6, 0x66, 0x00, 0x00, 0xD6, 0x65, 0xDA, 0x6E, /* 0x08-0x0B */ @@ -6225,7 +6225,7 @@ static unsigned char u2c_73[512] = { 0xD6, 0x74, 0xD6, 0x70, 0xB2, 0x7B, 0xD6, 0x75, /* 0xFC-0xFF */ }; -static unsigned char u2c_74[512] = { +static const unsigned char u2c_74[512] = { 0xD6, 0x72, 0xD6, 0x6F, 0x00, 0x00, 0xB2, 0x79, /* 0x00-0x03 */ 0xD6, 0x6E, 0xB2, 0x77, 0xB2, 0x7A, 0xD6, 0x71, /* 0x04-0x07 */ 0xD6, 0x79, 0xAF, 0x5B, 0xB2, 0x78, 0xD6, 0x77, /* 0x08-0x0B */ @@ -6293,7 +6293,7 @@ static unsigned char u2c_74[512] = { 0x00, 0x00, 0xDE, 0xC2, 0xDE, 0xC1, 0xDE, 0xC0, /* 0xFC-0xFF */ }; -static unsigned char u2c_75[512] = { +static const unsigned char u2c_75[512] = { 0xE2, 0xD5, 0x00, 0x00, 0xE2, 0xD6, 0xE2, 0xD7, /* 0x00-0x03 */ 0xBA, 0xC2, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xAD, /* 0x04-0x07 */ 0xE6, 0xAC, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x69, /* 0x08-0x0B */ @@ -6361,7 +6361,7 @@ static unsigned char u2c_75[512] = { 0xDE, 0xCC, 0xDE, 0xD4, 0xDE, 0xCB, 0xB7, 0xF5, /* 0xFC-0xFF */ }; -static unsigned char u2c_76[512] = { +static const unsigned char u2c_76[512] = { 0xB7, 0xEF, 0xB7, 0xF1, 0x00, 0x00, 0xDE, 0xC9, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0xE2, 0xDB, 0xBA, 0xC7, 0xE2, 0xDF, 0xBA, 0xC6, /* 0x08-0x0B */ @@ -6429,7 +6429,7 @@ static unsigned char u2c_76[512] = { 0xAC, 0xDF, 0x00, 0x00, 0xAC, 0xDE, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_77[512] = { +static const unsigned char u2c_77[512] = { 0x00, 0x00, 0xAC, 0xD9, 0x00, 0x00, 0xCF, 0xE1, /* 0x00-0x03 */ 0xCF, 0xE2, 0xCF, 0xE3, 0x00, 0x00, 0xAC, 0xE0, /* 0x04-0x07 */ 0xCF, 0xE0, 0xAC, 0xDC, 0xCF, 0xE4, 0xAC, 0xDD, /* 0x08-0x0B */ @@ -6497,7 +6497,7 @@ static unsigned char u2c_77[512] = { 0xCD, 0x7B, 0xAA, 0xBF, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_78[512] = { +static const unsigned char u2c_78[512] = { 0x00, 0x00, 0x00, 0x00, 0xAC, 0xE2, 0xCF, 0xF2, /* 0x00-0x03 */ 0x00, 0x00, 0xCF, 0xED, 0xCF, 0xEA, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xCF, 0xF1, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -6565,7 +6565,7 @@ static unsigned char u2c_78[512] = { 0xED, 0xA9, 0xED, 0xA6, 0xED, 0xAD, 0xF0, 0x56, /* 0xFC-0xFF */ }; -static unsigned char u2c_79[512] = { +static const unsigned char u2c_79[512] = { 0x00, 0x00, 0xC1, 0x47, 0xED, 0xA7, 0x00, 0x00, /* 0x00-0x03 */ 0xED, 0xAE, 0xED, 0xAB, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0xF0, 0x5A, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -6633,7 +6633,7 @@ static unsigned char u2c_79[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_7A[512] = { +static const unsigned char u2c_7A[512] = { 0xB5, 0x7D, 0x00, 0x00, 0xDA, 0xD6, 0xDA, 0xD8, /* 0x00-0x03 */ 0xDA, 0xDA, 0xB5, 0x7C, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0xB5, 0x7A, 0x00, 0x00, 0xDA, 0xD7, 0xB5, 0x7B, /* 0x08-0x0B */ @@ -6701,7 +6701,7 @@ static unsigned char u2c_7A[512] = { 0x00, 0x00, 0xAC, 0xF2, 0x00, 0x00, 0xAC, 0xF1, /* 0xFC-0xFF */ }; -static unsigned char u2c_7B[512] = { +static const unsigned char u2c_7B[512] = { 0xD0, 0x42, 0xD0, 0x43, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0xD3, 0x40, 0xD3, 0x42, 0xAF, 0xB9, 0x00, 0x00, /* 0x04-0x07 */ 0xD3, 0x44, 0xD3, 0x47, 0xD3, 0x45, 0x00, 0x00, /* 0x08-0x0B */ @@ -6769,7 +6769,7 @@ static unsigned char u2c_7B[512] = { 0x00, 0x00, 0xED, 0xC9, 0xC1, 0x4E, 0xED, 0xBE, /* 0xFC-0xFF */ }; -static unsigned char u2c_7C[512] = { +static const unsigned char u2c_7C[512] = { 0xED, 0xBD, 0xED, 0xC7, 0xED, 0xC4, 0xED, 0xC6, /* 0x00-0x03 */ 0x00, 0x00, 0xED, 0xBA, 0xED, 0xCA, 0xC1, 0x4C, /* 0x04-0x07 */ 0x00, 0x00, 0xED, 0xC5, 0xED, 0xCE, 0xED, 0xC2, /* 0x08-0x0B */ @@ -6837,7 +6837,7 @@ static unsigned char u2c_7C[512] = { 0x00, 0x00, 0xCD, 0xA9, 0xAA, 0xC8, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_7D[512] = { +static const unsigned char u2c_7D[512] = { 0xAC, 0xF6, 0xD0, 0x4C, 0xAC, 0xF4, 0xD0, 0x4A, /* 0x00-0x03 */ 0xAC, 0xF9, 0xAC, 0xF5, 0xAC, 0xFA, 0xAC, 0xF8, /* 0x04-0x07 */ 0xD0, 0x4B, 0xAC, 0xF7, 0xAF, 0xBF, 0xAF, 0xBE, /* 0x08-0x0B */ @@ -6904,7 +6904,7 @@ static unsigned char u2c_7D[512] = { 0x00, 0x00, 0xBD, 0x7B, 0xE6, 0xEA, 0xBD, 0x6F, /* 0xF8-0xFB */ }; -static unsigned char u2c_7E[512] = { +static const unsigned char u2c_7E[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE9, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0xBF, 0xA2, 0xBF, 0xA7, 0xBF, 0x7E, 0xEA, 0xD8, /* 0x08-0x0B */ @@ -6948,7 +6948,7 @@ static unsigned char u2c_7E[512] = { 0xC6, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ }; -static unsigned char u2c_7F[512] = { +static const unsigned char u2c_7F[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -7016,7 +7016,7 @@ static unsigned char u2c_7F[512] = { 0xC1, 0x6C, 0xF2, 0xBE, 0xF2, 0xBF, 0xF4, 0xB1, /* 0xFC-0xFF */ }; -static unsigned char u2c_80[512] = { +static const unsigned char u2c_80[512] = { 0xC4, 0xA3, 0xA6, 0xD1, 0x00, 0x00, 0xA6, 0xD2, /* 0x00-0x03 */ 0xAC, 0xFE, 0xAA, 0xCC, 0xAF, 0xCF, 0xD0, 0x51, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB5, 0xC0, /* 0x08-0x0B */ @@ -7084,7 +7084,7 @@ static unsigned char u2c_80[512] = { 0xAF, 0xE2, 0xAF, 0xE0, 0xDB, 0x48, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_81[512] = { +static const unsigned char u2c_81[512] = { 0xD3, 0x6F, 0xD3, 0x6D, 0xAF, 0xD7, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xAF, 0xD9, 0xAF, 0xDC, 0x00, 0x00, /* 0x04-0x07 */ 0xAF, 0xDF, 0x00, 0x00, 0xAF, 0xE1, 0x00, 0x00, /* 0x08-0x0B */ @@ -7152,7 +7152,7 @@ static unsigned char u2c_81[512] = { 0xA6, 0xDD, 0x00, 0x00, 0xAA, 0xD8, 0xD0, 0x68, /* 0xFC-0xFF */ }; -static unsigned char u2c_82[512] = { +static const unsigned char u2c_82[512] = { 0xAF, 0xE6, 0xD3, 0x70, 0xB2, 0xEA, 0x00, 0x00, /* 0x00-0x03 */ 0xDB, 0x57, 0xB8, 0xA4, 0x00, 0x00, 0xBB, 0x50, /* 0x04-0x07 */ 0xBF, 0xB3, 0xC1, 0x7C, 0xC2, 0xC2, 0xF4, 0xB5, /* 0x08-0x0B */ @@ -7220,7 +7220,7 @@ static unsigned char u2c_82[512] = { 0x00, 0x00, 0x00, 0x00, 0xD0, 0x6C, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_83[512] = { +static const unsigned char u2c_83[512] = { 0xD0, 0x70, 0xAD, 0x5F, 0xAD, 0x5A, 0xAD, 0x53, /* 0x00-0x03 */ 0xAD, 0x58, 0xAD, 0x54, 0xAD, 0x67, 0xD0, 0x6E, /* 0x04-0x07 */ 0xD3, 0xA5, 0xAD, 0x5B, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -7288,7 +7288,7 @@ static unsigned char u2c_83[512] = { 0xDB, 0x65, 0xB5, 0xE0, 0xDB, 0xB0, 0xDB, 0x71, /* 0xFC-0xFF */ }; -static unsigned char u2c_84[512] = { +static const unsigned char u2c_84[512] = { 0x00, 0x00, 0xDB, 0x6D, 0x00, 0x00, 0xB5, 0xD1, /* 0x00-0x03 */ 0xB5, 0xE5, 0x00, 0x00, 0xDB, 0x7C, 0xB5, 0xE7, /* 0x04-0x07 */ 0x00, 0x00, 0xDB, 0x78, 0xB5, 0xDC, 0xB5, 0xD6, /* 0x08-0x0B */ @@ -7356,7 +7356,7 @@ static unsigned char u2c_84[512] = { 0xE7, 0x64, 0xE7, 0x6E, 0xE7, 0x69, 0xBD, 0xB6, /* 0xFC-0xFF */ }; -static unsigned char u2c_85[512] = { +static const unsigned char u2c_85[512] = { 0xE7, 0x4F, 0x00, 0x00, 0xE7, 0x6D, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0xBD, 0xB7, 0xDF, 0xBD, /* 0x04-0x07 */ 0xE7, 0x5B, 0xE7, 0x52, 0xE7, 0x55, 0xE7, 0x7B, /* 0x08-0x0B */ @@ -7424,7 +7424,7 @@ static unsigned char u2c_85[512] = { 0x00, 0x00, 0xF4, 0xC3, 0xF4, 0xBB, 0xF4, 0xB9, /* 0xFC-0xFF */ }; -static unsigned char u2c_86[512] = { +static const unsigned char u2c_86[512] = { 0xF4, 0xBD, 0xF4, 0xBA, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0xF4, 0xBF, 0xF4, 0xC1, 0xC4, 0xAA, 0xC4, 0xAC, /* 0x04-0x07 */ 0x00, 0x00, 0xF4, 0xC0, 0xC4, 0xAD, 0xC4, 0xAB, /* 0x08-0x0B */ @@ -7492,7 +7492,7 @@ static unsigned char u2c_86[512] = { 0x00, 0x00, 0x00, 0x00, 0xB8, 0xBF, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_87[512] = { +static const unsigned char u2c_87[512] = { 0xB8, 0xBE, 0xDF, 0xED, 0xB8, 0xC1, 0xB8, 0xC2, /* 0x00-0x03 */ 0xDF, 0xE3, 0xDF, 0xF0, 0xB8, 0xC3, 0xB8, 0xBD, /* 0x04-0x07 */ 0xB8, 0xBC, 0xDF, 0xEC, 0xB8, 0xC4, 0xDF, 0xE2, /* 0x08-0x0B */ @@ -7560,7 +7560,7 @@ static unsigned char u2c_87[512] = { 0xF2, 0xE4, 0x00, 0x00, 0xC3, 0xCA, 0xF2, 0xE6, /* 0xFC-0xFF */ }; -static unsigned char u2c_88[512] = { +static const unsigned char u2c_88[512] = { 0xF2, 0xDB, 0xF0, 0xCE, 0xF2, 0xE8, 0xF2, 0xDD, /* 0x00-0x03 */ 0x00, 0x00, 0xC3, 0xC7, 0xF2, 0xE3, 0x00, 0x00, /* 0x04-0x07 */ 0xF2, 0xE5, 0xF2, 0xE0, 0xF2, 0xE7, 0xF2, 0xE2, /* 0x08-0x0B */ @@ -7628,7 +7628,7 @@ static unsigned char u2c_88[512] = { 0xE3, 0xFC, 0xBB, 0x73, 0xE3, 0xFA, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_89[512] = { +static const unsigned char u2c_89[512] = { 0x00, 0x00, 0xDB, 0xCE, 0xBB, 0x6F, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xE7, 0xC2, 0xE7, 0xC9, 0xBD, 0xC6, /* 0x04-0x07 */ 0x00, 0x00, 0xE7, 0xCD, 0xBD, 0xCA, 0xE7, 0xC5, /* 0x08-0x0B */ @@ -7696,7 +7696,7 @@ static unsigned char u2c_89[512] = { 0xC5, 0xA9, 0x00, 0x00, 0xF7, 0xFE, 0xF9, 0x4C, /* 0xFC-0xFF */ }; -static unsigned char u2c_8A[512] = { +static const unsigned char u2c_8A[512] = { 0xA8, 0xA5, 0x00, 0x00, 0xAD, 0x71, 0xAD, 0x72, /* 0x00-0x03 */ 0xD0, 0xB0, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xB1, /* 0x04-0x07 */ 0xAD, 0x70, 0x00, 0x00, 0xB0, 0x54, 0x00, 0x00, /* 0x08-0x0B */ @@ -7764,7 +7764,7 @@ static unsigned char u2c_8A[512] = { 0xBF, 0xDC, 0x00, 0x00, 0xBF, 0xD5, 0xEB, 0xAE, /* 0xFC-0xFF */ }; -static unsigned char u2c_8B[512] = { +static const unsigned char u2c_8B[512] = { 0xBF, 0xD1, 0xBF, 0xD6, 0xBF, 0xD7, 0x00, 0x00, /* 0x00-0x03 */ 0xC1, 0xC3, 0xEE, 0xA4, 0xEE, 0xAD, 0xEE, 0xAA, /* 0x04-0x07 */ 0xEE, 0xAC, 0x00, 0x00, 0xC1, 0xC0, 0xEE, 0xA5, /* 0x08-0x0B */ @@ -7808,7 +7808,7 @@ static unsigned char u2c_8B[512] = { 0xC6, 0x6D, 0x00, 0x00, 0xF9, 0xA9, 0xF9, 0xC8, /* 0x9C-0x9F */ }; -static unsigned char u2c_8C[512] = { +static const unsigned char u2c_8C[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -7876,7 +7876,7 @@ static unsigned char u2c_8C[512] = { 0xC1, 0xCA, 0xC1, 0xC9, 0xF0, 0xF3, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_8D[512] = { +static const unsigned char u2c_8D[512] = { 0xF0, 0xF6, 0x00, 0x00, 0xF0, 0xF5, 0x00, 0x00, /* 0x00-0x03 */ 0xF0, 0xF4, 0xC2, 0xD8, 0xF3, 0x48, 0xF3, 0x49, /* 0x04-0x07 */ 0xC3, 0xD8, 0xF3, 0x4A, 0xC3, 0xD9, 0x00, 0x00, /* 0x08-0x0B */ @@ -7944,7 +7944,7 @@ static unsigned char u2c_8D[512] = { 0xBB, 0xB1, 0xE4, 0x5B, 0xE4, 0x61, 0xE4, 0x59, /* 0xFC-0xFF */ }; -static unsigned char u2c_8E[512] = { +static const unsigned char u2c_8E[512] = { 0xE4, 0x62, 0x00, 0x00, 0xE4, 0x58, 0xE4, 0x5D, /* 0x00-0x03 */ 0xE4, 0x63, 0xE4, 0x60, 0xE4, 0x5F, 0xE4, 0x5E, /* 0x04-0x07 */ 0x00, 0x00, 0xE4, 0x57, 0xE4, 0x5C, 0x00, 0x00, /* 0x08-0x0B */ @@ -8012,7 +8012,7 @@ static unsigned char u2c_8E[512] = { 0xB6, 0x63, 0x00, 0x00, 0xB8, 0xFD, 0xE0, 0x75, /* 0xFC-0xFF */ }; -static unsigned char u2c_8F[512] = { +static const unsigned char u2c_8F[512] = { 0xE0, 0x77, 0xE0, 0x76, 0xE0, 0x7B, 0xB8, 0xFB, /* 0x00-0x03 */ 0x00, 0x00, 0xE0, 0x78, 0xE0, 0x74, 0xE0, 0x79, /* 0x04-0x07 */ 0xE0, 0x7A, 0xB8, 0xFC, 0xB8, 0xFE, 0xE0, 0x7C, /* 0x08-0x0B */ @@ -8080,7 +8080,7 @@ static unsigned char u2c_8F[512] = { 0xD3, 0xF0, 0xB0, 0x6C, 0xD3, 0xEA, 0xD3, 0xED, /* 0xFC-0xFF */ }; -static unsigned char u2c_90[512] = { +static const unsigned char u2c_90[512] = { 0xB0, 0x68, 0xB0, 0x65, 0xD3, 0xEC, 0xB0, 0x6B, /* 0x00-0x03 */ 0xD3, 0xEF, 0xB0, 0x6D, 0xB0, 0x66, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD7, 0xE3, /* 0x08-0x0B */ @@ -8148,7 +8148,7 @@ static unsigned char u2c_90[512] = { 0xDC, 0x54, 0xB3, 0xA3, 0xB6, 0x6E, 0xDC, 0x53, /* 0xFC-0xFF */ }; -static unsigned char u2c_91[512] = { +static const unsigned char u2c_91[512] = { 0xDC, 0x59, 0xDC, 0x58, 0xB6, 0x6B, 0xDC, 0x5C, /* 0x00-0x03 */ 0xDC, 0x52, 0xDC, 0x5B, 0xDC, 0x50, 0xDC, 0x5A, /* 0x04-0x07 */ 0xDC, 0x55, 0xB6, 0x6D, 0x00, 0x00, 0xE0, 0xAA, /* 0x08-0x0B */ @@ -8216,7 +8216,7 @@ static unsigned char u2c_91[512] = { 0x00, 0x00, 0xDC, 0x6D, 0x00, 0x00, 0xDC, 0x6C, /* 0xFC-0xFF */ }; -static unsigned char u2c_92[512] = { +static const unsigned char u2c_92[512] = { 0xDC, 0x6A, 0xDC, 0x62, 0xDC, 0x71, 0xDC, 0x65, /* 0x00-0x03 */ 0xDC, 0x6F, 0xDC, 0x76, 0xDC, 0x6E, 0xB6, 0x79, /* 0x04-0x07 */ 0x00, 0x00, 0xB6, 0x75, 0xDC, 0x63, 0x00, 0x00, /* 0x08-0x0B */ @@ -8284,7 +8284,7 @@ static unsigned char u2c_92[512] = { 0xBF, 0xFB, 0x00, 0x00, 0xEC, 0x41, 0xEB, 0xF8, /* 0xFC-0xFF */ }; -static unsigned char u2c_93[512] = { +static const unsigned char u2c_93[512] = { 0xEC, 0x43, 0xEB, 0xE9, 0xEB, 0xF6, 0x00, 0x00, /* 0x00-0x03 */ 0xBF, 0xFD, 0x00, 0x00, 0xEB, 0xE1, 0x00, 0x00, /* 0x04-0x07 */ 0xEB, 0xDF, 0xEC, 0x42, 0x00, 0x00, 0xEC, 0x40, /* 0x08-0x0B */ @@ -8352,7 +8352,7 @@ static unsigned char u2c_93[512] = { 0xF5, 0x40, 0xC4, 0xC3, 0xF4, 0xED, 0xF4, 0xFE, /* 0xFC-0xFF */ }; -static unsigned char u2c_94[512] = { +static const unsigned char u2c_94[512] = { 0xF4, 0xF4, 0x00, 0x00, 0x00, 0x00, 0xC4, 0xC2, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0xF5, 0x44, 0xF4, 0xF6, /* 0x04-0x07 */ 0x00, 0x00, 0xF4, 0xFB, 0xF4, 0xFD, 0xF4, 0xE7, /* 0x08-0x0B */ @@ -8389,7 +8389,7 @@ static unsigned char u2c_94[512] = { 0xF9, 0xC0, 0xF9, 0xC1, 0xF9, 0xBF, 0xF9, 0xC9, /* 0x80-0x83 */ }; -static unsigned char u2c_95[512] = { +static const unsigned char u2c_95[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -8451,7 +8451,7 @@ static unsigned char u2c_95[512] = { 0xF6, 0x6C, 0xF6, 0x6B, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ }; -static unsigned char u2c_96[512] = { +static const unsigned char u2c_96[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -8519,7 +8519,7 @@ static unsigned char u2c_96[512] = { 0x00, 0x00, 0xE0, 0xD7, 0x00, 0x00, 0xE4, 0xBD, /* 0xFC-0xFF */ }; -static unsigned char u2c_97[512] = { +static const unsigned char u2c_97[512] = { 0xBB, 0xDD, 0x00, 0x00, 0xE8, 0xAF, 0x00, 0x00, /* 0x00-0x03 */ 0xBE, 0x5D, 0xE8, 0xAD, 0xBE, 0x5E, 0xBE, 0x5F, /* 0x04-0x07 */ 0xE8, 0xAE, 0xBE, 0x60, 0x00, 0x00, 0xEC, 0x51, /* 0x08-0x0B */ @@ -8587,7 +8587,7 @@ static unsigned char u2c_97[512] = { 0x00, 0x00, 0xF5, 0x4C, 0xF5, 0x4D, 0xC5, 0x54, /* 0xFC-0xFF */ }; -static unsigned char u2c_98[512] = { +static const unsigned char u2c_98[512] = { 0xF8, 0x51, 0xAD, 0xB6, 0xB3, 0xBB, 0xB3, 0xBC, /* 0x00-0x03 */ 0xD8, 0x4E, 0xB6, 0xB5, 0xB6, 0xB6, 0xDC, 0xAC, /* 0x04-0x07 */ 0xB6, 0xB7, 0x00, 0x00, 0xB9, 0x7A, 0x00, 0x00, /* 0x08-0x0B */ @@ -8655,7 +8655,7 @@ static unsigned char u2c_98[512] = { 0xB9, 0x7D, 0xB9, 0xA1, 0xB9, 0xA2, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_99[512] = { +static const unsigned char u2c_99[512] = { 0xE4, 0xCF, 0x00, 0x00, 0xE4, 0xCE, 0xBB, 0xE5, /* 0x00-0x03 */ 0x00, 0x00, 0xBB, 0xE6, 0x00, 0x00, 0xE4, 0xD0, /* 0x04-0x07 */ 0xE8, 0xBF, 0xBB, 0xE8, 0xBE, 0x69, 0x00, 0x00, /* 0x08-0x0B */ @@ -8723,7 +8723,7 @@ static unsigned char u2c_99[512] = { 0xEF, 0x62, 0xEF, 0x60, 0xEF, 0x61, 0xC2, 0x40, /* 0xFC-0xFF */ }; -static unsigned char u2c_9A[512] = { +static const unsigned char u2c_9A[512] = { 0x00, 0x00, 0xC1, 0xFE, 0xEF, 0x58, 0xEF, 0x63, /* 0x00-0x03 */ 0xF1, 0xB3, 0xF1, 0xB6, 0xF1, 0xB8, 0xF1, 0xB7, /* 0x04-0x07 */ 0x00, 0x00, 0xF1, 0xB1, 0xF1, 0xB5, 0xF1, 0xB0, /* 0x08-0x0B */ @@ -8791,7 +8791,7 @@ static unsigned char u2c_9A[512] = { 0xEF, 0x68, 0xEF, 0x66, 0xEF, 0x65, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_9B[512] = { +static const unsigned char u2c_9B[512] = { 0x00, 0x00, 0xEF, 0x67, 0x00, 0x00, 0xC3, 0x4F, /* 0x00-0x03 */ 0xF1, 0xBC, 0xF1, 0xBD, 0xC3, 0x50, 0x00, 0x00, /* 0x04-0x07 */ 0xF1, 0xBB, 0x00, 0x00, 0xF3, 0xC3, 0xF3, 0xC2, /* 0x08-0x0B */ @@ -8859,7 +8859,7 @@ static unsigned char u2c_9B[512] = { 0x00, 0x00, 0xC3, 0x56, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ }; -static unsigned char u2c_9C[512] = { +static const unsigned char u2c_9C[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0xF5, 0x6D, 0xF5, 0x73, 0xF5, 0x71, /* 0x04-0x07 */ 0xF5, 0x6B, 0xF5, 0x76, 0x00, 0x00, 0xF5, 0x6A, /* 0x08-0x0B */ @@ -8927,7 +8927,7 @@ static unsigned char u2c_9C[512] = { 0xE8, 0xE4, 0xE8, 0xE6, 0x00, 0x00, 0xE8, 0xE7, /* 0xFC-0xFF */ }; -static unsigned char u2c_9D[512] = { +static const unsigned char u2c_9D[512] = { 0xE8, 0xEA, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xA1, /* 0x00-0x03 */ 0xE8, 0xEF, 0xE8, 0xEE, 0xBE, 0x7D, 0xE8, 0xE9, /* 0x04-0x07 */ 0xE8, 0xED, 0xBE, 0x7E, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -8995,7 +8995,7 @@ static unsigned char u2c_9D[512] = { 0x00, 0x00, 0xF8, 0xE6, 0xF8, 0xDD, 0xF8, 0xE5, /* 0xFC-0xFF */ }; -static unsigned char u2c_9E[512] = { +static const unsigned char u2c_9E[512] = { 0xF8, 0xE2, 0xF8, 0xE3, 0xF8, 0xDC, 0xF8, 0xDF, /* 0x00-0x03 */ 0xF8, 0xE7, 0xF8, 0xE1, 0xF8, 0xE0, 0xF8, 0xDE, /* 0x04-0x07 */ 0x00, 0x00, 0xF8, 0xE4, 0x00, 0x00, 0xF9, 0x5D, /* 0x08-0x0B */ @@ -9063,7 +9063,7 @@ static unsigned char u2c_9E[512] = { 0xF3, 0xF5, 0xE0, 0xEF, 0x00, 0x00, 0xEF, 0xB1, /* 0xFC-0xFF */ }; -static unsigned char u2c_9F[512] = { +static const unsigned char u2c_9F[512] = { 0xF1, 0xE2, 0xF1, 0xE1, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0xF8, 0x78, 0xC6, 0x52, /* 0x04-0x07 */ 0x00, 0x00, 0xF9, 0x65, 0xF9, 0x7E, 0x00, 0x00, /* 0x08-0x0B */ @@ -9109,11 +9109,11 @@ static unsigned char u2c_9F[512] = { 0xF9, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ }; -static unsigned char u2c_DC[512] = { +static const unsigned char u2c_DC[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ }; -static unsigned char u2c_F9[512] = { +static const unsigned char u2c_F9[512] = { 0xB0, 0x5A, 0xA7, 0xF3, 0xA8, 0xAE, 0xB8, 0xEB, /* 0x00-0x03 */ 0xB7, 0xC6, 0xA6, 0xEA, 0xA5, 0x79, 0xC0, 0x74, /* 0x04-0x07 */ 0xC0, 0x74, 0xAB, 0xB4, 0xAA, 0xF7, 0xB3, 0xE2, /* 0x08-0x0B */ @@ -9181,7 +9181,7 @@ static unsigned char u2c_F9[512] = { 0xC3, 0xD1, 0xA4, 0xB0, 0xAF, 0xF9, 0xA8, 0xEB, /* 0xFC-0xFF */ }; -static unsigned char u2c_FA[512] = { +static const unsigned char u2c_FA[512] = { 0xA4, 0xC1, 0xAB, 0xD7, 0xA9, 0xDD, 0xBF, 0x7D, /* 0x00-0x03 */ 0xA6, 0x76, 0xAC, 0x7D, 0xBC, 0xC9, 0xBF, 0xE7, /* 0x04-0x07 */ 0xA6, 0xE6, 0xAD, 0xB0, 0xA8, 0xA3, 0xB9, 0xF8, /* 0x08-0x0B */ @@ -9196,7 +9196,7 @@ static unsigned char u2c_FA[512] = { 0xC0, 0x5D, 0xC5, 0x62, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ }; -static unsigned char u2c_FE[512] = { +static const unsigned char u2c_FE[512] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ @@ -9226,7 +9226,7 @@ static unsigned char u2c_FE[512] = { 0xA2, 0x42, 0xA2, 0x4C, 0xA2, 0x4D, 0xA2, 0x4E, /* 0x68-0x6B */ }; -static unsigned char u2c_FF[512] = { +static const unsigned char u2c_FF[512] = { 0x00, 0x00, 0xA1, 0x49, 0xA1, 0xA8, 0xA1, 0xAD, /* 0x00-0x03 */ 0xA2, 0x43, 0xA2, 0x48, 0xA1, 0xAE, 0xA1, 0xA6, /* 0x04-0x07 */ 0xA1, 0x5D, 0xA1, 0x5E, 0xA1, 0xAF, 0xA1, 0xCF, /* 0x08-0x0B */ @@ -9288,7 +9288,7 @@ static unsigned char u2c_FF[512] = { 0x00, 0x00, 0xA2, 0x44, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { NULL, NULL, u2c_02, u2c_03, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -9322,7 +9322,7 @@ static unsigned char *page_uni2charset[256] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, u2c_F9, u2c_FA, NULL, NULL, NULL, u2c_FE, u2c_FF, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -9358,7 +9358,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -9397,7 +9397,7 @@ static unsigned char charset2upper[256] = { static int uni2char(const wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni&0xFF; unsigned char ch = (uni>>8)&0xFF; int n; @@ -9429,7 +9429,7 @@ static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) { unsigned char ch, cl; - wchar_t *charset2uni; + const wchar_t *charset2uni; int n; if (boundlen <= 0) diff --git a/fs/nls/nls_euc-jp.c b/fs/nls/nls_euc-jp.c index 73293511578b..7424929a278b 100644 --- a/fs/nls/nls_euc-jp.c +++ b/fs/nls/nls_euc-jp.c @@ -57,7 +57,7 @@ static struct nls_table *p_nls; } while(0) /* SJIS IBM extended characters to EUC map */ -static unsigned char sjisibm2euc_map[][2] = { +static const unsigned char sjisibm2euc_map[][2] = { {0xF3, 0xF3}, {0xF3, 0xF4}, {0xF3, 0xF5}, {0xF3, 0xF6}, {0xF3, 0xF7}, {0xF3, 0xF8}, {0xF3, 0xF9}, {0xF3, 0xFA}, {0xF3, 0xFB}, {0xF3, 0xFC}, {0xF3, 0xFD}, {0xF3, 0xFE}, {0xF4, 0xA1}, {0xF4, 0xA2}, {0xF4, 0xA3}, @@ -243,7 +243,7 @@ static struct { }; /* EUC to SJIS IBM extended characters map (G3 Upper block) */ -static unsigned char euc2sjisibm_g3upper_map[][2] = { +static const unsigned char euc2sjisibm_g3upper_map[][2] = { {0xFA, 0x40}, {0xFA, 0x41}, {0xFA, 0x42}, {0xFA, 0x43}, {0xFA, 0x44}, {0xFA, 0x45}, {0xFA, 0x46}, {0xFA, 0x47}, {0xFA, 0x48}, {0xFA, 0x49}, {0xFA, 0x4A}, {0xFA, 0x4B}, {0xFA, 0x4C}, {0xFA, 0x4D}, {0xFA, 0x4E}, diff --git a/fs/nls/nls_iso8859-1.c b/fs/nls/nls_iso8859-1.c index 2483c3c6c1c1..7b951bb5849c 100644 --- a/fs/nls/nls_iso8859-1.c +++ b/fs/nls/nls_iso8859-1.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x00fc, 0x00fd, 0x00fe, 0x00ff, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -132,11 +132,11 @@ static unsigned char page00[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -172,7 +172,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -210,7 +210,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_iso8859-13.c b/fs/nls/nls_iso8859-13.c index 7b8721d74368..c4d52ea9f092 100644 --- a/fs/nls/nls_iso8859-13.c +++ b/fs/nls/nls_iso8859-13.c @@ -11,7 +11,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -94,7 +94,7 @@ static wchar_t charset2uni[256] = { 0x00fc, 0x017c, 0x017e, 0x2019, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -130,7 +130,7 @@ static unsigned char page00[256] = { 0xb8, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, /* 0xf8-0xff */ }; -static unsigned char page01[256] = { +static const unsigned char page01[256] = { 0xc2, 0xe2, 0x00, 0x00, 0xc0, 0xe0, 0xc3, 0xe3, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0xc7, 0xe7, 0x00, 0x00, 0xcb, 0xeb, /* 0x10-0x17 */ @@ -149,14 +149,14 @@ static unsigned char page01[256] = { 0x00, 0xca, 0xea, 0xdd, 0xfd, 0xde, 0xfe, 0x00, /* 0x78-0x7f */ }; -static unsigned char page20[256] = { +static const unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ 0x00, 0xff, 0x00, 0x00, 0xb4, 0xa1, 0xa5, 0x00, /* 0x18-0x1f */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, page01, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -164,7 +164,7 @@ static unsigned char *page_uni2charset[256] = { page20, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -200,7 +200,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -238,7 +238,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_iso8859-14.c b/fs/nls/nls_iso8859-14.c index 2e895e638dba..dc02600c7fe1 100644 --- a/fs/nls/nls_iso8859-14.c +++ b/fs/nls/nls_iso8859-14.c @@ -18,7 +18,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -101,7 +101,7 @@ static wchar_t charset2uni[256] = { 0x00fc, 0x00fd, 0x0177, 0x00ff, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -137,7 +137,7 @@ static unsigned char page00[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0x00, 0xff, /* 0xf8-0xff */ }; -static unsigned char page01[256] = { +static const unsigned char page01[256] = { 0x00, 0x00, 0xa1, 0xa2, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0xa6, 0xab, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -173,7 +173,7 @@ static unsigned char page01[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ }; -static unsigned char page1e[256] = { +static const unsigned char page1e[256] = { 0x00, 0x00, 0xa1, 0xa2, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0xa6, 0xab, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -209,7 +209,7 @@ static unsigned char page1e[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, page01, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -220,7 +220,7 @@ static unsigned char *page_uni2charset[256] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -256,7 +256,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -294,7 +294,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_iso8859-15.c b/fs/nls/nls_iso8859-15.c index 5c91592779fe..3c7dfc832ef1 100644 --- a/fs/nls/nls_iso8859-15.c +++ b/fs/nls/nls_iso8859-15.c @@ -11,7 +11,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -94,7 +94,7 @@ static wchar_t charset2uni[256] = { 0x00fc, 0x00fd, 0x00fe, 0x00ff, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -130,7 +130,7 @@ static unsigned char page00[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char page01[256] = { +static const unsigned char page01[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -149,7 +149,7 @@ static unsigned char page01[256] = { 0xbe, 0x00, 0x00, 0x00, 0x00, 0xb4, 0xb8, 0x00, /* 0x78-0x7f */ }; -static unsigned char page20[256] = { +static const unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -175,7 +175,7 @@ static unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, page01, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -186,7 +186,7 @@ static unsigned char *page_uni2charset[256] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -222,7 +222,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -260,7 +260,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_iso8859-2.c b/fs/nls/nls_iso8859-2.c index 892d38fe9530..a2d2197e4c77 100644 --- a/fs/nls/nls_iso8859-2.c +++ b/fs/nls/nls_iso8859-2.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x00fc, 0x00fd, 0x0163, 0x02d9, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -132,7 +132,7 @@ static unsigned char page00[256] = { 0x00, 0x00, 0xfa, 0x00, 0xfc, 0xfd, 0x00, 0x00, /* 0xf8-0xff */ }; -static unsigned char page01[256] = { +static const unsigned char page01[256] = { 0x00, 0x00, 0xc3, 0xe3, 0xa1, 0xb1, 0xc6, 0xe6, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0xcf, 0xef, /* 0x08-0x0f */ 0xd0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -151,7 +151,7 @@ static unsigned char page01[256] = { 0x00, 0xac, 0xbc, 0xaf, 0xbf, 0xae, 0xbe, 0x00, /* 0x78-0x7f */ }; -static unsigned char page02[256] = { +static const unsigned char page02[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -183,11 +183,11 @@ static unsigned char page02[256] = { 0xa2, 0xff, 0x00, 0xb2, 0x00, 0xbd, 0x00, 0x00, /* 0xd8-0xdf */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, page01, page02, NULL, NULL, NULL, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -223,7 +223,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -261,7 +261,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_iso8859-3.c b/fs/nls/nls_iso8859-3.c index 49317bcdb4be..a61e0daa3a86 100644 --- a/fs/nls/nls_iso8859-3.c +++ b/fs/nls/nls_iso8859-3.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x00fc, 0x016d, 0x015d, 0x02d9, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -132,7 +132,7 @@ static unsigned char page00[256] = { 0x00, 0xf9, 0xfa, 0xfb, 0xfc, 0x00, 0x00, 0x00, /* 0xf8-0xff */ }; -static unsigned char page01[256] = { +static const unsigned char page01[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0xc6, 0xe6, 0xc5, 0xe5, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -151,7 +151,7 @@ static unsigned char page01[256] = { 0x00, 0x00, 0x00, 0xaf, 0xbf, 0x00, 0x00, 0x00, /* 0x78-0x7f */ }; -static unsigned char page02[256] = { +static const unsigned char page02[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -183,11 +183,11 @@ static unsigned char page02[256] = { 0xa2, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, page01, page02, NULL, NULL, NULL, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -223,7 +223,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -261,7 +261,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_iso8859-4.c b/fs/nls/nls_iso8859-4.c index 9f3b9368c2cf..e8ff555483b6 100644 --- a/fs/nls/nls_iso8859-4.c +++ b/fs/nls/nls_iso8859-4.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x00fc, 0x0169, 0x016b, 0x02d9, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -132,7 +132,7 @@ static unsigned char page00[256] = { 0xf8, 0x00, 0xfa, 0xfb, 0xfc, 0x00, 0x00, 0x00, /* 0xf8-0xff */ }; -static unsigned char page01[256] = { +static const unsigned char page01[256] = { 0xc0, 0xe0, 0x00, 0x00, 0xa1, 0xb1, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0x00, 0x00, /* 0x08-0x0f */ 0xd0, 0xf0, 0xaa, 0xba, 0x00, 0x00, 0xcc, 0xec, /* 0x10-0x17 */ @@ -151,7 +151,7 @@ static unsigned char page01[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0xbe, 0x00, /* 0x78-0x7f */ }; -static unsigned char page02[256] = { +static const unsigned char page02[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -183,11 +183,11 @@ static unsigned char page02[256] = { 0x00, 0xff, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, page01, page02, NULL, NULL, NULL, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -223,7 +223,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -261,7 +261,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_iso8859-5.c b/fs/nls/nls_iso8859-5.c index 001a2bb132ce..4721e8930124 100644 --- a/fs/nls/nls_iso8859-5.c +++ b/fs/nls/nls_iso8859-5.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x045c, 0x00a7, 0x045e, 0x045f, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -122,7 +122,7 @@ static unsigned char page00[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, /* 0xa8-0xaf */ }; -static unsigned char page04[256] = { +static const unsigned char page04[256] = { 0x00, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0x00-0x07 */ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0x00, 0xae, 0xaf, /* 0x08-0x0f */ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0x10-0x17 */ @@ -137,13 +137,13 @@ static unsigned char page04[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0x00, 0xfe, 0xff, /* 0x58-0x5f */ }; -static unsigned char page21[256] = { +static const unsigned char page21[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, /* 0x10-0x17 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, NULL, NULL, NULL, page04, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -151,7 +151,7 @@ static unsigned char *page_uni2charset[256] = { NULL, page21, NULL, NULL, NULL, NULL, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -187,7 +187,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -225,7 +225,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_iso8859-6.c b/fs/nls/nls_iso8859-6.c index 8cec03d66088..01a517d6d306 100644 --- a/fs/nls/nls_iso8859-6.c +++ b/fs/nls/nls_iso8859-6.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x0000, 0x0000, 0x0000, 0x0000, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -122,7 +122,7 @@ static unsigned char page00[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, /* 0xa8-0xaf */ }; -static unsigned char page06[256] = { +static const unsigned char page06[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -139,11 +139,11 @@ static unsigned char page06[256] = { 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, NULL, NULL, NULL, NULL, NULL, page06, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -179,7 +179,7 @@ static unsigned char charset2lower[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -216,7 +216,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_iso8859-7.c b/fs/nls/nls_iso8859-7.c index 1be707d5ac31..2d27b93ef19e 100644 --- a/fs/nls/nls_iso8859-7.c +++ b/fs/nls/nls_iso8859-7.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x03cc, 0x03cd, 0x03ce, 0x0000, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -124,7 +124,7 @@ static unsigned char page00[256] = { 0x00, 0x00, 0x00, 0xbb, 0x00, 0xbd, 0x00, 0x00, /* 0xb8-0xbf */ }; -static unsigned char page02[256] = { +static const unsigned char page02[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -152,7 +152,7 @@ static unsigned char page02[256] = { 0x00, 0x00, 0x00, 0x00, 0xa2, 0xa1, 0x00, 0x00, /* 0xb8-0xbf */ }; -static unsigned char page03[256] = { +static const unsigned char page03[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -182,13 +182,13 @@ static unsigned char page03[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0x00, /* 0xc8-0xcf */ }; -static unsigned char page20[256] = { +static const unsigned char page20[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, /* 0x10-0x17 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, NULL, page02, page03, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -196,7 +196,7 @@ static unsigned char *page_uni2charset[256] = { page20, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -232,7 +232,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0x00, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -270,7 +270,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_iso8859-9.c b/fs/nls/nls_iso8859-9.c index 8c0146f73834..694bf070c721 100644 --- a/fs/nls/nls_iso8859-9.c +++ b/fs/nls/nls_iso8859-9.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x00fc, 0x0131, 0x015f, 0x00ff, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -132,7 +132,7 @@ static unsigned char page00[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0x00, 0x00, 0xff, /* 0xf8-0xff */ }; -static unsigned char page01[256] = { +static const unsigned char page01[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -147,11 +147,11 @@ static unsigned char page01[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xfe, /* 0x58-0x5f */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, page01, NULL, NULL, NULL, NULL, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -187,7 +187,7 @@ static unsigned char charset2lower[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -225,7 +225,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_koi8-r.c b/fs/nls/nls_koi8-r.c index fefbe0807265..43875310540d 100644 --- a/fs/nls/nls_koi8-r.c +++ b/fs/nls/nls_koi8-r.c @@ -13,7 +13,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -96,7 +96,7 @@ static wchar_t charset2uni[256] = { 0x042d, 0x0429, 0x0427, 0x042a, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -131,7 +131,7 @@ static unsigned char page00[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, /* 0xf0-0xf7 */ }; -static unsigned char page04[256] = { +static const unsigned char page04[256] = { 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0xe1, 0xe2, 0xf7, 0xe7, 0xe4, 0xe5, 0xf6, 0xfa, /* 0x10-0x17 */ @@ -145,7 +145,7 @@ static unsigned char page04[256] = { 0x00, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ }; -static unsigned char page22[256] = { +static const unsigned char page22[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -161,7 +161,7 @@ static unsigned char page22[256] = { 0x00, 0x00, 0x00, 0x00, 0x98, 0x99, 0x00, 0x00, /* 0x60-0x67 */ }; -static unsigned char page23[256] = { +static const unsigned char page23[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -169,7 +169,7 @@ static unsigned char page23[256] = { 0x93, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ }; -static unsigned char page25[256] = { +static const unsigned char page25[256] = { 0x80, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x83, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -194,7 +194,7 @@ static unsigned char page25[256] = { 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, NULL, NULL, NULL, page04, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -202,7 +202,7 @@ static unsigned char *page_uni2charset[256] = { NULL, NULL, page22, page23, NULL, page25, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -238,7 +238,7 @@ static unsigned char charset2lower[256] = { 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -276,7 +276,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/nls/nls_koi8-u.c b/fs/nls/nls_koi8-u.c index 015070211f22..8c9f0292b5ae 100644 --- a/fs/nls/nls_koi8-u.c +++ b/fs/nls/nls_koi8-u.c @@ -11,7 +11,7 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { +static const wchar_t charset2uni[256] = { /* 0x00*/ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -94,7 +94,7 @@ static wchar_t charset2uni[256] = { 0x042d, 0x0429, 0x0427, 0x042a, }; -static unsigned char page00[256] = { +static const unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -129,7 +129,7 @@ static unsigned char page00[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, /* 0xf0-0xf7 */ }; -static unsigned char page04[256] = { +static const unsigned char page04[256] = { 0x00, 0xb3, 0x00, 0x00, 0xb4, 0x00, 0xb6, 0xb7, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0xe1, 0xe2, 0xf7, 0xe7, 0xe4, 0xe5, 0xf6, 0xfa, /* 0x10-0x17 */ @@ -152,7 +152,7 @@ static unsigned char page04[256] = { 0xbd, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ }; -static unsigned char page22[256] = { +static const unsigned char page22[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -168,7 +168,7 @@ static unsigned char page22[256] = { 0x00, 0x00, 0x00, 0x00, 0x98, 0x99, 0x00, 0x00, /* 0x60-0x67 */ }; -static unsigned char page23[256] = { +static const unsigned char page23[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -176,7 +176,7 @@ static unsigned char page23[256] = { 0x93, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ }; -static unsigned char page25[256] = { +static const unsigned char page25[256] = { 0x80, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, /* 0x08-0x0f */ 0x83, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, /* 0x10-0x17 */ @@ -201,7 +201,7 @@ static unsigned char page25[256] = { 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ }; -static unsigned char *page_uni2charset[256] = { +static const unsigned char *const page_uni2charset[256] = { page00, NULL, NULL, NULL, page04, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -209,7 +209,7 @@ static unsigned char *page_uni2charset[256] = { NULL, NULL, page22, page23, NULL, page25, NULL, NULL, }; -static unsigned char charset2lower[256] = { +static const unsigned char charset2lower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -245,7 +245,7 @@ static unsigned char charset2lower[256] = { 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xf8-0xff */ }; -static unsigned char charset2upper[256] = { +static const unsigned char charset2upper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ @@ -283,7 +283,7 @@ static unsigned char charset2upper[256] = { static int uni2char(wchar_t uni, unsigned char *out, int boundlen) { - unsigned char *uni2charset; + const unsigned char *uni2charset; unsigned char cl = uni & 0x00ff; unsigned char ch = (uni & 0xff00) >> 8; diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index af4ef808fa94..345798ebd366 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -17,6 +17,18 @@ ToDo/Notes: happen is unclear however so it is worth waiting until someone hits the problem. +2.1.29 - Fix a deadlock at mount time. + + - During mount the VFS holds s_umount lock on the superblock. So when + we try to empty the journal $LogFile contents by calling + ntfs_attr_set() when the machine does not have much memory and the + journal is large ntfs_attr_set() results in the VM trying to balance + dirty pages which in turn tries to that the s_umount lock and thus we + get a deadlock. The solution is to not use ntfs_attr_set() and + instead do the zeroing by hand at the block level rather than page + cache level. + - Fix sparse warnings. + 2.1.28 - Fix a deadlock. - Fix deadlock in fs/ntfs/inode.c::ntfs_put_inode(). Thanks to Sergey diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile index 825508385565..58b6be992544 100644 --- a/fs/ntfs/Makefile +++ b/fs/ntfs/Makefile @@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \ index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \ unistr.o upcase.o -EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.28\" +EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.29\" ifeq ($(CONFIG_NTFS_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index 6e5c2534f4bc..cfdc7900d271 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c @@ -2,7 +2,7 @@ * aops.c - NTFS kernel address space operations and page cache handling. * Part of the Linux-NTFS project. * - * Copyright (c) 2001-2006 Anton Altaparmakov + * Copyright (c) 2001-2007 Anton Altaparmakov * Copyright (c) 2002 Richard Russon * * This program/include file is free software; you can redistribute it and/or @@ -396,7 +396,7 @@ static int ntfs_readpage(struct file *file, struct page *page) loff_t i_size; struct inode *vi; ntfs_inode *ni, *base_ni; - u8 *kaddr; + u8 *addr; ntfs_attr_search_ctx *ctx; MFT_RECORD *mrec; unsigned long flags; @@ -491,15 +491,15 @@ retry_readpage: /* Race with shrinking truncate. */ attr_len = i_size; } - kaddr = kmap_atomic(page, KM_USER0); + addr = kmap_atomic(page, KM_USER0); /* Copy the data to the page. */ - memcpy(kaddr, (u8*)ctx->attr + + memcpy(addr, (u8*)ctx->attr + le16_to_cpu(ctx->attr->data.resident.value_offset), attr_len); /* Zero the remainder of the page. */ - memset(kaddr + attr_len, 0, PAGE_CACHE_SIZE - attr_len); + memset(addr + attr_len, 0, PAGE_CACHE_SIZE - attr_len); flush_dcache_page(page); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(addr, KM_USER0); put_unm_err_out: ntfs_attr_put_search_ctx(ctx); unm_err_out: @@ -1344,7 +1344,7 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc) loff_t i_size; struct inode *vi = page->mapping->host; ntfs_inode *base_ni = NULL, *ni = NTFS_I(vi); - char *kaddr; + char *addr; ntfs_attr_search_ctx *ctx = NULL; MFT_RECORD *m = NULL; u32 attr_len; @@ -1484,14 +1484,14 @@ retry_writepage: /* Shrinking cannot fail. */ BUG_ON(err); } - kaddr = kmap_atomic(page, KM_USER0); + addr = kmap_atomic(page, KM_USER0); /* Copy the data from the page to the mft record. */ memcpy((u8*)ctx->attr + le16_to_cpu(ctx->attr->data.resident.value_offset), - kaddr, attr_len); + addr, attr_len); /* Zero out of bounds area in the page cache page. */ - memset(kaddr + attr_len, 0, PAGE_CACHE_SIZE - attr_len); - kunmap_atomic(kaddr, KM_USER0); + memset(addr + attr_len, 0, PAGE_CACHE_SIZE - attr_len); + kunmap_atomic(addr, KM_USER0); flush_dcache_page(page); flush_dcache_mft_record_page(ctx->ntfs_ino); /* We are done with the page. */ diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 1c08fefe487a..92dabdcf2b80 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -1,7 +1,7 @@ /** * attrib.c - NTFS attribute operations. Part of the Linux-NTFS project. * - * Copyright (c) 2001-2006 Anton Altaparmakov + * Copyright (c) 2001-2007 Anton Altaparmakov * Copyright (c) 2002 Richard Russon * * This program/include file is free software; you can redistribute it and/or @@ -2500,7 +2500,7 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val) struct page *page; u8 *kaddr; pgoff_t idx, end; - unsigned int start_ofs, end_ofs, size; + unsigned start_ofs, end_ofs, size; ntfs_debug("Entering for ofs 0x%llx, cnt 0x%llx, val 0x%hx.", (long long)ofs, (long long)cnt, val); @@ -2548,6 +2548,8 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val) kunmap_atomic(kaddr, KM_USER0); set_page_dirty(page); page_cache_release(page); + balance_dirty_pages_ratelimited(mapping); + cond_resched(); if (idx == end) goto done; idx++; @@ -2604,6 +2606,8 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val) kunmap_atomic(kaddr, KM_USER0); set_page_dirty(page); page_cache_release(page); + balance_dirty_pages_ratelimited(mapping); + cond_resched(); } done: ntfs_debug("Done."); diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index ffcc504a1667..6cd08dfdc2ed 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -1,7 +1,7 @@ /* * file.c - NTFS kernel file operations. Part of the Linux-NTFS project. * - * Copyright (c) 2001-2006 Anton Altaparmakov + * Copyright (c) 2001-2007 Anton Altaparmakov * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -26,7 +26,6 @@ #include <linux/swap.h> #include <linux/uio.h> #include <linux/writeback.h> -#include <linux/sched.h> #include <asm/page.h> #include <asm/uaccess.h> @@ -62,7 +61,7 @@ static int ntfs_file_open(struct inode *vi, struct file *filp) { if (sizeof(unsigned long) < 8) { if (i_size_read(vi) > MAX_LFS_FILESIZE) - return -EFBIG; + return -EOVERFLOW; } return generic_file_open(vi, filp); } @@ -362,7 +361,7 @@ static inline void ntfs_fault_in_pages_readable(const char __user *uaddr, volatile char c; /* Set @end to the first byte outside the last page we care about. */ - end = (const char __user*)PAGE_ALIGN((ptrdiff_t __user)uaddr + bytes); + end = (const char __user*)PAGE_ALIGN((unsigned long)uaddr + bytes); while (!__get_user(c, uaddr) && (uaddr += PAGE_SIZE, uaddr < end)) ; @@ -532,7 +531,8 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages, blocksize_bits = vol->sb->s_blocksize_bits; u = 0; do { - struct page *page = pages[u]; + page = pages[u]; + BUG_ON(!page); /* * create_empty_buffers() will create uptodate/dirty buffers if * the page is uptodate/dirty. @@ -1291,7 +1291,7 @@ static inline size_t ntfs_copy_from_user(struct page **pages, size_t bytes) { struct page **last_page = pages + nr_pages; - char *kaddr; + char *addr; size_t total = 0; unsigned len; int left; @@ -1300,13 +1300,13 @@ static inline size_t ntfs_copy_from_user(struct page **pages, len = PAGE_CACHE_SIZE - ofs; if (len > bytes) len = bytes; - kaddr = kmap_atomic(*pages, KM_USER0); - left = __copy_from_user_inatomic(kaddr + ofs, buf, len); - kunmap_atomic(kaddr, KM_USER0); + addr = kmap_atomic(*pages, KM_USER0); + left = __copy_from_user_inatomic(addr + ofs, buf, len); + kunmap_atomic(addr, KM_USER0); if (unlikely(left)) { /* Do it the slow way. */ - kaddr = kmap(*pages); - left = __copy_from_user(kaddr + ofs, buf, len); + addr = kmap(*pages); + left = __copy_from_user(addr + ofs, buf, len); kunmap(*pages); if (unlikely(left)) goto err_out; @@ -1408,26 +1408,26 @@ static inline size_t ntfs_copy_from_user_iovec(struct page **pages, size_t *iov_ofs, size_t bytes) { struct page **last_page = pages + nr_pages; - char *kaddr; + char *addr; size_t copied, len, total = 0; do { len = PAGE_CACHE_SIZE - ofs; if (len > bytes) len = bytes; - kaddr = kmap_atomic(*pages, KM_USER0); - copied = __ntfs_copy_from_user_iovec_inatomic(kaddr + ofs, + addr = kmap_atomic(*pages, KM_USER0); + copied = __ntfs_copy_from_user_iovec_inatomic(addr + ofs, *iov, *iov_ofs, len); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(addr, KM_USER0); if (unlikely(copied != len)) { /* Do it the slow way. */ - kaddr = kmap(*pages); - copied = __ntfs_copy_from_user_iovec_inatomic(kaddr + ofs, + addr = kmap(*pages); + copied = __ntfs_copy_from_user_iovec_inatomic(addr + ofs, *iov, *iov_ofs, len); /* * Zero the rest of the target like __copy_from_user(). */ - memset(kaddr + ofs + copied, 0, len - copied); + memset(addr + ofs + copied, 0, len - copied); kunmap(*pages); if (unlikely(copied != len)) goto err_out; @@ -1735,8 +1735,6 @@ static int ntfs_commit_pages_after_write(struct page **pages, read_unlock_irqrestore(&ni->size_lock, flags); BUG_ON(initialized_size != i_size); if (end > initialized_size) { - unsigned long flags; - write_lock_irqsave(&ni->size_lock, flags); ni->initialized_size = end; i_size_write(vi, end); diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index b532a730cec2..e9da092e2772 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -34,7 +34,6 @@ #include "dir.h" #include "debug.h" #include "inode.h" -#include "attrib.h" #include "lcnalloc.h" #include "malloc.h" #include "mft.h" @@ -2500,8 +2499,6 @@ retry_truncate: /* Resize the attribute record to best fit the new attribute size. */ if (new_size < vol->mft_record_size && !ntfs_resident_attr_value_resize(m, a, new_size)) { - unsigned long flags; - /* The resize succeeded! */ flush_dcache_mft_record_page(ctx->ntfs_ino); mark_mft_record_dirty(ctx->ntfs_ino); diff --git a/fs/ntfs/logfile.c b/fs/ntfs/logfile.c index acfed325f4ec..d7932e95b1fd 100644 --- a/fs/ntfs/logfile.c +++ b/fs/ntfs/logfile.c @@ -1,7 +1,7 @@ /* * logfile.c - NTFS kernel journal handling. Part of the Linux-NTFS project. * - * Copyright (c) 2002-2005 Anton Altaparmakov + * Copyright (c) 2002-2007 Anton Altaparmakov * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -724,24 +724,139 @@ bool ntfs_is_logfile_clean(struct inode *log_vi, const RESTART_PAGE_HEADER *rp) */ bool ntfs_empty_logfile(struct inode *log_vi) { - ntfs_volume *vol = NTFS_SB(log_vi->i_sb); + VCN vcn, end_vcn; + ntfs_inode *log_ni = NTFS_I(log_vi); + ntfs_volume *vol = log_ni->vol; + struct super_block *sb = vol->sb; + runlist_element *rl; + unsigned long flags; + unsigned block_size, block_size_bits; + int err; + bool should_wait = true; ntfs_debug("Entering."); - if (!NVolLogFileEmpty(vol)) { - int err; - - err = ntfs_attr_set(NTFS_I(log_vi), 0, i_size_read(log_vi), - 0xff); - if (unlikely(err)) { - ntfs_error(vol->sb, "Failed to fill $LogFile with " - "0xff bytes (error code %i).", err); - return false; - } - /* Set the flag so we do not have to do it again on remount. */ - NVolSetLogFileEmpty(vol); + if (NVolLogFileEmpty(vol)) { + ntfs_debug("Done."); + return true; } + /* + * We cannot use ntfs_attr_set() because we may be still in the middle + * of a mount operation. Thus we do the emptying by hand by first + * zapping the page cache pages for the $LogFile/$DATA attribute and + * then emptying each of the buffers in each of the clusters specified + * by the runlist by hand. + */ + block_size = sb->s_blocksize; + block_size_bits = sb->s_blocksize_bits; + vcn = 0; + read_lock_irqsave(&log_ni->size_lock, flags); + end_vcn = (log_ni->initialized_size + vol->cluster_size_mask) >> + vol->cluster_size_bits; + read_unlock_irqrestore(&log_ni->size_lock, flags); + truncate_inode_pages(log_vi->i_mapping, 0); + down_write(&log_ni->runlist.lock); + rl = log_ni->runlist.rl; + if (unlikely(!rl || vcn < rl->vcn || !rl->length)) { +map_vcn: + err = ntfs_map_runlist_nolock(log_ni, vcn, NULL); + if (err) { + ntfs_error(sb, "Failed to map runlist fragment (error " + "%d).", -err); + goto err; + } + rl = log_ni->runlist.rl; + BUG_ON(!rl || vcn < rl->vcn || !rl->length); + } + /* Seek to the runlist element containing @vcn. */ + while (rl->length && vcn >= rl[1].vcn) + rl++; + do { + LCN lcn; + sector_t block, end_block; + s64 len; + + /* + * If this run is not mapped map it now and start again as the + * runlist will have been updated. + */ + lcn = rl->lcn; + if (unlikely(lcn == LCN_RL_NOT_MAPPED)) { + vcn = rl->vcn; + goto map_vcn; + } + /* If this run is not valid abort with an error. */ + if (unlikely(!rl->length || lcn < LCN_HOLE)) + goto rl_err; + /* Skip holes. */ + if (lcn == LCN_HOLE) + continue; + block = lcn << vol->cluster_size_bits >> block_size_bits; + len = rl->length; + if (rl[1].vcn > end_vcn) + len = end_vcn - rl->vcn; + end_block = (lcn + len) << vol->cluster_size_bits >> + block_size_bits; + /* Iterate over the blocks in the run and empty them. */ + do { + struct buffer_head *bh; + + /* Obtain the buffer, possibly not uptodate. */ + bh = sb_getblk(sb, block); + BUG_ON(!bh); + /* Setup buffer i/o submission. */ + lock_buffer(bh); + bh->b_end_io = end_buffer_write_sync; + get_bh(bh); + /* Set the entire contents of the buffer to 0xff. */ + memset(bh->b_data, -1, block_size); + if (!buffer_uptodate(bh)) + set_buffer_uptodate(bh); + if (buffer_dirty(bh)) + clear_buffer_dirty(bh); + /* + * Submit the buffer and wait for i/o to complete but + * only for the first buffer so we do not miss really + * serious i/o errors. Once the first buffer has + * completed ignore errors afterwards as we can assume + * that if one buffer worked all of them will work. + */ + submit_bh(WRITE, bh); + if (should_wait) { + should_wait = false; + wait_on_buffer(bh); + if (unlikely(!buffer_uptodate(bh))) + goto io_err; + } + brelse(bh); + } while (++block < end_block); + } while ((++rl)->vcn < end_vcn); + up_write(&log_ni->runlist.lock); + /* + * Zap the pages again just in case any got instantiated whilst we were + * emptying the blocks by hand. FIXME: We may not have completed + * writing to all the buffer heads yet so this may happen too early. + * We really should use a kernel thread to do the emptying + * asynchronously and then we can also set the volume dirty and output + * an error message if emptying should fail. + */ + truncate_inode_pages(log_vi->i_mapping, 0); + /* Set the flag so we do not have to do it again on remount. */ + NVolSetLogFileEmpty(vol); ntfs_debug("Done."); return true; +io_err: + ntfs_error(sb, "Failed to write buffer. Unmount and run chkdsk."); + goto dirty_err; +rl_err: + ntfs_error(sb, "Runlist is corrupt. Unmount and run chkdsk."); +dirty_err: + NVolSetErrors(vol); + err = -EIO; +err: + up_write(&log_ni->runlist.lock); + ntfs_error(sb, "Failed to fill $LogFile with 0xff bytes (error %d).", + -err); + return false; } #endif /* NTFS_RW */ diff --git a/fs/ntfs/runlist.c b/fs/ntfs/runlist.c index 9afd72c7ad0d..56a9a6d25a2a 100644 --- a/fs/ntfs/runlist.c +++ b/fs/ntfs/runlist.c @@ -1,7 +1,7 @@ /** * runlist.c - NTFS runlist handling code. Part of the Linux-NTFS project. * - * Copyright (c) 2001-2005 Anton Altaparmakov + * Copyright (c) 2001-2007 Anton Altaparmakov * Copyright (c) 2002-2005 Richard Russon * * This program/include file is free software; you can redistribute it and/or @@ -1714,7 +1714,7 @@ extend_hole: sizeof(*rl)); /* Adjust the beginning of the tail if necessary. */ if (end > rl->vcn) { - s64 delta = end - rl->vcn; + delta = end - rl->vcn; rl->vcn = end; rl->length -= delta; /* Only adjust the lcn if it is real. */ diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 90c4e3a29706..3e76f3b216bc 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -2381,14 +2381,14 @@ static void ntfs_put_super(struct super_block *sb) */ ntfs_commit_inode(vol->mft_ino); write_inode_now(vol->mft_ino, 1); - if (!list_empty(&sb->s_dirty)) { + if (sb_has_dirty_inodes(sb)) { const char *s1, *s2; mutex_lock(&vol->mft_ino->i_mutex); truncate_inode_pages(vol->mft_ino->i_mapping, 0); mutex_unlock(&vol->mft_ino->i_mutex); write_inode_now(vol->mft_ino, 1); - if (!list_empty(&sb->s_dirty)) { + if (sb_has_dirty_inodes(sb)) { static const char *_s1 = "inodes"; static const char *_s2 = ""; s1 = _s1; @@ -3080,8 +3080,7 @@ struct kmem_cache *ntfs_inode_cache; struct kmem_cache *ntfs_big_inode_cache; /* Init once constructor for the inode slab cache. */ -static void ntfs_big_inode_init_once(void *foo, struct kmem_cache *cachep, - unsigned long flags) +static void ntfs_big_inode_init_once(struct kmem_cache *cachep, void *foo) { ntfs_inode *ni = (ntfs_inode *)foo; diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 778a850b4634..4ba7f0bdc248 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -354,7 +354,6 @@ struct ocfs2_insert_type { enum ocfs2_append_type ins_appending; enum ocfs2_contig_type ins_contig; int ins_contig_index; - int ins_free_records; int ins_tree_depth; }; @@ -362,7 +361,6 @@ struct ocfs2_merge_ctxt { enum ocfs2_contig_type c_contig_type; int c_has_empty_extent; int c_split_covers_rec; - int c_used_tail_recs; }; /* @@ -2808,36 +2806,28 @@ static int ocfs2_try_to_merge_extent(struct inode *inode, struct ocfs2_merge_ctxt *ctxt) { - int ret = 0, delete_tail_recs = 0; + int ret = 0; struct ocfs2_extent_list *el = path_leaf_el(left_path); struct ocfs2_extent_rec *rec = &el->l_recs[split_index]; BUG_ON(ctxt->c_contig_type == CONTIG_NONE); - if (ctxt->c_split_covers_rec) { - delete_tail_recs++; - - if (ctxt->c_contig_type == CONTIG_LEFTRIGHT || - ctxt->c_has_empty_extent) - delete_tail_recs++; - - if (ctxt->c_has_empty_extent) { - /* - * The merge code will need to create an empty - * extent to take the place of the newly - * emptied slot. Remove any pre-existing empty - * extents - having more than one in a leaf is - * illegal. - */ - ret = ocfs2_rotate_tree_left(inode, handle, left_path, - dealloc); - if (ret) { - mlog_errno(ret); - goto out; - } - split_index--; - rec = &el->l_recs[split_index]; + if (ctxt->c_split_covers_rec && ctxt->c_has_empty_extent) { + /* + * The merge code will need to create an empty + * extent to take the place of the newly + * emptied slot. Remove any pre-existing empty + * extents - having more than one in a leaf is + * illegal. + */ + ret = ocfs2_rotate_tree_left(inode, handle, left_path, + dealloc); + if (ret) { + mlog_errno(ret); + goto out; } + split_index--; + rec = &el->l_recs[split_index]; } if (ctxt->c_contig_type == CONTIG_LEFTRIGHT) { @@ -3593,6 +3583,7 @@ static int ocfs2_figure_insert_type(struct inode *inode, struct buffer_head *di_bh, struct buffer_head **last_eb_bh, struct ocfs2_extent_rec *insert_rec, + int *free_records, struct ocfs2_insert_type *insert) { int ret; @@ -3633,7 +3624,7 @@ static int ocfs2_figure_insert_type(struct inode *inode, * XXX: This test is simplistic, we can search for empty * extent records too. */ - insert->ins_free_records = le16_to_cpu(el->l_count) - + *free_records = le16_to_cpu(el->l_count) - le16_to_cpu(el->l_next_free_rec); if (!insert->ins_tree_depth) { @@ -3730,10 +3721,13 @@ int ocfs2_insert_extent(struct ocfs2_super *osb, struct ocfs2_alloc_context *meta_ac) { int status; + int uninitialized_var(free_records); struct buffer_head *last_eb_bh = NULL; struct ocfs2_insert_type insert = {0, }; struct ocfs2_extent_rec rec; + BUG_ON(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL); + mlog(0, "add %u clusters at position %u to inode %llu\n", new_clusters, cpos, (unsigned long long)OCFS2_I(inode)->ip_blkno); @@ -3752,7 +3746,7 @@ int ocfs2_insert_extent(struct ocfs2_super *osb, rec.e_flags = flags; status = ocfs2_figure_insert_type(inode, fe_bh, &last_eb_bh, &rec, - &insert); + &free_records, &insert); if (status < 0) { mlog_errno(status); goto bail; @@ -3762,9 +3756,9 @@ int ocfs2_insert_extent(struct ocfs2_super *osb, "Insert.contig_index: %d, Insert.free_records: %d, " "Insert.tree_depth: %d\n", insert.ins_appending, insert.ins_contig, insert.ins_contig_index, - insert.ins_free_records, insert.ins_tree_depth); + free_records, insert.ins_tree_depth); - if (insert.ins_contig == CONTIG_NONE && insert.ins_free_records == 0) { + if (insert.ins_contig == CONTIG_NONE && free_records == 0) { status = ocfs2_grow_tree(inode, handle, fe_bh, &insert.ins_tree_depth, &last_eb_bh, meta_ac); @@ -3847,26 +3841,17 @@ leftright: if (le16_to_cpu(rightmost_el->l_next_free_rec) == le16_to_cpu(rightmost_el->l_count)) { - int old_depth = depth; - ret = ocfs2_grow_tree(inode, handle, di_bh, &depth, last_eb_bh, meta_ac); if (ret) { mlog_errno(ret); goto out; } - - if (old_depth != depth) { - eb = (struct ocfs2_extent_block *)(*last_eb_bh)->b_data; - rightmost_el = &eb->h_list; - } } memset(&insert, 0, sizeof(struct ocfs2_insert_type)); insert.ins_appending = APPEND_NONE; insert.ins_contig = CONTIG_NONE; - insert.ins_free_records = le16_to_cpu(rightmost_el->l_count) - - le16_to_cpu(rightmost_el->l_next_free_rec); insert.ins_tree_depth = depth; insert_range = le32_to_cpu(split_rec.e_cpos) + @@ -4015,11 +4000,6 @@ static int __ocfs2_mark_extent_written(struct inode *inode, } else rightmost_el = path_root_el(path); - ctxt.c_used_tail_recs = le16_to_cpu(rightmost_el->l_next_free_rec); - if (ctxt.c_used_tail_recs > 0 && - ocfs2_is_empty_extent(&rightmost_el->l_recs[0])) - ctxt.c_used_tail_recs--; - if (rec->e_cpos == split_rec->e_cpos && rec->e_leaf_clusters == split_rec->e_leaf_clusters) ctxt.c_split_covers_rec = 1; @@ -4028,10 +4008,9 @@ static int __ocfs2_mark_extent_written(struct inode *inode, ctxt.c_has_empty_extent = ocfs2_is_empty_extent(&el->l_recs[0]); - mlog(0, "index: %d, contig: %u, used_tail_recs: %u, " - "has_empty: %u, split_covers: %u\n", split_index, - ctxt.c_contig_type, ctxt.c_used_tail_recs, - ctxt.c_has_empty_extent, ctxt.c_split_covers_rec); + mlog(0, "index: %d, contig: %u, has_empty: %u, split_covers: %u\n", + split_index, ctxt.c_contig_type, ctxt.c_has_empty_extent, + ctxt.c_split_covers_rec); if (ctxt.c_contig_type == CONTIG_NONE) { if (ctxt.c_split_covers_rec) @@ -4180,27 +4159,18 @@ static int ocfs2_split_tree(struct inode *inode, struct buffer_head *di_bh, if (le16_to_cpu(rightmost_el->l_next_free_rec) == le16_to_cpu(rightmost_el->l_count)) { - int old_depth = depth; - ret = ocfs2_grow_tree(inode, handle, di_bh, &depth, &last_eb_bh, meta_ac); if (ret) { mlog_errno(ret); goto out; } - - if (old_depth != depth) { - eb = (struct ocfs2_extent_block *)last_eb_bh->b_data; - rightmost_el = &eb->h_list; - } } memset(&insert, 0, sizeof(struct ocfs2_insert_type)); insert.ins_appending = APPEND_NONE; insert.ins_contig = CONTIG_NONE; insert.ins_split = SPLIT_RIGHT; - insert.ins_free_records = le16_to_cpu(rightmost_el->l_count) - - le16_to_cpu(rightmost_el->l_next_free_rec); insert.ins_tree_depth = depth; ret = ocfs2_do_insert_extent(inode, handle, di_bh, &split_rec, &insert); @@ -5665,12 +5635,50 @@ static int ocfs2_ordered_zero_func(handle_t *handle, struct buffer_head *bh) return ocfs2_journal_dirty_data(handle, bh); } +static void ocfs2_map_and_dirty_page(struct inode *inode, handle_t *handle, + unsigned int from, unsigned int to, + struct page *page, int zero, u64 *phys) +{ + int ret, partial = 0; + + ret = ocfs2_map_page_blocks(page, phys, inode, from, to, 0); + if (ret) + mlog_errno(ret); + + if (zero) + zero_user_page(page, from, to - from, KM_USER0); + + /* + * Need to set the buffers we zero'd into uptodate + * here if they aren't - ocfs2_map_page_blocks() + * might've skipped some + */ + if (ocfs2_should_order_data(inode)) { + ret = walk_page_buffers(handle, + page_buffers(page), + from, to, &partial, + ocfs2_ordered_zero_func); + if (ret < 0) + mlog_errno(ret); + } else { + ret = walk_page_buffers(handle, page_buffers(page), + from, to, &partial, + ocfs2_writeback_zero_func); + if (ret < 0) + mlog_errno(ret); + } + + if (!partial) + SetPageUptodate(page); + + flush_dcache_page(page); +} + static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t start, loff_t end, struct page **pages, int numpages, u64 phys, handle_t *handle) { - int i, ret, partial = 0; - void *kaddr; + int i; struct page *page; unsigned int from, to = PAGE_CACHE_SIZE; struct super_block *sb = inode->i_sb; @@ -5691,87 +5699,31 @@ static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t start, BUG_ON(from > PAGE_CACHE_SIZE); BUG_ON(to > PAGE_CACHE_SIZE); - ret = ocfs2_map_page_blocks(page, &phys, inode, from, to, 0); - if (ret) - mlog_errno(ret); - - kaddr = kmap_atomic(page, KM_USER0); - memset(kaddr + from, 0, to - from); - kunmap_atomic(kaddr, KM_USER0); - - /* - * Need to set the buffers we zero'd into uptodate - * here if they aren't - ocfs2_map_page_blocks() - * might've skipped some - */ - if (ocfs2_should_order_data(inode)) { - ret = walk_page_buffers(handle, - page_buffers(page), - from, to, &partial, - ocfs2_ordered_zero_func); - if (ret < 0) - mlog_errno(ret); - } else { - ret = walk_page_buffers(handle, page_buffers(page), - from, to, &partial, - ocfs2_writeback_zero_func); - if (ret < 0) - mlog_errno(ret); - } - - if (!partial) - SetPageUptodate(page); - - flush_dcache_page(page); + ocfs2_map_and_dirty_page(inode, handle, from, to, page, 1, + &phys); start = (page->index + 1) << PAGE_CACHE_SHIFT; } out: - if (pages) { - for (i = 0; i < numpages; i++) { - page = pages[i]; - unlock_page(page); - mark_page_accessed(page); - page_cache_release(page); - } - } + if (pages) + ocfs2_unlock_and_free_pages(pages, numpages); } static int ocfs2_grab_eof_pages(struct inode *inode, loff_t start, loff_t end, - struct page **pages, int *num, u64 *phys) + struct page **pages, int *num) { - int i, numpages = 0, ret = 0; - unsigned int ext_flags; + int numpages, ret = 0; struct super_block *sb = inode->i_sb; struct address_space *mapping = inode->i_mapping; unsigned long index; loff_t last_page_bytes; - BUG_ON(!ocfs2_sparse_alloc(OCFS2_SB(sb))); BUG_ON(start > end); - if (start == end) - goto out; - BUG_ON(start >> OCFS2_SB(sb)->s_clustersize_bits != (end - 1) >> OCFS2_SB(sb)->s_clustersize_bits); - ret = ocfs2_extent_map_get_blocks(inode, start >> sb->s_blocksize_bits, - phys, NULL, &ext_flags); - if (ret) { - mlog_errno(ret); - goto out; - } - - /* Tail is a hole. */ - if (*phys == 0) - goto out; - - /* Tail is marked as unwritten, we can count on write to zero - * in that case. */ - if (ext_flags & OCFS2_EXT_UNWRITTEN) - goto out; - + numpages = 0; last_page_bytes = PAGE_ALIGN(end); index = start >> PAGE_CACHE_SHIFT; do { @@ -5788,14 +5740,8 @@ static int ocfs2_grab_eof_pages(struct inode *inode, loff_t start, loff_t end, out: if (ret != 0) { - if (pages) { - for (i = 0; i < numpages; i++) { - if (pages[i]) { - unlock_page(pages[i]); - page_cache_release(pages[i]); - } - } - } + if (pages) + ocfs2_unlock_and_free_pages(pages, numpages); numpages = 0; } @@ -5816,18 +5762,20 @@ out: int ocfs2_zero_range_for_truncate(struct inode *inode, handle_t *handle, u64 range_start, u64 range_end) { - int ret, numpages; + int ret = 0, numpages; struct page **pages = NULL; u64 phys; + unsigned int ext_flags; + struct super_block *sb = inode->i_sb; /* * File systems which don't support sparse files zero on every * extend. */ - if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) + if (!ocfs2_sparse_alloc(OCFS2_SB(sb))) return 0; - pages = kcalloc(ocfs2_pages_per_cluster(inode->i_sb), + pages = kcalloc(ocfs2_pages_per_cluster(sb), sizeof(struct page *), GFP_NOFS); if (pages == NULL) { ret = -ENOMEM; @@ -5835,16 +5783,31 @@ int ocfs2_zero_range_for_truncate(struct inode *inode, handle_t *handle, goto out; } - ret = ocfs2_grab_eof_pages(inode, range_start, range_end, pages, - &numpages, &phys); + if (range_start == range_end) + goto out; + + ret = ocfs2_extent_map_get_blocks(inode, + range_start >> sb->s_blocksize_bits, + &phys, NULL, &ext_flags); if (ret) { mlog_errno(ret); goto out; } - if (numpages == 0) + /* + * Tail is a hole, or is marked unwritten. In either case, we + * can count on read and write to return/push zero's. + */ + if (phys == 0 || ext_flags & OCFS2_EXT_UNWRITTEN) goto out; + ret = ocfs2_grab_eof_pages(inode, range_start, range_end, pages, + &numpages); + if (ret) { + mlog_errno(ret); + goto out; + } + ocfs2_zero_cluster_pages(inode, range_start, range_end, pages, numpages, phys, handle); @@ -5865,6 +5828,178 @@ out: return ret; } +static void ocfs2_zero_dinode_id2(struct inode *inode, struct ocfs2_dinode *di) +{ + unsigned int blocksize = 1 << inode->i_sb->s_blocksize_bits; + + memset(&di->id2, 0, blocksize - offsetof(struct ocfs2_dinode, id2)); +} + +void ocfs2_dinode_new_extent_list(struct inode *inode, + struct ocfs2_dinode *di) +{ + ocfs2_zero_dinode_id2(inode, di); + di->id2.i_list.l_tree_depth = 0; + di->id2.i_list.l_next_free_rec = 0; + di->id2.i_list.l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(inode->i_sb)); +} + +void ocfs2_set_inode_data_inline(struct inode *inode, struct ocfs2_dinode *di) +{ + struct ocfs2_inode_info *oi = OCFS2_I(inode); + struct ocfs2_inline_data *idata = &di->id2.i_data; + + spin_lock(&oi->ip_lock); + oi->ip_dyn_features |= OCFS2_INLINE_DATA_FL; + di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features); + spin_unlock(&oi->ip_lock); + + /* + * We clear the entire i_data structure here so that all + * fields can be properly initialized. + */ + ocfs2_zero_dinode_id2(inode, di); + + idata->id_count = cpu_to_le16(ocfs2_max_inline_data(inode->i_sb)); +} + +int ocfs2_convert_inline_data_to_extents(struct inode *inode, + struct buffer_head *di_bh) +{ + int ret, i, has_data, num_pages = 0; + handle_t *handle; + u64 uninitialized_var(block); + struct ocfs2_inode_info *oi = OCFS2_I(inode); + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + struct ocfs2_alloc_context *data_ac = NULL; + struct page **pages = NULL; + loff_t end = osb->s_clustersize; + + has_data = i_size_read(inode) ? 1 : 0; + + if (has_data) { + pages = kcalloc(ocfs2_pages_per_cluster(osb->sb), + sizeof(struct page *), GFP_NOFS); + if (pages == NULL) { + ret = -ENOMEM; + mlog_errno(ret); + goto out; + } + + ret = ocfs2_reserve_clusters(osb, 1, &data_ac); + if (ret) { + mlog_errno(ret); + goto out; + } + } + + handle = ocfs2_start_trans(osb, OCFS2_INLINE_TO_EXTENTS_CREDITS); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + mlog_errno(ret); + goto out_unlock; + } + + ret = ocfs2_journal_access(handle, inode, di_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + if (has_data) { + u32 bit_off, num; + unsigned int page_end; + u64 phys; + + ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off, + &num); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + /* + * Save two copies, one for insert, and one that can + * be changed by ocfs2_map_and_dirty_page() below. + */ + block = phys = ocfs2_clusters_to_blocks(inode->i_sb, bit_off); + + /* + * Non sparse file systems zero on extend, so no need + * to do that now. + */ + if (!ocfs2_sparse_alloc(osb) && + PAGE_CACHE_SIZE < osb->s_clustersize) + end = PAGE_CACHE_SIZE; + + ret = ocfs2_grab_eof_pages(inode, 0, end, pages, &num_pages); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + /* + * This should populate the 1st page for us and mark + * it up to date. + */ + ret = ocfs2_read_inline_data(inode, pages[0], di_bh); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + page_end = PAGE_CACHE_SIZE; + if (PAGE_CACHE_SIZE > osb->s_clustersize) + page_end = osb->s_clustersize; + + for (i = 0; i < num_pages; i++) + ocfs2_map_and_dirty_page(inode, handle, 0, page_end, + pages[i], i > 0, &phys); + } + + spin_lock(&oi->ip_lock); + oi->ip_dyn_features &= ~OCFS2_INLINE_DATA_FL; + di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features); + spin_unlock(&oi->ip_lock); + + ocfs2_dinode_new_extent_list(inode, di); + + ocfs2_journal_dirty(handle, di_bh); + + if (has_data) { + /* + * An error at this point should be extremely rare. If + * this proves to be false, we could always re-build + * the in-inode data from our pages. + */ + ret = ocfs2_insert_extent(osb, handle, inode, di_bh, + 0, block, 1, 0, NULL); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + inode->i_blocks = ocfs2_inode_sector_count(inode); + } + +out_commit: + ocfs2_commit_trans(osb, handle); + +out_unlock: + if (data_ac) + ocfs2_free_alloc_context(data_ac); + +out: + if (pages) { + ocfs2_unlock_and_free_pages(pages, num_pages); + kfree(pages); + } + + return ret; +} + /* * It is expected, that by the time you call this function, * inode->i_size and fe->i_size have been adjusted. @@ -6090,6 +6225,81 @@ bail: return status; } +/* + * 'start' is inclusive, 'end' is not. + */ +int ocfs2_truncate_inline(struct inode *inode, struct buffer_head *di_bh, + unsigned int start, unsigned int end, int trunc) +{ + int ret; + unsigned int numbytes; + handle_t *handle; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + struct ocfs2_inline_data *idata = &di->id2.i_data; + + if (end > i_size_read(inode)) + end = i_size_read(inode); + + BUG_ON(start >= end); + + if (!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) || + !(le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL) || + !ocfs2_supports_inline_data(osb)) { + ocfs2_error(inode->i_sb, + "Inline data flags for inode %llu don't agree! " + "Disk: 0x%x, Memory: 0x%x, Superblock: 0x%x\n", + (unsigned long long)OCFS2_I(inode)->ip_blkno, + le16_to_cpu(di->i_dyn_features), + OCFS2_I(inode)->ip_dyn_features, + osb->s_feature_incompat); + ret = -EROFS; + goto out; + } + + handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + mlog_errno(ret); + goto out; + } + + ret = ocfs2_journal_access(handle, inode, di_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + numbytes = end - start; + memset(idata->id_data + start, 0, numbytes); + + /* + * No need to worry about the data page here - it's been + * truncated already and inline data doesn't need it for + * pushing zero's to disk, so we'll let readpage pick it up + * later. + */ + if (trunc) { + i_size_write(inode, start); + di->i_size = cpu_to_le64(start); + } + + inode->i_blocks = ocfs2_inode_sector_count(inode); + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + + di->i_ctime = di->i_mtime = cpu_to_le64(inode->i_ctime.tv_sec); + di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec); + + ocfs2_journal_dirty(handle, di_bh); + +out_commit: + ocfs2_commit_trans(osb, handle); + +out: + return ret; +} + static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc) { /* diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h index 990df48ae8d3..42ff94bd8011 100644 --- a/fs/ocfs2/alloc.h +++ b/fs/ocfs2/alloc.h @@ -62,6 +62,11 @@ static inline int ocfs2_extend_meta_needed(struct ocfs2_dinode *fe) return le16_to_cpu(fe->id2.i_list.l_tree_depth) + 2; } +void ocfs2_dinode_new_extent_list(struct inode *inode, struct ocfs2_dinode *di); +void ocfs2_set_inode_data_inline(struct inode *inode, struct ocfs2_dinode *di); +int ocfs2_convert_inline_data_to_extents(struct inode *inode, + struct buffer_head *di_bh); + int ocfs2_truncate_log_init(struct ocfs2_super *osb); void ocfs2_truncate_log_shutdown(struct ocfs2_super *osb); void ocfs2_schedule_truncate_log_flush(struct ocfs2_super *osb, @@ -115,6 +120,8 @@ int ocfs2_commit_truncate(struct ocfs2_super *osb, struct inode *inode, struct buffer_head *fe_bh, struct ocfs2_truncate_context *tc); +int ocfs2_truncate_inline(struct inode *inode, struct buffer_head *di_bh, + unsigned int start, unsigned int end, int trunc); int ocfs2_find_leaf(struct inode *inode, struct ocfs2_extent_list *root_el, u32 cpos, struct buffer_head **leaf_bh); diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index f37f25c931f5..c69c1b300155 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -206,9 +206,70 @@ bail: return err; } +int ocfs2_read_inline_data(struct inode *inode, struct page *page, + struct buffer_head *di_bh) +{ + void *kaddr; + unsigned int size; + struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + + if (!(le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL)) { + ocfs2_error(inode->i_sb, "Inode %llu lost inline data flag", + (unsigned long long)OCFS2_I(inode)->ip_blkno); + return -EROFS; + } + + size = i_size_read(inode); + + if (size > PAGE_CACHE_SIZE || + size > ocfs2_max_inline_data(inode->i_sb)) { + ocfs2_error(inode->i_sb, + "Inode %llu has with inline data has bad size: %u", + (unsigned long long)OCFS2_I(inode)->ip_blkno, size); + return -EROFS; + } + + kaddr = kmap_atomic(page, KM_USER0); + if (size) + memcpy(kaddr, di->id2.i_data.id_data, size); + /* Clear the remaining part of the page */ + memset(kaddr + size, 0, PAGE_CACHE_SIZE - size); + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); + + SetPageUptodate(page); + + return 0; +} + +static int ocfs2_readpage_inline(struct inode *inode, struct page *page) +{ + int ret; + struct buffer_head *di_bh = NULL; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + + BUG_ON(!PageLocked(page)); + BUG_ON(!OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL); + + ret = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, &di_bh, + OCFS2_BH_CACHED, inode); + if (ret) { + mlog_errno(ret); + goto out; + } + + ret = ocfs2_read_inline_data(inode, page, di_bh); +out: + unlock_page(page); + + brelse(di_bh); + return ret; +} + static int ocfs2_readpage(struct file *file, struct page *page) { struct inode *inode = page->mapping->host; + struct ocfs2_inode_info *oi = OCFS2_I(inode); loff_t start = (loff_t)page->index << PAGE_CACHE_SHIFT; int ret, unlock = 1; @@ -222,7 +283,7 @@ static int ocfs2_readpage(struct file *file, struct page *page) goto out; } - if (down_read_trylock(&OCFS2_I(inode)->ip_alloc_sem) == 0) { + if (down_read_trylock(&oi->ip_alloc_sem) == 0) { ret = AOP_TRUNCATED_PAGE; goto out_meta_unlock; } @@ -252,7 +313,10 @@ static int ocfs2_readpage(struct file *file, struct page *page) goto out_alloc; } - ret = block_read_full_page(page, ocfs2_get_block); + if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) + ret = ocfs2_readpage_inline(inode, page); + else + ret = block_read_full_page(page, ocfs2_get_block); unlock = 0; ocfs2_data_unlock(inode, 0); @@ -301,12 +365,8 @@ int ocfs2_prepare_write_nolock(struct inode *inode, struct page *page, { int ret; - down_read(&OCFS2_I(inode)->ip_alloc_sem); - ret = block_prepare_write(page, from, to, ocfs2_get_block); - up_read(&OCFS2_I(inode)->ip_alloc_sem); - return ret; } @@ -401,7 +461,9 @@ static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block) down_read(&OCFS2_I(inode)->ip_alloc_sem); } - err = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL, NULL); + if (!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)) + err = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL, + NULL); if (!INODE_JOURNAL(inode)) { up_read(&OCFS2_I(inode)->ip_alloc_sem); @@ -415,7 +477,6 @@ static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block) goto bail; } - bail: status = err ? 0 : p_blkno; @@ -570,6 +631,13 @@ static ssize_t ocfs2_direct_IO(int rw, mlog_entry_void(); + /* + * Fallback to buffered I/O if we see an inode without + * extents. + */ + if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) + return 0; + if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) { /* * We get PR data locks even for O_DIRECT. This @@ -834,18 +902,22 @@ struct ocfs2_write_ctxt { struct ocfs2_cached_dealloc_ctxt w_dealloc; }; -static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc) +void ocfs2_unlock_and_free_pages(struct page **pages, int num_pages) { int i; - for(i = 0; i < wc->w_num_pages; i++) { - if (wc->w_pages[i] == NULL) - continue; - - unlock_page(wc->w_pages[i]); - mark_page_accessed(wc->w_pages[i]); - page_cache_release(wc->w_pages[i]); + for(i = 0; i < num_pages; i++) { + if (pages[i]) { + unlock_page(pages[i]); + mark_page_accessed(pages[i]); + page_cache_release(pages[i]); + } } +} + +static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc) +{ + ocfs2_unlock_and_free_pages(wc->w_pages, wc->w_num_pages); brelse(wc->w_di_bh); kfree(wc); @@ -1360,6 +1432,160 @@ out: return ret; } +static int ocfs2_write_begin_inline(struct address_space *mapping, + struct inode *inode, + struct ocfs2_write_ctxt *wc) +{ + int ret; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + struct page *page; + handle_t *handle; + struct ocfs2_dinode *di = (struct ocfs2_dinode *)wc->w_di_bh->b_data; + + page = find_or_create_page(mapping, 0, GFP_NOFS); + if (!page) { + ret = -ENOMEM; + mlog_errno(ret); + goto out; + } + /* + * If we don't set w_num_pages then this page won't get unlocked + * and freed on cleanup of the write context. + */ + wc->w_pages[0] = wc->w_target_page = page; + wc->w_num_pages = 1; + + handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + mlog_errno(ret); + goto out; + } + + ret = ocfs2_journal_access(handle, inode, wc->w_di_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + ocfs2_commit_trans(osb, handle); + + mlog_errno(ret); + goto out; + } + + if (!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)) + ocfs2_set_inode_data_inline(inode, di); + + if (!PageUptodate(page)) { + ret = ocfs2_read_inline_data(inode, page, wc->w_di_bh); + if (ret) { + ocfs2_commit_trans(osb, handle); + + goto out; + } + } + + wc->w_handle = handle; +out: + return ret; +} + +int ocfs2_size_fits_inline_data(struct buffer_head *di_bh, u64 new_size) +{ + struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + + if (new_size < le16_to_cpu(di->id2.i_data.id_count)) + return 1; + return 0; +} + +static int ocfs2_try_to_write_inline_data(struct address_space *mapping, + struct inode *inode, loff_t pos, + unsigned len, struct page *mmap_page, + struct ocfs2_write_ctxt *wc) +{ + int ret, written = 0; + loff_t end = pos + len; + struct ocfs2_inode_info *oi = OCFS2_I(inode); + + mlog(0, "Inode %llu, write of %u bytes at off %llu. features: 0x%x\n", + (unsigned long long)oi->ip_blkno, len, (unsigned long long)pos, + oi->ip_dyn_features); + + /* + * Handle inodes which already have inline data 1st. + */ + if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) { + if (mmap_page == NULL && + ocfs2_size_fits_inline_data(wc->w_di_bh, end)) + goto do_inline_write; + + /* + * The write won't fit - we have to give this inode an + * inline extent list now. + */ + ret = ocfs2_convert_inline_data_to_extents(inode, wc->w_di_bh); + if (ret) + mlog_errno(ret); + goto out; + } + + /* + * Check whether the inode can accept inline data. + */ + if (oi->ip_clusters != 0 || i_size_read(inode) != 0) + return 0; + + /* + * Check whether the write can fit. + */ + if (mmap_page || end > ocfs2_max_inline_data(inode->i_sb)) + return 0; + +do_inline_write: + ret = ocfs2_write_begin_inline(mapping, inode, wc); + if (ret) { + mlog_errno(ret); + goto out; + } + + /* + * This signals to the caller that the data can be written + * inline. + */ + written = 1; +out: + return written ? written : ret; +} + +/* + * This function only does anything for file systems which can't + * handle sparse files. + * + * What we want to do here is fill in any hole between the current end + * of allocation and the end of our write. That way the rest of the + * write path can treat it as an non-allocating write, which has no + * special case code for sparse/nonsparse files. + */ +static int ocfs2_expand_nonsparse_inode(struct inode *inode, loff_t pos, + unsigned len, + struct ocfs2_write_ctxt *wc) +{ + int ret; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + loff_t newsize = pos + len; + + if (ocfs2_sparse_alloc(osb)) + return 0; + + if (newsize <= i_size_read(inode)) + return 0; + + ret = ocfs2_extend_no_holes(inode, newsize, newsize - len); + if (ret) + mlog_errno(ret); + + return ret; +} + int ocfs2_write_begin_nolock(struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata, @@ -1381,6 +1607,25 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, return ret; } + if (ocfs2_supports_inline_data(osb)) { + ret = ocfs2_try_to_write_inline_data(mapping, inode, pos, len, + mmap_page, wc); + if (ret == 1) { + ret = 0; + goto success; + } + if (ret < 0) { + mlog_errno(ret); + goto out; + } + } + + ret = ocfs2_expand_nonsparse_inode(inode, pos, len, wc); + if (ret) { + mlog_errno(ret); + goto out; + } + ret = ocfs2_populate_write_desc(inode, wc, &clusters_to_alloc, &extents_to_split); if (ret) { @@ -1462,6 +1707,7 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, if (meta_ac) ocfs2_free_alloc_context(meta_ac); +success: *pagep = wc->w_target_page; *fsdata = wc; return 0; @@ -1478,9 +1724,9 @@ out: return ret; } -int ocfs2_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata) +static int ocfs2_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { int ret; struct buffer_head *di_bh = NULL; @@ -1529,6 +1775,31 @@ out_fail: return ret; } +static void ocfs2_write_end_inline(struct inode *inode, loff_t pos, + unsigned len, unsigned *copied, + struct ocfs2_dinode *di, + struct ocfs2_write_ctxt *wc) +{ + void *kaddr; + + if (unlikely(*copied < len)) { + if (!PageUptodate(wc->w_target_page)) { + *copied = 0; + return; + } + } + + kaddr = kmap_atomic(wc->w_target_page, KM_USER0); + memcpy(di->id2.i_data.id_data + pos, kaddr + pos, *copied); + kunmap_atomic(kaddr, KM_USER0); + + mlog(0, "Data written to inode at offset %llu. " + "id_count = %u, copied = %u, i_dyn_features = 0x%x\n", + (unsigned long long)pos, *copied, + le16_to_cpu(di->id2.i_data.id_count), + le16_to_cpu(di->i_dyn_features)); +} + int ocfs2_write_end_nolock(struct address_space *mapping, loff_t pos, unsigned len, unsigned copied, struct page *page, void *fsdata) @@ -1542,6 +1813,11 @@ int ocfs2_write_end_nolock(struct address_space *mapping, handle_t *handle = wc->w_handle; struct page *tmppage; + if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { + ocfs2_write_end_inline(inode, pos, len, &copied, di, wc); + goto out_write_size; + } + if (unlikely(copied < len)) { if (!PageUptodate(wc->w_target_page)) copied = 0; @@ -1579,6 +1855,7 @@ int ocfs2_write_end_nolock(struct address_space *mapping, block_commit_write(tmppage, from, to); } +out_write_size: pos += copied; if (pos > inode->i_size) { i_size_write(inode, pos); @@ -1600,9 +1877,9 @@ int ocfs2_write_end_nolock(struct address_space *mapping, return copied; } -int ocfs2_write_end(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) +static int ocfs2_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) { int ret; struct inode *inode = mapping->host; @@ -1619,6 +1896,8 @@ int ocfs2_write_end(struct file *file, struct address_space *mapping, const struct address_space_operations ocfs2_aops = { .readpage = ocfs2_readpage, .writepage = ocfs2_writepage, + .write_begin = ocfs2_write_begin, + .write_end = ocfs2_write_end, .bmap = ocfs2_bmap, .sync_page = block_sync_page, .direct_IO = ocfs2_direct_IO, diff --git a/fs/ocfs2/aops.h b/fs/ocfs2/aops.h index 389579bd64e3..503e49232e11 100644 --- a/fs/ocfs2/aops.h +++ b/fs/ocfs2/aops.h @@ -34,6 +34,8 @@ int ocfs2_map_page_blocks(struct page *page, u64 *p_blkno, struct inode *inode, unsigned int from, unsigned int to, int new); +void ocfs2_unlock_and_free_pages(struct page **pages, int num_pages); + int walk_page_buffers( handle_t *handle, struct buffer_head *head, unsigned from, @@ -42,14 +44,6 @@ int walk_page_buffers( handle_t *handle, int (*fn)( handle_t *handle, struct buffer_head *bh)); -int ocfs2_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata); - -int ocfs2_write_end(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata); - int ocfs2_write_end_nolock(struct address_space *mapping, loff_t pos, unsigned len, unsigned copied, struct page *page, void *fsdata); @@ -59,6 +53,10 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, struct page **pagep, void **fsdata, struct buffer_head *di_bh, struct page *mmap_page); +int ocfs2_read_inline_data(struct inode *inode, struct page *page, + struct buffer_head *di_bh); +int ocfs2_size_fits_inline_data(struct buffer_head *di_bh, u64 new_size); + /* all ocfs2_dio_end_io()'s fault */ #define ocfs2_iocb_is_rw_locked(iocb) \ test_bit(0, (unsigned long *)&iocb->private) diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 2bd7f788cf34..9cc7c0418b70 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -216,8 +216,7 @@ static void o2hb_wait_on_io(struct o2hb_region *reg, wait_for_completion(&wc->wc_io_complete); } -static int o2hb_bio_end_io(struct bio *bio, - unsigned int bytes_done, +static void o2hb_bio_end_io(struct bio *bio, int error) { struct o2hb_bio_wait_ctxt *wc = bio->bi_private; @@ -227,12 +226,8 @@ static int o2hb_bio_end_io(struct bio *bio, wc->wc_error = error; } - if (bio->bi_size) - return 1; - o2hb_bio_wait_dec(wc, 1); bio_put(bio); - return 0; } /* Setup a Bio to cover I/O against num_slots slots starting at @@ -1377,7 +1372,7 @@ static ssize_t o2hb_region_pid_read(struct o2hb_region *reg, spin_lock(&o2hb_live_lock); if (reg->hr_task) - pid = reg->hr_task->pid; + pid = task_pid_nr(reg->hr_task); spin_unlock(&o2hb_live_lock); if (!pid) diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c index e9e042b93dbf..a4882c8df945 100644 --- a/fs/ocfs2/cluster/masklog.c +++ b/fs/ocfs2/cluster/masklog.c @@ -143,7 +143,7 @@ static struct kobj_type mlog_ktype = { }; static struct kset mlog_kset = { - .kobj = {.name = "logmask", .ktype = &mlog_ktype}, + .kobj = {.ktype = &mlog_ktype}, }; int mlog_sys_init(struct kset *o2cb_subsys) @@ -156,6 +156,7 @@ int mlog_sys_init(struct kset *o2cb_subsys) } mlog_attr_ptrs[i] = NULL; + kobject_set_name(&mlog_kset.kobj, "logmask"); kobj_set_kset_s(&mlog_kset, *o2cb_subsys); return kset_register(&mlog_kset); } diff --git a/fs/ocfs2/cluster/masklog.h b/fs/ocfs2/cluster/masklog.h index 75cd877f6d42..cd046060114e 100644 --- a/fs/ocfs2/cluster/masklog.h +++ b/fs/ocfs2/cluster/masklog.h @@ -192,7 +192,7 @@ extern struct mlog_bits mlog_and_bits, mlog_not_bits; * previous token if args expands to nothing. */ #define __mlog_printk(level, fmt, args...) \ - printk(level "(%u,%lu):%s:%d " fmt, current->pid, \ + printk(level "(%u,%lu):%s:%d " fmt, task_pid_nr(current), \ __mlog_cpu_guess, __PRETTY_FUNCTION__, __LINE__ , \ ##args) diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index 0d5fdde959c8..6a2f143e269c 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -55,10 +55,16 @@ #include "journal.h" #include "namei.h" #include "suballoc.h" +#include "super.h" #include "uptodate.h" #include "buffer_head_io.h" +#define NAMEI_RA_CHUNKS 2 +#define NAMEI_RA_BLOCKS 4 +#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS) +#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b)) + static unsigned char ocfs2_filetype_table[] = { DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK }; @@ -66,12 +72,614 @@ static unsigned char ocfs2_filetype_table[] = { static int ocfs2_extend_dir(struct ocfs2_super *osb, struct inode *dir, struct buffer_head *parent_fe_bh, + unsigned int blocks_wanted, struct buffer_head **new_de_bh); +static int ocfs2_do_extend_dir(struct super_block *sb, + handle_t *handle, + struct inode *dir, + struct buffer_head *parent_fe_bh, + struct ocfs2_alloc_context *data_ac, + struct ocfs2_alloc_context *meta_ac, + struct buffer_head **new_bh); + /* - * ocfs2_readdir() + * bh passed here can be an inode block or a dir data block, depending + * on the inode inline data flag. + */ +static int ocfs2_check_dir_entry(struct inode * dir, + struct ocfs2_dir_entry * de, + struct buffer_head * bh, + unsigned long offset) +{ + const char *error_msg = NULL; + const int rlen = le16_to_cpu(de->rec_len); + + if (rlen < OCFS2_DIR_REC_LEN(1)) + error_msg = "rec_len is smaller than minimal"; + else if (rlen % 4 != 0) + error_msg = "rec_len % 4 != 0"; + else if (rlen < OCFS2_DIR_REC_LEN(de->name_len)) + error_msg = "rec_len is too small for name_len"; + else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize) + error_msg = "directory entry across blocks"; + + if (error_msg != NULL) + mlog(ML_ERROR, "bad entry in directory #%llu: %s - " + "offset=%lu, inode=%llu, rec_len=%d, name_len=%d\n", + (unsigned long long)OCFS2_I(dir)->ip_blkno, error_msg, + offset, (unsigned long long)le64_to_cpu(de->inode), rlen, + de->name_len); + return error_msg == NULL ? 1 : 0; +} + +static inline int ocfs2_match(int len, + const char * const name, + struct ocfs2_dir_entry *de) +{ + if (len != de->name_len) + return 0; + if (!de->inode) + return 0; + return !memcmp(name, de->name, len); +} + +/* + * Returns 0 if not found, -1 on failure, and 1 on success + */ +static int inline ocfs2_search_dirblock(struct buffer_head *bh, + struct inode *dir, + const char *name, int namelen, + unsigned long offset, + char *first_de, + unsigned int bytes, + struct ocfs2_dir_entry **res_dir) +{ + struct ocfs2_dir_entry *de; + char *dlimit, *de_buf; + int de_len; + int ret = 0; + + mlog_entry_void(); + + de_buf = first_de; + dlimit = de_buf + bytes; + + while (de_buf < dlimit) { + /* this code is executed quadratically often */ + /* do minimal checking `by hand' */ + + de = (struct ocfs2_dir_entry *) de_buf; + + if (de_buf + namelen <= dlimit && + ocfs2_match(namelen, name, de)) { + /* found a match - just to be sure, do a full check */ + if (!ocfs2_check_dir_entry(dir, de, bh, offset)) { + ret = -1; + goto bail; + } + *res_dir = de; + ret = 1; + goto bail; + } + + /* prevent looping on a bad block */ + de_len = le16_to_cpu(de->rec_len); + if (de_len <= 0) { + ret = -1; + goto bail; + } + + de_buf += de_len; + offset += de_len; + } + +bail: + mlog_exit(ret); + return ret; +} + +static struct buffer_head *ocfs2_find_entry_id(const char *name, + int namelen, + struct inode *dir, + struct ocfs2_dir_entry **res_dir) +{ + int ret, found; + struct buffer_head *di_bh = NULL; + struct ocfs2_dinode *di; + struct ocfs2_inline_data *data; + + ret = ocfs2_read_block(OCFS2_SB(dir->i_sb), OCFS2_I(dir)->ip_blkno, + &di_bh, OCFS2_BH_CACHED, dir); + if (ret) { + mlog_errno(ret); + goto out; + } + + di = (struct ocfs2_dinode *)di_bh->b_data; + data = &di->id2.i_data; + + found = ocfs2_search_dirblock(di_bh, dir, name, namelen, 0, + data->id_data, i_size_read(dir), res_dir); + if (found == 1) + return di_bh; + + brelse(di_bh); +out: + return NULL; +} + +struct buffer_head *ocfs2_find_entry_el(const char *name, int namelen, + struct inode *dir, + struct ocfs2_dir_entry **res_dir) +{ + struct super_block *sb; + struct buffer_head *bh_use[NAMEI_RA_SIZE]; + struct buffer_head *bh, *ret = NULL; + unsigned long start, block, b; + int ra_max = 0; /* Number of bh's in the readahead + buffer, bh_use[] */ + int ra_ptr = 0; /* Current index into readahead + buffer */ + int num = 0; + int nblocks, i, err; + + mlog_entry_void(); + + sb = dir->i_sb; + + nblocks = i_size_read(dir) >> sb->s_blocksize_bits; + start = OCFS2_I(dir)->ip_dir_start_lookup; + if (start >= nblocks) + start = 0; + block = start; + +restart: + do { + /* + * We deal with the read-ahead logic here. + */ + if (ra_ptr >= ra_max) { + /* Refill the readahead buffer */ + ra_ptr = 0; + b = block; + for (ra_max = 0; ra_max < NAMEI_RA_SIZE; ra_max++) { + /* + * Terminate if we reach the end of the + * directory and must wrap, or if our + * search has finished at this block. + */ + if (b >= nblocks || (num && block == start)) { + bh_use[ra_max] = NULL; + break; + } + num++; + + bh = ocfs2_bread(dir, b++, &err, 1); + bh_use[ra_max] = bh; + } + } + if ((bh = bh_use[ra_ptr++]) == NULL) + goto next; + wait_on_buffer(bh); + if (!buffer_uptodate(bh)) { + /* read error, skip block & hope for the best */ + ocfs2_error(dir->i_sb, "reading directory %llu, " + "offset %lu\n", + (unsigned long long)OCFS2_I(dir)->ip_blkno, + block); + brelse(bh); + goto next; + } + i = ocfs2_search_dirblock(bh, dir, name, namelen, + block << sb->s_blocksize_bits, + bh->b_data, sb->s_blocksize, + res_dir); + if (i == 1) { + OCFS2_I(dir)->ip_dir_start_lookup = block; + ret = bh; + goto cleanup_and_exit; + } else { + brelse(bh); + if (i < 0) + goto cleanup_and_exit; + } + next: + if (++block >= nblocks) + block = 0; + } while (block != start); + + /* + * If the directory has grown while we were searching, then + * search the last part of the directory before giving up. + */ + block = nblocks; + nblocks = i_size_read(dir) >> sb->s_blocksize_bits; + if (block < nblocks) { + start = 0; + goto restart; + } + +cleanup_and_exit: + /* Clean up the read-ahead blocks */ + for (; ra_ptr < ra_max; ra_ptr++) + brelse(bh_use[ra_ptr]); + + mlog_exit_ptr(ret); + return ret; +} + +/* + * Try to find an entry of the provided name within 'dir'. * + * If nothing was found, NULL is returned. Otherwise, a buffer_head + * and pointer to the dir entry are passed back. + * + * Caller can NOT assume anything about the contents of the + * buffer_head - it is passed back only so that it can be passed into + * any one of the manipulation functions (add entry, delete entry, + * etc). As an example, bh in the extent directory case is a data + * block, in the inline-data case it actually points to an inode. */ -int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir) +struct buffer_head *ocfs2_find_entry(const char *name, int namelen, + struct inode *dir, + struct ocfs2_dir_entry **res_dir) +{ + *res_dir = NULL; + + if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) + return ocfs2_find_entry_id(name, namelen, dir, res_dir); + + return ocfs2_find_entry_el(name, namelen, dir, res_dir); +} + +/* + * Update inode number and type of a previously found directory entry. + */ +int ocfs2_update_entry(struct inode *dir, handle_t *handle, + struct buffer_head *de_bh, struct ocfs2_dir_entry *de, + struct inode *new_entry_inode) +{ + int ret; + + /* + * The same code works fine for both inline-data and extent + * based directories, so no need to split this up. + */ + + ret = ocfs2_journal_access(handle, dir, de_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); + goto out; + } + + de->inode = cpu_to_le64(OCFS2_I(new_entry_inode)->ip_blkno); + ocfs2_set_de_type(de, new_entry_inode->i_mode); + + ocfs2_journal_dirty(handle, de_bh); + +out: + return ret; +} + +static int __ocfs2_delete_entry(handle_t *handle, struct inode *dir, + struct ocfs2_dir_entry *de_del, + struct buffer_head *bh, char *first_de, + unsigned int bytes) +{ + struct ocfs2_dir_entry *de, *pde; + int i, status = -ENOENT; + + mlog_entry("(0x%p, 0x%p, 0x%p, 0x%p)\n", handle, dir, de_del, bh); + + i = 0; + pde = NULL; + de = (struct ocfs2_dir_entry *) first_de; + while (i < bytes) { + if (!ocfs2_check_dir_entry(dir, de, bh, i)) { + status = -EIO; + mlog_errno(status); + goto bail; + } + if (de == de_del) { + status = ocfs2_journal_access(handle, dir, bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (status < 0) { + status = -EIO; + mlog_errno(status); + goto bail; + } + if (pde) + pde->rec_len = + cpu_to_le16(le16_to_cpu(pde->rec_len) + + le16_to_cpu(de->rec_len)); + else + de->inode = 0; + dir->i_version++; + status = ocfs2_journal_dirty(handle, bh); + goto bail; + } + i += le16_to_cpu(de->rec_len); + pde = de; + de = (struct ocfs2_dir_entry *)((char *)de + le16_to_cpu(de->rec_len)); + } +bail: + mlog_exit(status); + return status; +} + +static inline int ocfs2_delete_entry_id(handle_t *handle, + struct inode *dir, + struct ocfs2_dir_entry *de_del, + struct buffer_head *bh) +{ + int ret; + struct buffer_head *di_bh = NULL; + struct ocfs2_dinode *di; + struct ocfs2_inline_data *data; + + ret = ocfs2_read_block(OCFS2_SB(dir->i_sb), OCFS2_I(dir)->ip_blkno, + &di_bh, OCFS2_BH_CACHED, dir); + if (ret) { + mlog_errno(ret); + goto out; + } + + di = (struct ocfs2_dinode *)di_bh->b_data; + data = &di->id2.i_data; + + ret = __ocfs2_delete_entry(handle, dir, de_del, bh, data->id_data, + i_size_read(dir)); + + brelse(di_bh); +out: + return ret; +} + +static inline int ocfs2_delete_entry_el(handle_t *handle, + struct inode *dir, + struct ocfs2_dir_entry *de_del, + struct buffer_head *bh) +{ + return __ocfs2_delete_entry(handle, dir, de_del, bh, bh->b_data, + bh->b_size); +} + +/* + * ocfs2_delete_entry deletes a directory entry by merging it with the + * previous entry + */ +int ocfs2_delete_entry(handle_t *handle, + struct inode *dir, + struct ocfs2_dir_entry *de_del, + struct buffer_head *bh) +{ + if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) + return ocfs2_delete_entry_id(handle, dir, de_del, bh); + + return ocfs2_delete_entry_el(handle, dir, de_del, bh); +} + +/* + * Check whether 'de' has enough room to hold an entry of + * 'new_rec_len' bytes. + */ +static inline int ocfs2_dirent_would_fit(struct ocfs2_dir_entry *de, + unsigned int new_rec_len) +{ + unsigned int de_really_used; + + /* Check whether this is an empty record with enough space */ + if (le64_to_cpu(de->inode) == 0 && + le16_to_cpu(de->rec_len) >= new_rec_len) + return 1; + + /* + * Record might have free space at the end which we can + * use. + */ + de_really_used = OCFS2_DIR_REC_LEN(de->name_len); + if (le16_to_cpu(de->rec_len) >= (de_really_used + new_rec_len)) + return 1; + + return 0; +} + +/* we don't always have a dentry for what we want to add, so people + * like orphan dir can call this instead. + * + * If you pass me insert_bh, I'll skip the search of the other dir + * blocks and put the record in there. + */ +int __ocfs2_add_entry(handle_t *handle, + struct inode *dir, + const char *name, int namelen, + struct inode *inode, u64 blkno, + struct buffer_head *parent_fe_bh, + struct buffer_head *insert_bh) +{ + unsigned long offset; + unsigned short rec_len; + struct ocfs2_dir_entry *de, *de1; + struct ocfs2_dinode *di = (struct ocfs2_dinode *)parent_fe_bh->b_data; + struct super_block *sb = dir->i_sb; + int retval, status; + unsigned int size = sb->s_blocksize; + char *data_start = insert_bh->b_data; + + mlog_entry_void(); + + if (!namelen) + return -EINVAL; + + if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { + data_start = di->id2.i_data.id_data; + size = i_size_read(dir); + + BUG_ON(insert_bh != parent_fe_bh); + } + + rec_len = OCFS2_DIR_REC_LEN(namelen); + offset = 0; + de = (struct ocfs2_dir_entry *) data_start; + while (1) { + BUG_ON((char *)de >= (size + data_start)); + + /* These checks should've already been passed by the + * prepare function, but I guess we can leave them + * here anyway. */ + if (!ocfs2_check_dir_entry(dir, de, insert_bh, offset)) { + retval = -ENOENT; + goto bail; + } + if (ocfs2_match(namelen, name, de)) { + retval = -EEXIST; + goto bail; + } + + if (ocfs2_dirent_would_fit(de, rec_len)) { + dir->i_mtime = dir->i_ctime = CURRENT_TIME; + retval = ocfs2_mark_inode_dirty(handle, dir, parent_fe_bh); + if (retval < 0) { + mlog_errno(retval); + goto bail; + } + + status = ocfs2_journal_access(handle, dir, insert_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + /* By now the buffer is marked for journaling */ + offset += le16_to_cpu(de->rec_len); + if (le64_to_cpu(de->inode)) { + de1 = (struct ocfs2_dir_entry *)((char *) de + + OCFS2_DIR_REC_LEN(de->name_len)); + de1->rec_len = + cpu_to_le16(le16_to_cpu(de->rec_len) - + OCFS2_DIR_REC_LEN(de->name_len)); + de->rec_len = cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len)); + de = de1; + } + de->file_type = OCFS2_FT_UNKNOWN; + if (blkno) { + de->inode = cpu_to_le64(blkno); + ocfs2_set_de_type(de, inode->i_mode); + } else + de->inode = 0; + de->name_len = namelen; + memcpy(de->name, name, namelen); + + dir->i_version++; + status = ocfs2_journal_dirty(handle, insert_bh); + retval = 0; + goto bail; + } + offset += le16_to_cpu(de->rec_len); + de = (struct ocfs2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len)); + } + + /* when you think about it, the assert above should prevent us + * from ever getting here. */ + retval = -ENOSPC; +bail: + + mlog_exit(retval); + return retval; +} + +static int ocfs2_dir_foreach_blk_id(struct inode *inode, + u64 *f_version, + loff_t *f_pos, void *priv, + filldir_t filldir, int *filldir_err) +{ + int ret, i, filldir_ret; + unsigned long offset = *f_pos; + struct buffer_head *di_bh = NULL; + struct ocfs2_dinode *di; + struct ocfs2_inline_data *data; + struct ocfs2_dir_entry *de; + + ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno, + &di_bh, OCFS2_BH_CACHED, inode); + if (ret) { + mlog(ML_ERROR, "Unable to read inode block for dir %llu\n", + (unsigned long long)OCFS2_I(inode)->ip_blkno); + goto out; + } + + di = (struct ocfs2_dinode *)di_bh->b_data; + data = &di->id2.i_data; + + while (*f_pos < i_size_read(inode)) { +revalidate: + /* If the dir block has changed since the last call to + * readdir(2), then we might be pointing to an invalid + * dirent right now. Scan from the start of the block + * to make sure. */ + if (*f_version != inode->i_version) { + for (i = 0; i < i_size_read(inode) && i < offset; ) { + de = (struct ocfs2_dir_entry *) + (data->id_data + i); + /* It's too expensive to do a full + * dirent test each time round this + * loop, but we do have to test at + * least that it is non-zero. A + * failure will be detected in the + * dirent test below. */ + if (le16_to_cpu(de->rec_len) < + OCFS2_DIR_REC_LEN(1)) + break; + i += le16_to_cpu(de->rec_len); + } + *f_pos = offset = i; + *f_version = inode->i_version; + } + + de = (struct ocfs2_dir_entry *) (data->id_data + *f_pos); + if (!ocfs2_check_dir_entry(inode, de, di_bh, *f_pos)) { + /* On error, skip the f_pos to the end. */ + *f_pos = i_size_read(inode); + goto out; + } + offset += le16_to_cpu(de->rec_len); + if (le64_to_cpu(de->inode)) { + /* We might block in the next section + * if the data destination is + * currently swapped out. So, use a + * version stamp to detect whether or + * not the directory has been modified + * during the copy operation. + */ + u64 version = *f_version; + unsigned char d_type = DT_UNKNOWN; + + if (de->file_type < OCFS2_FT_MAX) + d_type = ocfs2_filetype_table[de->file_type]; + + filldir_ret = filldir(priv, de->name, + de->name_len, + *f_pos, + le64_to_cpu(de->inode), + d_type); + if (filldir_ret) { + if (filldir_err) + *filldir_err = filldir_ret; + break; + } + if (version != *f_version) + goto revalidate; + } + *f_pos += le16_to_cpu(de->rec_len); + } + +out: + brelse(di_bh); + + return 0; +} + +static int ocfs2_dir_foreach_blk_el(struct inode *inode, + u64 *f_version, + loff_t *f_pos, void *priv, + filldir_t filldir, int *filldir_err) { int error = 0; unsigned long offset, blk, last_ra_blk = 0; @@ -79,45 +687,23 @@ int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir) struct buffer_head * bh, * tmp; struct ocfs2_dir_entry * de; int err; - struct inode *inode = filp->f_path.dentry->d_inode; struct super_block * sb = inode->i_sb; unsigned int ra_sectors = 16; - int lock_level = 0; - - mlog_entry("dirino=%llu\n", - (unsigned long long)OCFS2_I(inode)->ip_blkno); stored = 0; bh = NULL; - error = ocfs2_meta_lock_atime(inode, filp->f_vfsmnt, &lock_level); - if (lock_level && error >= 0) { - /* We release EX lock which used to update atime - * and get PR lock again to reduce contention - * on commonly accessed directories. */ - ocfs2_meta_unlock(inode, 1); - lock_level = 0; - error = ocfs2_meta_lock(inode, NULL, 0); - } - if (error < 0) { - if (error != -ENOENT) - mlog_errno(error); - /* we haven't got any yet, so propagate the error. */ - stored = error; - goto bail_nolock; - } + offset = (*f_pos) & (sb->s_blocksize - 1); - offset = filp->f_pos & (sb->s_blocksize - 1); - - while (!error && !stored && filp->f_pos < i_size_read(inode)) { - blk = (filp->f_pos) >> sb->s_blocksize_bits; + while (!error && !stored && *f_pos < i_size_read(inode)) { + blk = (*f_pos) >> sb->s_blocksize_bits; bh = ocfs2_bread(inode, blk, &err, 0); if (!bh) { mlog(ML_ERROR, "directory #%llu contains a hole at offset %lld\n", (unsigned long long)OCFS2_I(inode)->ip_blkno, - filp->f_pos); - filp->f_pos += sb->s_blocksize - offset; + *f_pos); + *f_pos += sb->s_blocksize - offset; continue; } @@ -143,7 +729,7 @@ revalidate: * readdir(2), then we might be pointing to an invalid * dirent right now. Scan from the start of the block * to make sure. */ - if (filp->f_version != inode->i_version) { + if (*f_version != inode->i_version) { for (i = 0; i < sb->s_blocksize && i < offset; ) { de = (struct ocfs2_dir_entry *) (bh->b_data + i); /* It's too expensive to do a full @@ -158,21 +744,20 @@ revalidate: i += le16_to_cpu(de->rec_len); } offset = i; - filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) + *f_pos = ((*f_pos) & ~(sb->s_blocksize - 1)) | offset; - filp->f_version = inode->i_version; + *f_version = inode->i_version; } - while (!error && filp->f_pos < i_size_read(inode) + while (!error && *f_pos < i_size_read(inode) && offset < sb->s_blocksize) { de = (struct ocfs2_dir_entry *) (bh->b_data + offset); if (!ocfs2_check_dir_entry(inode, de, bh, offset)) { /* On error, skip the f_pos to the next block. */ - filp->f_pos = (filp->f_pos | - (sb->s_blocksize - 1)) + 1; + *f_pos = ((*f_pos) | (sb->s_blocksize - 1)) + 1; brelse(bh); - goto bail; + goto out; } offset += le16_to_cpu(de->rec_len); if (le64_to_cpu(de->inode)) { @@ -183,36 +768,109 @@ revalidate: * not the directory has been modified * during the copy operation. */ - unsigned long version = filp->f_version; + unsigned long version = *f_version; unsigned char d_type = DT_UNKNOWN; if (de->file_type < OCFS2_FT_MAX) d_type = ocfs2_filetype_table[de->file_type]; - error = filldir(dirent, de->name, + error = filldir(priv, de->name, de->name_len, - filp->f_pos, - ino_from_blkno(sb, le64_to_cpu(de->inode)), + *f_pos, + le64_to_cpu(de->inode), d_type); - if (error) + if (error) { + if (filldir_err) + *filldir_err = error; break; - if (version != filp->f_version) + } + if (version != *f_version) goto revalidate; stored ++; } - filp->f_pos += le16_to_cpu(de->rec_len); + *f_pos += le16_to_cpu(de->rec_len); } offset = 0; brelse(bh); } stored = 0; -bail: +out: + return stored; +} + +static int ocfs2_dir_foreach_blk(struct inode *inode, u64 *f_version, + loff_t *f_pos, void *priv, filldir_t filldir, + int *filldir_err) +{ + if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) + return ocfs2_dir_foreach_blk_id(inode, f_version, f_pos, priv, + filldir, filldir_err); + + return ocfs2_dir_foreach_blk_el(inode, f_version, f_pos, priv, filldir, + filldir_err); +} + +/* + * This is intended to be called from inside other kernel functions, + * so we fake some arguments. + */ +int ocfs2_dir_foreach(struct inode *inode, loff_t *f_pos, void *priv, + filldir_t filldir) +{ + int ret = 0, filldir_err = 0; + u64 version = inode->i_version; + + while (*f_pos < i_size_read(inode)) { + ret = ocfs2_dir_foreach_blk(inode, &version, f_pos, priv, + filldir, &filldir_err); + if (ret || filldir_err) + break; + } + + if (ret > 0) + ret = -EIO; + + return 0; +} + +/* + * ocfs2_readdir() + * + */ +int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir) +{ + int error = 0; + struct inode *inode = filp->f_path.dentry->d_inode; + int lock_level = 0; + + mlog_entry("dirino=%llu\n", + (unsigned long long)OCFS2_I(inode)->ip_blkno); + + error = ocfs2_meta_lock_atime(inode, filp->f_vfsmnt, &lock_level); + if (lock_level && error >= 0) { + /* We release EX lock which used to update atime + * and get PR lock again to reduce contention + * on commonly accessed directories. */ + ocfs2_meta_unlock(inode, 1); + lock_level = 0; + error = ocfs2_meta_lock(inode, NULL, 0); + } + if (error < 0) { + if (error != -ENOENT) + mlog_errno(error); + /* we haven't got any yet, so propagate the error. */ + goto bail_nolock; + } + + error = ocfs2_dir_foreach_blk(inode, &filp->f_version, &filp->f_pos, + dirent, filldir, NULL); + ocfs2_meta_unlock(inode, lock_level); bail_nolock: - mlog_exit(stored); + mlog_exit(error); - return stored; + return error; } /* @@ -252,6 +910,23 @@ leave: return status; } +/* + * Convenience function for callers which just want the block number + * mapped to a name and don't require the full dirent info, etc. + */ +int ocfs2_lookup_ino_from_name(struct inode *dir, const char *name, + int namelen, u64 *blkno) +{ + int ret; + struct buffer_head *bh = NULL; + struct ocfs2_dir_entry *dirent = NULL; + + ret = ocfs2_find_files_on_disk(name, namelen, blkno, dir, &bh, &dirent); + brelse(bh); + + return ret; +} + /* Check for a name within a directory. * * Return 0 if the name does not exist @@ -284,77 +959,414 @@ bail: return ret; } +struct ocfs2_empty_dir_priv { + unsigned seen_dot; + unsigned seen_dot_dot; + unsigned seen_other; +}; +static int ocfs2_empty_dir_filldir(void *priv, const char *name, int name_len, + loff_t pos, u64 ino, unsigned type) +{ + struct ocfs2_empty_dir_priv *p = priv; + + /* + * Check the positions of "." and ".." records to be sure + * they're in the correct place. + */ + if (name_len == 1 && !strncmp(".", name, 1) && pos == 0) { + p->seen_dot = 1; + return 0; + } + + if (name_len == 2 && !strncmp("..", name, 2) && + pos == OCFS2_DIR_REC_LEN(1)) { + p->seen_dot_dot = 1; + return 0; + } + + p->seen_other = 1; + return 1; +} /* * routine to check that the specified directory is empty (for rmdir) + * + * Returns 1 if dir is empty, zero otherwise. */ int ocfs2_empty_dir(struct inode *inode) { - unsigned long offset; - struct buffer_head * bh; - struct ocfs2_dir_entry * de, * de1; - struct super_block * sb; - int err; + int ret; + loff_t start = 0; + struct ocfs2_empty_dir_priv priv; + + memset(&priv, 0, sizeof(priv)); + + ret = ocfs2_dir_foreach(inode, &start, &priv, ocfs2_empty_dir_filldir); + if (ret) + mlog_errno(ret); - sb = inode->i_sb; - if ((i_size_read(inode) < - (OCFS2_DIR_REC_LEN(1) + OCFS2_DIR_REC_LEN(2))) || - !(bh = ocfs2_bread(inode, 0, &err, 0))) { - mlog(ML_ERROR, "bad directory (dir #%llu) - no data block\n", + if (!priv.seen_dot || !priv.seen_dot_dot) { + mlog(ML_ERROR, "bad directory (dir #%llu) - no `.' or `..'\n", (unsigned long long)OCFS2_I(inode)->ip_blkno); + /* + * XXX: Is it really safe to allow an unlink to continue? + */ return 1; } - de = (struct ocfs2_dir_entry *) bh->b_data; - de1 = (struct ocfs2_dir_entry *) - ((char *)de + le16_to_cpu(de->rec_len)); - if ((le64_to_cpu(de->inode) != OCFS2_I(inode)->ip_blkno) || - !le64_to_cpu(de1->inode) || - strcmp(".", de->name) || - strcmp("..", de1->name)) { - mlog(ML_ERROR, "bad directory (dir #%llu) - no `.' or `..'\n", - (unsigned long long)OCFS2_I(inode)->ip_blkno); - brelse(bh); - return 1; + return !priv.seen_other; +} + +static void ocfs2_fill_initial_dirents(struct inode *inode, + struct inode *parent, + char *start, unsigned int size) +{ + struct ocfs2_dir_entry *de = (struct ocfs2_dir_entry *)start; + + de->inode = cpu_to_le64(OCFS2_I(inode)->ip_blkno); + de->name_len = 1; + de->rec_len = + cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len)); + strcpy(de->name, "."); + ocfs2_set_de_type(de, S_IFDIR); + + de = (struct ocfs2_dir_entry *) ((char *)de + le16_to_cpu(de->rec_len)); + de->inode = cpu_to_le64(OCFS2_I(parent)->ip_blkno); + de->rec_len = cpu_to_le16(size - OCFS2_DIR_REC_LEN(1)); + de->name_len = 2; + strcpy(de->name, ".."); + ocfs2_set_de_type(de, S_IFDIR); +} + +/* + * This works together with code in ocfs2_mknod_locked() which sets + * the inline-data flag and initializes the inline-data section. + */ +static int ocfs2_fill_new_dir_id(struct ocfs2_super *osb, + handle_t *handle, + struct inode *parent, + struct inode *inode, + struct buffer_head *di_bh) +{ + int ret; + struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + struct ocfs2_inline_data *data = &di->id2.i_data; + unsigned int size = le16_to_cpu(data->id_count); + + ret = ocfs2_journal_access(handle, inode, di_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); + goto out; } - offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len); - de = (struct ocfs2_dir_entry *)((char *)de1 + le16_to_cpu(de1->rec_len)); - while (offset < i_size_read(inode) ) { - if (!bh || (void *)de >= (void *)(bh->b_data + sb->s_blocksize)) { - brelse(bh); - bh = ocfs2_bread(inode, - offset >> sb->s_blocksize_bits, &err, 0); - if (!bh) { - mlog(ML_ERROR, "dir %llu has a hole at %lu\n", - (unsigned long long)OCFS2_I(inode)->ip_blkno, offset); - offset += sb->s_blocksize; - continue; - } - de = (struct ocfs2_dir_entry *) bh->b_data; - } - if (!ocfs2_check_dir_entry(inode, de, bh, offset)) { - brelse(bh); - return 1; + + ocfs2_fill_initial_dirents(inode, parent, data->id_data, size); + + ocfs2_journal_dirty(handle, di_bh); + if (ret) { + mlog_errno(ret); + goto out; + } + + i_size_write(inode, size); + inode->i_nlink = 2; + inode->i_blocks = ocfs2_inode_sector_count(inode); + + ret = ocfs2_mark_inode_dirty(handle, inode, di_bh); + if (ret < 0) + mlog_errno(ret); + +out: + return ret; +} + +static int ocfs2_fill_new_dir_el(struct ocfs2_super *osb, + handle_t *handle, + struct inode *parent, + struct inode *inode, + struct buffer_head *fe_bh, + struct ocfs2_alloc_context *data_ac) +{ + int status; + struct buffer_head *new_bh = NULL; + + mlog_entry_void(); + + status = ocfs2_do_extend_dir(osb->sb, handle, inode, fe_bh, + data_ac, NULL, &new_bh); + if (status < 0) { + mlog_errno(status); + goto bail; + } + + ocfs2_set_new_buffer_uptodate(inode, new_bh); + + status = ocfs2_journal_access(handle, inode, new_bh, + OCFS2_JOURNAL_ACCESS_CREATE); + if (status < 0) { + mlog_errno(status); + goto bail; + } + memset(new_bh->b_data, 0, osb->sb->s_blocksize); + + ocfs2_fill_initial_dirents(inode, parent, new_bh->b_data, + osb->sb->s_blocksize); + + status = ocfs2_journal_dirty(handle, new_bh); + if (status < 0) { + mlog_errno(status); + goto bail; + } + + i_size_write(inode, inode->i_sb->s_blocksize); + inode->i_nlink = 2; + inode->i_blocks = ocfs2_inode_sector_count(inode); + status = ocfs2_mark_inode_dirty(handle, inode, fe_bh); + if (status < 0) { + mlog_errno(status); + goto bail; + } + + status = 0; +bail: + if (new_bh) + brelse(new_bh); + + mlog_exit(status); + return status; +} + +int ocfs2_fill_new_dir(struct ocfs2_super *osb, + handle_t *handle, + struct inode *parent, + struct inode *inode, + struct buffer_head *fe_bh, + struct ocfs2_alloc_context *data_ac) +{ + BUG_ON(!ocfs2_supports_inline_data(osb) && data_ac == NULL); + + if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) + return ocfs2_fill_new_dir_id(osb, handle, parent, inode, fe_bh); + + return ocfs2_fill_new_dir_el(osb, handle, parent, inode, fe_bh, + data_ac); +} + +static void ocfs2_expand_last_dirent(char *start, unsigned int old_size, + unsigned int new_size) +{ + struct ocfs2_dir_entry *de; + struct ocfs2_dir_entry *prev_de; + char *de_buf, *limit; + unsigned int bytes = new_size - old_size; + + limit = start + old_size; + de_buf = start; + de = (struct ocfs2_dir_entry *)de_buf; + do { + prev_de = de; + de_buf += le16_to_cpu(de->rec_len); + de = (struct ocfs2_dir_entry *)de_buf; + } while (de_buf < limit); + + le16_add_cpu(&prev_de->rec_len, bytes); +} + +/* + * We allocate enough clusters to fulfill "blocks_wanted", but set + * i_size to exactly one block. Ocfs2_extend_dir() will handle the + * rest automatically for us. + * + * *first_block_bh is a pointer to the 1st data block allocated to the + * directory. + */ +static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, + unsigned int blocks_wanted, + struct buffer_head **first_block_bh) +{ + int ret, credits = OCFS2_INLINE_TO_EXTENTS_CREDITS; + u32 alloc, bit_off, len; + struct super_block *sb = dir->i_sb; + u64 blkno, bytes = blocks_wanted << sb->s_blocksize_bits; + struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); + struct ocfs2_inode_info *oi = OCFS2_I(dir); + struct ocfs2_alloc_context *data_ac; + struct buffer_head *dirdata_bh = NULL; + struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + handle_t *handle; + + alloc = ocfs2_clusters_for_bytes(sb, bytes); + + /* + * We should never need more than 2 clusters for this - + * maximum dirent size is far less than one block. In fact, + * the only time we'd need more than one cluster is if + * blocksize == clustersize and the dirent won't fit in the + * extra space that the expansion to a single block gives. As + * of today, that only happens on 4k/4k file systems. + */ + BUG_ON(alloc > 2); + + ret = ocfs2_reserve_clusters(osb, alloc, &data_ac); + if (ret) { + mlog_errno(ret); + goto out; + } + + down_write(&oi->ip_alloc_sem); + + /* + * Prepare for worst case allocation scenario of two seperate + * extents. + */ + if (alloc == 2) + credits += OCFS2_SUBALLOC_ALLOC; + + handle = ocfs2_start_trans(osb, credits); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + mlog_errno(ret); + goto out_sem; + } + + /* + * Try to claim as many clusters as the bitmap can give though + * if we only get one now, that's enough to continue. The rest + * will be claimed after the conversion to extents. + */ + ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off, &len); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + /* + * Operations are carefully ordered so that we set up the new + * data block first. The conversion from inline data to + * extents follows. + */ + blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off); + dirdata_bh = sb_getblk(sb, blkno); + if (!dirdata_bh) { + ret = -EIO; + mlog_errno(ret); + goto out_commit; + } + + ocfs2_set_new_buffer_uptodate(dir, dirdata_bh); + + ret = ocfs2_journal_access(handle, dir, dirdata_bh, + OCFS2_JOURNAL_ACCESS_CREATE); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + memcpy(dirdata_bh->b_data, di->id2.i_data.id_data, i_size_read(dir)); + memset(dirdata_bh->b_data + i_size_read(dir), 0, + sb->s_blocksize - i_size_read(dir)); + ocfs2_expand_last_dirent(dirdata_bh->b_data, i_size_read(dir), + sb->s_blocksize); + + ret = ocfs2_journal_dirty(handle, dirdata_bh); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + /* + * Set extent, i_size, etc on the directory. After this, the + * inode should contain the same exact dirents as before and + * be fully accessible from system calls. + * + * We let the later dirent insert modify c/mtime - to the user + * the data hasn't changed. + */ + ret = ocfs2_journal_access(handle, dir, di_bh, + OCFS2_JOURNAL_ACCESS_CREATE); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + spin_lock(&oi->ip_lock); + oi->ip_dyn_features &= ~OCFS2_INLINE_DATA_FL; + di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features); + spin_unlock(&oi->ip_lock); + + ocfs2_dinode_new_extent_list(dir, di); + + i_size_write(dir, sb->s_blocksize); + dir->i_mtime = dir->i_ctime = CURRENT_TIME; + + di->i_size = cpu_to_le64(sb->s_blocksize); + di->i_ctime = di->i_mtime = cpu_to_le64(dir->i_ctime.tv_sec); + di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(dir->i_ctime.tv_nsec); + dir->i_blocks = ocfs2_inode_sector_count(dir); + + /* + * This should never fail as our extent list is empty and all + * related blocks have been journaled already. + */ + ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 0, blkno, len, 0, + NULL); + if (ret) { + mlog_errno(ret); + goto out; + } + + ret = ocfs2_journal_dirty(handle, di_bh); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + /* + * We asked for two clusters, but only got one in the 1st + * pass. Claim the 2nd cluster as a separate extent. + */ + if (alloc > len) { + ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off, + &len); + if (ret) { + mlog_errno(ret); + goto out_commit; } - if (le64_to_cpu(de->inode)) { - brelse(bh); - return 0; + blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off); + + ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 1, blkno, + len, 0, NULL); + if (ret) { + mlog_errno(ret); + goto out; } - offset += le16_to_cpu(de->rec_len); - de = (struct ocfs2_dir_entry *) - ((char *)de + le16_to_cpu(de->rec_len)); } - brelse(bh); - return 1; + + *first_block_bh = dirdata_bh; + dirdata_bh = NULL; + +out_commit: + ocfs2_commit_trans(osb, handle); + +out_sem: + up_write(&oi->ip_alloc_sem); + +out: + if (data_ac) + ocfs2_free_alloc_context(data_ac); + + brelse(dirdata_bh); + + return ret; } /* returns a bh of the 1st new block in the allocation. */ -int ocfs2_do_extend_dir(struct super_block *sb, - handle_t *handle, - struct inode *dir, - struct buffer_head *parent_fe_bh, - struct ocfs2_alloc_context *data_ac, - struct ocfs2_alloc_context *meta_ac, - struct buffer_head **new_bh) +static int ocfs2_do_extend_dir(struct super_block *sb, + handle_t *handle, + struct inode *dir, + struct buffer_head *parent_fe_bh, + struct ocfs2_alloc_context *data_ac, + struct ocfs2_alloc_context *meta_ac, + struct buffer_head **new_bh) { int status; int extend; @@ -396,10 +1408,18 @@ bail: return status; } -/* assumes you already have a cluster lock on the directory. */ +/* + * Assumes you already have a cluster lock on the directory. + * + * 'blocks_wanted' is only used if we have an inline directory which + * is to be turned into an extent based one. The size of the dirent to + * insert might be larger than the space gained by growing to just one + * block, so we may have to grow the inode by two blocks in that case. + */ static int ocfs2_extend_dir(struct ocfs2_super *osb, struct inode *dir, struct buffer_head *parent_fe_bh, + unsigned int blocks_wanted, struct buffer_head **new_de_bh) { int status = 0; @@ -415,6 +1435,38 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb, mlog_entry_void(); + if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { + status = ocfs2_expand_inline_dir(dir, parent_fe_bh, + blocks_wanted, &new_bh); + if (status) { + mlog_errno(status); + goto bail; + } + + if (blocks_wanted == 1) { + /* + * If the new dirent will fit inside the space + * created by pushing out to one block, then + * we can complete the operation + * here. Otherwise we have to expand i_size + * and format the 2nd block below. + */ + BUG_ON(new_bh == NULL); + goto bail_bh; + } + + /* + * Get rid of 'new_bh' - we want to format the 2nd + * data block and return that instead. + */ + brelse(new_bh); + new_bh = NULL; + + dir_i_size = i_size_read(dir); + credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS; + goto do_extend; + } + dir_i_size = i_size_read(dir); mlog(0, "extending dir %llu (i_size = %lld)\n", (unsigned long long)OCFS2_I(dir)->ip_blkno, dir_i_size); @@ -452,6 +1504,7 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb, credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS; } +do_extend: down_write(&OCFS2_I(dir)->ip_alloc_sem); drop_alloc_sem = 1; @@ -497,6 +1550,7 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb, goto bail; } +bail_bh: *new_de_bh = new_bh; get_bh(*new_de_bh); bail: @@ -517,41 +1571,71 @@ bail: return status; } -/* - * Search the dir for a good spot, extending it if necessary. The - * block containing an appropriate record is returned in ret_de_bh. - */ -int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb, - struct inode *dir, - struct buffer_head *parent_fe_bh, - const char *name, - int namelen, - struct buffer_head **ret_de_bh) +static int ocfs2_find_dir_space_id(struct inode *dir, struct buffer_head *di_bh, + const char *name, int namelen, + struct buffer_head **ret_de_bh, + unsigned int *blocks_wanted) { - unsigned long offset; - struct buffer_head * bh = NULL; - unsigned short rec_len; - struct ocfs2_dinode *fe; - struct ocfs2_dir_entry *de; - struct super_block *sb; - int status; + int ret; + struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + struct ocfs2_dir_entry *de, *last_de = NULL; + char *de_buf, *limit; + unsigned long offset = 0; + unsigned int rec_len, new_rec_len; + + de_buf = di->id2.i_data.id_data; + limit = de_buf + i_size_read(dir); + rec_len = OCFS2_DIR_REC_LEN(namelen); - mlog_entry_void(); + while (de_buf < limit) { + de = (struct ocfs2_dir_entry *)de_buf; - mlog(0, "getting ready to insert namelen %d into dir %llu\n", - namelen, (unsigned long long)OCFS2_I(dir)->ip_blkno); + if (!ocfs2_check_dir_entry(dir, de, di_bh, offset)) { + ret = -ENOENT; + goto out; + } + if (ocfs2_match(namelen, name, de)) { + ret = -EEXIST; + goto out; + } + if (ocfs2_dirent_would_fit(de, rec_len)) { + /* Ok, we found a spot. Return this bh and let + * the caller actually fill it in. */ + *ret_de_bh = di_bh; + get_bh(*ret_de_bh); + ret = 0; + goto out; + } - BUG_ON(!S_ISDIR(dir->i_mode)); - fe = (struct ocfs2_dinode *) parent_fe_bh->b_data; - BUG_ON(le64_to_cpu(fe->i_size) != i_size_read(dir)); + last_de = de; + de_buf += le16_to_cpu(de->rec_len); + offset += le16_to_cpu(de->rec_len); + } - sb = dir->i_sb; + /* + * We're going to require expansion of the directory - figure + * out how many blocks we'll need so that a place for the + * dirent can be found. + */ + *blocks_wanted = 1; + new_rec_len = le16_to_cpu(last_de->rec_len) + (dir->i_sb->s_blocksize - i_size_read(dir)); + if (new_rec_len < (rec_len + OCFS2_DIR_REC_LEN(last_de->name_len))) + *blocks_wanted = 2; + + ret = -ENOSPC; +out: + return ret; +} - if (!namelen) { - status = -EINVAL; - mlog_errno(status); - goto bail; - } +static int ocfs2_find_dir_space_el(struct inode *dir, const char *name, + int namelen, struct buffer_head **ret_de_bh) +{ + unsigned long offset; + struct buffer_head *bh = NULL; + unsigned short rec_len; + struct ocfs2_dir_entry *de; + struct super_block *sb = dir->i_sb; + int status; bh = ocfs2_bread(dir, 0, &status, 0); if (!bh) { @@ -568,17 +1652,11 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb, bh = NULL; if (i_size_read(dir) <= offset) { - status = ocfs2_extend_dir(osb, - dir, - parent_fe_bh, - &bh); - if (status < 0) { - mlog_errno(status); - goto bail; - } - BUG_ON(!bh); - *ret_de_bh = bh; - get_bh(*ret_de_bh); + /* + * Caller will have to expand this + * directory. + */ + status = -ENOSPC; goto bail; } bh = ocfs2_bread(dir, @@ -600,10 +1678,7 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb, status = -EEXIST; goto bail; } - if (((le64_to_cpu(de->inode) == 0) && - (le16_to_cpu(de->rec_len) >= rec_len)) || - (le16_to_cpu(de->rec_len) >= - (OCFS2_DIR_REC_LEN(de->name_len) + rec_len))) { + if (ocfs2_dirent_would_fit(de, rec_len)) { /* Ok, we found a spot. Return this bh and let * the caller actually fill it in. */ *ret_de_bh = bh; @@ -623,3 +1698,61 @@ bail: mlog_exit(status); return status; } + +int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb, + struct inode *dir, + struct buffer_head *parent_fe_bh, + const char *name, + int namelen, + struct buffer_head **ret_de_bh) +{ + int ret; + unsigned int blocks_wanted = 1; + struct buffer_head *bh = NULL; + + mlog(0, "getting ready to insert namelen %d into dir %llu\n", + namelen, (unsigned long long)OCFS2_I(dir)->ip_blkno); + + *ret_de_bh = NULL; + + if (!namelen) { + ret = -EINVAL; + mlog_errno(ret); + goto out; + } + + if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { + ret = ocfs2_find_dir_space_id(dir, parent_fe_bh, name, + namelen, &bh, &blocks_wanted); + } else + ret = ocfs2_find_dir_space_el(dir, name, namelen, &bh); + + if (ret && ret != -ENOSPC) { + mlog_errno(ret); + goto out; + } + + if (ret == -ENOSPC) { + /* + * We have to expand the directory to add this name. + */ + BUG_ON(bh); + + ret = ocfs2_extend_dir(osb, dir, parent_fe_bh, blocks_wanted, + &bh); + if (ret) { + if (ret != -ENOSPC) + mlog_errno(ret); + goto out; + } + + BUG_ON(!bh); + } + + *ret_de_bh = bh; + bh = NULL; +out: + if (bh) + brelse(bh); + return ret; +} diff --git a/fs/ocfs2/dir.h b/fs/ocfs2/dir.h index 3f67e146864a..ce48b9080d87 100644 --- a/fs/ocfs2/dir.h +++ b/fs/ocfs2/dir.h @@ -26,17 +26,49 @@ #ifndef OCFS2_DIR_H #define OCFS2_DIR_H +struct buffer_head *ocfs2_find_entry(const char *name, + int namelen, + struct inode *dir, + struct ocfs2_dir_entry **res_dir); +int ocfs2_delete_entry(handle_t *handle, + struct inode *dir, + struct ocfs2_dir_entry *de_del, + struct buffer_head *bh); +int __ocfs2_add_entry(handle_t *handle, + struct inode *dir, + const char *name, int namelen, + struct inode *inode, u64 blkno, + struct buffer_head *parent_fe_bh, + struct buffer_head *insert_bh); +static inline int ocfs2_add_entry(handle_t *handle, + struct dentry *dentry, + struct inode *inode, u64 blkno, + struct buffer_head *parent_fe_bh, + struct buffer_head *insert_bh) +{ + return __ocfs2_add_entry(handle, dentry->d_parent->d_inode, + dentry->d_name.name, dentry->d_name.len, + inode, blkno, parent_fe_bh, insert_bh); +} +int ocfs2_update_entry(struct inode *dir, handle_t *handle, + struct buffer_head *de_bh, struct ocfs2_dir_entry *de, + struct inode *new_entry_inode); + int ocfs2_check_dir_for_entry(struct inode *dir, const char *name, int namelen); -int ocfs2_empty_dir(struct inode *inode); /* FIXME: to namei.c */ +int ocfs2_empty_dir(struct inode *inode); int ocfs2_find_files_on_disk(const char *name, int namelen, u64 *blkno, struct inode *inode, struct buffer_head **dirent_bh, struct ocfs2_dir_entry **dirent); +int ocfs2_lookup_ino_from_name(struct inode *dir, const char *name, + int namelen, u64 *blkno); int ocfs2_readdir(struct file *filp, void *dirent, filldir_t filldir); +int ocfs2_dir_foreach(struct inode *inode, loff_t *f_pos, void *priv, + filldir_t filldir); int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb, struct inode *dir, struct buffer_head *parent_fe_bh, @@ -44,11 +76,11 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb, int namelen, struct buffer_head **ret_de_bh); struct ocfs2_alloc_context; -int ocfs2_do_extend_dir(struct super_block *sb, - handle_t *handle, - struct inode *dir, - struct buffer_head *parent_fe_bh, - struct ocfs2_alloc_context *data_ac, - struct ocfs2_alloc_context *meta_ac, - struct buffer_head **new_bh); +int ocfs2_fill_new_dir(struct ocfs2_super *osb, + handle_t *handle, + struct inode *parent, + struct inode *inode, + struct buffer_head *fe_bh, + struct ocfs2_alloc_context *data_ac); + #endif /* OCFS2_DIR_H */ diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c index 7418dc83de1c..6639baab0798 100644 --- a/fs/ocfs2/dlm/dlmfs.c +++ b/fs/ocfs2/dlm/dlmfs.c @@ -255,9 +255,8 @@ static ssize_t dlmfs_file_write(struct file *filp, return writelen; } -static void dlmfs_init_once(void *foo, - struct kmem_cache *cachep, - unsigned long flags) +static void dlmfs_init_once(struct kmem_cache *cachep, + void *foo) { struct dlmfs_inode_private *ip = (struct dlmfs_inode_private *) foo; @@ -588,13 +587,17 @@ static int __init init_dlmfs_fs(void) dlmfs_print_version(); + status = bdi_init(&dlmfs_backing_dev_info); + if (status) + return status; + dlmfs_inode_cache = kmem_cache_create("dlmfs_inode_cache", sizeof(struct dlmfs_inode_private), 0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), dlmfs_init_once); if (!dlmfs_inode_cache) - return -ENOMEM; + goto bail; cleanup_inode = 1; user_dlm_worker = create_singlethread_workqueue("user_dlm"); @@ -611,6 +614,7 @@ bail: kmem_cache_destroy(dlmfs_inode_cache); if (cleanup_worker) destroy_workqueue(user_dlm_worker); + bdi_destroy(&dlmfs_backing_dev_info); } else printk("OCFS2 User DLM kernel interface loaded\n"); return status; @@ -624,6 +628,8 @@ static void __exit exit_dlmfs_fs(void) destroy_workqueue(user_dlm_worker); kmem_cache_destroy(dlmfs_inode_cache); + + bdi_destroy(&dlmfs_backing_dev_info); } MODULE_AUTHOR("Oracle"); diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c index a2c33160bfd6..2fde7bf91434 100644 --- a/fs/ocfs2/dlm/dlmrecovery.c +++ b/fs/ocfs2/dlm/dlmrecovery.c @@ -259,7 +259,7 @@ static void dlm_print_reco_node_status(struct dlm_ctxt *dlm) struct dlm_lock_resource *res; mlog(ML_NOTICE, "%s(%d): recovery info, state=%s, dead=%u, master=%u\n", - dlm->name, dlm->dlm_reco_thread_task->pid, + dlm->name, task_pid_nr(dlm->dlm_reco_thread_task), dlm->reco.state & DLM_RECO_STATE_ACTIVE ? "ACTIVE" : "inactive", dlm->reco.dead_node, dlm->reco.new_master); @@ -420,7 +420,7 @@ void dlm_wait_for_recovery(struct dlm_ctxt *dlm) if (dlm_in_recovery(dlm)) { mlog(0, "%s: reco thread %d in recovery: " "state=%d, master=%u, dead=%u\n", - dlm->name, dlm->dlm_reco_thread_task->pid, + dlm->name, task_pid_nr(dlm->dlm_reco_thread_task), dlm->reco.state, dlm->reco.new_master, dlm->reco.dead_node); } @@ -483,7 +483,7 @@ static int dlm_do_recovery(struct dlm_ctxt *dlm) return 0; } mlog(0, "%s(%d):recovery thread found node %u in the recovery map!\n", - dlm->name, dlm->dlm_reco_thread_task->pid, + dlm->name, task_pid_nr(dlm->dlm_reco_thread_task), dlm->reco.dead_node); spin_unlock(&dlm->spinlock); @@ -507,7 +507,7 @@ static int dlm_do_recovery(struct dlm_ctxt *dlm) mlog(0, "another node will master this recovery session.\n"); } mlog(0, "dlm=%s (%d), new_master=%u, this node=%u, dead_node=%u\n", - dlm->name, dlm->dlm_reco_thread_task->pid, dlm->reco.new_master, + dlm->name, task_pid_nr(dlm->dlm_reco_thread_task), dlm->reco.new_master, dlm->node_num, dlm->reco.dead_node); /* it is safe to start everything back up here @@ -520,7 +520,7 @@ static int dlm_do_recovery(struct dlm_ctxt *dlm) master_here: mlog(0, "(%d) mastering recovery of %s:%u here(this=%u)!\n", - dlm->dlm_reco_thread_task->pid, + task_pid_nr(dlm->dlm_reco_thread_task), dlm->name, dlm->reco.dead_node, dlm->node_num); status = dlm_remaster_locks(dlm, dlm->reco.dead_node); diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index f71250ed166f..41c76ff2fcfb 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c @@ -1482,6 +1482,7 @@ static void __ocfs2_stuff_meta_lvb(struct inode *inode) lvb->lvb_imtime_packed = cpu_to_be64(ocfs2_pack_timespec(&inode->i_mtime)); lvb->lvb_iattr = cpu_to_be32(oi->ip_attr); + lvb->lvb_idynfeatures = cpu_to_be16(oi->ip_dyn_features); lvb->lvb_igeneration = cpu_to_be32(inode->i_generation); out: @@ -1515,6 +1516,7 @@ static void ocfs2_refresh_inode_from_lvb(struct inode *inode) i_size_write(inode, be64_to_cpu(lvb->lvb_isize)); oi->ip_attr = be32_to_cpu(lvb->lvb_iattr); + oi->ip_dyn_features = be16_to_cpu(lvb->lvb_idynfeatures); ocfs2_set_inode_flags(inode); /* fast-symlinks are a special case */ diff --git a/fs/ocfs2/dlmglue.h b/fs/ocfs2/dlmglue.h index 492bad32a8c0..87a785e41205 100644 --- a/fs/ocfs2/dlmglue.h +++ b/fs/ocfs2/dlmglue.h @@ -29,12 +29,12 @@ #include "dcache.h" -#define OCFS2_LVB_VERSION 4 +#define OCFS2_LVB_VERSION 5 struct ocfs2_meta_lvb { __u8 lvb_version; __u8 lvb_reserved0; - __be16 lvb_reserved1; + __be16 lvb_idynfeatures; __be32 lvb_iclusters; __be32 lvb_iuid; __be32 lvb_igid; diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c index bc48177bd183..c3bbc198f9ce 100644 --- a/fs/ocfs2/export.c +++ b/fs/ocfs2/export.c @@ -88,8 +88,6 @@ static struct dentry *ocfs2_get_parent(struct dentry *child) struct dentry *parent; struct inode *inode; struct inode *dir = child->d_inode; - struct buffer_head *dirent_bh = NULL; - struct ocfs2_dir_entry *dirent; mlog_entry("(0x%p, '%.*s')\n", child, child->d_name.len, child->d_name.name); @@ -105,8 +103,7 @@ static struct dentry *ocfs2_get_parent(struct dentry *child) goto bail; } - status = ocfs2_find_files_on_disk("..", 2, &blkno, dir, &dirent_bh, - &dirent); + status = ocfs2_lookup_ino_from_name(dir, "..", 2, &blkno); if (status < 0) { parent = ERR_PTR(-ENOENT); goto bail_unlock; @@ -131,9 +128,6 @@ static struct dentry *ocfs2_get_parent(struct dentry *child) bail_unlock: ocfs2_meta_unlock(dir, 0); - if (dirent_bh) - brelse(dirent_bh); - bail: mlog_exit_ptr(parent); diff --git a/fs/ocfs2/extent_map.c b/fs/ocfs2/extent_map.c index 03c1d365c78b..c58668a326fe 100644 --- a/fs/ocfs2/extent_map.c +++ b/fs/ocfs2/extent_map.c @@ -387,6 +387,12 @@ int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, struct ocfs2_extent_rec *rec; u32 coff; + if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { + ret = -ERANGE; + mlog_errno(ret); + goto out; + } + ret = ocfs2_extent_map_lookup(inode, v_cluster, p_cluster, num_clusters, extent_flags); if (ret == 0) diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index f3bc3658e7a5..f92fe91ff260 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -397,6 +397,15 @@ static int ocfs2_truncate_file(struct inode *inode, unmap_mapping_range(inode->i_mapping, new_i_size + PAGE_SIZE - 1, 0, 1); truncate_inode_pages(inode->i_mapping, new_i_size); + if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { + status = ocfs2_truncate_inline(inode, di_bh, new_i_size, + i_size_read(inode), 0); + if (status) + mlog_errno(status); + + goto bail_unlock_data; + } + /* alright, we're going to need to do a full blown alloc size * change. Orphan the inode so that recovery can complete the * truncate if necessary. This does the task of marking @@ -779,25 +788,6 @@ leave: return status; } -static int ocfs2_extend_allocation(struct inode *inode, u32 logical_start, - u32 clusters_to_add, int mark_unwritten) -{ - int ret; - - /* - * The alloc sem blocks peope in read/write from reading our - * allocation until we're done changing it. We depend on - * i_mutex to block other extend/truncate calls while we're - * here. - */ - down_write(&OCFS2_I(inode)->ip_alloc_sem); - ret = __ocfs2_extend_allocation(inode, logical_start, clusters_to_add, - mark_unwritten); - up_write(&OCFS2_I(inode)->ip_alloc_sem); - - return ret; -} - /* Some parts of this taken from generic_cont_expand, which turned out * to be too fragile to do exactly what we need without us having to * worry about recursive locking in ->prepare_write() and @@ -889,25 +879,48 @@ out: return ret; } -/* - * A tail_to_skip value > 0 indicates that we're being called from - * ocfs2_file_aio_write(). This has the following implications: - * - * - we don't want to update i_size - * - di_bh will be NULL, which is fine because it's only used in the - * case where we want to update i_size. - * - ocfs2_zero_extend() will then only be filling the hole created - * between i_size and the start of the write. - */ +int ocfs2_extend_no_holes(struct inode *inode, u64 new_i_size, u64 zero_to) +{ + int ret; + u32 clusters_to_add; + struct ocfs2_inode_info *oi = OCFS2_I(inode); + + clusters_to_add = ocfs2_clusters_for_bytes(inode->i_sb, new_i_size); + if (clusters_to_add < oi->ip_clusters) + clusters_to_add = 0; + else + clusters_to_add -= oi->ip_clusters; + + if (clusters_to_add) { + ret = __ocfs2_extend_allocation(inode, oi->ip_clusters, + clusters_to_add, 0); + if (ret) { + mlog_errno(ret); + goto out; + } + } + + /* + * Call this even if we don't add any clusters to the tree. We + * still need to zero the area between the old i_size and the + * new i_size. + */ + ret = ocfs2_zero_extend(inode, zero_to); + if (ret < 0) + mlog_errno(ret); + +out: + return ret; +} + static int ocfs2_extend_file(struct inode *inode, struct buffer_head *di_bh, - u64 new_i_size, - size_t tail_to_skip) + u64 new_i_size) { - int ret = 0; - u32 clusters_to_add = 0; + int ret = 0, data_locked = 0; + struct ocfs2_inode_info *oi = OCFS2_I(inode); - BUG_ON(!tail_to_skip && !di_bh); + BUG_ON(!di_bh); /* setattr sometimes calls us like this. */ if (new_i_size == 0) @@ -917,13 +930,18 @@ static int ocfs2_extend_file(struct inode *inode, goto out; BUG_ON(new_i_size < i_size_read(inode)); - if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) { - BUG_ON(tail_to_skip != 0); + /* + * Fall through for converting inline data, even if the fs + * supports sparse files. + * + * The check for inline data here is legal - nobody can add + * the feature since we have i_mutex. We must check it again + * after acquiring ip_alloc_sem though, as paths like mmap + * might have raced us to converting the inode to extents. + */ + if (!(oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) + && ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) goto out_update_size; - } - - clusters_to_add = ocfs2_clusters_for_bytes(inode->i_sb, new_i_size) - - OCFS2_I(inode)->ip_clusters; /* * protect the pages that ocfs2_zero_extend is going to be @@ -937,39 +955,52 @@ static int ocfs2_extend_file(struct inode *inode, mlog_errno(ret); goto out; } + data_locked = 1; + + /* + * The alloc sem blocks people in read/write from reading our + * allocation until we're done changing it. We depend on + * i_mutex to block other extend/truncate calls while we're + * here. + */ + down_write(&oi->ip_alloc_sem); + + if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) { + /* + * We can optimize small extends by keeping the inodes + * inline data. + */ + if (ocfs2_size_fits_inline_data(di_bh, new_i_size)) { + up_write(&oi->ip_alloc_sem); + goto out_update_size; + } + + ret = ocfs2_convert_inline_data_to_extents(inode, di_bh); + if (ret) { + up_write(&oi->ip_alloc_sem); - if (clusters_to_add) { - ret = ocfs2_extend_allocation(inode, - OCFS2_I(inode)->ip_clusters, - clusters_to_add, 0); - if (ret < 0) { mlog_errno(ret); goto out_unlock; } } - /* - * Call this even if we don't add any clusters to the tree. We - * still need to zero the area between the old i_size and the - * new i_size. - */ - ret = ocfs2_zero_extend(inode, (u64)new_i_size - tail_to_skip); + if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) + ret = ocfs2_extend_no_holes(inode, new_i_size, new_i_size); + + up_write(&oi->ip_alloc_sem); + if (ret < 0) { mlog_errno(ret); goto out_unlock; } out_update_size: - if (!tail_to_skip) { - /* We're being called from ocfs2_setattr() which wants - * us to update i_size */ - ret = ocfs2_simple_size_update(inode, di_bh, new_i_size); - if (ret < 0) - mlog_errno(ret); - } + ret = ocfs2_simple_size_update(inode, di_bh, new_i_size); + if (ret < 0) + mlog_errno(ret); out_unlock: - if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) + if (data_locked) ocfs2_data_unlock(inode, 1); out: @@ -1035,7 +1066,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) if (i_size_read(inode) > attr->ia_size) status = ocfs2_truncate_file(inode, bh, attr->ia_size); else - status = ocfs2_extend_file(inode, bh, attr->ia_size, 0); + status = ocfs2_extend_file(inode, bh, attr->ia_size); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); @@ -1243,6 +1274,31 @@ static int ocfs2_allocate_unwritten_extents(struct inode *inode, { int ret; u32 cpos, phys_cpos, clusters, alloc_size; + u64 end = start + len; + struct buffer_head *di_bh = NULL; + + if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { + ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), + OCFS2_I(inode)->ip_blkno, &di_bh, + OCFS2_BH_CACHED, inode); + if (ret) { + mlog_errno(ret); + goto out; + } + + /* + * Nothing to do if the requested reservation range + * fits within the inode. + */ + if (ocfs2_size_fits_inline_data(di_bh, end)) + goto out; + + ret = ocfs2_convert_inline_data_to_extents(inode, di_bh); + if (ret) { + mlog_errno(ret); + goto out; + } + } /* * We consider both start and len to be inclusive. @@ -1288,6 +1344,8 @@ next: ret = 0; out: + + brelse(di_bh); return ret; } @@ -1469,6 +1527,14 @@ static int ocfs2_remove_inode_range(struct inode *inode, if (byte_len == 0) return 0; + if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { + ret = ocfs2_truncate_inline(inode, di_bh, byte_start, + byte_start + byte_len, 1); + if (ret) + mlog_errno(ret); + return ret; + } + trunc_start = ocfs2_clusters_for_bytes(osb->sb, byte_start); trunc_len = (byte_start + byte_len) >> osb->s_clustersize_bits; if (trunc_len >= trunc_start) @@ -1713,15 +1779,13 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry, int appending, int *direct_io) { - int ret = 0, meta_level = appending; + int ret = 0, meta_level = 0; struct inode *inode = dentry->d_inode; - u32 clusters; - loff_t newsize, saved_pos; + loff_t saved_pos, end; /* - * We sample i_size under a read level meta lock to see if our write - * is extending the file, if it is we back off and get a write level - * meta lock. + * We start with a read level meta lock and only jump to an ex + * if we need to make modifications here. */ for(;;) { ret = ocfs2_meta_lock(inode, NULL, meta_level); @@ -1763,87 +1827,47 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry, saved_pos = *ppos; } - if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) { - loff_t end = saved_pos + count; + end = saved_pos + count; - /* - * Skip the O_DIRECT checks if we don't need - * them. - */ - if (!direct_io || !(*direct_io)) - break; - - /* - * Allowing concurrent direct writes means - * i_size changes wouldn't be synchronized, so - * one node could wind up truncating another - * nodes writes. - */ - if (end > i_size_read(inode)) { - *direct_io = 0; - break; - } - - /* - * We don't fill holes during direct io, so - * check for them here. If any are found, the - * caller will have to retake some cluster - * locks and initiate the io as buffered. - */ - ret = ocfs2_check_range_for_holes(inode, saved_pos, - count); - if (ret == 1) { - *direct_io = 0; - ret = 0; - } else if (ret < 0) - mlog_errno(ret); + /* + * Skip the O_DIRECT checks if we don't need + * them. + */ + if (!direct_io || !(*direct_io)) break; - } /* - * The rest of this loop is concerned with legacy file - * systems which don't support sparse files. + * There's no sane way to do direct writes to an inode + * with inline data. */ - - newsize = count + saved_pos; - - mlog(0, "pos=%lld newsize=%lld cursize=%lld\n", - (long long) saved_pos, (long long) newsize, - (long long) i_size_read(inode)); - - /* No need for a higher level metadata lock if we're - * never going past i_size. */ - if (newsize <= i_size_read(inode)) + if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { + *direct_io = 0; break; - - if (meta_level == 0) { - ocfs2_meta_unlock(inode, meta_level); - meta_level = 1; - continue; } - spin_lock(&OCFS2_I(inode)->ip_lock); - clusters = ocfs2_clusters_for_bytes(inode->i_sb, newsize) - - OCFS2_I(inode)->ip_clusters; - spin_unlock(&OCFS2_I(inode)->ip_lock); - - mlog(0, "Writing at EOF, may need more allocation: " - "i_size = %lld, newsize = %lld, need %u clusters\n", - (long long) i_size_read(inode), (long long) newsize, - clusters); - - /* We only want to continue the rest of this loop if - * our extend will actually require more - * allocation. */ - if (!clusters) + /* + * Allowing concurrent direct writes means + * i_size changes wouldn't be synchronized, so + * one node could wind up truncating another + * nodes writes. + */ + if (end > i_size_read(inode)) { + *direct_io = 0; break; - - ret = ocfs2_extend_file(inode, NULL, newsize, count); - if (ret < 0) { - if (ret != -ENOSPC) - mlog_errno(ret); - goto out_unlock; } + + /* + * We don't fill holes during direct io, so + * check for them here. If any are found, the + * caller will have to retake some cluster + * locks and initiate the io as buffered. + */ + ret = ocfs2_check_range_for_holes(inode, saved_pos, count); + if (ret == 1) { + *direct_io = 0; + ret = 0; + } else if (ret < 0) + mlog_errno(ret); break; } @@ -1857,143 +1881,13 @@ out: return ret; } -static inline void -ocfs2_set_next_iovec(const struct iovec **iovp, size_t *basep, size_t bytes) -{ - const struct iovec *iov = *iovp; - size_t base = *basep; - - do { - int copy = min(bytes, iov->iov_len - base); - - bytes -= copy; - base += copy; - if (iov->iov_len == base) { - iov++; - base = 0; - } - } while (bytes); - *iovp = iov; - *basep = base; -} - -static struct page * ocfs2_get_write_source(char **ret_src_buf, - const struct iovec *cur_iov, - size_t iov_offset) -{ - int ret; - char *buf = cur_iov->iov_base + iov_offset; - struct page *src_page = NULL; - unsigned long off; - - off = (unsigned long)(buf) & ~PAGE_CACHE_MASK; - - if (!segment_eq(get_fs(), KERNEL_DS)) { - /* - * Pull in the user page. We want to do this outside - * of the meta data locks in order to preserve locking - * order in case of page fault. - */ - ret = get_user_pages(current, current->mm, - (unsigned long)buf & PAGE_CACHE_MASK, 1, - 0, 0, &src_page, NULL); - if (ret == 1) - *ret_src_buf = kmap(src_page) + off; - else - src_page = ERR_PTR(-EFAULT); - } else { - *ret_src_buf = buf; - } - - return src_page; -} - -static void ocfs2_put_write_source(struct page *page) -{ - if (page) { - kunmap(page); - page_cache_release(page); - } -} - -static ssize_t ocfs2_file_buffered_write(struct file *file, loff_t *ppos, - const struct iovec *iov, - unsigned long nr_segs, - size_t count, - ssize_t o_direct_written) -{ - int ret = 0; - ssize_t copied, total = 0; - size_t iov_offset = 0, bytes; - loff_t pos; - const struct iovec *cur_iov = iov; - struct page *user_page, *page; - char * uninitialized_var(buf); - char *dst; - void *fsdata; - - /* - * handle partial DIO write. Adjust cur_iov if needed. - */ - ocfs2_set_next_iovec(&cur_iov, &iov_offset, o_direct_written); - - do { - pos = *ppos; - - user_page = ocfs2_get_write_source(&buf, cur_iov, iov_offset); - if (IS_ERR(user_page)) { - ret = PTR_ERR(user_page); - goto out; - } - - /* Stay within our page boundaries */ - bytes = min((PAGE_CACHE_SIZE - ((unsigned long)pos & ~PAGE_CACHE_MASK)), - (PAGE_CACHE_SIZE - ((unsigned long)buf & ~PAGE_CACHE_MASK))); - /* Stay within the vector boundary */ - bytes = min_t(size_t, bytes, cur_iov->iov_len - iov_offset); - /* Stay within count */ - bytes = min(bytes, count); - - page = NULL; - ret = ocfs2_write_begin(file, file->f_mapping, pos, bytes, 0, - &page, &fsdata); - if (ret) { - mlog_errno(ret); - goto out; - } - - dst = kmap_atomic(page, KM_USER0); - memcpy(dst + (pos & (loff_t)(PAGE_CACHE_SIZE - 1)), buf, bytes); - kunmap_atomic(dst, KM_USER0); - flush_dcache_page(page); - ocfs2_put_write_source(user_page); - - copied = ocfs2_write_end(file, file->f_mapping, pos, bytes, - bytes, page, fsdata); - if (copied < 0) { - mlog_errno(copied); - ret = copied; - goto out; - } - - total += copied; - *ppos = pos + copied; - count -= copied; - - ocfs2_set_next_iovec(&cur_iov, &iov_offset, copied); - } while(count); - -out: - return total ? total : ret; -} - static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { int ret, direct_io, appending, rw_level, have_alloc_sem = 0; - int can_do_direct, sync = 0; + int can_do_direct; ssize_t written = 0; size_t ocount; /* original count */ size_t count; /* after file limit checks */ @@ -2009,12 +1903,6 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, if (iocb->ki_left == 0) return 0; - ret = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ); - if (ret) - return ret; - - count = ocount; - vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); appending = file->f_flags & O_APPEND ? 1 : 0; @@ -2058,33 +1946,23 @@ relock: rw_level = -1; direct_io = 0; - sync = 1; goto relock; } - if (!sync && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) - sync = 1; - - /* - * XXX: Is it ok to execute these checks a second time? - */ - ret = generic_write_checks(file, ppos, &count, S_ISBLK(inode->i_mode)); - if (ret) - goto out; - - /* - * Set pos so that sync_page_range_nolock() below understands - * where to start from. We might've moved it around via the - * calls above. The range we want to actually sync starts from - * *ppos here. - * - */ - pos = *ppos; - /* communicate with ocfs2_dio_end_io */ ocfs2_iocb_set_rw_locked(iocb, rw_level); if (direct_io) { + ret = generic_segment_checks(iov, &nr_segs, &ocount, + VERIFY_READ); + if (ret) + goto out_dio; + + ret = generic_write_checks(file, ppos, &count, + S_ISBLK(inode->i_mode)); + if (ret) + goto out_dio; + written = generic_file_direct_write(iocb, iov, &nr_segs, *ppos, ppos, count, ocount); if (written < 0) { @@ -2092,14 +1970,8 @@ relock: goto out_dio; } } else { - written = ocfs2_file_buffered_write(file, ppos, iov, nr_segs, - count, written); - if (written < 0) { - ret = written; - if (ret != -EFAULT || ret != -ENOSPC) - mlog_errno(ret); - goto out; - } + written = generic_file_aio_write_nolock(iocb, iov, nr_segs, + *ppos); } out_dio: @@ -2129,97 +2001,12 @@ out_sems: if (have_alloc_sem) up_read(&inode->i_alloc_sem); - if (written > 0 && sync) { - ssize_t err; - - err = sync_page_range_nolock(inode, file->f_mapping, pos, count); - if (err < 0) - written = err; - } - mutex_unlock(&inode->i_mutex); mlog_exit(ret); return written ? written : ret; } -static int ocfs2_splice_write_actor(struct pipe_inode_info *pipe, - struct pipe_buffer *buf, - struct splice_desc *sd) -{ - int ret, count; - ssize_t copied = 0; - struct file *file = sd->u.file; - unsigned int offset; - struct page *page = NULL; - void *fsdata; - char *src, *dst; - - ret = buf->ops->confirm(pipe, buf); - if (ret) - goto out; - - offset = sd->pos & ~PAGE_CACHE_MASK; - count = sd->len; - if (count + offset > PAGE_CACHE_SIZE) - count = PAGE_CACHE_SIZE - offset; - - ret = ocfs2_write_begin(file, file->f_mapping, sd->pos, count, 0, - &page, &fsdata); - if (ret) { - mlog_errno(ret); - goto out; - } - - src = buf->ops->map(pipe, buf, 1); - dst = kmap_atomic(page, KM_USER1); - memcpy(dst + offset, src + buf->offset, count); - kunmap_atomic(dst, KM_USER1); - buf->ops->unmap(pipe, buf, src); - - copied = ocfs2_write_end(file, file->f_mapping, sd->pos, count, count, - page, fsdata); - if (copied < 0) { - mlog_errno(copied); - ret = copied; - goto out; - } -out: - - return copied ? copied : ret; -} - -static ssize_t __ocfs2_file_splice_write(struct pipe_inode_info *pipe, - struct file *out, - loff_t *ppos, - size_t len, - unsigned int flags) -{ - int ret, err; - struct address_space *mapping = out->f_mapping; - struct inode *inode = mapping->host; - struct splice_desc sd = { - .total_len = len, - .flags = flags, - .pos = *ppos, - .u.file = out, - }; - - ret = __splice_from_pipe(pipe, &sd, ocfs2_splice_write_actor); - if (ret > 0) { - *ppos += ret; - - if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(inode))) { - err = generic_osync_inode(inode, mapping, - OSYNC_METADATA|OSYNC_DATA); - if (err) - ret = err; - } - } - - return ret; -} - static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe, struct file *out, loff_t *ppos, @@ -2249,8 +2036,7 @@ static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe, goto out_unlock; } - /* ok, we're done with i_size and alloc work */ - ret = __ocfs2_file_splice_write(pipe, out, ppos, len, flags); + ret = generic_file_splice_write_nolock(pipe, out, ppos, len, flags); out_unlock: ocfs2_rw_unlock(inode, 1); diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h index 36fe27f268ee..066f14add3a8 100644 --- a/fs/ocfs2/file.h +++ b/fs/ocfs2/file.h @@ -47,6 +47,8 @@ int ocfs2_do_extend_allocation(struct ocfs2_super *osb, struct ocfs2_alloc_context *data_ac, struct ocfs2_alloc_context *meta_ac, enum ocfs2_alloc_restarted *reason_ret); +int ocfs2_extend_no_holes(struct inode *inode, u64 new_i_size, + u64 zero_to); int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di, u32 clusters_to_add, u32 extents_to_split, struct ocfs2_alloc_context **data_ac, diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index c53a6763bbbe..1d5e0cb0fda1 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c @@ -241,6 +241,7 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe, OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters); OCFS2_I(inode)->ip_attr = le32_to_cpu(fe->i_attr); + OCFS2_I(inode)->ip_dyn_features = le16_to_cpu(fe->i_dyn_features); inode->i_version = 1; inode->i_generation = le32_to_cpu(fe->i_generation); @@ -513,6 +514,10 @@ static int ocfs2_truncate_for_delete(struct ocfs2_super *osb, fe = (struct ocfs2_dinode *) fe_bh->b_data; + /* + * This check will also skip truncate of inodes with inline + * data and fast symlinks. + */ if (fe->i_clusters) { handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); if (IS_ERR(handle)) { @@ -1220,6 +1225,7 @@ int ocfs2_mark_inode_dirty(handle_t *handle, fe->i_clusters = cpu_to_le32(OCFS2_I(inode)->ip_clusters); ocfs2_get_inode_flags(OCFS2_I(inode)); fe->i_attr = cpu_to_le32(OCFS2_I(inode)->ip_attr); + fe->i_dyn_features = cpu_to_le16(OCFS2_I(inode)->ip_dyn_features); spin_unlock(&OCFS2_I(inode)->ip_lock); fe->i_size = cpu_to_le64(i_size_read(inode)); @@ -1257,6 +1263,7 @@ void ocfs2_refresh_inode(struct inode *inode, OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters); OCFS2_I(inode)->ip_attr = le32_to_cpu(fe->i_attr); + OCFS2_I(inode)->ip_dyn_features = le16_to_cpu(fe->i_dyn_features); ocfs2_set_inode_flags(inode); i_size_write(inode, le64_to_cpu(fe->i_size)); inode->i_nlink = le16_to_cpu(fe->i_links_count); diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h index a41d0817121b..70e881c55536 100644 --- a/fs/ocfs2/inode.h +++ b/fs/ocfs2/inode.h @@ -51,6 +51,7 @@ struct ocfs2_inode_info u32 ip_flags; /* see below */ u32 ip_attr; /* inode attributes */ + u16 ip_dyn_features; /* protected by recovery_lock. */ struct inode *ip_next_orphan; diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index dbfb20bb27ea..f9d01e25298d 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c @@ -35,13 +35,13 @@ #include "ocfs2.h" #include "alloc.h" +#include "dir.h" #include "dlmglue.h" #include "extent_map.h" #include "heartbeat.h" #include "inode.h" #include "journal.h" #include "localalloc.h" -#include "namei.h" #include "slot_map.h" #include "super.h" #include "vote.h" @@ -1213,17 +1213,49 @@ bail: return status; } +struct ocfs2_orphan_filldir_priv { + struct inode *head; + struct ocfs2_super *osb; +}; + +static int ocfs2_orphan_filldir(void *priv, const char *name, int name_len, + loff_t pos, u64 ino, unsigned type) +{ + struct ocfs2_orphan_filldir_priv *p = priv; + struct inode *iter; + + if (name_len == 1 && !strncmp(".", name, 1)) + return 0; + if (name_len == 2 && !strncmp("..", name, 2)) + return 0; + + /* Skip bad inodes so that recovery can continue */ + iter = ocfs2_iget(p->osb, ino, + OCFS2_FI_FLAG_ORPHAN_RECOVERY); + if (IS_ERR(iter)) + return 0; + + mlog(0, "queue orphan %llu\n", + (unsigned long long)OCFS2_I(iter)->ip_blkno); + /* No locking is required for the next_orphan queue as there + * is only ever a single process doing orphan recovery. */ + OCFS2_I(iter)->ip_next_orphan = p->head; + p->head = iter; + + return 0; +} + static int ocfs2_queue_orphans(struct ocfs2_super *osb, int slot, struct inode **head) { int status; struct inode *orphan_dir_inode = NULL; - struct inode *iter; - unsigned long offset, blk, local; - struct buffer_head *bh = NULL; - struct ocfs2_dir_entry *de; - struct super_block *sb = osb->sb; + struct ocfs2_orphan_filldir_priv priv; + loff_t pos = 0; + + priv.osb = osb; + priv.head = *head; orphan_dir_inode = ocfs2_get_system_file_inode(osb, ORPHAN_DIR_SYSTEM_INODE, @@ -1241,77 +1273,15 @@ static int ocfs2_queue_orphans(struct ocfs2_super *osb, goto out; } - offset = 0; - iter = NULL; - while(offset < i_size_read(orphan_dir_inode)) { - blk = offset >> sb->s_blocksize_bits; - - bh = ocfs2_bread(orphan_dir_inode, blk, &status, 0); - if (!bh) - status = -EINVAL; - if (status < 0) { - if (bh) - brelse(bh); - mlog_errno(status); - goto out_unlock; - } - - local = 0; - while(offset < i_size_read(orphan_dir_inode) - && local < sb->s_blocksize) { - de = (struct ocfs2_dir_entry *) (bh->b_data + local); - - if (!ocfs2_check_dir_entry(orphan_dir_inode, - de, bh, local)) { - status = -EINVAL; - mlog_errno(status); - brelse(bh); - goto out_unlock; - } - - local += le16_to_cpu(de->rec_len); - offset += le16_to_cpu(de->rec_len); - - /* I guess we silently fail on no inode? */ - if (!le64_to_cpu(de->inode)) - continue; - if (de->file_type > OCFS2_FT_MAX) { - mlog(ML_ERROR, - "block %llu contains invalid de: " - "inode = %llu, rec_len = %u, " - "name_len = %u, file_type = %u, " - "name='%.*s'\n", - (unsigned long long)bh->b_blocknr, - (unsigned long long)le64_to_cpu(de->inode), - le16_to_cpu(de->rec_len), - de->name_len, - de->file_type, - de->name_len, - de->name); - continue; - } - if (de->name_len == 1 && !strncmp(".", de->name, 1)) - continue; - if (de->name_len == 2 && !strncmp("..", de->name, 2)) - continue; - - iter = ocfs2_iget(osb, le64_to_cpu(de->inode), - OCFS2_FI_FLAG_ORPHAN_RECOVERY); - if (IS_ERR(iter)) - continue; - - mlog(0, "queue orphan %llu\n", - (unsigned long long)OCFS2_I(iter)->ip_blkno); - /* No locking is required for the next_orphan - * queue as there is only ever a single - * process doing orphan recovery. */ - OCFS2_I(iter)->ip_next_orphan = *head; - *head = iter; - } - brelse(bh); + status = ocfs2_dir_foreach(orphan_dir_inode, &pos, &priv, + ocfs2_orphan_filldir); + if (status) { + mlog_errno(status); + goto out; } -out_unlock: + *head = priv.head; + ocfs2_meta_unlock(orphan_dir_inode, 0); out: mutex_unlock(&orphan_dir_inode->i_mutex); diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h index ce60aab013aa..4b32e0961568 100644 --- a/fs/ocfs2/journal.h +++ b/fs/ocfs2/journal.h @@ -282,6 +282,9 @@ int ocfs2_journal_dirty_data(handle_t *handle, * prev. group desc. if we relink. */ #define OCFS2_SUBALLOC_ALLOC (3) +#define OCFS2_INLINE_TO_EXTENTS_CREDITS (OCFS2_SUBALLOC_ALLOC \ + + OCFS2_INODE_UPDATE_CREDITS) + /* dinode + group descriptor update. We don't relink on free yet. */ #define OCFS2_SUBALLOC_FREE (2) diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 701e6d04ed5d..729259016c18 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -64,29 +64,6 @@ #include "buffer_head_io.h" -#define NAMEI_RA_CHUNKS 2 -#define NAMEI_RA_BLOCKS 4 -#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS) -#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b)) - -static int inline ocfs2_search_dirblock(struct buffer_head *bh, - struct inode *dir, - const char *name, int namelen, - unsigned long offset, - struct ocfs2_dir_entry **res_dir); - -static int ocfs2_delete_entry(handle_t *handle, - struct inode *dir, - struct ocfs2_dir_entry *de_del, - struct buffer_head *bh); - -static int __ocfs2_add_entry(handle_t *handle, - struct inode *dir, - const char *name, int namelen, - struct inode *inode, u64 blkno, - struct buffer_head *parent_fe_bh, - struct buffer_head *insert_bh); - static int ocfs2_mknod_locked(struct ocfs2_super *osb, struct inode *dir, struct dentry *dentry, int mode, @@ -97,13 +74,6 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb, struct inode **ret_inode, struct ocfs2_alloc_context *inode_ac); -static int ocfs2_fill_new_dir(struct ocfs2_super *osb, - handle_t *handle, - struct inode *parent, - struct inode *inode, - struct buffer_head *fe_bh, - struct ocfs2_alloc_context *data_ac); - static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb, struct inode **ret_orphan_dir, struct inode *inode, @@ -123,17 +93,6 @@ static int ocfs2_create_symlink_data(struct ocfs2_super *osb, struct inode *inode, const char *symname); -static inline int ocfs2_add_entry(handle_t *handle, - struct dentry *dentry, - struct inode *inode, u64 blkno, - struct buffer_head *parent_fe_bh, - struct buffer_head *insert_bh) -{ - return __ocfs2_add_entry(handle, dentry->d_parent->d_inode, - dentry->d_name.name, dentry->d_name.len, - inode, blkno, parent_fe_bh, insert_bh); -} - /* An orphan dir name is an 8 byte value, printed as a hex string */ #define OCFS2_ORPHAN_NAMELEN ((int)(2 * sizeof(u64))) @@ -142,10 +101,8 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry, { int status; u64 blkno; - struct buffer_head *dirent_bh = NULL; struct inode *inode = NULL; struct dentry *ret; - struct ocfs2_dir_entry *dirent; struct ocfs2_inode_info *oi; mlog_entry("(0x%p, 0x%p, '%.*s')\n", dir, dentry, @@ -167,9 +124,8 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry, goto bail; } - status = ocfs2_find_files_on_disk(dentry->d_name.name, - dentry->d_name.len, &blkno, - dir, &dirent_bh, &dirent); + status = ocfs2_lookup_ino_from_name(dir, dentry->d_name.name, + dentry->d_name.len, &blkno); if (status < 0) goto bail_add; @@ -224,83 +180,12 @@ bail_unlock: ocfs2_meta_unlock(dir, 0); bail: - if (dirent_bh) - brelse(dirent_bh); mlog_exit_ptr(ret); return ret; } -static int ocfs2_fill_new_dir(struct ocfs2_super *osb, - handle_t *handle, - struct inode *parent, - struct inode *inode, - struct buffer_head *fe_bh, - struct ocfs2_alloc_context *data_ac) -{ - int status; - struct buffer_head *new_bh = NULL; - struct ocfs2_dir_entry *de = NULL; - - mlog_entry_void(); - - status = ocfs2_do_extend_dir(osb->sb, handle, inode, fe_bh, - data_ac, NULL, &new_bh); - if (status < 0) { - mlog_errno(status); - goto bail; - } - - ocfs2_set_new_buffer_uptodate(inode, new_bh); - - status = ocfs2_journal_access(handle, inode, new_bh, - OCFS2_JOURNAL_ACCESS_CREATE); - if (status < 0) { - mlog_errno(status); - goto bail; - } - memset(new_bh->b_data, 0, osb->sb->s_blocksize); - - de = (struct ocfs2_dir_entry *) new_bh->b_data; - de->inode = cpu_to_le64(OCFS2_I(inode)->ip_blkno); - de->name_len = 1; - de->rec_len = - cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len)); - strcpy(de->name, "."); - ocfs2_set_de_type(de, S_IFDIR); - de = (struct ocfs2_dir_entry *) ((char *)de + le16_to_cpu(de->rec_len)); - de->inode = cpu_to_le64(OCFS2_I(parent)->ip_blkno); - de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize - - OCFS2_DIR_REC_LEN(1)); - de->name_len = 2; - strcpy(de->name, ".."); - ocfs2_set_de_type(de, S_IFDIR); - - status = ocfs2_journal_dirty(handle, new_bh); - if (status < 0) { - mlog_errno(status); - goto bail; - } - - i_size_write(inode, inode->i_sb->s_blocksize); - inode->i_nlink = 2; - inode->i_blocks = ocfs2_inode_sector_count(inode); - status = ocfs2_mark_inode_dirty(handle, inode, fe_bh); - if (status < 0) { - mlog_errno(status); - goto bail; - } - - status = 0; -bail: - if (new_bh) - brelse(new_bh); - - mlog_exit(status); - return status; -} - static int ocfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, @@ -365,9 +250,8 @@ static int ocfs2_mknod(struct inode *dir, goto leave; } - /* are we making a directory? If so, reserve a cluster for his - * 1st extent. */ - if (S_ISDIR(mode)) { + /* Reserve a cluster if creating an extent based directory. */ + if (S_ISDIR(mode) && !ocfs2_supports_inline_data(osb)) { status = ocfs2_reserve_clusters(osb, 1, &data_ac); if (status < 0) { if (status != -ENOSPC) @@ -564,10 +448,21 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb, cpu_to_le32(CURRENT_TIME.tv_nsec); fe->i_dtime = 0; - fel = &fe->id2.i_list; - fel->l_tree_depth = 0; - fel->l_next_free_rec = 0; - fel->l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(osb->sb)); + /* + * If supported, directories start with inline data. + */ + if (S_ISDIR(mode) && ocfs2_supports_inline_data(osb)) { + u16 feat = le16_to_cpu(fe->i_dyn_features); + + fe->i_dyn_features = cpu_to_le16(feat | OCFS2_INLINE_DATA_FL); + + fe->id2.i_data.id_count = cpu_to_le16(ocfs2_max_inline_data(osb->sb)); + } else { + fel = &fe->id2.i_list; + fel->l_tree_depth = 0; + fel->l_next_free_rec = 0; + fel->l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(osb->sb)); + } status = ocfs2_journal_dirty(handle, *new_fe_bh); if (status < 0) { @@ -1048,11 +943,6 @@ static void ocfs2_double_unlock(struct inode *inode1, struct inode *inode2) ocfs2_meta_unlock(inode2, 1); } -#define PARENT_INO(buffer) \ - ((struct ocfs2_dir_entry *) \ - ((char *)buffer + \ - le16_to_cpu(((struct ocfs2_dir_entry *)buffer)->rec_len)))->inode - static int ocfs2_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, @@ -1070,12 +960,12 @@ static int ocfs2_rename(struct inode *old_dir, struct buffer_head *old_inode_bh = NULL; struct buffer_head *insert_entry_bh = NULL; struct ocfs2_super *osb = NULL; - u64 newfe_blkno; + u64 newfe_blkno, old_de_ino; handle_t *handle = NULL; struct buffer_head *old_dir_bh = NULL; struct buffer_head *new_dir_bh = NULL; - struct ocfs2_dir_entry *old_de = NULL, *new_de = NULL; // dirent for old_dentry - // and new_dentry + struct ocfs2_dir_entry *old_inode_dot_dot_de = NULL, *old_de = NULL, + *new_de = NULL; struct buffer_head *new_de_bh = NULL, *old_de_bh = NULL; // bhs for above struct buffer_head *old_inode_de_bh = NULL; // if old_dentry is a dir, // this is the 1st dirent bh @@ -1159,27 +1049,35 @@ static int ocfs2_rename(struct inode *old_dir, } if (S_ISDIR(old_inode->i_mode)) { - status = -EIO; - old_inode_de_bh = ocfs2_bread(old_inode, 0, &status, 0); - if (!old_inode_de_bh) + u64 old_inode_parent; + + status = ocfs2_find_files_on_disk("..", 2, &old_inode_parent, + old_inode, &old_inode_de_bh, + &old_inode_dot_dot_de); + if (status) { + status = -EIO; goto bail; + } - status = -EIO; - if (le64_to_cpu(PARENT_INO(old_inode_de_bh->b_data)) != - OCFS2_I(old_dir)->ip_blkno) + if (old_inode_parent != OCFS2_I(old_dir)->ip_blkno) { + status = -EIO; goto bail; - status = -EMLINK; - if (!new_inode && new_dir!=old_dir && - new_dir->i_nlink >= OCFS2_LINK_MAX) + } + + if (!new_inode && new_dir != old_dir && + new_dir->i_nlink >= OCFS2_LINK_MAX) { + status = -EMLINK; goto bail; + } } - status = -ENOENT; - old_de_bh = ocfs2_find_entry(old_dentry->d_name.name, - old_dentry->d_name.len, - old_dir, &old_de); - if (!old_de_bh) + status = ocfs2_lookup_ino_from_name(old_dir, old_dentry->d_name.name, + old_dentry->d_name.len, + &old_de_ino); + if (status) { + status = -ENOENT; goto bail; + } /* * Check for inode number is _not_ due to possible IO errors. @@ -1187,8 +1085,10 @@ static int ocfs2_rename(struct inode *old_dir, * and merrily kill the link to whatever was created under the * same name. Goodbye sticky bit ;-< */ - if (le64_to_cpu(old_de->inode) != OCFS2_I(old_inode)->ip_blkno) + if (old_de_ino != OCFS2_I(old_inode)->ip_blkno) { + status = -ENOENT; goto bail; + } /* check if the target already exists (in which case we need * to delete it */ @@ -1321,20 +1221,13 @@ static int ocfs2_rename(struct inode *old_dir, } /* change the dirent to point to the correct inode */ - status = ocfs2_journal_access(handle, new_dir, new_de_bh, - OCFS2_JOURNAL_ACCESS_WRITE); + status = ocfs2_update_entry(new_dir, handle, new_de_bh, + new_de, old_inode); if (status < 0) { mlog_errno(status); goto bail; } - new_de->inode = cpu_to_le64(OCFS2_I(old_inode)->ip_blkno); - new_de->file_type = old_de->file_type; new_dir->i_version++; - status = ocfs2_journal_dirty(handle, new_de_bh); - if (status < 0) { - mlog_errno(status); - goto bail; - } if (S_ISDIR(new_inode->i_mode)) newfe->i_links_count = 0; @@ -1370,7 +1263,21 @@ static int ocfs2_rename(struct inode *old_dir, } else mlog_errno(status); - /* now that the name has been added to new_dir, remove the old name */ + /* + * Now that the name has been added to new_dir, remove the old name. + * + * We don't keep any directory entry context around until now + * because the insert might have changed the type of directory + * we're dealing with. + */ + old_de_bh = ocfs2_find_entry(old_dentry->d_name.name, + old_dentry->d_name.len, + old_dir, &old_de); + if (!old_de_bh) { + status = -EIO; + goto bail; + } + status = ocfs2_delete_entry(handle, old_dir, old_de, old_de_bh); if (status < 0) { mlog_errno(status); @@ -1383,12 +1290,8 @@ static int ocfs2_rename(struct inode *old_dir, } old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; if (old_inode_de_bh) { - status = ocfs2_journal_access(handle, old_inode, - old_inode_de_bh, - OCFS2_JOURNAL_ACCESS_WRITE); - PARENT_INO(old_inode_de_bh->b_data) = - cpu_to_le64(OCFS2_I(new_dir)->ip_blkno); - status = ocfs2_journal_dirty(handle, old_inode_de_bh); + status = ocfs2_update_entry(old_inode, handle, old_inode_de_bh, + old_inode_dot_dot_de, new_dir); old_dir->i_nlink--; if (new_inode) { new_inode->i_nlink--; @@ -1767,329 +1670,6 @@ bail: return status; } -int ocfs2_check_dir_entry(struct inode * dir, - struct ocfs2_dir_entry * de, - struct buffer_head * bh, - unsigned long offset) -{ - const char *error_msg = NULL; - const int rlen = le16_to_cpu(de->rec_len); - - if (rlen < OCFS2_DIR_REC_LEN(1)) - error_msg = "rec_len is smaller than minimal"; - else if (rlen % 4 != 0) - error_msg = "rec_len % 4 != 0"; - else if (rlen < OCFS2_DIR_REC_LEN(de->name_len)) - error_msg = "rec_len is too small for name_len"; - else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize) - error_msg = "directory entry across blocks"; - - if (error_msg != NULL) - mlog(ML_ERROR, "bad entry in directory #%llu: %s - " - "offset=%lu, inode=%llu, rec_len=%d, name_len=%d\n", - (unsigned long long)OCFS2_I(dir)->ip_blkno, error_msg, - offset, (unsigned long long)le64_to_cpu(de->inode), rlen, - de->name_len); - return error_msg == NULL ? 1 : 0; -} - -/* we don't always have a dentry for what we want to add, so people - * like orphan dir can call this instead. - * - * If you pass me insert_bh, I'll skip the search of the other dir - * blocks and put the record in there. - */ -static int __ocfs2_add_entry(handle_t *handle, - struct inode *dir, - const char *name, int namelen, - struct inode *inode, u64 blkno, - struct buffer_head *parent_fe_bh, - struct buffer_head *insert_bh) -{ - unsigned long offset; - unsigned short rec_len; - struct ocfs2_dir_entry *de, *de1; - struct super_block *sb; - int retval, status; - - mlog_entry_void(); - - sb = dir->i_sb; - - if (!namelen) - return -EINVAL; - - rec_len = OCFS2_DIR_REC_LEN(namelen); - offset = 0; - de = (struct ocfs2_dir_entry *) insert_bh->b_data; - while (1) { - BUG_ON((char *)de >= sb->s_blocksize + insert_bh->b_data); - /* These checks should've already been passed by the - * prepare function, but I guess we can leave them - * here anyway. */ - if (!ocfs2_check_dir_entry(dir, de, insert_bh, offset)) { - retval = -ENOENT; - goto bail; - } - if (ocfs2_match(namelen, name, de)) { - retval = -EEXIST; - goto bail; - } - if (((le64_to_cpu(de->inode) == 0) && - (le16_to_cpu(de->rec_len) >= rec_len)) || - (le16_to_cpu(de->rec_len) >= - (OCFS2_DIR_REC_LEN(de->name_len) + rec_len))) { - dir->i_mtime = dir->i_ctime = CURRENT_TIME; - retval = ocfs2_mark_inode_dirty(handle, dir, parent_fe_bh); - if (retval < 0) { - mlog_errno(retval); - goto bail; - } - - status = ocfs2_journal_access(handle, dir, insert_bh, - OCFS2_JOURNAL_ACCESS_WRITE); - /* By now the buffer is marked for journaling */ - offset += le16_to_cpu(de->rec_len); - if (le64_to_cpu(de->inode)) { - de1 = (struct ocfs2_dir_entry *)((char *) de + - OCFS2_DIR_REC_LEN(de->name_len)); - de1->rec_len = - cpu_to_le16(le16_to_cpu(de->rec_len) - - OCFS2_DIR_REC_LEN(de->name_len)); - de->rec_len = cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len)); - de = de1; - } - de->file_type = OCFS2_FT_UNKNOWN; - if (blkno) { - de->inode = cpu_to_le64(blkno); - ocfs2_set_de_type(de, inode->i_mode); - } else - de->inode = 0; - de->name_len = namelen; - memcpy(de->name, name, namelen); - - dir->i_version++; - status = ocfs2_journal_dirty(handle, insert_bh); - retval = 0; - goto bail; - } - offset += le16_to_cpu(de->rec_len); - de = (struct ocfs2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len)); - } - - /* when you think about it, the assert above should prevent us - * from ever getting here. */ - retval = -ENOSPC; -bail: - - mlog_exit(retval); - return retval; -} - - -/* - * ocfs2_delete_entry deletes a directory entry by merging it with the - * previous entry - */ -static int ocfs2_delete_entry(handle_t *handle, - struct inode *dir, - struct ocfs2_dir_entry *de_del, - struct buffer_head *bh) -{ - struct ocfs2_dir_entry *de, *pde; - int i, status = -ENOENT; - - mlog_entry("(0x%p, 0x%p, 0x%p, 0x%p)\n", handle, dir, de_del, bh); - - i = 0; - pde = NULL; - de = (struct ocfs2_dir_entry *) bh->b_data; - while (i < bh->b_size) { - if (!ocfs2_check_dir_entry(dir, de, bh, i)) { - status = -EIO; - mlog_errno(status); - goto bail; - } - if (de == de_del) { - status = ocfs2_journal_access(handle, dir, bh, - OCFS2_JOURNAL_ACCESS_WRITE); - if (status < 0) { - status = -EIO; - mlog_errno(status); - goto bail; - } - if (pde) - pde->rec_len = - cpu_to_le16(le16_to_cpu(pde->rec_len) + - le16_to_cpu(de->rec_len)); - else - de->inode = 0; - dir->i_version++; - status = ocfs2_journal_dirty(handle, bh); - goto bail; - } - i += le16_to_cpu(de->rec_len); - pde = de; - de = (struct ocfs2_dir_entry *)((char *)de + le16_to_cpu(de->rec_len)); - } -bail: - mlog_exit(status); - return status; -} - -/* - * Returns 0 if not found, -1 on failure, and 1 on success - */ -static int inline ocfs2_search_dirblock(struct buffer_head *bh, - struct inode *dir, - const char *name, int namelen, - unsigned long offset, - struct ocfs2_dir_entry **res_dir) -{ - struct ocfs2_dir_entry *de; - char *dlimit, *de_buf; - int de_len; - int ret = 0; - - mlog_entry_void(); - - de_buf = bh->b_data; - dlimit = de_buf + dir->i_sb->s_blocksize; - - while (de_buf < dlimit) { - /* this code is executed quadratically often */ - /* do minimal checking `by hand' */ - - de = (struct ocfs2_dir_entry *) de_buf; - - if (de_buf + namelen <= dlimit && - ocfs2_match(namelen, name, de)) { - /* found a match - just to be sure, do a full check */ - if (!ocfs2_check_dir_entry(dir, de, bh, offset)) { - ret = -1; - goto bail; - } - *res_dir = de; - ret = 1; - goto bail; - } - - /* prevent looping on a bad block */ - de_len = le16_to_cpu(de->rec_len); - if (de_len <= 0) { - ret = -1; - goto bail; - } - - de_buf += de_len; - offset += de_len; - } - -bail: - mlog_exit(ret); - return ret; -} - -struct buffer_head *ocfs2_find_entry(const char *name, int namelen, - struct inode *dir, - struct ocfs2_dir_entry **res_dir) -{ - struct super_block *sb; - struct buffer_head *bh_use[NAMEI_RA_SIZE]; - struct buffer_head *bh, *ret = NULL; - unsigned long start, block, b; - int ra_max = 0; /* Number of bh's in the readahead - buffer, bh_use[] */ - int ra_ptr = 0; /* Current index into readahead - buffer */ - int num = 0; - int nblocks, i, err; - - mlog_entry_void(); - - *res_dir = NULL; - sb = dir->i_sb; - - nblocks = i_size_read(dir) >> sb->s_blocksize_bits; - start = OCFS2_I(dir)->ip_dir_start_lookup; - if (start >= nblocks) - start = 0; - block = start; - -restart: - do { - /* - * We deal with the read-ahead logic here. - */ - if (ra_ptr >= ra_max) { - /* Refill the readahead buffer */ - ra_ptr = 0; - b = block; - for (ra_max = 0; ra_max < NAMEI_RA_SIZE; ra_max++) { - /* - * Terminate if we reach the end of the - * directory and must wrap, or if our - * search has finished at this block. - */ - if (b >= nblocks || (num && block == start)) { - bh_use[ra_max] = NULL; - break; - } - num++; - - bh = ocfs2_bread(dir, b++, &err, 1); - bh_use[ra_max] = bh; - } - } - if ((bh = bh_use[ra_ptr++]) == NULL) - goto next; - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) { - /* read error, skip block & hope for the best */ - ocfs2_error(dir->i_sb, "reading directory %llu, " - "offset %lu\n", - (unsigned long long)OCFS2_I(dir)->ip_blkno, - block); - brelse(bh); - goto next; - } - i = ocfs2_search_dirblock(bh, dir, name, namelen, - block << sb->s_blocksize_bits, - res_dir); - if (i == 1) { - OCFS2_I(dir)->ip_dir_start_lookup = block; - ret = bh; - goto cleanup_and_exit; - } else { - brelse(bh); - if (i < 0) - goto cleanup_and_exit; - } - next: - if (++block >= nblocks) - block = 0; - } while (block != start); - - /* - * If the directory has grown while we were searching, then - * search the last part of the directory before giving up. - */ - block = nblocks; - nblocks = i_size_read(dir) >> sb->s_blocksize_bits; - if (block < nblocks) { - start = 0; - goto restart; - } - -cleanup_and_exit: - /* Clean up the read-ahead blocks */ - for (; ra_ptr < ra_max; ra_ptr++) - brelse(bh_use[ra_ptr]); - - mlog_exit_ptr(ret); - return ret; -} - static int ocfs2_blkno_stringify(u64 blkno, char *name) { int status, namelen; diff --git a/fs/ocfs2/namei.h b/fs/ocfs2/namei.h index 0975c7b7212b..688aef64c879 100644 --- a/fs/ocfs2/namei.h +++ b/fs/ocfs2/namei.h @@ -30,29 +30,10 @@ extern const struct inode_operations ocfs2_dir_iops; struct dentry *ocfs2_get_parent(struct dentry *child); -int ocfs2_check_dir_entry (struct inode *dir, - struct ocfs2_dir_entry *de, - struct buffer_head *bh, - unsigned long offset); -struct buffer_head *ocfs2_find_entry(const char *name, - int namelen, - struct inode *dir, - struct ocfs2_dir_entry **res_dir); int ocfs2_orphan_del(struct ocfs2_super *osb, handle_t *handle, struct inode *orphan_dir_inode, struct inode *inode, struct buffer_head *orphan_dir_bh); -static inline int ocfs2_match(int len, - const char * const name, - struct ocfs2_dir_entry *de) -{ - if (len != de->name_len) - return 0; - if (!de->inode) - return 0; - return !memcmp(name, de->name, len); -} - #endif /* OCFS2_NAMEI_H */ diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 58307853fb4a..60a23e1906b0 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h @@ -319,6 +319,13 @@ static inline int ocfs2_writes_unwritten_extents(struct ocfs2_super *osb) return 0; } +static inline int ocfs2_supports_inline_data(struct ocfs2_super *osb) +{ + if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_INLINE_DATA) + return 1; + return 0; +} + /* set / clear functions because cluster events can make these happen * in parallel so we want the transitions to be atomic. this also * means that any future flags osb_flags must be protected by spinlock diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h index 82f8a75b207e..6ef876759a73 100644 --- a/fs/ocfs2/ocfs2_fs.h +++ b/fs/ocfs2/ocfs2_fs.h @@ -87,7 +87,8 @@ #define OCFS2_FEATURE_COMPAT_SUPP OCFS2_FEATURE_COMPAT_BACKUP_SB #define OCFS2_FEATURE_INCOMPAT_SUPP (OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT \ - | OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC) + | OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC \ + | OCFS2_FEATURE_INCOMPAT_INLINE_DATA) #define OCFS2_FEATURE_RO_COMPAT_SUPP OCFS2_FEATURE_RO_COMPAT_UNWRITTEN /* @@ -111,6 +112,20 @@ #define OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC 0x0010 /* + * Tunefs sets this incompat flag before starting an operation which + * would require cleanup on abort. This is done to protect users from + * inadvertently mounting the fs after an aborted run without + * fsck-ing. + * + * s_tunefs_flags on the super block describes precisely which + * operations were in progress. + */ +#define OCFS2_FEATURE_INCOMPAT_TUNEFS_INPROG 0x0020 + +/* Support for data packed into inode blocks */ +#define OCFS2_FEATURE_INCOMPAT_INLINE_DATA 0x0040 + +/* * backup superblock flag is used to indicate that this volume * has backup superblocks. */ @@ -130,6 +145,11 @@ #define OCFS2_MAX_BACKUP_SUPERBLOCKS 6 /* + * Flags on ocfs2_super_block.s_tunefs_flags + */ +#define OCFS2_TUNEFS_INPROG_REMOVE_SLOT 0x0001 /* Removing slots */ + +/* * Flags on ocfs2_dinode.i_flags */ #define OCFS2_VALID_FL (0x00000001) /* Inode is valid */ @@ -146,6 +166,17 @@ #define OCFS2_CHAIN_FL (0x00000400) /* Chain allocator */ #define OCFS2_DEALLOC_FL (0x00000800) /* Truncate log */ +/* + * Flags on ocfs2_dinode.i_dyn_features + * + * These can change much more often than i_flags. When adding flags, + * keep in mind that i_dyn_features is only 16 bits wide. + */ +#define OCFS2_INLINE_DATA_FL (0x0001) /* Data stored in inode block */ +#define OCFS2_HAS_XATTR_FL (0x0002) +#define OCFS2_INLINE_XATTR_FL (0x0004) +#define OCFS2_INDEXED_DIR_FL (0x0008) + /* Inode attributes, keep in sync with EXT2 */ #define OCFS2_SECRM_FL (0x00000001) /* Secure deletion */ #define OCFS2_UNRM_FL (0x00000002) /* Undelete */ @@ -447,8 +478,8 @@ struct ocfs2_super_block { __le32 s_clustersize_bits; /* Clustersize for this fs */ /*40*/ __le16 s_max_slots; /* Max number of simultaneous mounts before tunefs required */ - __le16 s_reserved1; - __le32 s_reserved2; + __le16 s_tunefs_flag; + __le32 s_reserved1; __le64 s_first_cluster_group; /* Block offset of 1st cluster * group header */ /*50*/ __u8 s_label[OCFS2_MAX_VOL_LABEL_LEN]; /* Label for mounting, etc. */ @@ -471,6 +502,19 @@ struct ocfs2_local_alloc }; /* + * Data-in-inode header. This is only used if i_dyn_features has + * OCFS2_INLINE_DATA_FL set. + */ +struct ocfs2_inline_data +{ +/*00*/ __le16 id_count; /* Number of bytes that can be used + * for data, starting at id_data */ + __le16 id_reserved0; + __le32 id_reserved1; + __u8 id_data[0]; /* Start of user data */ +}; + +/* * On disk inode for OCFS2 */ struct ocfs2_dinode { @@ -502,7 +546,7 @@ struct ocfs2_dinode { __le32 i_attr; __le16 i_orphaned_slot; /* Only valid when OCFS2_ORPHANED_FL was set in i_flags */ - __le16 i_reserved1; + __le16 i_dyn_features; /*70*/ __le64 i_reserved2[8]; /*B8*/ union { __le64 i_pad1; /* Generic way to refer to this @@ -528,6 +572,7 @@ struct ocfs2_dinode { struct ocfs2_chain_list i_chain; struct ocfs2_extent_list i_list; struct ocfs2_truncate_log i_dealloc; + struct ocfs2_inline_data i_data; __u8 i_symlink[0]; } id2; /* Actual on-disk size is one block */ @@ -577,6 +622,12 @@ static inline int ocfs2_fast_symlink_chars(struct super_block *sb) offsetof(struct ocfs2_dinode, id2.i_symlink); } +static inline int ocfs2_max_inline_data(struct super_block *sb) +{ + return sb->s_blocksize - + offsetof(struct ocfs2_dinode, id2.i_data.id_data); +} + static inline int ocfs2_extent_recs_per_inode(struct super_block *sb) { int size; @@ -656,6 +707,11 @@ static inline int ocfs2_fast_symlink_chars(int blocksize) return blocksize - offsetof(struct ocfs2_dinode, id2.i_symlink); } +static inline int ocfs2_max_inline_data(int blocksize) +{ + return blocksize - offsetof(struct ocfs2_dinode, id2.i_data.id_data); +} + static inline int ocfs2_extent_recs_per_inode(int blocksize) { int size; diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index c034b5129c1e..be562ac3e89c 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -39,6 +39,7 @@ #include <linux/parser.h> #include <linux/crc32.h> #include <linux/debugfs.h> +#include <linux/mount.h> #include <cluster/nodemanager.h> @@ -91,6 +92,7 @@ struct mount_options static int ocfs2_parse_options(struct super_block *sb, char *options, struct mount_options *mopt, int is_remount); +static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt); static void ocfs2_put_super(struct super_block *sb); static int ocfs2_mount_volume(struct super_block *sb); static int ocfs2_remount(struct super_block *sb, int *flags, char *data); @@ -105,7 +107,7 @@ static int ocfs2_sync_fs(struct super_block *sb, int wait); static int ocfs2_init_global_system_inodes(struct ocfs2_super *osb); static int ocfs2_init_local_system_inodes(struct ocfs2_super *osb); -static int ocfs2_release_system_inodes(struct ocfs2_super *osb); +static void ocfs2_release_system_inodes(struct ocfs2_super *osb); static int ocfs2_fill_local_node_info(struct ocfs2_super *osb); static int ocfs2_check_volume(struct ocfs2_super *osb); static int ocfs2_verify_volume(struct ocfs2_dinode *di, @@ -133,6 +135,7 @@ static const struct super_operations ocfs2_sops = { .write_super = ocfs2_write_super, .put_super = ocfs2_put_super, .remount_fs = ocfs2_remount, + .show_options = ocfs2_show_options, }; enum { @@ -177,7 +180,7 @@ static void ocfs2_write_super(struct super_block *sb) static int ocfs2_sync_fs(struct super_block *sb, int wait) { - int status = 0; + int status; tid_t target; struct ocfs2_super *osb = OCFS2_SB(sb); @@ -275,9 +278,9 @@ bail: return status; } -static int ocfs2_release_system_inodes(struct ocfs2_super *osb) +static void ocfs2_release_system_inodes(struct ocfs2_super *osb) { - int status = 0, i; + int i; struct inode *inode; mlog_entry_void(); @@ -302,8 +305,7 @@ static int ocfs2_release_system_inodes(struct ocfs2_super *osb) osb->root_inode = NULL; } - mlog_exit(status); - return status; + mlog_exit(0); } /* We're allocating fs objects, use GFP_NOFS */ @@ -453,7 +455,7 @@ static int ocfs2_sb_probe(struct super_block *sb, struct buffer_head **bh, int *sector_size) { - int status = 0, tmpstat; + int status, tmpstat; struct ocfs1_vol_disk_hdr *hdr; struct ocfs2_dinode *di; int blksize; @@ -830,6 +832,41 @@ bail: return status; } +static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt) +{ + struct ocfs2_super *osb = OCFS2_SB(mnt->mnt_sb); + unsigned long opts = osb->s_mount_opt; + + if (opts & OCFS2_MOUNT_HB_LOCAL) + seq_printf(s, ",_netdev,heartbeat=local"); + else + seq_printf(s, ",heartbeat=none"); + + if (opts & OCFS2_MOUNT_NOINTR) + seq_printf(s, ",nointr"); + + if (opts & OCFS2_MOUNT_DATA_WRITEBACK) + seq_printf(s, ",data=writeback"); + else + seq_printf(s, ",data=ordered"); + + if (opts & OCFS2_MOUNT_BARRIER) + seq_printf(s, ",barrier=1"); + + if (opts & OCFS2_MOUNT_ERRORS_PANIC) + seq_printf(s, ",errors=panic"); + else + seq_printf(s, ",errors=remount-ro"); + + if (osb->preferred_slot != OCFS2_INVALID_SLOT) + seq_printf(s, ",preferred_slot=%d", osb->preferred_slot); + + if (osb->s_atime_quantum != OCFS2_DEFAULT_ATIME_QUANTUM) + seq_printf(s, ",atime_quantum=%u", osb->s_atime_quantum); + + return 0; +} + static int __init ocfs2_init(void) { int status; @@ -963,9 +1000,7 @@ bail: return status; } -static void ocfs2_inode_init_once(void *data, - struct kmem_cache *cachep, - unsigned long flags) +static void ocfs2_inode_init_once(struct kmem_cache *cachep, void *data) { struct ocfs2_inode_info *oi = data; @@ -1209,12 +1244,13 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err) tmp = ocfs2_request_umount_vote(osb); if (tmp < 0) mlog_errno(tmp); + } - if (osb->slot_num != OCFS2_INVALID_SLOT) - ocfs2_put_slot(osb); + if (osb->slot_num != OCFS2_INVALID_SLOT) + ocfs2_put_slot(osb); + if (osb->dlm) ocfs2_super_unlock(osb, 1); - } ocfs2_release_system_inodes(osb); @@ -1275,7 +1311,7 @@ static int ocfs2_initialize_super(struct super_block *sb, struct buffer_head *bh, int sector_size) { - int status = 0; + int status; int i, cbits, bbits; struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data; struct inode *inode = NULL; @@ -1596,7 +1632,7 @@ static int ocfs2_verify_volume(struct ocfs2_dinode *di, static int ocfs2_check_volume(struct ocfs2_super *osb) { - int status = 0; + int status; int dirty; int local; struct ocfs2_dinode *local_alloc = NULL; /* only used if we diff --git a/fs/ocfs2/sysfile.c b/fs/ocfs2/sysfile.c index 5df6e35d09b1..fd2e846e3e6f 100644 --- a/fs/ocfs2/sysfile.c +++ b/fs/ocfs2/sysfile.c @@ -100,17 +100,14 @@ static struct inode * _ocfs2_get_system_file_inode(struct ocfs2_super *osb, char namebuf[40]; struct inode *inode = NULL; u64 blkno; - struct buffer_head *dirent_bh = NULL; - struct ocfs2_dir_entry *de = NULL; int status = 0; ocfs2_sprintf_system_inode_name(namebuf, sizeof(namebuf), type, slot); - status = ocfs2_find_files_on_disk(namebuf, strlen(namebuf), - &blkno, osb->sys_root_inode, - &dirent_bh, &de); + status = ocfs2_lookup_ino_from_name(osb->sys_root_inode, namebuf, + strlen(namebuf), &blkno); if (status < 0) { goto bail; } @@ -122,8 +119,7 @@ static struct inode * _ocfs2_get_system_file_inode(struct ocfs2_super *osb, goto bail; } bail: - if (dirent_bh) - brelse(dirent_bh); + return inode; } diff --git a/fs/open.c b/fs/open.c index 1d9e5e98bf4e..75385144df7d 100644 --- a/fs/open.c +++ b/fs/open.c @@ -658,7 +658,8 @@ static int chown_common(struct dentry * dentry, uid_t user, gid_t group) newattrs.ia_gid = group; } if (!S_ISDIR(inode->i_mode)) - newattrs.ia_valid |= ATTR_KILL_SUID|ATTR_KILL_SGID; + newattrs.ia_valid |= + ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV; mutex_lock(&inode->i_mutex); error = notify_change(dentry, &newattrs); mutex_unlock(&inode->i_mutex); @@ -757,6 +758,10 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, f->f_op = fops_get(inode->i_fop); file_move(f, &inode->i_sb->s_files); + error = security_dentry_open(f); + if (error) + goto cleanup_all; + if (!open && f->f_op) open = f->f_op->open; if (open) { @@ -1173,7 +1178,7 @@ asmlinkage long sys_vhangup(void) int generic_file_open(struct inode * inode, struct file * filp) { if (!(filp->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS) - return -EFBIG; + return -EOVERFLOW; return 0; } diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c index dd86be2aa6c9..d88173840082 100644 --- a/fs/openpromfs/inode.c +++ b/fs/openpromfs/inode.c @@ -415,7 +415,7 @@ static struct file_system_type openprom_fs_type = { .kill_sb = kill_anon_super, }; -static void op_inode_init_once(void *data, struct kmem_cache * cachep, unsigned long flags) +static void op_inode_init_once(struct kmem_cache * cachep, void *data) { struct op_inode_info *oi = (struct op_inode_info *) data; diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 783c57ec07d3..722e12e5acc7 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -381,10 +381,12 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, p->partno = part; p->policy = disk->policy; - if (isdigit(disk->kobj.name[strlen(disk->kobj.name)-1])) - snprintf(p->kobj.name,KOBJ_NAME_LEN,"%sp%d",disk->kobj.name,part); + if (isdigit(disk->kobj.k_name[strlen(disk->kobj.k_name)-1])) + kobject_set_name(&p->kobj, "%sp%d", + kobject_name(&disk->kobj), part); else - snprintf(p->kobj.name,KOBJ_NAME_LEN,"%s%d",disk->kobj.name,part); + kobject_set_name(&p->kobj, "%s%d", + kobject_name(&disk->kobj),part); p->kobj.parent = &disk->kobj; p->kobj.ktype = &ktype_part; kobject_init(&p->kobj); @@ -477,9 +479,9 @@ void register_disk(struct gendisk *disk) struct hd_struct *p; int err; - strlcpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN); + kobject_set_name(&disk->kobj, "%s", disk->disk_name); /* ewww... some of these buggers have / in name... */ - s = strchr(disk->kobj.name, '/'); + s = strchr(disk->kobj.k_name, '/'); if (s) *s = '!'; if ((err = kobject_add(&disk->kobj))) diff --git a/fs/partitions/sun.c b/fs/partitions/sun.c index 794118da4ef3..c95e6a62c01d 100644 --- a/fs/partitions/sun.c +++ b/fs/partitions/sun.c @@ -95,8 +95,8 @@ int sun_partition(struct parsed_partitions *state, struct block_device *bdev) * So that old Linux-Sun partitions continue to work, * alow the VTOC to be used under the additional condition ... */ - use_vtoc = use_vtoc || !(label->vtoc.sanity | - label->vtoc.version | label->vtoc.nparts); + use_vtoc = use_vtoc || !(label->vtoc.sanity || + label->vtoc.version || label->vtoc.nparts); spc = be16_to_cpu(label->ntrks) * be16_to_cpu(label->nsect); for (i = 0; i < nparts; i++, p++) { unsigned long st_sector; diff --git a/fs/pipe.c b/fs/pipe.c index 6b3d91a691bf..e66ec48e95d8 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -45,8 +45,7 @@ void pipe_wait(struct pipe_inode_info *pipe) * Pipes are system-local resources, so sleeping on them * is considered a noninteractive wait: */ - prepare_to_wait(&pipe->wait, &wait, - TASK_INTERRUPTIBLE | TASK_NONINTERACTIVE); + prepare_to_wait(&pipe->wait, &wait, TASK_INTERRUPTIBLE); if (pipe->inode) mutex_unlock(&pipe->inode->i_mutex); schedule(); @@ -383,7 +382,7 @@ redo: /* Signal writers asynchronously that there is more room. */ if (do_wakeup) { - wake_up_interruptible(&pipe->wait); + wake_up_interruptible_sync(&pipe->wait); kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); } if (ret > 0) @@ -556,7 +555,7 @@ redo2: out: mutex_unlock(&inode->i_mutex); if (do_wakeup) { - wake_up_interruptible(&pipe->wait); + wake_up_interruptible_sync(&pipe->wait); kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); } if (ret > 0) @@ -650,7 +649,7 @@ pipe_release(struct inode *inode, int decr, int decw) if (!pipe->readers && !pipe->writers) { free_pipe_info(inode); } else { - wake_up_interruptible(&pipe->wait); + wake_up_interruptible_sync(&pipe->wait); kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); } diff --git a/fs/proc/Makefile b/fs/proc/Makefile index bce38e3f06cb..ebaba0213546 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile @@ -11,6 +11,7 @@ proc-y += inode.o root.o base.o generic.o array.o \ proc_tty.o proc_misc.o proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o +proc-$(CONFIG_NET) += proc_net.o proc-$(CONFIG_PROC_KCORE) += kcore.o proc-$(CONFIG_PROC_VMCORE) += vmcore.o proc-$(CONFIG_PROC_DEVICETREE) += proc_devtree.o diff --git a/fs/proc/array.c b/fs/proc/array.c index ee4814dd98f9..63c95afb561f 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -77,6 +77,7 @@ #include <linux/cpuset.h> #include <linux/rcupdate.h> #include <linux/delayacct.h> +#include <linux/pid_namespace.h> #include <asm/pgtable.h> #include <asm/processor.h> @@ -145,8 +146,7 @@ static inline const char *get_task_state(struct task_struct *tsk) TASK_UNINTERRUPTIBLE | TASK_STOPPED | TASK_TRACED)) | - (tsk->exit_state & (EXIT_ZOMBIE | - EXIT_DEAD)); + tsk->exit_state; const char **p = &task_state_array[0]; while (state) { @@ -161,8 +161,15 @@ static inline char *task_state(struct task_struct *p, char *buffer) struct group_info *group_info; int g; struct fdtable *fdt = NULL; + struct pid_namespace *ns; + pid_t ppid, tpid; + ns = current->nsproxy->pid_ns; rcu_read_lock(); + ppid = pid_alive(p) ? + task_tgid_nr_ns(rcu_dereference(p->real_parent), ns) : 0; + tpid = pid_alive(p) && p->ptrace ? + task_ppid_nr_ns(rcu_dereference(p->parent), ns) : 0; buffer += sprintf(buffer, "State:\t%s\n" "Tgid:\t%d\n" @@ -172,9 +179,9 @@ static inline char *task_state(struct task_struct *p, char *buffer) "Uid:\t%d\t%d\t%d\t%d\n" "Gid:\t%d\t%d\t%d\t%d\n", get_task_state(p), - p->tgid, p->pid, - pid_alive(p) ? rcu_dereference(p->real_parent)->tgid : 0, - pid_alive(p) && p->ptrace ? rcu_dereference(p->parent)->pid : 0, + task_tgid_nr_ns(p, ns), + task_pid_nr_ns(p, ns), + ppid, tpid, p->uid, p->euid, p->suid, p->fsuid, p->gid, p->egid, p->sgid, p->fsgid); @@ -370,6 +377,11 @@ static cputime_t task_stime(struct task_struct *p) } #endif +static cputime_t task_gtime(struct task_struct *p) +{ + return p->gtime; +} + static int do_task_stat(struct task_struct *task, char *buffer, int whole) { unsigned long vsize, eip, esp, wchan = ~0UL; @@ -385,9 +397,13 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole) unsigned long cmin_flt = 0, cmaj_flt = 0; unsigned long min_flt = 0, maj_flt = 0; cputime_t cutime, cstime, utime, stime; + cputime_t cgtime, gtime; unsigned long rsslim = 0; char tcomm[sizeof(task->comm)]; unsigned long flags; + struct pid_namespace *ns; + + ns = current->nsproxy->pid_ns; state = *get_task_state(task); vsize = eip = esp = 0; @@ -403,13 +419,14 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole) sigemptyset(&sigign); sigemptyset(&sigcatch); cutime = cstime = utime = stime = cputime_zero; + cgtime = gtime = cputime_zero; rcu_read_lock(); if (lock_task_sighand(task, &flags)) { struct signal_struct *sig = task->signal; if (sig->tty) { - tty_pgrp = pid_nr(sig->tty->pgrp); + tty_pgrp = pid_nr_ns(sig->tty->pgrp, ns); tty_nr = new_encode_dev(tty_devnum(sig->tty)); } @@ -420,6 +437,7 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole) cmaj_flt = sig->cmaj_flt; cutime = sig->cutime; cstime = sig->cstime; + cgtime = sig->cgtime; rsslim = sig->rlim[RLIMIT_RSS].rlim_cur; /* add up live thread stats at the group level */ @@ -430,6 +448,7 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole) maj_flt += t->maj_flt; utime = cputime_add(utime, task_utime(t)); stime = cputime_add(stime, task_stime(t)); + gtime = cputime_add(gtime, task_gtime(t)); t = next_thread(t); } while (t != task); @@ -437,11 +456,12 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole) maj_flt += sig->maj_flt; utime = cputime_add(utime, sig->utime); stime = cputime_add(stime, sig->stime); + gtime = cputime_add(gtime, sig->gtime); } - sid = signal_session(sig); - pgid = process_group(task); - ppid = rcu_dereference(task->real_parent)->tgid; + sid = task_session_nr_ns(task, ns); + pgid = task_pgrp_nr_ns(task, ns); + ppid = task_ppid_nr_ns(task, ns); unlock_task_sighand(task, &flags); } @@ -454,6 +474,7 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole) maj_flt = task->maj_flt; utime = task_utime(task); stime = task_stime(task); + gtime = task_gtime(task); } /* scale priority and nice values from timeslices to -20..20 */ @@ -471,8 +492,8 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole) res = sprintf(buffer, "%d (%s) %c %d %d %d %d %d %u %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \ -%lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu\n", - task->pid, +%lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld\n", + task_pid_nr_ns(task, ns), tcomm, state, ppid, @@ -516,7 +537,9 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole) task_cpu(task), task->rt_priority, task->policy, - (unsigned long long)delayacct_blkio_ticks(task)); + (unsigned long long)delayacct_blkio_ticks(task), + cputime_to_clock_t(gtime), + cputime_to_clock_t(cgtime)); if (mm) mmput(mm); return res; diff --git a/fs/proc/base.c b/fs/proc/base.c index 19489b0d5554..39a3d7c969c5 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -63,16 +63,19 @@ #include <linux/mm.h> #include <linux/rcupdate.h> #include <linux/kallsyms.h> +#include <linux/resource.h> #include <linux/module.h> #include <linux/mount.h> #include <linux/security.h> #include <linux/ptrace.h> +#include <linux/cgroup.h> #include <linux/cpuset.h> #include <linux/audit.h> #include <linux/poll.h> #include <linux/nsproxy.h> #include <linux/oom.h> #include <linux/elf.h> +#include <linux/pid_namespace.h> #include "internal.h" /* NOTE: @@ -199,27 +202,6 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \ security_ptrace(current,task) == 0)) -static int proc_pid_environ(struct task_struct *task, char * buffer) -{ - int res = 0; - struct mm_struct *mm = get_task_mm(task); - if (mm) { - unsigned int len; - - res = -ESRCH; - if (!ptrace_may_attach(task)) - goto out; - - len = mm->env_end - mm->env_start; - if (len > PAGE_SIZE) - len = PAGE_SIZE; - res = access_process_vm(task, mm->env_start, buffer, len, 0); -out: - mmput(mm); - } - return res; -} - static int proc_pid_cmdline(struct task_struct *task, char * buffer) { int res = 0; @@ -304,7 +286,7 @@ static int proc_pid_schedstat(struct task_struct *task, char *buffer) return sprintf(buffer, "%llu %llu %lu\n", task->sched_info.cpu_time, task->sched_info.run_delay, - task->sched_info.pcnt); + task->sched_info.pcount); } #endif @@ -322,6 +304,78 @@ static int proc_oom_score(struct task_struct *task, char *buffer) return sprintf(buffer, "%lu\n", points); } +struct limit_names { + char *name; + char *unit; +}; + +static const struct limit_names lnames[RLIM_NLIMITS] = { + [RLIMIT_CPU] = {"Max cpu time", "ms"}, + [RLIMIT_FSIZE] = {"Max file size", "bytes"}, + [RLIMIT_DATA] = {"Max data size", "bytes"}, + [RLIMIT_STACK] = {"Max stack size", "bytes"}, + [RLIMIT_CORE] = {"Max core file size", "bytes"}, + [RLIMIT_RSS] = {"Max resident set", "bytes"}, + [RLIMIT_NPROC] = {"Max processes", "processes"}, + [RLIMIT_NOFILE] = {"Max open files", "files"}, + [RLIMIT_MEMLOCK] = {"Max locked memory", "bytes"}, + [RLIMIT_AS] = {"Max address space", "bytes"}, + [RLIMIT_LOCKS] = {"Max file locks", "locks"}, + [RLIMIT_SIGPENDING] = {"Max pending signals", "signals"}, + [RLIMIT_MSGQUEUE] = {"Max msgqueue size", "bytes"}, + [RLIMIT_NICE] = {"Max nice priority", NULL}, + [RLIMIT_RTPRIO] = {"Max realtime priority", NULL}, +}; + +/* Display limits for a process */ +static int proc_pid_limits(struct task_struct *task, char *buffer) +{ + unsigned int i; + int count = 0; + unsigned long flags; + char *bufptr = buffer; + + struct rlimit rlim[RLIM_NLIMITS]; + + rcu_read_lock(); + if (!lock_task_sighand(task,&flags)) { + rcu_read_unlock(); + return 0; + } + memcpy(rlim, task->signal->rlim, sizeof(struct rlimit) * RLIM_NLIMITS); + unlock_task_sighand(task, &flags); + rcu_read_unlock(); + + /* + * print the file header + */ + count += sprintf(&bufptr[count], "%-25s %-20s %-20s %-10s\n", + "Limit", "Soft Limit", "Hard Limit", "Units"); + + for (i = 0; i < RLIM_NLIMITS; i++) { + if (rlim[i].rlim_cur == RLIM_INFINITY) + count += sprintf(&bufptr[count], "%-25s %-20s ", + lnames[i].name, "unlimited"); + else + count += sprintf(&bufptr[count], "%-25s %-20lu ", + lnames[i].name, rlim[i].rlim_cur); + + if (rlim[i].rlim_max == RLIM_INFINITY) + count += sprintf(&bufptr[count], "%-20s ", "unlimited"); + else + count += sprintf(&bufptr[count], "%-20lu ", + rlim[i].rlim_max); + + if (lnames[i].unit) + count += sprintf(&bufptr[count], "%-10s\n", + lnames[i].unit); + else + count += sprintf(&bufptr[count], "\n"); + } + + return count; +} + /************************************************************************/ /* Here the fs part begins */ /************************************************************************/ @@ -370,18 +424,21 @@ struct proc_mounts { static int mounts_open(struct inode *inode, struct file *file) { struct task_struct *task = get_proc_task(inode); + struct nsproxy *nsp; struct mnt_namespace *ns = NULL; struct proc_mounts *p; int ret = -EINVAL; if (task) { - task_lock(task); - if (task->nsproxy) { - ns = task->nsproxy->mnt_ns; + rcu_read_lock(); + nsp = task_nsproxy(task); + if (nsp) { + ns = nsp->mnt_ns; if (ns) get_mnt_ns(ns); } - task_unlock(task); + rcu_read_unlock(); + put_task_struct(task); } @@ -444,16 +501,20 @@ static int mountstats_open(struct inode *inode, struct file *file) if (!ret) { struct seq_file *m = file->private_data; + struct nsproxy *nsp; struct mnt_namespace *mnt_ns = NULL; struct task_struct *task = get_proc_task(inode); if (task) { - task_lock(task); - if (task->nsproxy) - mnt_ns = task->nsproxy->mnt_ns; - if (mnt_ns) - get_mnt_ns(mnt_ns); - task_unlock(task); + rcu_read_lock(); + nsp = task_nsproxy(task); + if (nsp) { + mnt_ns = nsp->mnt_ns; + if (mnt_ns) + get_mnt_ns(mnt_ns); + } + rcu_read_unlock(); + put_task_struct(task); } @@ -492,7 +553,7 @@ static ssize_t proc_info_read(struct file * file, char __user * buf, count = PROC_BLOCK_SIZE; length = -ENOMEM; - if (!(page = __get_free_page(GFP_KERNEL))) + if (!(page = __get_free_page(GFP_TEMPORARY))) goto out; length = PROC_I(inode)->op.proc_read(task, (char*)page); @@ -532,7 +593,7 @@ static ssize_t mem_read(struct file * file, char __user * buf, goto out; ret = -ENOMEM; - page = (char *)__get_free_page(GFP_USER); + page = (char *)__get_free_page(GFP_TEMPORARY); if (!page) goto out; @@ -602,7 +663,7 @@ static ssize_t mem_write(struct file * file, const char __user *buf, goto out; copied = -ENOMEM; - page = (char *)__get_free_page(GFP_USER); + page = (char *)__get_free_page(GFP_TEMPORARY); if (!page) goto out; @@ -658,6 +719,76 @@ static const struct file_operations proc_mem_operations = { .open = mem_open, }; +static ssize_t environ_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct task_struct *task = get_proc_task(file->f_dentry->d_inode); + char *page; + unsigned long src = *ppos; + int ret = -ESRCH; + struct mm_struct *mm; + + if (!task) + goto out_no_task; + + if (!ptrace_may_attach(task)) + goto out; + + ret = -ENOMEM; + page = (char *)__get_free_page(GFP_TEMPORARY); + if (!page) + goto out; + + ret = 0; + + mm = get_task_mm(task); + if (!mm) + goto out_free; + + while (count > 0) { + int this_len, retval, max_len; + + this_len = mm->env_end - (mm->env_start + src); + + if (this_len <= 0) + break; + + max_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; + this_len = (this_len > max_len) ? max_len : this_len; + + retval = access_process_vm(task, (mm->env_start + src), + page, this_len, 0); + + if (retval <= 0) { + ret = retval; + break; + } + + if (copy_to_user(buf, page, retval)) { + ret = -EFAULT; + break; + } + + ret += retval; + src += retval; + buf += retval; + count -= retval; + } + *ppos = src; + + mmput(mm); +out_free: + free_page((unsigned long) page); +out: + put_task_struct(task); +out_no_task: + return ret; +} + +static const struct file_operations proc_environ_operations = { + .read = environ_read, +}; + static ssize_t oom_adjust_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -788,7 +919,7 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf, /* No partial writes. */ return -EINVAL; } - page = (char*)__get_free_page(GFP_USER); + page = (char*)__get_free_page(GFP_TEMPORARY); if (!page) return -ENOMEM; length = -EFAULT; @@ -954,7 +1085,8 @@ static int do_proc_readlink(struct dentry *dentry, struct vfsmount *mnt, char __user *buffer, int buflen) { struct inode * inode; - char *tmp = (char*)__get_free_page(GFP_KERNEL), *path; + char *tmp = (char*)__get_free_page(GFP_TEMPORARY); + char *path; int len; if (!tmp) @@ -1387,7 +1519,7 @@ static int proc_readfd_common(struct file * filp, void * dirent, struct dentry *dentry = filp->f_path.dentry; struct inode *inode = dentry->d_inode; struct task_struct *p = get_proc_task(inode); - unsigned int fd, tid, ino; + unsigned int fd, ino; int retval; struct files_struct * files; struct fdtable *fdt; @@ -1396,7 +1528,6 @@ static int proc_readfd_common(struct file * filp, void * dirent, if (!p) goto out_no_task; retval = 0; - tid = p->pid; fd = filp->f_pos; switch (fd) { @@ -1631,7 +1762,6 @@ static int proc_pident_readdir(struct file *filp, const struct pid_entry *ents, unsigned int nents) { int i; - int pid; struct dentry *dentry = filp->f_path.dentry; struct inode *inode = dentry->d_inode; struct task_struct *task = get_proc_task(inode); @@ -1644,7 +1774,6 @@ static int proc_pident_readdir(struct file *filp, goto out_no_task; ret = 0; - pid = task->pid; i = filp->f_pos; switch (i) { case 0: @@ -1726,7 +1855,7 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf, goto out; length = -ENOMEM; - page = (char*)__get_free_page(GFP_USER); + page = (char*)__get_free_page(GFP_TEMPORARY); if (!page) goto out; @@ -1878,14 +2007,14 @@ static int proc_self_readlink(struct dentry *dentry, char __user *buffer, int buflen) { char tmp[PROC_NUMBUF]; - sprintf(tmp, "%d", current->tgid); + sprintf(tmp, "%d", task_tgid_vnr(current)); return vfs_readlink(dentry,buffer,buflen,tmp); } static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) { char tmp[PROC_NUMBUF]; - sprintf(tmp, "%d", current->tgid); + sprintf(tmp, "%d", task_tgid_vnr(current)); return ERR_PTR(vfs_follow_link(nd,tmp)); } @@ -2048,9 +2177,10 @@ static const struct pid_entry tgid_base_stuff[] = { DIR("task", S_IRUGO|S_IXUGO, task), DIR("fd", S_IRUSR|S_IXUSR, fd), DIR("fdinfo", S_IRUSR|S_IXUSR, fdinfo), - INF("environ", S_IRUSR, pid_environ), + REG("environ", S_IRUSR, environ), INF("auxv", S_IRUSR, pid_auxv), INF("status", S_IRUGO, pid_status), + INF("limits", S_IRUSR, pid_limits), #ifdef CONFIG_SCHED_DEBUG REG("sched", S_IRUGO|S_IWUSR, pid_sched), #endif @@ -2080,9 +2210,12 @@ static const struct pid_entry tgid_base_stuff[] = { #ifdef CONFIG_SCHEDSTATS INF("schedstat", S_IRUGO, pid_schedstat), #endif -#ifdef CONFIG_CPUSETS +#ifdef CONFIG_PROC_PID_CPUSET REG("cpuset", S_IRUGO, cpuset), #endif +#ifdef CONFIG_CGROUPS + REG("cgroup", S_IRUGO, cgroup), +#endif INF("oom_score", S_IRUGO, oom_score), REG("oom_adj", S_IRUGO|S_IWUSR, oom_adjust), #ifdef CONFIG_AUDITSYSCALL @@ -2143,27 +2276,27 @@ static const struct inode_operations proc_tgid_base_inode_operations = { * that no dcache entries will exist at process exit time it * just makes it very unlikely that any will persist. */ -void proc_flush_task(struct task_struct *task) +static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid) { struct dentry *dentry, *leader, *dir; char buf[PROC_NUMBUF]; struct qstr name; name.name = buf; - name.len = snprintf(buf, sizeof(buf), "%d", task->pid); - dentry = d_hash_and_lookup(proc_mnt->mnt_root, &name); + name.len = snprintf(buf, sizeof(buf), "%d", pid); + dentry = d_hash_and_lookup(mnt->mnt_root, &name); if (dentry) { shrink_dcache_parent(dentry); d_drop(dentry); dput(dentry); } - if (thread_group_leader(task)) + if (tgid == 0) goto out; name.name = buf; - name.len = snprintf(buf, sizeof(buf), "%d", task->tgid); - leader = d_hash_and_lookup(proc_mnt->mnt_root, &name); + name.len = snprintf(buf, sizeof(buf), "%d", tgid); + leader = d_hash_and_lookup(mnt->mnt_root, &name); if (!leader) goto out; @@ -2174,7 +2307,7 @@ void proc_flush_task(struct task_struct *task) goto out_put_leader; name.name = buf; - name.len = snprintf(buf, sizeof(buf), "%d", task->pid); + name.len = snprintf(buf, sizeof(buf), "%d", pid); dentry = d_hash_and_lookup(dir, &name); if (dentry) { shrink_dcache_parent(dentry); @@ -2189,6 +2322,36 @@ out: return; } +/* + * when flushing dentries from proc one need to flush them from global + * proc (proc_mnt) and from all the namespaces' procs this task was seen + * in. this call is supposed to make all this job. + */ + +void proc_flush_task(struct task_struct *task) +{ + int i, leader; + struct pid *pid, *tgid; + struct upid *upid; + + leader = thread_group_leader(task); + proc_flush_task_mnt(proc_mnt, task->pid, leader ? task->tgid : 0); + pid = task_pid(task); + if (pid->level == 0) + return; + + tgid = task_tgid(task); + for (i = 1; i <= pid->level; i++) { + upid = &pid->numbers[i]; + proc_flush_task_mnt(upid->ns->proc_mnt, upid->nr, + leader ? 0 : tgid->numbers[i].nr); + } + + upid = &pid->numbers[pid->level]; + if (upid->nr == 1) + pid_ns_release_proc(upid->ns); +} + static struct dentry *proc_pid_instantiate(struct inode *dir, struct dentry * dentry, struct task_struct *task, const void *ptr) @@ -2224,6 +2387,7 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct struct dentry *result = ERR_PTR(-ENOENT); struct task_struct *task; unsigned tgid; + struct pid_namespace *ns; result = proc_base_lookup(dir, dentry); if (!IS_ERR(result) || PTR_ERR(result) != -ENOENT) @@ -2233,8 +2397,9 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct if (tgid == ~0U) goto out; + ns = dentry->d_sb->s_fs_info; rcu_read_lock(); - task = find_task_by_pid(tgid); + task = find_task_by_pid_ns(tgid, ns); if (task) get_task_struct(task); rcu_read_unlock(); @@ -2251,7 +2416,8 @@ out: * Find the first task with tgid >= tgid * */ -static struct task_struct *next_tgid(unsigned int tgid) +static struct task_struct *next_tgid(unsigned int tgid, + struct pid_namespace *ns) { struct task_struct *task; struct pid *pid; @@ -2259,9 +2425,9 @@ static struct task_struct *next_tgid(unsigned int tgid) rcu_read_lock(); retry: task = NULL; - pid = find_ge_pid(tgid); + pid = find_ge_pid(tgid, ns); if (pid) { - tgid = pid->nr + 1; + tgid = pid_nr_ns(pid, ns) + 1; task = pid_task(pid, PIDTYPE_PID); /* What we to know is if the pid we have find is the * pid of a thread_group_leader. Testing for task @@ -2301,6 +2467,7 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) struct task_struct *reaper = get_proc_task(filp->f_path.dentry->d_inode); struct task_struct *task; int tgid; + struct pid_namespace *ns; if (!reaper) goto out_no_task; @@ -2311,11 +2478,12 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) goto out; } + ns = filp->f_dentry->d_sb->s_fs_info; tgid = filp->f_pos - TGID_OFFSET; - for (task = next_tgid(tgid); + for (task = next_tgid(tgid, ns); task; - put_task_struct(task), task = next_tgid(tgid + 1)) { - tgid = task->pid; + put_task_struct(task), task = next_tgid(tgid + 1, ns)) { + tgid = task_pid_nr_ns(task, ns); filp->f_pos = tgid + TGID_OFFSET; if (proc_pid_fill_cache(filp, dirent, filldir, task, tgid) < 0) { put_task_struct(task); @@ -2335,9 +2503,10 @@ out_no_task: static const struct pid_entry tid_base_stuff[] = { DIR("fd", S_IRUSR|S_IXUSR, fd), DIR("fdinfo", S_IRUSR|S_IXUSR, fdinfo), - INF("environ", S_IRUSR, pid_environ), + REG("environ", S_IRUSR, environ), INF("auxv", S_IRUSR, pid_auxv), INF("status", S_IRUGO, pid_status), + INF("limits", S_IRUSR, pid_limits), #ifdef CONFIG_SCHED_DEBUG REG("sched", S_IRUGO|S_IWUSR, pid_sched), #endif @@ -2366,9 +2535,12 @@ static const struct pid_entry tid_base_stuff[] = { #ifdef CONFIG_SCHEDSTATS INF("schedstat", S_IRUGO, pid_schedstat), #endif -#ifdef CONFIG_CPUSETS +#ifdef CONFIG_PROC_PID_CPUSET REG("cpuset", S_IRUGO, cpuset), #endif +#ifdef CONFIG_CGROUPS + REG("cgroup", S_IRUGO, cgroup), +#endif INF("oom_score", S_IRUGO, oom_score), REG("oom_adj", S_IRUGO|S_IWUSR, oom_adjust), #ifdef CONFIG_AUDITSYSCALL @@ -2436,6 +2608,7 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry struct task_struct *task; struct task_struct *leader = get_proc_task(dir); unsigned tid; + struct pid_namespace *ns; if (!leader) goto out_no_task; @@ -2444,14 +2617,15 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry if (tid == ~0U) goto out; + ns = dentry->d_sb->s_fs_info; rcu_read_lock(); - task = find_task_by_pid(tid); + task = find_task_by_pid_ns(tid, ns); if (task) get_task_struct(task); rcu_read_unlock(); if (!task) goto out; - if (leader->tgid != task->tgid) + if (!same_thread_group(leader, task)) goto out_drop_task; result = proc_task_instantiate(dir, dentry, task, NULL); @@ -2476,14 +2650,14 @@ out_no_task: * threads past it. */ static struct task_struct *first_tid(struct task_struct *leader, - int tid, int nr) + int tid, int nr, struct pid_namespace *ns) { struct task_struct *pos; rcu_read_lock(); /* Attempt to start with the pid of a thread */ if (tid && (nr > 0)) { - pos = find_task_by_pid(tid); + pos = find_task_by_pid_ns(tid, ns); if (pos && (pos->group_leader == leader)) goto found; } @@ -2552,6 +2726,7 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi ino_t ino; int tid; unsigned long pos = filp->f_pos; /* avoiding "long long" filp->f_pos */ + struct pid_namespace *ns; task = get_proc_task(inode); if (!task) @@ -2585,16 +2760,17 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi /* f_version caches the tgid value that the last readdir call couldn't * return. lseek aka telldir automagically resets f_version to 0. */ - tid = filp->f_version; + ns = filp->f_dentry->d_sb->s_fs_info; + tid = (int)filp->f_version; filp->f_version = 0; - for (task = first_tid(leader, tid, pos - 2); + for (task = first_tid(leader, tid, pos - 2, ns); task; task = next_tid(task), pos++) { - tid = task->pid; + tid = task_pid_nr_ns(task, ns); if (proc_task_fill_cache(filp, dirent, filldir, task, tid) < 0) { /* returning this tgid failed, save it as the first * pid for the next readir call */ - filp->f_version = tid; + filp->f_version = (u64)tid; put_task_struct(task); break; } diff --git a/fs/proc/generic.c b/fs/proc/generic.c index b5e7155d30d8..1bdb62435758 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -74,7 +74,7 @@ proc_file_read(struct file *file, char __user *buf, size_t nbytes, nbytes = MAX_NON_LFS - pos; dp = PDE(inode); - if (!(page = (char*) __get_free_page(GFP_KERNEL))) + if (!(page = (char*) __get_free_page(GFP_TEMPORARY))) return -ENOMEM; while ((nbytes > 0) && !eof) { diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 0e4d37c93eea..abe6a3f04368 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -107,7 +107,7 @@ static void proc_destroy_inode(struct inode *inode) kmem_cache_free(proc_inode_cachep, PROC_I(inode)); } -static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(struct kmem_cache * cachep, void *foo) { struct proc_inode *ei = (struct proc_inode *) foo; @@ -119,10 +119,8 @@ int __init proc_init_inodecache(void) proc_inode_cachep = kmem_cache_create("proc_inode_cache", sizeof(struct proc_inode), 0, (SLAB_RECLAIM_ACCOUNT| - SLAB_MEM_SPREAD), + SLAB_MEM_SPREAD|SLAB_PANIC), init_once); - if (proc_inode_cachep == NULL) - return -ENOMEM; return 0; } @@ -450,7 +448,7 @@ out_mod: return NULL; } -int proc_fill_super(struct super_block *s, void *data, int silent) +int proc_fill_super(struct super_block *s) { struct inode * root_inode; diff --git a/fs/proc/internal.h b/fs/proc/internal.h index b215c3524fa6..1820eb2ef762 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -16,6 +16,11 @@ extern int proc_sys_init(void); #else static inline void proc_sys_init(void) { } #endif +#ifdef CONFIG_NET +extern int proc_net_init(void); +#else +static inline int proc_net_init(void) { return 0; } +#endif struct vmalloc_info { unsigned long used; diff --git a/fs/proc/mmu.c b/fs/proc/mmu.c index 25d2d9c6e329..8ae221dfd010 100644 --- a/fs/proc/mmu.c +++ b/fs/proc/mmu.c @@ -8,27 +8,10 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/time.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/mman.h> -#include <linux/proc_fs.h> -#include <linux/mm.h> -#include <linux/mmzone.h> -#include <linux/pagemap.h> -#include <linux/swap.h> -#include <linux/slab.h> -#include <linux/smp.h> -#include <linux/seq_file.h> -#include <linux/hugetlb.h> +#include <linux/spinlock.h> #include <linux/vmalloc.h> -#include <asm/uaccess.h> +#include <linux/highmem.h> #include <asm/pgtable.h> -#include <asm/tlb.h> -#include <asm/div64.h> #include "internal.h" void get_vmalloc_info(struct vmalloc_info *vmi) diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index bee251cb87c8..e0d064e9764e 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -66,7 +66,6 @@ extern int get_stram_list(char *); extern int get_filesystem_list(char *); extern int get_exec_domain_list(char *); extern int get_dma_list(char *); -extern int get_locks_status (char *, char **, off_t, int); static int proc_calc_metrics(char *page, char **start, off_t off, int count, int *eof, int len) @@ -92,7 +91,8 @@ static int loadavg_read_proc(char *page, char **start, off_t off, LOAD_INT(a), LOAD_FRAC(a), LOAD_INT(b), LOAD_FRAC(b), LOAD_INT(c), LOAD_FRAC(c), - nr_running(), nr_threads, current->nsproxy->pid_ns->last_pid); + nr_running(), nr_threads, + task_active_pid_ns(current)->last_pid); return proc_calc_metrics(page, start, off, count, eof, len); } @@ -230,6 +230,19 @@ static const struct file_operations fragmentation_file_operations = { .release = seq_release, }; +extern struct seq_operations pagetypeinfo_op; +static int pagetypeinfo_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &pagetypeinfo_op); +} + +static const struct file_operations pagetypeinfo_file_ops = { + .open = pagetypeinfo_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + extern struct seq_operations zoneinfo_op; static int zoneinfo_open(struct inode *inode, struct file *file) { @@ -443,6 +456,7 @@ static int show_stat(struct seq_file *p, void *v) int i; unsigned long jif; cputime64_t user, nice, system, idle, iowait, irq, softirq, steal; + cputime64_t guest; u64 sum = 0; struct timespec boottime; unsigned int *per_irq_sum; @@ -453,6 +467,7 @@ static int show_stat(struct seq_file *p, void *v) user = nice = system = idle = iowait = irq = softirq = steal = cputime64_zero; + guest = cputime64_zero; getboottime(&boottime); jif = boottime.tv_sec; @@ -467,6 +482,7 @@ static int show_stat(struct seq_file *p, void *v) irq = cputime64_add(irq, kstat_cpu(i).cpustat.irq); softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq); steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal); + guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest); for (j = 0; j < NR_IRQS; j++) { unsigned int temp = kstat_cpu(i).irqs[j]; sum += temp; @@ -474,7 +490,7 @@ static int show_stat(struct seq_file *p, void *v) } } - seq_printf(p, "cpu %llu %llu %llu %llu %llu %llu %llu %llu\n", + seq_printf(p, "cpu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n", (unsigned long long)cputime64_to_clock_t(user), (unsigned long long)cputime64_to_clock_t(nice), (unsigned long long)cputime64_to_clock_t(system), @@ -482,7 +498,8 @@ static int show_stat(struct seq_file *p, void *v) (unsigned long long)cputime64_to_clock_t(iowait), (unsigned long long)cputime64_to_clock_t(irq), (unsigned long long)cputime64_to_clock_t(softirq), - (unsigned long long)cputime64_to_clock_t(steal)); + (unsigned long long)cputime64_to_clock_t(steal), + (unsigned long long)cputime64_to_clock_t(guest)); for_each_online_cpu(i) { /* Copy values here to work around gcc-2.95.3, gcc-2.96 */ @@ -494,7 +511,9 @@ static int show_stat(struct seq_file *p, void *v) irq = kstat_cpu(i).cpustat.irq; softirq = kstat_cpu(i).cpustat.softirq; steal = kstat_cpu(i).cpustat.steal; - seq_printf(p, "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu\n", + guest = kstat_cpu(i).cpustat.guest; + seq_printf(p, + "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu\n", i, (unsigned long long)cputime64_to_clock_t(user), (unsigned long long)cputime64_to_clock_t(nice), @@ -503,15 +522,13 @@ static int show_stat(struct seq_file *p, void *v) (unsigned long long)cputime64_to_clock_t(iowait), (unsigned long long)cputime64_to_clock_t(irq), (unsigned long long)cputime64_to_clock_t(softirq), - (unsigned long long)cputime64_to_clock_t(steal)); + (unsigned long long)cputime64_to_clock_t(steal), + (unsigned long long)cputime64_to_clock_t(guest)); } seq_printf(p, "intr %llu", (unsigned long long)sum); -#ifndef CONFIG_SMP - /* Touches too many cache lines on SMP setups */ for (i = 0; i < NR_IRQS; i++) seq_printf(p, " %u", per_irq_sum[i]); -#endif seq_printf(p, "\nctxt %llu\n" @@ -617,16 +634,18 @@ static int cmdline_read_proc(char *page, char **start, off_t off, return proc_calc_metrics(page, start, off, count, eof, len); } -static int locks_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int locks_open(struct inode *inode, struct file *filp) { - int len = get_locks_status(page, start, off, count); - - if (len < count) - *eof = 1; - return len; + return seq_open(filp, &locks_seq_operations); } +static const struct file_operations proc_locks_operations = { + .open = locks_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + static int execdomains_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -684,7 +703,6 @@ void __init proc_misc_init(void) #endif {"filesystems", filesystems_read_proc}, {"cmdline", cmdline_read_proc}, - {"locks", locks_read_proc}, {"execdomains", execdomains_read_proc}, {NULL,} }; @@ -702,6 +720,7 @@ void __init proc_misc_init(void) entry->proc_fops = &proc_kmsg_operations; } #endif + create_seq_entry("locks", 0, &proc_locks_operations); create_seq_entry("devices", 0, &proc_devinfo_operations); create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations); #ifdef CONFIG_BLOCK @@ -716,6 +735,7 @@ void __init proc_misc_init(void) #endif #endif create_seq_entry("buddyinfo",S_IRUGO, &fragmentation_file_operations); + create_seq_entry("pagetypeinfo", S_IRUGO, &pagetypeinfo_file_ops); create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations); create_seq_entry("zoneinfo",S_IRUGO, &proc_zoneinfo_file_operations); #ifdef CONFIG_BLOCK diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c new file mode 100644 index 000000000000..2e91fb756e9a --- /dev/null +++ b/fs/proc/proc_net.c @@ -0,0 +1,200 @@ +/* + * linux/fs/proc/net.c + * + * Copyright (C) 2007 + * + * Author: Eric Biederman <ebiederm@xmission.com> + * + * proc net directory handling functions + */ + +#include <asm/uaccess.h> + +#include <linux/errno.h> +#include <linux/time.h> +#include <linux/proc_fs.h> +#include <linux/stat.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/module.h> +#include <linux/bitops.h> +#include <linux/smp_lock.h> +#include <linux/mount.h> +#include <linux/nsproxy.h> +#include <net/net_namespace.h> + +#include "internal.h" + + +struct proc_dir_entry *proc_net_create(struct net *net, + const char *name, mode_t mode, get_info_t *get_info) +{ + return create_proc_info_entry(name,mode, net->proc_net, get_info); +} +EXPORT_SYMBOL_GPL(proc_net_create); + +struct proc_dir_entry *proc_net_fops_create(struct net *net, + const char *name, mode_t mode, const struct file_operations *fops) +{ + struct proc_dir_entry *res; + + res = create_proc_entry(name, mode, net->proc_net); + if (res) + res->proc_fops = fops; + return res; +} +EXPORT_SYMBOL_GPL(proc_net_fops_create); + +void proc_net_remove(struct net *net, const char *name) +{ + remove_proc_entry(name, net->proc_net); +} +EXPORT_SYMBOL_GPL(proc_net_remove); + +struct net *get_proc_net(const struct inode *inode) +{ + return maybe_get_net(PDE_NET(PDE(inode))); +} +EXPORT_SYMBOL_GPL(get_proc_net); + +static struct proc_dir_entry *proc_net_shadow; + +static struct dentry *proc_net_shadow_dentry(struct dentry *parent, + struct proc_dir_entry *de) +{ + struct dentry *shadow = NULL; + struct inode *inode; + if (!de) + goto out; + de_get(de); + inode = proc_get_inode(parent->d_inode->i_sb, de->low_ino, de); + if (!inode) + goto out_de_put; + shadow = d_alloc_name(parent, de->name); + if (!shadow) + goto out_iput; + shadow->d_op = parent->d_op; /* proc_dentry_operations */ + d_instantiate(shadow, inode); +out: + return shadow; +out_iput: + iput(inode); +out_de_put: + de_put(de); + goto out; +} + +static void *proc_net_follow_link(struct dentry *parent, struct nameidata *nd) +{ + struct net *net = current->nsproxy->net_ns; + struct dentry *shadow; + shadow = proc_net_shadow_dentry(parent, net->proc_net); + if (!shadow) + return ERR_PTR(-ENOENT); + + dput(nd->dentry); + /* My dentry count is 1 and that should be enough as the + * shadow dentry is thrown away immediately. + */ + nd->dentry = shadow; + return NULL; +} + +static struct dentry *proc_net_lookup(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) +{ + struct net *net = current->nsproxy->net_ns; + struct dentry *shadow; + + shadow = proc_net_shadow_dentry(nd->dentry, net->proc_net); + if (!shadow) + return ERR_PTR(-ENOENT); + + dput(nd->dentry); + nd->dentry = shadow; + + return shadow->d_inode->i_op->lookup(shadow->d_inode, dentry, nd); +} + +static int proc_net_setattr(struct dentry *dentry, struct iattr *iattr) +{ + struct net *net = current->nsproxy->net_ns; + struct dentry *shadow; + int ret; + + shadow = proc_net_shadow_dentry(dentry->d_parent, net->proc_net); + if (!shadow) + return -ENOENT; + ret = shadow->d_inode->i_op->setattr(shadow, iattr); + dput(shadow); + return ret; +} + +static const struct file_operations proc_net_dir_operations = { + .read = generic_read_dir, +}; + +static struct inode_operations proc_net_dir_inode_operations = { + .follow_link = proc_net_follow_link, + .lookup = proc_net_lookup, + .setattr = proc_net_setattr, +}; + +static __net_init int proc_net_ns_init(struct net *net) +{ + struct proc_dir_entry *root, *netd, *net_statd; + int err; + + err = -ENOMEM; + root = kzalloc(sizeof(*root), GFP_KERNEL); + if (!root) + goto out; + + err = -EEXIST; + netd = proc_mkdir("net", root); + if (!netd) + goto free_root; + + err = -EEXIST; + net_statd = proc_mkdir("stat", netd); + if (!net_statd) + goto free_net; + + root->data = net; + netd->data = net; + net_statd->data = net; + + net->proc_net_root = root; + net->proc_net = netd; + net->proc_net_stat = net_statd; + err = 0; + +out: + return err; +free_net: + remove_proc_entry("net", root); +free_root: + kfree(root); + goto out; +} + +static __net_exit void proc_net_ns_exit(struct net *net) +{ + remove_proc_entry("stat", net->proc_net); + remove_proc_entry("net", net->proc_net_root); + kfree(net->proc_net_root); +} + +struct pernet_operations __net_initdata proc_net_ns_ops = { + .init = proc_net_ns_init, + .exit = proc_net_ns_exit, +}; + +int __init proc_net_init(void) +{ + proc_net_shadow = proc_mkdir("net", NULL); + proc_net_shadow->proc_iops = &proc_net_dir_inode_operations; + proc_net_shadow->proc_fops = &proc_net_dir_operations; + + return register_pernet_subsys(&proc_net_ns_ops); +} diff --git a/fs/proc/root.c b/fs/proc/root.c index 41f17037f738..ec9cb3b6c93b 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -18,32 +18,90 @@ #include <linux/bitops.h> #include <linux/smp_lock.h> #include <linux/mount.h> +#include <linux/pid_namespace.h> #include "internal.h" -struct proc_dir_entry *proc_net, *proc_net_stat, *proc_bus, *proc_root_fs, *proc_root_driver; +struct proc_dir_entry *proc_bus, *proc_root_fs, *proc_root_driver; + +static int proc_test_super(struct super_block *sb, void *data) +{ + return sb->s_fs_info == data; +} + +static int proc_set_super(struct super_block *sb, void *data) +{ + struct pid_namespace *ns; + + ns = (struct pid_namespace *)data; + sb->s_fs_info = get_pid_ns(ns); + return set_anon_super(sb, NULL); +} static int proc_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) { + int err; + struct super_block *sb; + struct pid_namespace *ns; + struct proc_inode *ei; + if (proc_mnt) { /* Seed the root directory with a pid so it doesn't need * to be special in base.c. I would do this earlier but * the only task alive when /proc is mounted the first time * is the init_task and it doesn't have any pids. */ - struct proc_inode *ei; ei = PROC_I(proc_mnt->mnt_sb->s_root->d_inode); if (!ei->pid) ei->pid = find_get_pid(1); } - return get_sb_single(fs_type, flags, data, proc_fill_super, mnt); + + if (flags & MS_KERNMOUNT) + ns = (struct pid_namespace *)data; + else + ns = current->nsproxy->pid_ns; + + sb = sget(fs_type, proc_test_super, proc_set_super, ns); + if (IS_ERR(sb)) + return PTR_ERR(sb); + + if (!sb->s_root) { + sb->s_flags = flags; + err = proc_fill_super(sb); + if (err) { + up_write(&sb->s_umount); + deactivate_super(sb); + return err; + } + + ei = PROC_I(sb->s_root->d_inode); + if (!ei->pid) { + rcu_read_lock(); + ei->pid = get_pid(find_pid_ns(1, ns)); + rcu_read_unlock(); + } + + sb->s_flags |= MS_ACTIVE; + ns->proc_mnt = mnt; + } + + return simple_set_mnt(mnt, sb); +} + +static void proc_kill_sb(struct super_block *sb) +{ + struct pid_namespace *ns; + + ns = (struct pid_namespace *)sb->s_fs_info; + kill_anon_super(sb); + put_pid_ns(ns); } static struct file_system_type proc_fs_type = { .name = "proc", .get_sb = proc_get_sb, - .kill_sb = kill_anon_super, + .kill_sb = proc_kill_sb, }; void __init proc_root_init(void) @@ -54,15 +112,16 @@ void __init proc_root_init(void) err = register_filesystem(&proc_fs_type); if (err) return; - proc_mnt = kern_mount(&proc_fs_type); + proc_mnt = kern_mount_data(&proc_fs_type, &init_pid_ns); err = PTR_ERR(proc_mnt); if (IS_ERR(proc_mnt)) { unregister_filesystem(&proc_fs_type); return; } + proc_misc_init(); - proc_net = proc_mkdir("net", NULL); - proc_net_stat = proc_mkdir("net/stat", NULL); + + proc_net_init(); #ifdef CONFIG_SYSVIPC proc_mkdir("sysvipc", NULL); @@ -153,13 +212,27 @@ struct proc_dir_entry proc_root = { .parent = &proc_root, }; +int pid_ns_prepare_proc(struct pid_namespace *ns) +{ + struct vfsmount *mnt; + + mnt = kern_mount_data(&proc_fs_type, ns); + if (IS_ERR(mnt)) + return PTR_ERR(mnt); + + return 0; +} + +void pid_ns_release_proc(struct pid_namespace *ns) +{ + mntput(ns->proc_mnt); +} + EXPORT_SYMBOL(proc_symlink); EXPORT_SYMBOL(proc_mkdir); EXPORT_SYMBOL(create_proc_entry); EXPORT_SYMBOL(remove_proc_entry); EXPORT_SYMBOL(proc_root); EXPORT_SYMBOL(proc_root_fs); -EXPORT_SYMBOL(proc_net); -EXPORT_SYMBOL(proc_net_stat); EXPORT_SYMBOL(proc_bus); EXPORT_SYMBOL(proc_root_driver); diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 1bc8d873a9e1..638bdb963213 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -433,16 +433,21 @@ static int qnx4_writepage(struct page *page, struct writeback_control *wbc) { return block_write_full_page(page,qnx4_get_block, wbc); } + static int qnx4_readpage(struct file *file, struct page *page) { return block_read_full_page(page,qnx4_get_block); } -static int qnx4_prepare_write(struct file *file, struct page *page, - unsigned from, unsigned to) + +static int qnx4_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - struct qnx4_inode_info *qnx4_inode = qnx4_i(page->mapping->host); - return cont_prepare_write(page, from, to, qnx4_get_block, - &qnx4_inode->mmu_private); + struct qnx4_inode_info *qnx4_inode = qnx4_i(mapping->host); + *pagep = NULL; + return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + qnx4_get_block, + &qnx4_inode->mmu_private); } static sector_t qnx4_bmap(struct address_space *mapping, sector_t block) { @@ -452,8 +457,8 @@ static const struct address_space_operations qnx4_aops = { .readpage = qnx4_readpage, .writepage = qnx4_writepage, .sync_page = block_sync_page, - .prepare_write = qnx4_prepare_write, - .commit_write = generic_commit_write, + .write_begin = qnx4_write_begin, + .write_end = generic_write_end, .bmap = qnx4_bmap }; @@ -531,8 +536,7 @@ static void qnx4_destroy_inode(struct inode *inode) kmem_cache_free(qnx4_inode_cachep, qnx4_i(inode)); } -static void init_once(void *foo, struct kmem_cache * cachep, - unsigned long flags) +static void init_once(struct kmem_cache *cachep, void *foo) { struct qnx4_inode_info *ei = (struct qnx4_inode_info *) foo; diff --git a/fs/ramfs/Makefile b/fs/ramfs/Makefile index 5a0236e02ee1..c71e65dcad25 100644 --- a/fs/ramfs/Makefile +++ b/fs/ramfs/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux ramfs routines. # -obj-$(CONFIG_RAMFS) += ramfs.o +obj-y += ramfs.o file-mmu-y := file-nommu.o file-mmu-$(CONFIG_MMU) := file-mmu.o diff --git a/fs/ramfs/file-mmu.c b/fs/ramfs/file-mmu.c index 97bdc0b2f9d2..b41a514b0976 100644 --- a/fs/ramfs/file-mmu.c +++ b/fs/ramfs/file-mmu.c @@ -29,8 +29,8 @@ const struct address_space_operations ramfs_aops = { .readpage = simple_readpage, - .prepare_write = simple_prepare_write, - .commit_write = simple_commit_write, + .write_begin = simple_write_begin, + .write_end = simple_write_end, .set_page_dirty = __set_page_dirty_no_writeback, }; diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c index 237fe8b8e819..0989bc2c2f69 100644 --- a/fs/ramfs/file-nommu.c +++ b/fs/ramfs/file-nommu.c @@ -29,8 +29,8 @@ static int ramfs_nommu_setattr(struct dentry *, struct iattr *); const struct address_space_operations ramfs_aops = { .readpage = simple_readpage, - .prepare_write = simple_prepare_write, - .commit_write = simple_commit_write, + .write_begin = simple_write_begin, + .write_end = simple_write_end, .set_page_dirty = __set_page_dirty_no_writeback, }; diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index ef2b46d099ff..8428d5b2711d 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -223,7 +223,17 @@ module_exit(exit_ramfs_fs) int __init init_rootfs(void) { - return register_filesystem(&rootfs_fs_type); + int err; + + err = bdi_init(&ramfs_backing_dev_info); + if (err) + return err; + + err = register_filesystem(&rootfs_fs_type); + if (err) + bdi_destroy(&ramfs_backing_dev_info); + + return err; } MODULE_LICENSE("GPL"); diff --git a/fs/read_write.c b/fs/read_write.c index 507ddff48a9a..124693e8d3fa 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -205,7 +205,7 @@ int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count if (unlikely((pos < 0) || (loff_t) (pos + count) < 0)) goto Einval; - if (unlikely(inode->i_flock && MANDATORY_LOCK(inode))) { + if (unlikely(inode->i_flock && mandatory_lock(inode))) { int retval = locks_mandatory_area( read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE, inode, file, pos, count); diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c index b286ccb08587..16b331dd9913 100644 --- a/fs/reiserfs/bitmap.c +++ b/fs/reiserfs/bitmap.c @@ -47,7 +47,9 @@ test_bit(_ALLOC_ ## optname , &SB_ALLOC_OPTS(s)) static inline void get_bit_address(struct super_block *s, - b_blocknr_t block, int *bmap_nr, int *offset) + b_blocknr_t block, + unsigned int *bmap_nr, + unsigned int *offset) { /* It is in the bitmap block number equal to the block * number divided by the number of bits in a block. */ @@ -56,10 +58,10 @@ static inline void get_bit_address(struct super_block *s, *offset = block & ((s->s_blocksize << 3) - 1); } -#ifdef CONFIG_REISERFS_CHECK int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value) { - int bmap, offset; + unsigned int bmap, offset; + unsigned int bmap_count = reiserfs_bmap_count(s); if (block == 0 || block >= SB_BLOCK_COUNT(s)) { reiserfs_warning(s, @@ -75,25 +77,26 @@ int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value) if (unlikely(test_bit(REISERFS_OLD_FORMAT, &(REISERFS_SB(s)->s_properties)))) { b_blocknr_t bmap1 = REISERFS_SB(s)->s_sbh->b_blocknr + 1; - if (block >= bmap1 && block <= bmap1 + SB_BMAP_NR(s)) { + if (block >= bmap1 && + block <= bmap1 + bmap_count) { reiserfs_warning(s, "vs: 4019: is_reusable: " "bitmap block %lu(%u) can't be freed or reused", - block, SB_BMAP_NR(s)); + block, bmap_count); return 0; } } else { if (offset == 0) { reiserfs_warning(s, "vs: 4020: is_reusable: " "bitmap block %lu(%u) can't be freed or reused", - block, SB_BMAP_NR(s)); + block, bmap_count); return 0; } } - if (bmap >= SB_BMAP_NR(s)) { + if (bmap >= bmap_count) { reiserfs_warning(s, "vs-4030: is_reusable: there is no so many bitmap blocks: " - "block=%lu, bitmap_nr=%d", block, bmap); + "block=%lu, bitmap_nr=%u", block, bmap); return 0; } @@ -106,12 +109,11 @@ int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value) return 1; } -#endif /* CONFIG_REISERFS_CHECK */ /* searches in journal structures for a given block number (bmap, off). If block is found in reiserfs journal it suggests next free block candidate to test. */ -static inline int is_block_in_journal(struct super_block *s, int bmap, int - off, int *next) +static inline int is_block_in_journal(struct super_block *s, unsigned int bmap, + int off, int *next) { b_blocknr_t tmp; @@ -132,8 +134,8 @@ static inline int is_block_in_journal(struct super_block *s, int bmap, int /* it searches for a window of zero bits with given minimum and maximum lengths in one bitmap * block; */ static int scan_bitmap_block(struct reiserfs_transaction_handle *th, - int bmap_n, int *beg, int boundary, int min, - int max, int unfm) + unsigned int bmap_n, int *beg, int boundary, + int min, int max, int unfm) { struct super_block *s = th->t_super; struct reiserfs_bitmap_info *bi = &SB_AP_BITMAP(s)[bmap_n]; @@ -143,8 +145,8 @@ static int scan_bitmap_block(struct reiserfs_transaction_handle *th, BUG_ON(!th->t_trans_id); - RFALSE(bmap_n >= SB_BMAP_NR(s), "Bitmap %d is out of range (0..%d)", - bmap_n, SB_BMAP_NR(s) - 1); + RFALSE(bmap_n >= reiserfs_bmap_count(s), "Bitmap %u is out of " + "range (0..%u)", bmap_n, reiserfs_bmap_count(s) - 1); PROC_INFO_INC(s, scan_bitmap.bmap); /* this is unclear and lacks comments, explain how journal bitmaps work here for the reader. Convey a sense of the design here. What @@ -249,12 +251,12 @@ static int bmap_hash_id(struct super_block *s, u32 id) } else { hash_in = (char *)(&id); hash = keyed_hash(hash_in, 4); - bm = hash % SB_BMAP_NR(s); + bm = hash % reiserfs_bmap_count(s); if (!bm) bm = 1; } /* this can only be true when SB_BMAP_NR = 1 */ - if (bm >= SB_BMAP_NR(s)) + if (bm >= reiserfs_bmap_count(s)) bm = 0; return bm; } @@ -273,7 +275,7 @@ static inline int block_group_used(struct super_block *s, u32 id) * to make a better decision. This favors long-term performace gain * with a better on-disk layout vs. a short term gain of skipping the * read and potentially having a bad placement. */ - if (info->first_zero_hint == 0) { + if (info->free_count == UINT_MAX) { struct buffer_head *bh = reiserfs_read_bitmap_block(s, bm); brelse(bh); } @@ -309,16 +311,16 @@ __le32 reiserfs_choose_packing(struct inode * dir) * bitmap and place new blocks there. Returns number of allocated blocks. */ static int scan_bitmap(struct reiserfs_transaction_handle *th, b_blocknr_t * start, b_blocknr_t finish, - int min, int max, int unfm, unsigned long file_block) + int min, int max, int unfm, sector_t file_block) { int nr_allocated = 0; struct super_block *s = th->t_super; /* find every bm and bmap and bmap_nr in this file, and change them all to bitmap_blocknr * - Hans, it is not a block number - Zam. */ - int bm, off; - int end_bm, end_off; - int off_max = s->s_blocksize << 3; + unsigned int bm, off; + unsigned int end_bm, end_off; + unsigned int off_max = s->s_blocksize << 3; BUG_ON(!th->t_trans_id); @@ -328,10 +330,10 @@ static int scan_bitmap(struct reiserfs_transaction_handle *th, get_bit_address(s, *start, &bm, &off); get_bit_address(s, finish, &end_bm, &end_off); - if (bm > SB_BMAP_NR(s)) + if (bm > reiserfs_bmap_count(s)) return 0; - if (end_bm > SB_BMAP_NR(s)) - end_bm = SB_BMAP_NR(s); + if (end_bm > reiserfs_bmap_count(s)) + end_bm = reiserfs_bmap_count(s); /* When the bitmap is more than 10% free, anyone can allocate. * When it's less than 10% free, only files that already use the @@ -385,7 +387,7 @@ static void _reiserfs_free_block(struct reiserfs_transaction_handle *th, struct reiserfs_super_block *rs; struct buffer_head *sbh, *bmbh; struct reiserfs_bitmap_info *apbi; - int nr, offset; + unsigned int nr, offset; BUG_ON(!th->t_trans_id); @@ -397,10 +399,12 @@ static void _reiserfs_free_block(struct reiserfs_transaction_handle *th, get_bit_address(s, block, &nr, &offset); - if (nr >= sb_bmap_nr(rs)) { + if (nr >= reiserfs_bmap_count(s)) { reiserfs_warning(s, "vs-4075: reiserfs_free_block: " - "block %lu is out of range on %s", - block, reiserfs_bdevname(s)); + "block %lu is out of range on %s " + "(nr=%u,max=%u)", block, + reiserfs_bdevname(s), nr, + reiserfs_bmap_count(s)); return; } @@ -434,12 +438,19 @@ void reiserfs_free_block(struct reiserfs_transaction_handle *th, int for_unformatted) { struct super_block *s = th->t_super; - BUG_ON(!th->t_trans_id); RFALSE(!s, "vs-4061: trying to free block on nonexistent device"); - RFALSE(is_reusable(s, block, 1) == 0, - "vs-4071: can not free such block"); + if (!is_reusable(s, block, 1)) + return; + + if (block > sb_block_count(REISERFS_SB(s)->s_rs)) { + reiserfs_panic(th->t_super, "bitmap-4072", + "Trying to free block outside file system " + "boundaries (%lu > %lu)", + block, sb_block_count(REISERFS_SB(s)->s_rs)); + return; + } /* mark it before we clear it, just in case */ journal_mark_freed(th, s, block); _reiserfs_free_block(th, inode, block, for_unformatted); @@ -449,11 +460,11 @@ void reiserfs_free_block(struct reiserfs_transaction_handle *th, static void reiserfs_free_prealloc_block(struct reiserfs_transaction_handle *th, struct inode *inode, b_blocknr_t block) { + BUG_ON(!th->t_trans_id); RFALSE(!th->t_super, "vs-4060: trying to free block on nonexistent device"); - RFALSE(is_reusable(th->t_super, block, 1) == 0, - "vs-4070: can not free such block"); - BUG_ON(!th->t_trans_id); + if (!is_reusable(th->t_super, block, 1)) + return; _reiserfs_free_block(th, inode, block, 1); } @@ -1201,90 +1212,28 @@ int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t * hint, b_blocknr_t * new return ret; } -/* These 2 functions are here to provide blocks reservation to the rest of kernel */ -/* Reserve @blocks amount of blocks in fs pointed by @sb. Caller must make sure - there are actually this much blocks on the FS available */ -void reiserfs_claim_blocks_to_be_allocated(struct super_block *sb, /* super block of - filesystem where - blocks should be - reserved */ - int blocks /* How much to reserve */ - ) -{ - - /* Fast case, if reservation is zero - exit immediately. */ - if (!blocks) - return; - - spin_lock(&REISERFS_SB(sb)->bitmap_lock); - REISERFS_SB(sb)->reserved_blocks += blocks; - spin_unlock(&REISERFS_SB(sb)->bitmap_lock); -} - -/* Unreserve @blocks amount of blocks in fs pointed by @sb */ -void reiserfs_release_claimed_blocks(struct super_block *sb, /* super block of - filesystem where - blocks should be - reserved */ - int blocks /* How much to unreserve */ - ) -{ - - /* Fast case, if unreservation is zero - exit immediately. */ - if (!blocks) - return; - - spin_lock(&REISERFS_SB(sb)->bitmap_lock); - REISERFS_SB(sb)->reserved_blocks -= blocks; - spin_unlock(&REISERFS_SB(sb)->bitmap_lock); - RFALSE(REISERFS_SB(sb)->reserved_blocks < 0, - "amount of blocks reserved became zero?"); -} - -/* This function estimates how much pages we will be able to write to FS - used for reiserfs_file_write() purposes for now. */ -int reiserfs_can_fit_pages(struct super_block *sb /* superblock of filesystem - to estimate space */ ) -{ - int space; - - spin_lock(&REISERFS_SB(sb)->bitmap_lock); - space = - (SB_FREE_BLOCKS(sb) - - REISERFS_SB(sb)->reserved_blocks) >> (PAGE_CACHE_SHIFT - - sb->s_blocksize_bits); - spin_unlock(&REISERFS_SB(sb)->bitmap_lock); - - return space > 0 ? space : 0; -} - void reiserfs_cache_bitmap_metadata(struct super_block *sb, struct buffer_head *bh, struct reiserfs_bitmap_info *info) { unsigned long *cur = (unsigned long *)(bh->b_data + bh->b_size); - info->first_zero_hint = 1 << (sb->s_blocksize_bits + 3); + /* The first bit must ALWAYS be 1 */ + BUG_ON(!reiserfs_test_le_bit(0, (unsigned long *)bh->b_data)); + + info->free_count = 0; while (--cur >= (unsigned long *)bh->b_data) { - int base = ((char *)cur - bh->b_data) << 3; + int i; /* 0 and ~0 are special, we can optimize for them */ - if (*cur == 0) { - info->first_zero_hint = base; + if (*cur == 0) info->free_count += BITS_PER_LONG; - } else if (*cur != ~0L) { /* A mix, investigate */ - int b; - for (b = BITS_PER_LONG - 1; b >= 0; b--) { - if (!reiserfs_test_le_bit(b, cur)) { - info->first_zero_hint = base + b; + else if (*cur != ~0L) /* A mix, investigate */ + for (i = BITS_PER_LONG - 1; i >= 0; i--) + if (!reiserfs_test_le_bit(i, cur)) info->free_count++; - } - } - } } - /* The first bit must ALWAYS be 1 */ - BUG_ON(info->first_zero_hint == 0); } struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, @@ -1314,7 +1263,7 @@ struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, BUG_ON(!buffer_uptodate(bh)); BUG_ON(atomic_read(&bh->b_count) == 0); - if (info->first_zero_hint == 0) + if (info->free_count == UINT_MAX) reiserfs_cache_bitmap_metadata(sb, bh, info); } @@ -1324,12 +1273,13 @@ struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, int reiserfs_init_bitmap_cache(struct super_block *sb) { struct reiserfs_bitmap_info *bitmap; + unsigned int bmap_nr = reiserfs_bmap_count(sb); - bitmap = vmalloc(sizeof (*bitmap) * SB_BMAP_NR(sb)); + bitmap = vmalloc(sizeof(*bitmap) * bmap_nr); if (bitmap == NULL) return -ENOMEM; - memset(bitmap, 0, sizeof (*bitmap) * SB_BMAP_NR(sb)); + memset(bitmap, 0xff, sizeof(*bitmap) * bmap_nr); SB_AP_BITMAP(sb) = bitmap; diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c index ffbfc2caaf20..e6b03d2020c1 100644 --- a/fs/reiserfs/dir.c +++ b/fs/reiserfs/dir.c @@ -121,6 +121,16 @@ static int reiserfs_readdir(struct file *filp, void *dirent, filldir_t filldir) continue; d_reclen = entry_length(bh, ih, entry_num); d_name = B_I_DEH_ENTRY_FILE_NAME(bh, ih, deh); + + if (d_reclen <= 0 || + d_name + d_reclen > bh->b_data + bh->b_size) { + /* There is corrupted data in entry, + * We'd better stop here */ + pathrelse(&path_to_entry); + ret = -EIO; + goto out; + } + if (!d_name[d_reclen - 1]) d_reclen = strlen(d_name); diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index 2070aeee2a52..a804903d31d1 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c @@ -153,608 +153,6 @@ static int reiserfs_sync_file(struct file *p_s_filp, return (n_err < 0) ? -EIO : 0; } -/* I really do not want to play with memory shortage right now, so - to simplify the code, we are not going to write more than this much pages at - a time. This still should considerably improve performance compared to 4k - at a time case. This is 32 pages of 4k size. */ -#define REISERFS_WRITE_PAGES_AT_A_TIME (128 * 1024) / PAGE_CACHE_SIZE - -/* Allocates blocks for a file to fulfil write request. - Maps all unmapped but prepared pages from the list. - Updates metadata with newly allocated blocknumbers as needed */ -static int reiserfs_allocate_blocks_for_region(struct reiserfs_transaction_handle *th, struct inode *inode, /* Inode we work with */ - loff_t pos, /* Writing position */ - int num_pages, /* number of pages write going - to touch */ - int write_bytes, /* amount of bytes to write */ - struct page **prepared_pages, /* array of - prepared pages - */ - int blocks_to_allocate /* Amount of blocks we - need to allocate to - fit the data into file - */ - ) -{ - struct cpu_key key; // cpu key of item that we are going to deal with - struct item_head *ih; // pointer to item head that we are going to deal with - struct buffer_head *bh; // Buffer head that contains items that we are going to deal with - __le32 *item; // pointer to item we are going to deal with - INITIALIZE_PATH(path); // path to item, that we are going to deal with. - b_blocknr_t *allocated_blocks; // Pointer to a place where allocated blocknumbers would be stored. - reiserfs_blocknr_hint_t hint; // hint structure for block allocator. - size_t res; // return value of various functions that we call. - int curr_block; // current block used to keep track of unmapped blocks. - int i; // loop counter - int itempos; // position in item - unsigned int from = (pos & (PAGE_CACHE_SIZE - 1)); // writing position in - // first page - unsigned int to = ((pos + write_bytes - 1) & (PAGE_CACHE_SIZE - 1)) + 1; /* last modified byte offset in last page */ - __u64 hole_size; // amount of blocks for a file hole, if it needed to be created. - int modifying_this_item = 0; // Flag for items traversal code to keep track - // of the fact that we already prepared - // current block for journal - int will_prealloc = 0; - RFALSE(!blocks_to_allocate, - "green-9004: tried to allocate zero blocks?"); - - /* only preallocate if this is a small write */ - if (REISERFS_I(inode)->i_prealloc_count || - (!(write_bytes & (inode->i_sb->s_blocksize - 1)) && - blocks_to_allocate < - REISERFS_SB(inode->i_sb)->s_alloc_options.preallocsize)) - will_prealloc = - REISERFS_SB(inode->i_sb)->s_alloc_options.preallocsize; - - allocated_blocks = kmalloc((blocks_to_allocate + will_prealloc) * - sizeof(b_blocknr_t), GFP_NOFS); - if (!allocated_blocks) - return -ENOMEM; - - /* First we compose a key to point at the writing position, we want to do - that outside of any locking region. */ - make_cpu_key(&key, inode, pos + 1, TYPE_ANY, 3 /*key length */ ); - - /* If we came here, it means we absolutely need to open a transaction, - since we need to allocate some blocks */ - reiserfs_write_lock(inode->i_sb); // Journaling stuff and we need that. - res = journal_begin(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb)); // Wish I know if this number enough - if (res) - goto error_exit; - reiserfs_update_inode_transaction(inode); - - /* Look for the in-tree position of our write, need path for block allocator */ - res = search_for_position_by_key(inode->i_sb, &key, &path); - if (res == IO_ERROR) { - res = -EIO; - goto error_exit; - } - - /* Allocate blocks */ - /* First fill in "hint" structure for block allocator */ - hint.th = th; // transaction handle. - hint.path = &path; // Path, so that block allocator can determine packing locality or whatever it needs to determine. - hint.inode = inode; // Inode is needed by block allocator too. - hint.search_start = 0; // We have no hint on where to search free blocks for block allocator. - hint.key = key.on_disk_key; // on disk key of file. - hint.block = inode->i_blocks >> (inode->i_sb->s_blocksize_bits - 9); // Number of disk blocks this file occupies already. - hint.formatted_node = 0; // We are allocating blocks for unformatted node. - hint.preallocate = will_prealloc; - - /* Call block allocator to allocate blocks */ - res = - reiserfs_allocate_blocknrs(&hint, allocated_blocks, - blocks_to_allocate, blocks_to_allocate); - if (res != CARRY_ON) { - if (res == NO_DISK_SPACE) { - /* We flush the transaction in case of no space. This way some - blocks might become free */ - SB_JOURNAL(inode->i_sb)->j_must_wait = 1; - res = restart_transaction(th, inode, &path); - if (res) - goto error_exit; - - /* We might have scheduled, so search again */ - res = - search_for_position_by_key(inode->i_sb, &key, - &path); - if (res == IO_ERROR) { - res = -EIO; - goto error_exit; - } - - /* update changed info for hint structure. */ - res = - reiserfs_allocate_blocknrs(&hint, allocated_blocks, - blocks_to_allocate, - blocks_to_allocate); - if (res != CARRY_ON) { - res = res == QUOTA_EXCEEDED ? -EDQUOT : -ENOSPC; - pathrelse(&path); - goto error_exit; - } - } else { - res = res == QUOTA_EXCEEDED ? -EDQUOT : -ENOSPC; - pathrelse(&path); - goto error_exit; - } - } -#ifdef __BIG_ENDIAN - // Too bad, I have not found any way to convert a given region from - // cpu format to little endian format - { - int i; - for (i = 0; i < blocks_to_allocate; i++) - allocated_blocks[i] = cpu_to_le32(allocated_blocks[i]); - } -#endif - - /* Blocks allocating well might have scheduled and tree might have changed, - let's search the tree again */ - /* find where in the tree our write should go */ - res = search_for_position_by_key(inode->i_sb, &key, &path); - if (res == IO_ERROR) { - res = -EIO; - goto error_exit_free_blocks; - } - - bh = get_last_bh(&path); // Get a bufferhead for last element in path. - ih = get_ih(&path); // Get a pointer to last item head in path. - item = get_item(&path); // Get a pointer to last item in path - - /* Let's see what we have found */ - if (res != POSITION_FOUND) { /* position not found, this means that we - might need to append file with holes - first */ - // Since we are writing past the file's end, we need to find out if - // there is a hole that needs to be inserted before our writing - // position, and how many blocks it is going to cover (we need to - // populate pointers to file blocks representing the hole with zeros) - - { - int item_offset = 1; - /* - * if ih is stat data, its offset is 0 and we don't want to - * add 1 to pos in the hole_size calculation - */ - if (is_statdata_le_ih(ih)) - item_offset = 0; - hole_size = (pos + item_offset - - (le_key_k_offset - (get_inode_item_key_version(inode), - &(ih->ih_key)) + op_bytes_number(ih, - inode-> - i_sb-> - s_blocksize))) - >> inode->i_sb->s_blocksize_bits; - } - - if (hole_size > 0) { - int to_paste = min_t(__u64, hole_size, MAX_ITEM_LEN(inode->i_sb->s_blocksize) / UNFM_P_SIZE); // How much data to insert first time. - /* area filled with zeroes, to supply as list of zero blocknumbers - We allocate it outside of loop just in case loop would spin for - several iterations. */ - char *zeros = kzalloc(to_paste * UNFM_P_SIZE, GFP_ATOMIC); // We cannot insert more than MAX_ITEM_LEN bytes anyway. - if (!zeros) { - res = -ENOMEM; - goto error_exit_free_blocks; - } - do { - to_paste = - min_t(__u64, hole_size, - MAX_ITEM_LEN(inode->i_sb-> - s_blocksize) / - UNFM_P_SIZE); - if (is_indirect_le_ih(ih)) { - /* Ok, there is existing indirect item already. Need to append it */ - /* Calculate position past inserted item */ - make_cpu_key(&key, inode, - le_key_k_offset - (get_inode_item_key_version - (inode), - &(ih->ih_key)) + - op_bytes_number(ih, - inode-> - i_sb-> - s_blocksize), - TYPE_INDIRECT, 3); - res = - reiserfs_paste_into_item(th, &path, - &key, - inode, - (char *) - zeros, - UNFM_P_SIZE - * - to_paste); - if (res) { - kfree(zeros); - goto error_exit_free_blocks; - } - } else if (is_statdata_le_ih(ih)) { - /* No existing item, create it */ - /* item head for new item */ - struct item_head ins_ih; - - /* create a key for our new item */ - make_cpu_key(&key, inode, 1, - TYPE_INDIRECT, 3); - - /* Create new item head for our new item */ - make_le_item_head(&ins_ih, &key, - key.version, 1, - TYPE_INDIRECT, - to_paste * - UNFM_P_SIZE, - 0 /* free space */ ); - - /* Find where such item should live in the tree */ - res = - search_item(inode->i_sb, &key, - &path); - if (res != ITEM_NOT_FOUND) { - /* item should not exist, otherwise we have error */ - if (res != -ENOSPC) { - reiserfs_warning(inode-> - i_sb, - "green-9008: search_by_key (%K) returned %d", - &key, - res); - } - res = -EIO; - kfree(zeros); - goto error_exit_free_blocks; - } - res = - reiserfs_insert_item(th, &path, - &key, &ins_ih, - inode, - (char *)zeros); - } else { - reiserfs_panic(inode->i_sb, - "green-9011: Unexpected key type %K\n", - &key); - } - if (res) { - kfree(zeros); - goto error_exit_free_blocks; - } - /* Now we want to check if transaction is too full, and if it is - we restart it. This will also free the path. */ - if (journal_transaction_should_end - (th, th->t_blocks_allocated)) { - inode->i_size = cpu_key_k_offset(&key) + - (to_paste << inode->i_blkbits); - res = - restart_transaction(th, inode, - &path); - if (res) { - pathrelse(&path); - kfree(zeros); - goto error_exit; - } - } - - /* Well, need to recalculate path and stuff */ - set_cpu_key_k_offset(&key, - cpu_key_k_offset(&key) + - (to_paste << inode-> - i_blkbits)); - res = - search_for_position_by_key(inode->i_sb, - &key, &path); - if (res == IO_ERROR) { - res = -EIO; - kfree(zeros); - goto error_exit_free_blocks; - } - bh = get_last_bh(&path); - ih = get_ih(&path); - item = get_item(&path); - hole_size -= to_paste; - } while (hole_size); - kfree(zeros); - } - } - // Go through existing indirect items first - // replace all zeroes with blocknumbers from list - // Note that if no corresponding item was found, by previous search, - // it means there are no existing in-tree representation for file area - // we are going to overwrite, so there is nothing to scan through for holes. - for (curr_block = 0, itempos = path.pos_in_item; - curr_block < blocks_to_allocate && res == POSITION_FOUND;) { - retry: - - if (itempos >= ih_item_len(ih) / UNFM_P_SIZE) { - /* We run out of data in this indirect item, let's look for another - one. */ - /* First if we are already modifying current item, log it */ - if (modifying_this_item) { - journal_mark_dirty(th, inode->i_sb, bh); - modifying_this_item = 0; - } - /* Then set the key to look for a new indirect item (offset of old - item is added to old item length */ - set_cpu_key_k_offset(&key, - le_key_k_offset - (get_inode_item_key_version(inode), - &(ih->ih_key)) + - op_bytes_number(ih, - inode->i_sb-> - s_blocksize)); - /* Search ofor position of new key in the tree. */ - res = - search_for_position_by_key(inode->i_sb, &key, - &path); - if (res == IO_ERROR) { - res = -EIO; - goto error_exit_free_blocks; - } - bh = get_last_bh(&path); - ih = get_ih(&path); - item = get_item(&path); - itempos = path.pos_in_item; - continue; // loop to check all kinds of conditions and so on. - } - /* Ok, we have correct position in item now, so let's see if it is - representing file hole (blocknumber is zero) and fill it if needed */ - if (!item[itempos]) { - /* Ok, a hole. Now we need to check if we already prepared this - block to be journaled */ - while (!modifying_this_item) { // loop until succeed - /* Well, this item is not journaled yet, so we must prepare - it for journal first, before we can change it */ - struct item_head tmp_ih; // We copy item head of found item, - // here to detect if fs changed under - // us while we were preparing for - // journal. - int fs_gen; // We store fs generation here to find if someone - // changes fs under our feet - - copy_item_head(&tmp_ih, ih); // Remember itemhead - fs_gen = get_generation(inode->i_sb); // remember fs generation - reiserfs_prepare_for_journal(inode->i_sb, bh, 1); // Prepare a buffer within which indirect item is stored for changing. - if (fs_changed(fs_gen, inode->i_sb) - && item_moved(&tmp_ih, &path)) { - // Sigh, fs was changed under us, we need to look for new - // location of item we are working with - - /* unmark prepaerd area as journaled and search for it's - new position */ - reiserfs_restore_prepared_buffer(inode-> - i_sb, - bh); - res = - search_for_position_by_key(inode-> - i_sb, - &key, - &path); - if (res == IO_ERROR) { - res = -EIO; - goto error_exit_free_blocks; - } - bh = get_last_bh(&path); - ih = get_ih(&path); - item = get_item(&path); - itempos = path.pos_in_item; - goto retry; - } - modifying_this_item = 1; - } - item[itempos] = allocated_blocks[curr_block]; // Assign new block - curr_block++; - } - itempos++; - } - - if (modifying_this_item) { // We need to log last-accessed block, if it - // was modified, but not logged yet. - journal_mark_dirty(th, inode->i_sb, bh); - } - - if (curr_block < blocks_to_allocate) { - // Oh, well need to append to indirect item, or to create indirect item - // if there weren't any - if (is_indirect_le_ih(ih)) { - // Existing indirect item - append. First calculate key for append - // position. We do not need to recalculate path as it should - // already point to correct place. - make_cpu_key(&key, inode, - le_key_k_offset(get_inode_item_key_version - (inode), - &(ih->ih_key)) + - op_bytes_number(ih, - inode->i_sb->s_blocksize), - TYPE_INDIRECT, 3); - res = - reiserfs_paste_into_item(th, &path, &key, inode, - (char *)(allocated_blocks + - curr_block), - UNFM_P_SIZE * - (blocks_to_allocate - - curr_block)); - if (res) { - goto error_exit_free_blocks; - } - } else if (is_statdata_le_ih(ih)) { - // Last found item was statdata. That means we need to create indirect item. - struct item_head ins_ih; /* itemhead for new item */ - - /* create a key for our new item */ - make_cpu_key(&key, inode, 1, TYPE_INDIRECT, 3); // Position one, - // because that's - // where first - // indirect item - // begins - /* Create new item head for our new item */ - make_le_item_head(&ins_ih, &key, key.version, 1, - TYPE_INDIRECT, - (blocks_to_allocate - - curr_block) * UNFM_P_SIZE, - 0 /* free space */ ); - /* Find where such item should live in the tree */ - res = search_item(inode->i_sb, &key, &path); - if (res != ITEM_NOT_FOUND) { - /* Well, if we have found such item already, or some error - occured, we need to warn user and return error */ - if (res != -ENOSPC) { - reiserfs_warning(inode->i_sb, - "green-9009: search_by_key (%K) " - "returned %d", &key, - res); - } - res = -EIO; - goto error_exit_free_blocks; - } - /* Insert item into the tree with the data as its body */ - res = - reiserfs_insert_item(th, &path, &key, &ins_ih, - inode, - (char *)(allocated_blocks + - curr_block)); - } else { - reiserfs_panic(inode->i_sb, - "green-9010: unexpected item type for key %K\n", - &key); - } - } - // the caller is responsible for closing the transaction - // unless we return an error, they are also responsible for logging - // the inode. - // - pathrelse(&path); - /* - * cleanup prellocation from previous writes - * if this is a partial block write - */ - if (write_bytes & (inode->i_sb->s_blocksize - 1)) - reiserfs_discard_prealloc(th, inode); - reiserfs_write_unlock(inode->i_sb); - - // go through all the pages/buffers and map the buffers to newly allocated - // blocks (so that system knows where to write these pages later). - curr_block = 0; - for (i = 0; i < num_pages; i++) { - struct page *page = prepared_pages[i]; //current page - struct buffer_head *head = page_buffers(page); // first buffer for a page - int block_start, block_end; // in-page offsets for buffers. - - if (!page_buffers(page)) - reiserfs_panic(inode->i_sb, - "green-9005: No buffers for prepared page???"); - - /* For each buffer in page */ - for (bh = head, block_start = 0; bh != head || !block_start; - block_start = block_end, bh = bh->b_this_page) { - if (!bh) - reiserfs_panic(inode->i_sb, - "green-9006: Allocated but absent buffer for a page?"); - block_end = block_start + inode->i_sb->s_blocksize; - if (i == 0 && block_end <= from) - /* if this buffer is before requested data to map, skip it */ - continue; - if (i == num_pages - 1 && block_start >= to) - /* If this buffer is after requested data to map, abort - processing of current page */ - break; - - if (!buffer_mapped(bh)) { // Ok, unmapped buffer, need to map it - map_bh(bh, inode->i_sb, - le32_to_cpu(allocated_blocks - [curr_block])); - curr_block++; - set_buffer_new(bh); - } - } - } - - RFALSE(curr_block > blocks_to_allocate, - "green-9007: Used too many blocks? weird"); - - kfree(allocated_blocks); - return 0; - -// Need to deal with transaction here. - error_exit_free_blocks: - pathrelse(&path); - // free blocks - for (i = 0; i < blocks_to_allocate; i++) - reiserfs_free_block(th, inode, le32_to_cpu(allocated_blocks[i]), - 1); - - error_exit: - if (th->t_trans_id) { - int err; - // update any changes we made to blk count - mark_inode_dirty(inode); - err = - journal_end(th, inode->i_sb, - JOURNAL_PER_BALANCE_CNT * 3 + 1 + - 2 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb)); - if (err) - res = err; - } - reiserfs_write_unlock(inode->i_sb); - kfree(allocated_blocks); - - return res; -} - -/* Unlock pages prepared by reiserfs_prepare_file_region_for_write */ -static void reiserfs_unprepare_pages(struct page **prepared_pages, /* list of locked pages */ - size_t num_pages /* amount of pages */ ) -{ - int i; // loop counter - - for (i = 0; i < num_pages; i++) { - struct page *page = prepared_pages[i]; - - try_to_free_buffers(page); - unlock_page(page); - page_cache_release(page); - } -} - -/* This function will copy data from userspace to specified pages within - supplied byte range */ -static int reiserfs_copy_from_user_to_file_region(loff_t pos, /* In-file position */ - int num_pages, /* Number of pages affected */ - int write_bytes, /* Amount of bytes to write */ - struct page **prepared_pages, /* pointer to - array to - prepared pages - */ - const char __user * buf /* Pointer to user-supplied - data */ - ) -{ - long page_fault = 0; // status of copy_from_user. - int i; // loop counter. - int offset; // offset in page - - for (i = 0, offset = (pos & (PAGE_CACHE_SIZE - 1)); i < num_pages; - i++, offset = 0) { - size_t count = min_t(size_t, PAGE_CACHE_SIZE - offset, write_bytes); // How much of bytes to write to this page - struct page *page = prepared_pages[i]; // Current page we process. - - fault_in_pages_readable(buf, count); - - /* Copy data from userspace to the current page */ - kmap(page); - page_fault = __copy_from_user(page_address(page) + offset, buf, count); // Copy the data. - /* Flush processor's dcache for this page */ - flush_dcache_page(page); - kunmap(page); - buf += count; - write_bytes -= count; - - if (page_fault) - break; // Was there a fault? abort. - } - - return page_fault ? -EFAULT : 0; -} - /* taken fs/buffer.c:__block_commit_write */ int reiserfs_commit_page(struct inode *inode, struct page *page, unsigned from, unsigned to) @@ -824,432 +222,6 @@ int reiserfs_commit_page(struct inode *inode, struct page *page, return ret; } -/* Submit pages for write. This was separated from actual file copying - because we might want to allocate block numbers in-between. - This function assumes that caller will adjust file size to correct value. */ -static int reiserfs_submit_file_region_for_write(struct reiserfs_transaction_handle *th, struct inode *inode, loff_t pos, /* Writing position offset */ - size_t num_pages, /* Number of pages to write */ - size_t write_bytes, /* number of bytes to write */ - struct page **prepared_pages /* list of pages */ - ) -{ - int status; // return status of block_commit_write. - int retval = 0; // Return value we are going to return. - int i; // loop counter - int offset; // Writing offset in page. - int orig_write_bytes = write_bytes; - int sd_update = 0; - - for (i = 0, offset = (pos & (PAGE_CACHE_SIZE - 1)); i < num_pages; - i++, offset = 0) { - int count = min_t(int, PAGE_CACHE_SIZE - offset, write_bytes); // How much of bytes to write to this page - struct page *page = prepared_pages[i]; // Current page we process. - - status = - reiserfs_commit_page(inode, page, offset, offset + count); - if (status) - retval = status; // To not overcomplicate matters We are going to - // submit all the pages even if there was error. - // we only remember error status to report it on - // exit. - write_bytes -= count; - } - /* now that we've gotten all the ordered buffers marked dirty, - * we can safely update i_size and close any running transaction - */ - if (pos + orig_write_bytes > inode->i_size) { - inode->i_size = pos + orig_write_bytes; // Set new size - /* If the file have grown so much that tail packing is no - * longer possible, reset "need to pack" flag */ - if ((have_large_tails(inode->i_sb) && - inode->i_size > i_block_size(inode) * 4) || - (have_small_tails(inode->i_sb) && - inode->i_size > i_block_size(inode))) - REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask; - else if ((have_large_tails(inode->i_sb) && - inode->i_size < i_block_size(inode) * 4) || - (have_small_tails(inode->i_sb) && - inode->i_size < i_block_size(inode))) - REISERFS_I(inode)->i_flags |= i_pack_on_close_mask; - - if (th->t_trans_id) { - reiserfs_write_lock(inode->i_sb); - // this sets the proper flags for O_SYNC to trigger a commit - mark_inode_dirty(inode); - reiserfs_write_unlock(inode->i_sb); - } else { - reiserfs_write_lock(inode->i_sb); - reiserfs_update_inode_transaction(inode); - mark_inode_dirty(inode); - reiserfs_write_unlock(inode->i_sb); - } - - sd_update = 1; - } - if (th->t_trans_id) { - reiserfs_write_lock(inode->i_sb); - if (!sd_update) - mark_inode_dirty(inode); - status = journal_end(th, th->t_super, th->t_blocks_allocated); - if (status) - retval = status; - reiserfs_write_unlock(inode->i_sb); - } - th->t_trans_id = 0; - - /* - * we have to unlock the pages after updating i_size, otherwise - * we race with writepage - */ - for (i = 0; i < num_pages; i++) { - struct page *page = prepared_pages[i]; - unlock_page(page); - mark_page_accessed(page); - page_cache_release(page); - } - return retval; -} - -/* Look if passed writing region is going to touch file's tail - (if it is present). And if it is, convert the tail to unformatted node */ -static int reiserfs_check_for_tail_and_convert(struct inode *inode, /* inode to deal with */ - loff_t pos, /* Writing position */ - int write_bytes /* amount of bytes to write */ - ) -{ - INITIALIZE_PATH(path); // needed for search_for_position - struct cpu_key key; // Key that would represent last touched writing byte. - struct item_head *ih; // item header of found block; - int res; // Return value of various functions we call. - int cont_expand_offset; // We will put offset for generic_cont_expand here - // This can be int just because tails are created - // only for small files. - -/* this embodies a dependency on a particular tail policy */ - if (inode->i_size >= inode->i_sb->s_blocksize * 4) { - /* such a big files do not have tails, so we won't bother ourselves - to look for tails, simply return */ - return 0; - } - - reiserfs_write_lock(inode->i_sb); - /* find the item containing the last byte to be written, or if - * writing past the end of the file then the last item of the - * file (and then we check its type). */ - make_cpu_key(&key, inode, pos + write_bytes + 1, TYPE_ANY, - 3 /*key length */ ); - res = search_for_position_by_key(inode->i_sb, &key, &path); - if (res == IO_ERROR) { - reiserfs_write_unlock(inode->i_sb); - return -EIO; - } - ih = get_ih(&path); - res = 0; - if (is_direct_le_ih(ih)) { - /* Ok, closest item is file tail (tails are stored in "direct" - * items), so we need to unpack it. */ - /* To not overcomplicate matters, we just call generic_cont_expand - which will in turn call other stuff and finally will boil down to - reiserfs_get_block() that would do necessary conversion. */ - cont_expand_offset = - le_key_k_offset(get_inode_item_key_version(inode), - &(ih->ih_key)); - pathrelse(&path); - res = generic_cont_expand(inode, cont_expand_offset); - } else - pathrelse(&path); - - reiserfs_write_unlock(inode->i_sb); - return res; -} - -/* This function locks pages starting from @pos for @inode. - @num_pages pages are locked and stored in - @prepared_pages array. Also buffers are allocated for these pages. - First and last page of the region is read if it is overwritten only - partially. If last page did not exist before write (file hole or file - append), it is zeroed, then. - Returns number of unallocated blocks that should be allocated to cover - new file data.*/ -static int reiserfs_prepare_file_region_for_write(struct inode *inode - /* Inode of the file */ , - loff_t pos, /* position in the file */ - size_t num_pages, /* number of pages to - prepare */ - size_t write_bytes, /* Amount of bytes to be - overwritten from - @pos */ - struct page **prepared_pages /* pointer to array - where to store - prepared pages */ - ) -{ - int res = 0; // Return values of different functions we call. - unsigned long index = pos >> PAGE_CACHE_SHIFT; // Offset in file in pages. - int from = (pos & (PAGE_CACHE_SIZE - 1)); // Writing offset in first page - int to = ((pos + write_bytes - 1) & (PAGE_CACHE_SIZE - 1)) + 1; - /* offset of last modified byte in last - page */ - struct address_space *mapping = inode->i_mapping; // Pages are mapped here. - int i; // Simple counter - int blocks = 0; /* Return value (blocks that should be allocated) */ - struct buffer_head *bh, *head; // Current bufferhead and first bufferhead - // of a page. - unsigned block_start, block_end; // Starting and ending offsets of current - // buffer in the page. - struct buffer_head *wait[2], **wait_bh = wait; // Buffers for page, if - // Page appeared to be not up - // to date. Note how we have - // at most 2 buffers, this is - // because we at most may - // partially overwrite two - // buffers for one page. One at // the beginning of write area - // and one at the end. - // Everything inthe middle gets // overwritten totally. - - struct cpu_key key; // cpu key of item that we are going to deal with - struct item_head *ih = NULL; // pointer to item head that we are going to deal with - struct buffer_head *itembuf = NULL; // Buffer head that contains items that we are going to deal with - INITIALIZE_PATH(path); // path to item, that we are going to deal with. - __le32 *item = NULL; // pointer to item we are going to deal with - int item_pos = -1; /* Position in indirect item */ - - if (num_pages < 1) { - reiserfs_warning(inode->i_sb, - "green-9001: reiserfs_prepare_file_region_for_write " - "called with zero number of pages to process"); - return -EFAULT; - } - - /* We have 2 loops for pages. In first loop we grab and lock the pages, so - that nobody would touch these until we release the pages. Then - we'd start to deal with mapping buffers to blocks. */ - for (i = 0; i < num_pages; i++) { - prepared_pages[i] = grab_cache_page(mapping, index + i); // locks the page - if (!prepared_pages[i]) { - res = -ENOMEM; - goto failed_page_grabbing; - } - if (!page_has_buffers(prepared_pages[i])) - create_empty_buffers(prepared_pages[i], - inode->i_sb->s_blocksize, 0); - } - - /* Let's count amount of blocks for a case where all the blocks - overwritten are new (we will substract already allocated blocks later) */ - if (num_pages > 2) - /* These are full-overwritten pages so we count all the blocks in - these pages are counted as needed to be allocated */ - blocks = - (num_pages - 2) << (PAGE_CACHE_SHIFT - inode->i_blkbits); - - /* count blocks needed for first page (possibly partially written) */ - blocks += ((PAGE_CACHE_SIZE - from) >> inode->i_blkbits) + !!(from & (inode->i_sb->s_blocksize - 1)); /* roundup */ - - /* Now we account for last page. If last page == first page (we - overwrite only one page), we substract all the blocks past the - last writing position in a page out of already calculated number - of blocks */ - blocks += ((num_pages > 1) << (PAGE_CACHE_SHIFT - inode->i_blkbits)) - - ((PAGE_CACHE_SIZE - to) >> inode->i_blkbits); - /* Note how we do not roundup here since partial blocks still - should be allocated */ - - /* Now if all the write area lies past the file end, no point in - maping blocks, since there is none, so we just zero out remaining - parts of first and last pages in write area (if needed) */ - if ((pos & ~((loff_t) PAGE_CACHE_SIZE - 1)) > inode->i_size) { - if (from != 0) /* First page needs to be partially zeroed */ - zero_user_page(prepared_pages[0], 0, from, KM_USER0); - - if (to != PAGE_CACHE_SIZE) /* Last page needs to be partially zeroed */ - zero_user_page(prepared_pages[num_pages-1], to, - PAGE_CACHE_SIZE - to, KM_USER0); - - /* Since all blocks are new - use already calculated value */ - return blocks; - } - - /* Well, since we write somewhere into the middle of a file, there is - possibility we are writing over some already allocated blocks, so - let's map these blocks and substract number of such blocks out of blocks - we need to allocate (calculated above) */ - /* Mask write position to start on blocksize, we do it out of the - loop for performance reasons */ - pos &= ~((loff_t) inode->i_sb->s_blocksize - 1); - /* Set cpu key to the starting position in a file (on left block boundary) */ - make_cpu_key(&key, inode, - 1 + ((pos) & ~((loff_t) inode->i_sb->s_blocksize - 1)), - TYPE_ANY, 3 /*key length */ ); - - reiserfs_write_lock(inode->i_sb); // We need that for at least search_by_key() - for (i = 0; i < num_pages; i++) { - - head = page_buffers(prepared_pages[i]); - /* For each buffer in the page */ - for (bh = head, block_start = 0; bh != head || !block_start; - block_start = block_end, bh = bh->b_this_page) { - if (!bh) - reiserfs_panic(inode->i_sb, - "green-9002: Allocated but absent buffer for a page?"); - /* Find where this buffer ends */ - block_end = block_start + inode->i_sb->s_blocksize; - if (i == 0 && block_end <= from) - /* if this buffer is before requested data to map, skip it */ - continue; - - if (i == num_pages - 1 && block_start >= to) { - /* If this buffer is after requested data to map, abort - processing of current page */ - break; - } - - if (buffer_mapped(bh) && bh->b_blocknr != 0) { - /* This is optimisation for a case where buffer is mapped - and have blocknumber assigned. In case significant amount - of such buffers are present, we may avoid some amount - of search_by_key calls. - Probably it would be possible to move parts of this code - out of BKL, but I afraid that would overcomplicate code - without any noticeable benefit. - */ - item_pos++; - /* Update the key */ - set_cpu_key_k_offset(&key, - cpu_key_k_offset(&key) + - inode->i_sb->s_blocksize); - blocks--; // Decrease the amount of blocks that need to be - // allocated - continue; // Go to the next buffer - } - - if (!itembuf || /* if first iteration */ - item_pos >= ih_item_len(ih) / UNFM_P_SIZE) { /* or if we progressed past the - current unformatted_item */ - /* Try to find next item */ - res = - search_for_position_by_key(inode->i_sb, - &key, &path); - /* Abort if no more items */ - if (res != POSITION_FOUND) { - /* make sure later loops don't use this item */ - itembuf = NULL; - item = NULL; - break; - } - - /* Update information about current indirect item */ - itembuf = get_last_bh(&path); - ih = get_ih(&path); - item = get_item(&path); - item_pos = path.pos_in_item; - - RFALSE(!is_indirect_le_ih(ih), - "green-9003: indirect item expected"); - } - - /* See if there is some block associated with the file - at that position, map the buffer to this block */ - if (get_block_num(item, item_pos)) { - map_bh(bh, inode->i_sb, - get_block_num(item, item_pos)); - blocks--; // Decrease the amount of blocks that need to be - // allocated - } - item_pos++; - /* Update the key */ - set_cpu_key_k_offset(&key, - cpu_key_k_offset(&key) + - inode->i_sb->s_blocksize); - } - } - pathrelse(&path); // Free the path - reiserfs_write_unlock(inode->i_sb); - - /* Now zero out unmappend buffers for the first and last pages of - write area or issue read requests if page is mapped. */ - /* First page, see if it is not uptodate */ - if (!PageUptodate(prepared_pages[0])) { - head = page_buffers(prepared_pages[0]); - - /* For each buffer in page */ - for (bh = head, block_start = 0; bh != head || !block_start; - block_start = block_end, bh = bh->b_this_page) { - - if (!bh) - reiserfs_panic(inode->i_sb, - "green-9002: Allocated but absent buffer for a page?"); - /* Find where this buffer ends */ - block_end = block_start + inode->i_sb->s_blocksize; - if (block_end <= from) - /* if this buffer is before requested data to map, skip it */ - continue; - if (block_start < from) { /* Aha, our partial buffer */ - if (buffer_mapped(bh)) { /* If it is mapped, we need to - issue READ request for it to - not loose data */ - ll_rw_block(READ, 1, &bh); - *wait_bh++ = bh; - } else { /* Not mapped, zero it */ - zero_user_page(prepared_pages[0], - block_start, - from - block_start, KM_USER0); - set_buffer_uptodate(bh); - } - } - } - } - - /* Last page, see if it is not uptodate, or if the last page is past the end of the file. */ - if (!PageUptodate(prepared_pages[num_pages - 1]) || - ((pos + write_bytes) >> PAGE_CACHE_SHIFT) > - (inode->i_size >> PAGE_CACHE_SHIFT)) { - head = page_buffers(prepared_pages[num_pages - 1]); - - /* for each buffer in page */ - for (bh = head, block_start = 0; bh != head || !block_start; - block_start = block_end, bh = bh->b_this_page) { - - if (!bh) - reiserfs_panic(inode->i_sb, - "green-9002: Allocated but absent buffer for a page?"); - /* Find where this buffer ends */ - block_end = block_start + inode->i_sb->s_blocksize; - if (block_start >= to) - /* if this buffer is after requested data to map, skip it */ - break; - if (block_end > to) { /* Aha, our partial buffer */ - if (buffer_mapped(bh)) { /* If it is mapped, we need to - issue READ request for it to - not loose data */ - ll_rw_block(READ, 1, &bh); - *wait_bh++ = bh; - } else { /* Not mapped, zero it */ - zero_user_page(prepared_pages[num_pages-1], - to, block_end - to, KM_USER0); - set_buffer_uptodate(bh); - } - } - } - } - - /* Wait for read requests we made to happen, if necessary */ - while (wait_bh > wait) { - wait_on_buffer(*--wait_bh); - if (!buffer_uptodate(*wait_bh)) { - res = -EIO; - goto failed_read; - } - } - - return blocks; - failed_page_grabbing: - num_pages = i; - failed_read: - reiserfs_unprepare_pages(prepared_pages, num_pages); - return res; -} - /* Write @count bytes at position @ppos in a file indicated by @file from the buffer @buf. @@ -1284,14 +256,9 @@ static ssize_t reiserfs_file_write(struct file *file, /* the file we are going t * new current position before returning. */ ) { - size_t already_written = 0; // Number of bytes already written to the file. - loff_t pos; // Current position in the file. - ssize_t res; // return value of various functions that we call. - int err = 0; struct inode *inode = file->f_path.dentry->d_inode; // Inode of the file that we are writing to. /* To simplify coding at this time, we store locked pages in array for now */ - struct page *prepared_pages[REISERFS_WRITE_PAGES_AT_A_TIME]; struct reiserfs_transaction_handle th; th.t_trans_id = 0; @@ -1311,212 +278,7 @@ static ssize_t reiserfs_file_write(struct file *file, /* the file we are going t count = MAX_NON_LFS - (unsigned long)*ppos; } - if (file->f_flags & O_DIRECT) - return do_sync_write(file, buf, count, ppos); - - if (unlikely((ssize_t) count < 0)) - return -EINVAL; - - if (unlikely(!access_ok(VERIFY_READ, buf, count))) - return -EFAULT; - - mutex_lock(&inode->i_mutex); // locks the entire file for just us - - pos = *ppos; - - /* Check if we can write to specified region of file, file - is not overly big and this kind of stuff. Adjust pos and - count, if needed */ - res = generic_write_checks(file, &pos, &count, 0); - if (res) - goto out; - - if (count == 0) - goto out; - - res = remove_suid(file->f_path.dentry); - if (res) - goto out; - - file_update_time(file); - - // Ok, we are done with all the checks. - - // Now we should start real work - - /* If we are going to write past the file's packed tail or if we are going - to overwrite part of the tail, we need that tail to be converted into - unformatted node */ - res = reiserfs_check_for_tail_and_convert(inode, pos, count); - if (res) - goto out; - - while (count > 0) { - /* This is the main loop in which we running until some error occures - or until we write all of the data. */ - size_t num_pages; /* amount of pages we are going to write this iteration */ - size_t write_bytes; /* amount of bytes to write during this iteration */ - size_t blocks_to_allocate; /* how much blocks we need to allocate for this iteration */ - - /* (pos & (PAGE_CACHE_SIZE-1)) is an idiom for offset into a page of pos */ - num_pages = !!((pos + count) & (PAGE_CACHE_SIZE - 1)) + /* round up partial - pages */ - ((count + - (pos & (PAGE_CACHE_SIZE - 1))) >> PAGE_CACHE_SHIFT); - /* convert size to amount of - pages */ - reiserfs_write_lock(inode->i_sb); - if (num_pages > REISERFS_WRITE_PAGES_AT_A_TIME - || num_pages > reiserfs_can_fit_pages(inode->i_sb)) { - /* If we were asked to write more data than we want to or if there - is not that much space, then we shorten amount of data to write - for this iteration. */ - num_pages = - min_t(size_t, REISERFS_WRITE_PAGES_AT_A_TIME, - reiserfs_can_fit_pages(inode->i_sb)); - /* Also we should not forget to set size in bytes accordingly */ - write_bytes = (num_pages << PAGE_CACHE_SHIFT) - - (pos & (PAGE_CACHE_SIZE - 1)); - /* If position is not on the - start of the page, we need - to substract the offset - within page */ - } else - write_bytes = count; - - /* reserve the blocks to be allocated later, so that later on - we still have the space to write the blocks to */ - reiserfs_claim_blocks_to_be_allocated(inode->i_sb, - num_pages << - (PAGE_CACHE_SHIFT - - inode->i_blkbits)); - reiserfs_write_unlock(inode->i_sb); - - if (!num_pages) { /* If we do not have enough space even for a single page... */ - if (pos > - inode->i_size + inode->i_sb->s_blocksize - - (pos & (inode->i_sb->s_blocksize - 1))) { - res = -ENOSPC; - break; // In case we are writing past the end of the last file block, break. - } - // Otherwise we are possibly overwriting the file, so - // let's set write size to be equal or less than blocksize. - // This way we get it correctly for file holes. - // But overwriting files on absolutelly full volumes would not - // be very efficient. Well, people are not supposed to fill - // 100% of disk space anyway. - write_bytes = - min_t(size_t, count, - inode->i_sb->s_blocksize - - (pos & (inode->i_sb->s_blocksize - 1))); - num_pages = 1; - // No blocks were claimed before, so do it now. - reiserfs_claim_blocks_to_be_allocated(inode->i_sb, - 1 << - (PAGE_CACHE_SHIFT - - - inode-> - i_blkbits)); - } - - /* Prepare for writing into the region, read in all the - partially overwritten pages, if needed. And lock the pages, - so that nobody else can access these until we are done. - We get number of actual blocks needed as a result. */ - res = reiserfs_prepare_file_region_for_write(inode, pos, - num_pages, - write_bytes, - prepared_pages); - if (res < 0) { - reiserfs_release_claimed_blocks(inode->i_sb, - num_pages << - (PAGE_CACHE_SHIFT - - inode->i_blkbits)); - break; - } - - blocks_to_allocate = res; - - /* First we correct our estimate of how many blocks we need */ - reiserfs_release_claimed_blocks(inode->i_sb, - (num_pages << - (PAGE_CACHE_SHIFT - - inode->i_sb-> - s_blocksize_bits)) - - blocks_to_allocate); - - if (blocks_to_allocate > 0) { /*We only allocate blocks if we need to */ - /* Fill in all the possible holes and append the file if needed */ - res = - reiserfs_allocate_blocks_for_region(&th, inode, pos, - num_pages, - write_bytes, - prepared_pages, - blocks_to_allocate); - } - - /* well, we have allocated the blocks, so it is time to free - the reservation we made earlier. */ - reiserfs_release_claimed_blocks(inode->i_sb, - blocks_to_allocate); - if (res) { - reiserfs_unprepare_pages(prepared_pages, num_pages); - break; - } - -/* NOTE that allocating blocks and filling blocks can be done in reverse order - and probably we would do that just to get rid of garbage in files after a - crash */ - - /* Copy data from user-supplied buffer to file's pages */ - res = - reiserfs_copy_from_user_to_file_region(pos, num_pages, - write_bytes, - prepared_pages, buf); - if (res) { - reiserfs_unprepare_pages(prepared_pages, num_pages); - break; - } - - /* Send the pages to disk and unlock them. */ - res = - reiserfs_submit_file_region_for_write(&th, inode, pos, - num_pages, - write_bytes, - prepared_pages); - if (res) - break; - - already_written += write_bytes; - buf += write_bytes; - *ppos = pos += write_bytes; - count -= write_bytes; - balance_dirty_pages_ratelimited_nr(inode->i_mapping, num_pages); - } - - /* this is only true on error */ - if (th.t_trans_id) { - reiserfs_write_lock(inode->i_sb); - err = journal_end(&th, th.t_super, th.t_blocks_allocated); - reiserfs_write_unlock(inode->i_sb); - if (err) { - res = err; - goto out; - } - } - - if (likely(res >= 0) && - (unlikely((file->f_flags & O_SYNC) || IS_SYNC(inode)))) - res = generic_osync_inode(inode, file->f_mapping, - OSYNC_METADATA | OSYNC_DATA); - - mutex_unlock(&inode->i_mutex); - reiserfs_async_progress_wait(inode->i_sb); - return (already_written != 0) ? already_written : res; - - out: - mutex_unlock(&inode->i_mutex); // unlock the file on exit. - return res; + return do_sync_write(file, buf, count, ppos); } const struct file_operations reiserfs_file_operations = { diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index ddde489f1cb2..a991af96f3f0 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -17,11 +17,12 @@ #include <linux/mpage.h> #include <linux/writeback.h> #include <linux/quotaops.h> +#include <linux/swap.h> -static int reiserfs_commit_write(struct file *f, struct page *page, - unsigned from, unsigned to); -static int reiserfs_prepare_write(struct file *f, struct page *page, - unsigned from, unsigned to); +int reiserfs_commit_write(struct file *f, struct page *page, + unsigned from, unsigned to); +int reiserfs_prepare_write(struct file *f, struct page *page, + unsigned from, unsigned to); void reiserfs_delete_inode(struct inode *inode) { @@ -198,7 +199,7 @@ static inline void set_block_dev_mapped(struct buffer_head *bh, // files which were created in the earlier version can not be longer, // than 2 gb // -static int file_capable(struct inode *inode, long block) +static int file_capable(struct inode *inode, sector_t block) { if (get_inode_item_key_version(inode) != KEY_FORMAT_3_5 || // it is new file. block < (1 << (31 - inode->i_sb->s_blocksize_bits))) // old file, but 'block' is inside of 2gb @@ -207,8 +208,8 @@ static int file_capable(struct inode *inode, long block) return 0; } -/*static*/ int restart_transaction(struct reiserfs_transaction_handle *th, - struct inode *inode, struct treepath *path) +static int restart_transaction(struct reiserfs_transaction_handle *th, + struct inode *inode, struct treepath *path) { struct super_block *s = th->t_super; int len = th->t_blocks_allocated; @@ -241,7 +242,7 @@ static int file_capable(struct inode *inode, long block) // Please improve the english/clarity in the comment above, as it is // hard to understand. -static int _get_block_create_0(struct inode *inode, long block, +static int _get_block_create_0(struct inode *inode, sector_t block, struct buffer_head *bh_result, int args) { INITIALIZE_PATH(path); @@ -249,7 +250,7 @@ static int _get_block_create_0(struct inode *inode, long block, struct buffer_head *bh; struct item_head *ih, tmp_ih; int fs_gen; - int blocknr; + b_blocknr_t blocknr; char *p = NULL; int chars; int ret; @@ -568,7 +569,7 @@ static int convert_tail_for_hole(struct inode *inode, } static inline int _allocate_block(struct reiserfs_transaction_handle *th, - long block, + sector_t block, struct inode *inode, b_blocknr_t * allocated_block_nr, struct treepath *path, int flags) @@ -2550,8 +2551,78 @@ static int reiserfs_writepage(struct page *page, struct writeback_control *wbc) return reiserfs_write_full_page(page, wbc); } -static int reiserfs_prepare_write(struct file *f, struct page *page, - unsigned from, unsigned to) +static int reiserfs_write_begin(struct file *file, + struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) +{ + struct inode *inode; + struct page *page; + pgoff_t index; + int ret; + int old_ref = 0; + + inode = mapping->host; + *fsdata = 0; + if (flags & AOP_FLAG_CONT_EXPAND && + (pos & (inode->i_sb->s_blocksize - 1)) == 0) { + pos ++; + *fsdata = (void *)(unsigned long)flags; + } + + index = pos >> PAGE_CACHE_SHIFT; + page = __grab_cache_page(mapping, index); + if (!page) + return -ENOMEM; + *pagep = page; + + reiserfs_wait_on_write_block(inode->i_sb); + fix_tail_page_for_writing(page); + if (reiserfs_transaction_running(inode->i_sb)) { + struct reiserfs_transaction_handle *th; + th = (struct reiserfs_transaction_handle *)current-> + journal_info; + BUG_ON(!th->t_refcount); + BUG_ON(!th->t_trans_id); + old_ref = th->t_refcount; + th->t_refcount++; + } + ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + reiserfs_get_block); + if (ret && reiserfs_transaction_running(inode->i_sb)) { + struct reiserfs_transaction_handle *th = current->journal_info; + /* this gets a little ugly. If reiserfs_get_block returned an + * error and left a transacstion running, we've got to close it, + * and we've got to free handle if it was a persistent transaction. + * + * But, if we had nested into an existing transaction, we need + * to just drop the ref count on the handle. + * + * If old_ref == 0, the transaction is from reiserfs_get_block, + * and it was a persistent trans. Otherwise, it was nested above. + */ + if (th->t_refcount > old_ref) { + if (old_ref) + th->t_refcount--; + else { + int err; + reiserfs_write_lock(inode->i_sb); + err = reiserfs_end_persistent_transaction(th); + reiserfs_write_unlock(inode->i_sb); + if (err) + ret = err; + } + } + } + if (ret) { + unlock_page(page); + page_cache_release(page); + } + return ret; +} + +int reiserfs_prepare_write(struct file *f, struct page *page, + unsigned from, unsigned to) { struct inode *inode = page->mapping->host; int ret; @@ -2604,8 +2675,102 @@ static sector_t reiserfs_aop_bmap(struct address_space *as, sector_t block) return generic_block_bmap(as, block, reiserfs_bmap); } -static int reiserfs_commit_write(struct file *f, struct page *page, - unsigned from, unsigned to) +static int reiserfs_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) +{ + struct inode *inode = page->mapping->host; + int ret = 0; + int update_sd = 0; + struct reiserfs_transaction_handle *th; + unsigned start; + + if ((unsigned long)fsdata & AOP_FLAG_CONT_EXPAND) + pos ++; + + reiserfs_wait_on_write_block(inode->i_sb); + if (reiserfs_transaction_running(inode->i_sb)) + th = current->journal_info; + else + th = NULL; + + start = pos & (PAGE_CACHE_SIZE - 1); + if (unlikely(copied < len)) { + if (!PageUptodate(page)) + copied = 0; + + page_zero_new_buffers(page, start + copied, start + len); + } + flush_dcache_page(page); + + reiserfs_commit_page(inode, page, start, start + copied); + + /* generic_commit_write does this for us, but does not update the + ** transaction tracking stuff when the size changes. So, we have + ** to do the i_size updates here. + */ + pos += copied; + if (pos > inode->i_size) { + struct reiserfs_transaction_handle myth; + reiserfs_write_lock(inode->i_sb); + /* If the file have grown beyond the border where it + can have a tail, unmark it as needing a tail + packing */ + if ((have_large_tails(inode->i_sb) + && inode->i_size > i_block_size(inode) * 4) + || (have_small_tails(inode->i_sb) + && inode->i_size > i_block_size(inode))) + REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask; + + ret = journal_begin(&myth, inode->i_sb, 1); + if (ret) { + reiserfs_write_unlock(inode->i_sb); + goto journal_error; + } + reiserfs_update_inode_transaction(inode); + inode->i_size = pos; + /* + * this will just nest into our transaction. It's important + * to use mark_inode_dirty so the inode gets pushed around on the + * dirty lists, and so that O_SYNC works as expected + */ + mark_inode_dirty(inode); + reiserfs_update_sd(&myth, inode); + update_sd = 1; + ret = journal_end(&myth, inode->i_sb, 1); + reiserfs_write_unlock(inode->i_sb); + if (ret) + goto journal_error; + } + if (th) { + reiserfs_write_lock(inode->i_sb); + if (!update_sd) + mark_inode_dirty(inode); + ret = reiserfs_end_persistent_transaction(th); + reiserfs_write_unlock(inode->i_sb); + if (ret) + goto out; + } + + out: + unlock_page(page); + page_cache_release(page); + return ret == 0 ? copied : ret; + + journal_error: + if (th) { + reiserfs_write_lock(inode->i_sb); + if (!update_sd) + reiserfs_update_sd(th, inode); + ret = reiserfs_end_persistent_transaction(th); + reiserfs_write_unlock(inode->i_sb); + } + + goto out; +} + +int reiserfs_commit_write(struct file *f, struct page *page, + unsigned from, unsigned to) { struct inode *inode = page->mapping->host; loff_t pos = ((loff_t) page->index << PAGE_CACHE_SHIFT) + to; @@ -2896,7 +3061,11 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode; int error; - unsigned int ia_valid = attr->ia_valid; + unsigned int ia_valid; + + /* must be turned off for recursive notify_change calls */ + ia_valid = attr->ia_valid &= ~(ATTR_KILL_SUID|ATTR_KILL_SGID); + reiserfs_write_lock(inode->i_sb); if (attr->ia_valid & ATTR_SIZE) { /* version 2 items will be caught by the s_maxbytes check @@ -2909,7 +3078,7 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) } /* fill in hole pointers in the expanding truncate case. */ if (attr->ia_size > inode->i_size) { - error = generic_cont_expand(inode, attr->ia_size); + error = generic_cont_expand_simple(inode, attr->ia_size); if (REISERFS_I(inode)->i_prealloc_count > 0) { int err; struct reiserfs_transaction_handle th; @@ -2999,8 +3168,8 @@ const struct address_space_operations reiserfs_address_space_operations = { .releasepage = reiserfs_releasepage, .invalidatepage = reiserfs_invalidatepage, .sync_page = block_sync_page, - .prepare_write = reiserfs_prepare_write, - .commit_write = reiserfs_commit_write, + .write_begin = reiserfs_write_begin, + .write_end = reiserfs_write_end, .bmap = reiserfs_aop_bmap, .direct_IO = reiserfs_direct_IO, .set_page_dirty = reiserfs_set_page_dirty, diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c index 11a0fcc2d402..c438a8f83f26 100644 --- a/fs/reiserfs/ioctl.c +++ b/fs/reiserfs/ioctl.c @@ -128,6 +128,10 @@ long reiserfs_compat_ioctl(struct file *file, unsigned int cmd, } #endif +int reiserfs_commit_write(struct file *f, struct page *page, + unsigned from, unsigned to); +int reiserfs_prepare_write(struct file *f, struct page *page, + unsigned from, unsigned to); /* ** reiserfs_unpack ** Function try to convert tail from direct item into indirect. @@ -175,15 +179,13 @@ static int reiserfs_unpack(struct inode *inode, struct file *filp) if (!page) { goto out; } - retval = - mapping->a_ops->prepare_write(NULL, page, write_from, write_from); + retval = reiserfs_prepare_write(NULL, page, write_from, write_from); if (retval) goto out_unlock; /* conversion can change page contents, must flush */ flush_dcache_page(page); - retval = - mapping->a_ops->commit_write(NULL, page, write_from, write_from); + retval = reiserfs_commit_write(NULL, page, write_from, write_from); REISERFS_I(inode)->i_flags |= i_nopack_mask; out_unlock: diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index f25086aeef5f..bb05a3e51b93 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -219,11 +219,12 @@ static void allocate_bitmap_nodes(struct super_block *p_s_sb) } } -static int set_bit_in_list_bitmap(struct super_block *p_s_sb, int block, +static int set_bit_in_list_bitmap(struct super_block *p_s_sb, + b_blocknr_t block, struct reiserfs_list_bitmap *jb) { - int bmap_nr = block / (p_s_sb->s_blocksize << 3); - int bit_nr = block % (p_s_sb->s_blocksize << 3); + unsigned int bmap_nr = block / (p_s_sb->s_blocksize << 3); + unsigned int bit_nr = block % (p_s_sb->s_blocksize << 3); if (!jb->bitmaps[bmap_nr]) { jb->bitmaps[bmap_nr] = get_bitmap_node(p_s_sb); @@ -239,7 +240,7 @@ static void cleanup_bitmap_list(struct super_block *p_s_sb, if (jb->bitmaps == NULL) return; - for (i = 0; i < SB_BMAP_NR(p_s_sb); i++) { + for (i = 0; i < reiserfs_bmap_count(p_s_sb); i++) { if (jb->bitmaps[i]) { free_bitmap_node(p_s_sb, jb->bitmaps[i]); jb->bitmaps[i] = NULL; @@ -289,7 +290,7 @@ static int free_bitmap_nodes(struct super_block *p_s_sb) */ int reiserfs_allocate_list_bitmaps(struct super_block *p_s_sb, struct reiserfs_list_bitmap *jb_array, - int bmap_nr) + unsigned int bmap_nr) { int i; int failed = 0; @@ -483,7 +484,7 @@ static inline struct reiserfs_journal_cnode *get_journal_hash_dev(struct ** */ int reiserfs_in_journal(struct super_block *p_s_sb, - int bmap_nr, int bit_nr, int search_all, + unsigned int bmap_nr, int bit_nr, int search_all, b_blocknr_t * next_zero_bit) { struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); @@ -615,6 +616,31 @@ static int journal_list_still_alive(struct super_block *s, return 0; } +/* + * If page->mapping was null, we failed to truncate this page for + * some reason. Most likely because it was truncated after being + * logged via data=journal. + * + * This does a check to see if the buffer belongs to one of these + * lost pages before doing the final put_bh. If page->mapping was + * null, it tries to free buffers on the page, which should make the + * final page_cache_release drop the page from the lru. + */ +static void release_buffer_page(struct buffer_head *bh) +{ + struct page *page = bh->b_page; + if (!page->mapping && !TestSetPageLocked(page)) { + page_cache_get(page); + put_bh(bh); + if (!page->mapping) + try_to_free_buffers(page); + unlock_page(page); + page_cache_release(page); + } else { + put_bh(bh); + } +} + static void reiserfs_end_buffer_io_sync(struct buffer_head *bh, int uptodate) { char b[BDEVNAME_SIZE]; @@ -628,8 +654,9 @@ static void reiserfs_end_buffer_io_sync(struct buffer_head *bh, int uptodate) set_buffer_uptodate(bh); else clear_buffer_uptodate(bh); + unlock_buffer(bh); - put_bh(bh); + release_buffer_page(bh); } static void reiserfs_end_ordered_io(struct buffer_head *bh, int uptodate) @@ -966,7 +993,8 @@ static int flush_older_commits(struct super_block *s, } return 0; } -int reiserfs_async_progress_wait(struct super_block *s) + +static int reiserfs_async_progress_wait(struct super_block *s) { DEFINE_WAIT(wait); struct reiserfs_journal *j = SB_JOURNAL(s); @@ -986,7 +1014,7 @@ static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list *jl, int flushall) { int i; - int bn; + b_blocknr_t bn; struct buffer_head *tbh = NULL; unsigned long trans_id = jl->j_trans_id; struct reiserfs_journal *journal = SB_JOURNAL(s); @@ -1546,9 +1574,10 @@ static int flush_journal_list(struct super_block *s, BUG_ON(!test_clear_buffer_journal_dirty (cn->bh)); - /* undo the inc from journal_mark_dirty */ + /* drop one ref for us */ put_bh(cn->bh); - brelse(cn->bh); + /* drop one ref for journal_mark_dirty */ + release_buffer_page(cn->bh); } cn = cn->next; } @@ -2279,8 +2308,9 @@ static int journal_read_transaction(struct super_block *p_s_sb, Right now it is only used from journal code. But later we might use it from other places. Note: Do not use journal_getblk/sb_getblk functions here! */ -static struct buffer_head *reiserfs_breada(struct block_device *dev, int block, - int bufsize, unsigned int max_block) +static struct buffer_head *reiserfs_breada(struct block_device *dev, + b_blocknr_t block, int bufsize, + b_blocknr_t max_block) { struct buffer_head *bhlist[BUFNR]; unsigned int blocks = BUFNR; @@ -2621,6 +2651,61 @@ static int journal_init_dev(struct super_block *super, return result; } +/** + * When creating/tuning a file system user can assign some + * journal params within boundaries which depend on the ratio + * blocksize/standard_blocksize. + * + * For blocks >= standard_blocksize transaction size should + * be not less then JOURNAL_TRANS_MIN_DEFAULT, and not more + * then JOURNAL_TRANS_MAX_DEFAULT. + * + * For blocks < standard_blocksize these boundaries should be + * decreased proportionally. + */ +#define REISERFS_STANDARD_BLKSIZE (4096) + +static int check_advise_trans_params(struct super_block *p_s_sb, + struct reiserfs_journal *journal) +{ + if (journal->j_trans_max) { + /* Non-default journal params. + Do sanity check for them. */ + int ratio = 1; + if (p_s_sb->s_blocksize < REISERFS_STANDARD_BLKSIZE) + ratio = REISERFS_STANDARD_BLKSIZE / p_s_sb->s_blocksize; + + if (journal->j_trans_max > JOURNAL_TRANS_MAX_DEFAULT / ratio || + journal->j_trans_max < JOURNAL_TRANS_MIN_DEFAULT / ratio || + SB_ONDISK_JOURNAL_SIZE(p_s_sb) / journal->j_trans_max < + JOURNAL_MIN_RATIO) { + reiserfs_warning(p_s_sb, + "sh-462: bad transaction max size (%u). FSCK?", + journal->j_trans_max); + return 1; + } + if (journal->j_max_batch != (journal->j_trans_max) * + JOURNAL_MAX_BATCH_DEFAULT/JOURNAL_TRANS_MAX_DEFAULT) { + reiserfs_warning(p_s_sb, + "sh-463: bad transaction max batch (%u). FSCK?", + journal->j_max_batch); + return 1; + } + } else { + /* Default journal params. + The file system was created by old version + of mkreiserfs, so some fields contain zeros, + and we need to advise proper values for them */ + if (p_s_sb->s_blocksize != REISERFS_STANDARD_BLKSIZE) + reiserfs_panic(p_s_sb, "sh-464: bad blocksize (%u)", + p_s_sb->s_blocksize); + journal->j_trans_max = JOURNAL_TRANS_MAX_DEFAULT; + journal->j_max_batch = JOURNAL_MAX_BATCH_DEFAULT; + journal->j_max_commit_age = JOURNAL_MAX_COMMIT_AGE; + } + return 0; +} + /* ** must be called once on fs mount. calls journal_read for you */ @@ -2649,7 +2734,7 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name, journal->j_persistent_trans = 0; if (reiserfs_allocate_list_bitmaps(p_s_sb, journal->j_list_bitmap, - SB_BMAP_NR(p_s_sb))) + reiserfs_bmap_count(p_s_sb))) goto free_and_return; allocate_bitmap_nodes(p_s_sb); @@ -2657,7 +2742,7 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name, SB_JOURNAL_1st_RESERVED_BLOCK(p_s_sb) = (old_format ? REISERFS_OLD_DISK_OFFSET_IN_BYTES / p_s_sb->s_blocksize + - SB_BMAP_NR(p_s_sb) + + reiserfs_bmap_count(p_s_sb) + 1 : REISERFS_DISK_OFFSET_IN_BYTES / p_s_sb->s_blocksize + 2); @@ -2716,49 +2801,8 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name, le32_to_cpu(jh->jh_journal.jp_journal_max_commit_age); journal->j_max_trans_age = JOURNAL_MAX_TRANS_AGE; - if (journal->j_trans_max) { - /* make sure these parameters are available, assign it if they are not */ - __u32 initial = journal->j_trans_max; - __u32 ratio = 1; - - if (p_s_sb->s_blocksize < 4096) - ratio = 4096 / p_s_sb->s_blocksize; - - if (SB_ONDISK_JOURNAL_SIZE(p_s_sb) / journal->j_trans_max < - JOURNAL_MIN_RATIO) - journal->j_trans_max = - SB_ONDISK_JOURNAL_SIZE(p_s_sb) / JOURNAL_MIN_RATIO; - if (journal->j_trans_max > JOURNAL_TRANS_MAX_DEFAULT / ratio) - journal->j_trans_max = - JOURNAL_TRANS_MAX_DEFAULT / ratio; - if (journal->j_trans_max < JOURNAL_TRANS_MIN_DEFAULT / ratio) - journal->j_trans_max = - JOURNAL_TRANS_MIN_DEFAULT / ratio; - - if (journal->j_trans_max != initial) - reiserfs_warning(p_s_sb, - "sh-461: journal_init: wrong transaction max size (%u). Changed to %u", - initial, journal->j_trans_max); - - journal->j_max_batch = journal->j_trans_max * - JOURNAL_MAX_BATCH_DEFAULT / JOURNAL_TRANS_MAX_DEFAULT; - } - - if (!journal->j_trans_max) { - /*we have the file system was created by old version of mkreiserfs - so this field contains zero value */ - journal->j_trans_max = JOURNAL_TRANS_MAX_DEFAULT; - journal->j_max_batch = JOURNAL_MAX_BATCH_DEFAULT; - journal->j_max_commit_age = JOURNAL_MAX_COMMIT_AGE; - - /* for blocksize >= 4096 - max transaction size is 1024. For block size < 4096 - trans max size is decreased proportionally */ - if (p_s_sb->s_blocksize < 4096) { - journal->j_trans_max /= (4096 / p_s_sb->s_blocksize); - journal->j_max_batch = (journal->j_trans_max) * 9 / 10; - } - } - + if (check_advise_trans_params(p_s_sb, journal) != 0) + goto free_and_return; journal->j_default_max_commit_age = journal->j_max_commit_age; if (commit_max_age != 0) { @@ -3708,13 +3752,8 @@ int journal_mark_freed(struct reiserfs_transaction_handle *th, } } - if (bh) { - put_bh(bh); /* get_hash grabs the buffer */ - if (atomic_read(&(bh->b_count)) < 0) { - reiserfs_warning(p_s_sb, - "journal-2165: bh->b_count < 0"); - } - } + if (bh) + release_buffer_page(bh); /* get_hash grabs the buffer */ return 0; } diff --git a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c index bc808a91eeaa..5e7388b32d02 100644 --- a/fs/reiserfs/prints.c +++ b/fs/reiserfs/prints.c @@ -356,13 +356,11 @@ extern struct tree_balance *cur_tb; void reiserfs_panic(struct super_block *sb, const char *fmt, ...) { do_reiserfs_warning(fmt); - printk(KERN_EMERG "REISERFS: panic (device %s): %s\n", - reiserfs_bdevname(sb), error_buf); - BUG(); - /* this is not actually called, but makes reiserfs_panic() "noreturn" */ - panic("REISERFS: panic (device %s): %s\n", - reiserfs_bdevname(sb), error_buf); + dump_stack(); + + panic(KERN_EMERG "REISERFS: panic (device %s): %s\n", + reiserfs_bdevname(sb), error_buf); } void reiserfs_abort(struct super_block *sb, int errno, const char *fmt, ...) diff --git a/fs/reiserfs/resize.c b/fs/reiserfs/resize.c index 976cc7887a0d..f71c3948edef 100644 --- a/fs/reiserfs/resize.c +++ b/fs/reiserfs/resize.c @@ -61,7 +61,8 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new) } /* count used bits in last bitmap block */ - block_r = SB_BLOCK_COUNT(s) - (SB_BMAP_NR(s) - 1) * s->s_blocksize * 8; + block_r = SB_BLOCK_COUNT(s) - + (reiserfs_bmap_count(s) - 1) * s->s_blocksize * 8; /* count bitmap blocks in new fs */ bmap_nr_new = block_count_new / (s->s_blocksize * 8); @@ -73,7 +74,7 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new) /* save old values */ block_count = SB_BLOCK_COUNT(s); - bmap_nr = SB_BMAP_NR(s); + bmap_nr = reiserfs_bmap_count(s); /* resizing of reiserfs bitmaps (journal and real), if needed */ if (bmap_nr_new > bmap_nr) { @@ -119,7 +120,7 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new) return -ENOMEM; } memset(bitmap, 0, - sizeof(struct reiserfs_bitmap_info) * SB_BMAP_NR(s)); + sizeof(struct reiserfs_bitmap_info) * bmap_nr_new); for (i = 0; i < bmap_nr; i++) bitmap[i] = old_bitmap[i]; @@ -143,7 +144,6 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new) mark_buffer_dirty(bh); sync_dirty_buffer(bh); // update bitmap_info stuff - bitmap[i].first_zero_hint = 1; bitmap[i].free_count = sb_blocksize(sb) * 8 - 1; brelse(bh); } @@ -173,8 +173,6 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new) for (i = block_r; i < s->s_blocksize * 8; i++) reiserfs_test_and_clear_le_bit(i, bh->b_data); info->free_count += s->s_blocksize * 8 - block_r; - if (!info->first_zero_hint) - info->first_zero_hint = block_r; journal_mark_dirty(&th, s, bh); brelse(bh); @@ -196,9 +194,6 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new) brelse(bh); info->free_count -= s->s_blocksize * 8 - block_r_new; - /* Extreme case where last bitmap is the only valid block in itself. */ - if (!info->free_count) - info->first_zero_hint = 0; /* update super */ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1); free_blocks = SB_FREE_BLOCKS(s); @@ -206,7 +201,7 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new) free_blocks + (block_count_new - block_count - (bmap_nr_new - bmap_nr))); PUT_SB_BLOCK_COUNT(s, block_count_new); - PUT_SB_BMAP_NR(s, bmap_nr_new); + PUT_SB_BMAP_NR(s, bmap_would_wrap(bmap_nr_new) ? : bmap_nr_new); s->s_dirt = 1; journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s)); diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index 981027d1187b..ca41567d7890 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c @@ -559,7 +559,7 @@ static int is_tree_node(struct buffer_head *bh, int level) /* The function is NOT SCHEDULE-SAFE! */ static void search_by_key_reada(struct super_block *s, struct buffer_head **bh, - unsigned long *b, int num) + b_blocknr_t *b, int num) { int i, j; @@ -611,7 +611,7 @@ int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key, /* DISK_LEAF_NODE_LEVEL */ ) { - int n_block_number; + b_blocknr_t n_block_number; int expected_level; struct buffer_head *p_s_bh; struct path_element *p_s_last_element; @@ -619,7 +619,7 @@ int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key, /* int right_neighbor_of_leaf_node; int fs_gen; struct buffer_head *reada_bh[SEARCH_BY_KEY_READA]; - unsigned long reada_blocks[SEARCH_BY_KEY_READA]; + b_blocknr_t reada_blocks[SEARCH_BY_KEY_READA]; int reada_count = 0; #ifdef CONFIG_REISERFS_CHECK diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index a005451930b7..57adfe90d5ae 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -145,7 +145,7 @@ static int finish_unfinished(struct super_block *s) { INITIALIZE_PATH(path); struct cpu_key max_cpu_key, obj_key; - struct reiserfs_key save_link_key; + struct reiserfs_key save_link_key, last_inode_key; int retval = 0; struct item_head *ih; struct buffer_head *bh; @@ -166,6 +166,8 @@ static int finish_unfinished(struct super_block *s) set_cpu_key_k_offset(&max_cpu_key, ~0U); max_cpu_key.key_length = 3; + memset(&last_inode_key, 0, sizeof(last_inode_key)); + #ifdef CONFIG_QUOTA /* Needed for iput() to work correctly and not trash data */ if (s->s_flags & MS_ACTIVE) { @@ -278,8 +280,18 @@ static int finish_unfinished(struct super_block *s) REISERFS_I(inode)->i_flags |= i_link_saved_unlink_mask; /* not completed unlink (rmdir) found */ reiserfs_info(s, "Removing %k..", INODE_PKEY(inode)); - /* removal gets completed in iput */ - retval = 0; + if (memcmp(&last_inode_key, INODE_PKEY(inode), + sizeof(last_inode_key))){ + last_inode_key = *INODE_PKEY(inode); + /* removal gets completed in iput */ + retval = 0; + } else { + reiserfs_warning(s, "Dead loop in " + "finish_unfinished detected, " + "just remove save link\n"); + retval = remove_save_link_only(s, + &save_link_key, 0); + } } iput(inode); @@ -508,7 +520,7 @@ static void reiserfs_destroy_inode(struct inode *inode) kmem_cache_free(reiserfs_inode_cachep, REISERFS_I(inode)); } -static void init_once(void *foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(struct kmem_cache * cachep, void *foo) { struct reiserfs_inode_info *ei = (struct reiserfs_inode_info *)foo; @@ -1713,6 +1725,21 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) set_sb_umount_state(rs, REISERFS_ERROR_FS); set_sb_fs_state(rs, 0); + /* Clear out s_bmap_nr if it would wrap. We can handle this + * case, but older revisions can't. This will cause the + * file system to fail mount on those older implementations, + * avoiding corruption. -jeffm */ + if (bmap_would_wrap(reiserfs_bmap_count(s)) && + sb_bmap_nr(rs) != 0) { + reiserfs_warning(s, "super-2030: This file system " + "claims to use %u bitmap blocks in " + "its super block, but requires %u. " + "Clearing to zero.", sb_bmap_nr(rs), + reiserfs_bmap_count(s)); + + set_sb_bmap_nr(rs, 0); + } + if (old_format_only(s)) { /* filesystem of format 3.5 either with standard or non-standard journal */ diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index bf6e58214538..1597f6b649e0 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -426,6 +426,12 @@ static inline __u32 xattr_hash(const char *msg, int len) return csum_partial(msg, len, 0); } +int reiserfs_commit_write(struct file *f, struct page *page, + unsigned from, unsigned to); +int reiserfs_prepare_write(struct file *f, struct page *page, + unsigned from, unsigned to); + + /* Generic extended attribute operations that can be used by xa plugins */ /* @@ -478,7 +484,7 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer, /* Resize it so we're ok to write there */ newattrs.ia_size = buffer_size; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; - mutex_lock(&xinode->i_mutex); + mutex_lock_nested(&xinode->i_mutex, I_MUTEX_XATTR); err = notify_change(fp->f_path.dentry, &newattrs); if (err) goto out_filp; @@ -512,15 +518,15 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer, rxh->h_hash = cpu_to_le32(xahash); } - err = mapping->a_ops->prepare_write(fp, page, page_offset, - page_offset + chunk + skip); + err = reiserfs_prepare_write(fp, page, page_offset, + page_offset + chunk + skip); if (!err) { if (buffer) memcpy(data + skip, buffer + buffer_pos, chunk); err = - mapping->a_ops->commit_write(fp, page, page_offset, - page_offset + chunk + - skip); + reiserfs_commit_write(fp, page, page_offset, + page_offset + chunk + + skip); } unlock_page(page); reiserfs_put_page(page); @@ -1217,7 +1223,8 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags) if (!IS_ERR(dentry)) { if (!(mount_flags & MS_RDONLY) && !dentry->d_inode) { struct inode *inode = dentry->d_parent->d_inode; - mutex_lock(&inode->i_mutex); + mutex_lock_nested(&inode->i_mutex, + I_MUTEX_XATTR); err = inode->i_op->mkdir(inode, dentry, 0700); mutex_unlock(&inode->i_mutex); if (err) { diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c index dae7945f90e4..a49cf5b9a195 100644 --- a/fs/romfs/inode.c +++ b/fs/romfs/inode.c @@ -92,7 +92,7 @@ static inline unsigned long romfs_maxsize(struct super_block *sb) static inline struct romfs_inode_info *ROMFS_I(struct inode *inode) { - return list_entry(inode, struct romfs_inode_info, vfs_inode); + return container_of(inode, struct romfs_inode_info, vfs_inode); } static __u32 @@ -555,7 +555,7 @@ static struct kmem_cache * romfs_inode_cachep; static struct inode *romfs_alloc_inode(struct super_block *sb) { struct romfs_inode_info *ei; - ei = (struct romfs_inode_info *)kmem_cache_alloc(romfs_inode_cachep, GFP_KERNEL); + ei = kmem_cache_alloc(romfs_inode_cachep, GFP_KERNEL); if (!ei) return NULL; return &ei->vfs_inode; @@ -566,7 +566,7 @@ static void romfs_destroy_inode(struct inode *inode) kmem_cache_free(romfs_inode_cachep, ROMFS_I(inode)); } -static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags) +static void init_once(struct kmem_cache *cachep, void *foo) { struct romfs_inode_info *ei = foo; diff --git a/fs/select.c b/fs/select.c index 46dca31c607a..47f47925aea2 100644 --- a/fs/select.c +++ b/fs/select.c @@ -177,11 +177,6 @@ get_max: return max; } -#define BIT(i) (1UL << ((i)&(__NFDBITS-1))) -#define MEM(i,m) ((m)+(unsigned)(i)/__NFDBITS) -#define ISSET(i,m) (((i)&*(m)) != 0) -#define SET(i,m) (*(m) |= (i)) - #define POLLIN_SET (POLLRDNORM | POLLRDBAND | POLLIN | POLLHUP | POLLERR) #define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR) #define POLLEX_SET (POLLPRI) @@ -586,7 +581,7 @@ static int do_poll(unsigned int nfds, struct poll_list *list, /* Optimise the no-wait case */ if (!(*timeout)) pt = NULL; - + for (;;) { struct poll_list *walk; long __timeout; @@ -616,10 +611,12 @@ static int do_poll(unsigned int nfds, struct poll_list *list, * a poll_table to them on the next loop iteration. */ pt = NULL; - if (count || !*timeout || signal_pending(current)) - break; - count = wait->error; - if (count) + if (!count) { + count = wait->error; + if (signal_pending(current)) + count = -EINTR; + } + if (count || !*timeout) break; if (*timeout < 0) { @@ -651,93 +648,89 @@ static int do_poll(unsigned int nfds, struct poll_list *list, int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout) { struct poll_wqueues table; - int fdcount, err; - unsigned int i; - struct poll_list *head; - struct poll_list *walk; + int err = -EFAULT, fdcount, len, size; /* Allocate small arguments on the stack to save memory and be faster - use long to make sure the buffer is aligned properly on 64 bit archs to avoid unaligned access */ long stack_pps[POLL_STACK_ALLOC/sizeof(long)]; - struct poll_list *stack_pp = NULL; + struct poll_list *const head = (struct poll_list *)stack_pps; + struct poll_list *walk = head; + unsigned long todo = nfds; - /* Do a sanity check on nfds ... */ if (nfds > current->signal->rlim[RLIMIT_NOFILE].rlim_cur) return -EINVAL; - poll_initwait(&table); + len = min_t(unsigned int, nfds, N_STACK_PPS); + for (;;) { + walk->next = NULL; + walk->len = len; + if (!len) + break; - head = NULL; - walk = NULL; - i = nfds; - err = -ENOMEM; - while(i!=0) { - struct poll_list *pp; - int num, size; - if (stack_pp == NULL) - num = N_STACK_PPS; - else - num = POLLFD_PER_PAGE; - if (num > i) - num = i; - size = sizeof(struct poll_list) + sizeof(struct pollfd)*num; - if (!stack_pp) - stack_pp = pp = (struct poll_list *)stack_pps; - else { - pp = kmalloc(size, GFP_KERNEL); - if (!pp) - goto out_fds; - } - pp->next=NULL; - pp->len = num; - if (head == NULL) - head = pp; - else - walk->next = pp; + if (copy_from_user(walk->entries, ufds + nfds-todo, + sizeof(struct pollfd) * walk->len)) + goto out_fds; - walk = pp; - if (copy_from_user(pp->entries, ufds + nfds-i, - sizeof(struct pollfd)*num)) { - err = -EFAULT; + todo -= walk->len; + if (!todo) + break; + + len = min(todo, POLLFD_PER_PAGE); + size = sizeof(struct poll_list) + sizeof(struct pollfd) * len; + walk = walk->next = kmalloc(size, GFP_KERNEL); + if (!walk) { + err = -ENOMEM; goto out_fds; } - i -= pp->len; } + poll_initwait(&table); fdcount = do_poll(nfds, head, &table, timeout); + poll_freewait(&table); - /* OK, now copy the revents fields back to user space. */ - walk = head; - err = -EFAULT; - while(walk != NULL) { + for (walk = head; walk; walk = walk->next) { struct pollfd *fds = walk->entries; int j; - for (j=0; j < walk->len; j++, ufds++) { - if(__put_user(fds[j].revents, &ufds->revents)) + for (j = 0; j < walk->len; j++, ufds++) + if (__put_user(fds[j].revents, &ufds->revents)) goto out_fds; - } - walk = walk->next; } + err = fdcount; - if (!fdcount && signal_pending(current)) - err = -EINTR; out_fds: - walk = head; - while(walk!=NULL) { - struct poll_list *pp = walk->next; - if (walk != stack_pp) - kfree(walk); - walk = pp; + walk = head->next; + while (walk) { + struct poll_list *pos = walk; + walk = walk->next; + kfree(pos); } - poll_freewait(&table); + return err; } +static long do_restart_poll(struct restart_block *restart_block) +{ + struct pollfd __user *ufds = (struct pollfd __user*)restart_block->arg0; + int nfds = restart_block->arg1; + s64 timeout = ((s64)restart_block->arg3<<32) | (s64)restart_block->arg2; + int ret; + + ret = do_sys_poll(ufds, nfds, &timeout); + if (ret == -EINTR) { + restart_block->fn = do_restart_poll; + restart_block->arg2 = timeout & 0xFFFFFFFF; + restart_block->arg3 = (u64)timeout >> 32; + ret = -ERESTART_RESTARTBLOCK; + } + return ret; +} + asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds, long timeout_msecs) { s64 timeout_jiffies; + int ret; if (timeout_msecs > 0) { #if HZ > 1000 @@ -752,7 +745,18 @@ asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds, timeout_jiffies = timeout_msecs; } - return do_sys_poll(ufds, nfds, &timeout_jiffies); + ret = do_sys_poll(ufds, nfds, &timeout_jiffies); + if (ret == -EINTR) { + struct restart_block *restart_block; + restart_block = ¤t_thread_info()->restart_block; + restart_block->fn = do_restart_poll; + restart_block->arg0 = (unsigned long)ufds; + restart_block->arg1 = nfds; + restart_block->arg2 = timeout_jiffies & 0xFFFFFFFF; + restart_block->arg3 = (u64)timeout_jiffies >> 32; + ret = -ERESTART_RESTARTBLOCK; + } + return ret; } #ifdef TIF_RESTORE_SIGMASK diff --git a/fs/seq_file.c b/fs/seq_file.c index bbb19be260ce..ca71c115bdaa 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -429,6 +429,39 @@ int seq_release_private(struct inode *inode, struct file *file) } EXPORT_SYMBOL(seq_release_private); +void *__seq_open_private(struct file *f, const struct seq_operations *ops, + int psize) +{ + int rc; + void *private; + struct seq_file *seq; + + private = kzalloc(psize, GFP_KERNEL); + if (private == NULL) + goto out; + + rc = seq_open(f, ops); + if (rc < 0) + goto out_free; + + seq = f->private_data; + seq->private = private; + return private; + +out_free: + kfree(private); +out: + return NULL; +} +EXPORT_SYMBOL(__seq_open_private); + +int seq_open_private(struct file *filp, const struct seq_operations *ops, + int psize) +{ + return __seq_open_private(filp, ops, psize) ? 0 : -ENOMEM; +} +EXPORT_SYMBOL(seq_open_private); + int seq_putc(struct seq_file *m, char c) { if (m->count < m->size) { diff --git a/fs/signalfd.c b/fs/signalfd.c index aefb0be07942..fb7f7e8034df 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -74,45 +74,45 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, * If you change siginfo_t structure, please be sure * this code is fixed accordingly. */ - err |= __put_user(kinfo->si_signo, &uinfo->signo); - err |= __put_user(kinfo->si_errno, &uinfo->err); - err |= __put_user((short)kinfo->si_code, &uinfo->code); + err |= __put_user(kinfo->si_signo, &uinfo->ssi_signo); + err |= __put_user(kinfo->si_errno, &uinfo->ssi_errno); + err |= __put_user((short) kinfo->si_code, &uinfo->ssi_code); switch (kinfo->si_code & __SI_MASK) { case __SI_KILL: - err |= __put_user(kinfo->si_pid, &uinfo->pid); - err |= __put_user(kinfo->si_uid, &uinfo->uid); + err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid); + err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid); break; case __SI_TIMER: - err |= __put_user(kinfo->si_tid, &uinfo->tid); - err |= __put_user(kinfo->si_overrun, &uinfo->overrun); - err |= __put_user((long)kinfo->si_ptr, &uinfo->svptr); + err |= __put_user(kinfo->si_tid, &uinfo->ssi_tid); + err |= __put_user(kinfo->si_overrun, &uinfo->ssi_overrun); + err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr); break; case __SI_POLL: - err |= __put_user(kinfo->si_band, &uinfo->band); - err |= __put_user(kinfo->si_fd, &uinfo->fd); + err |= __put_user(kinfo->si_band, &uinfo->ssi_band); + err |= __put_user(kinfo->si_fd, &uinfo->ssi_fd); break; case __SI_FAULT: - err |= __put_user((long)kinfo->si_addr, &uinfo->addr); + err |= __put_user((long) kinfo->si_addr, &uinfo->ssi_addr); #ifdef __ARCH_SI_TRAPNO - err |= __put_user(kinfo->si_trapno, &uinfo->trapno); + err |= __put_user(kinfo->si_trapno, &uinfo->ssi_trapno); #endif break; case __SI_CHLD: - err |= __put_user(kinfo->si_pid, &uinfo->pid); - err |= __put_user(kinfo->si_uid, &uinfo->uid); - err |= __put_user(kinfo->si_status, &uinfo->status); - err |= __put_user(kinfo->si_utime, &uinfo->utime); - err |= __put_user(kinfo->si_stime, &uinfo->stime); + err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid); + err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid); + err |= __put_user(kinfo->si_status, &uinfo->ssi_status); + err |= __put_user(kinfo->si_utime, &uinfo->ssi_utime); + err |= __put_user(kinfo->si_stime, &uinfo->ssi_stime); break; case __SI_RT: /* This is not generated by the kernel as of now. */ case __SI_MESGQ: /* But this is */ - err |= __put_user(kinfo->si_pid, &uinfo->pid); - err |= __put_user(kinfo->si_uid, &uinfo->uid); - err |= __put_user((long)kinfo->si_ptr, &uinfo->svptr); + err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid); + err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid); + err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr); break; default: /* this is just in case for now ... */ - err |= __put_user(kinfo->si_pid, &uinfo->pid); - err |= __put_user(kinfo->si_uid, &uinfo->uid); + err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid); + err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid); break; } diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c index c5d78a7e492b..f5d14cebc75a 100644 --- a/fs/smbfs/file.c +++ b/fs/smbfs/file.c @@ -292,29 +292,45 @@ out: * If the writer ends up delaying the write, the writer needs to * increment the page use counts until he is done with the page. */ -static int smb_prepare_write(struct file *file, struct page *page, - unsigned offset, unsigned to) +static int smb_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { + pgoff_t index = pos >> PAGE_CACHE_SHIFT; + *pagep = __grab_cache_page(mapping, index); + if (!*pagep) + return -ENOMEM; return 0; } -static int smb_commit_write(struct file *file, struct page *page, - unsigned offset, unsigned to) +static int smb_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) { int status; + unsigned offset = pos & (PAGE_CACHE_SIZE - 1); - status = -EFAULT; lock_kernel(); - status = smb_updatepage(file, page, offset, to-offset); + status = smb_updatepage(file, page, offset, copied); unlock_kernel(); + + if (!status) { + if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE) + SetPageUptodate(page); + status = copied; + } + + unlock_page(page); + page_cache_release(page); + return status; } const struct address_space_operations smb_file_aops = { .readpage = smb_readpage, .writepage = smb_writepage, - .prepare_write = smb_prepare_write, - .commit_write = smb_commit_write + .write_begin = smb_write_begin, + .write_end = smb_write_end, }; /* diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 73d1450a95d4..ab517755ece0 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -67,7 +67,7 @@ static void smb_destroy_inode(struct inode *inode) kmem_cache_free(smb_inode_cachep, SMB_I(inode)); } -static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(struct kmem_cache *cachep, void *foo) { struct smb_inode_info *ei = (struct smb_inode_info *) foo; diff --git a/fs/smbfs/smbiod.c b/fs/smbfs/smbiod.c index 67176af8515f..283c5720c9de 100644 --- a/fs/smbfs/smbiod.c +++ b/fs/smbfs/smbiod.c @@ -45,7 +45,7 @@ static LIST_HEAD(smb_servers); static DEFINE_SPINLOCK(servers_lock); #define SMBIOD_DATA_READY (1<<0) -static long smbiod_flags; +static unsigned long smbiod_flags; static int smbiod(void *); static int smbiod_start(void); diff --git a/fs/splice.c b/fs/splice.c index e95a36228863..6bdcb6107bc3 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -447,7 +447,7 @@ fill_it: */ while (page_nr < nr_pages) page_cache_release(pages[page_nr++]); - in->f_ra.prev_index = index; + in->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT; if (spd.nr_pages) return splice_to_pipe(pipe, &spd); @@ -563,7 +563,7 @@ static int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf, struct address_space *mapping = file->f_mapping; unsigned int offset, this_len; struct page *page; - pgoff_t index; + void *fsdata; int ret; /* @@ -573,49 +573,16 @@ static int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf, if (unlikely(ret)) return ret; - index = sd->pos >> PAGE_CACHE_SHIFT; offset = sd->pos & ~PAGE_CACHE_MASK; this_len = sd->len; if (this_len + offset > PAGE_CACHE_SIZE) this_len = PAGE_CACHE_SIZE - offset; -find_page: - page = find_lock_page(mapping, index); - if (!page) { - ret = -ENOMEM; - page = page_cache_alloc_cold(mapping); - if (unlikely(!page)) - goto out_ret; - - /* - * This will also lock the page - */ - ret = add_to_page_cache_lru(page, mapping, index, - GFP_KERNEL); - if (unlikely(ret)) - goto out_release; - } - - ret = mapping->a_ops->prepare_write(file, page, offset, offset+this_len); - if (unlikely(ret)) { - loff_t isize = i_size_read(mapping->host); - - if (ret != AOP_TRUNCATED_PAGE) - unlock_page(page); - page_cache_release(page); - if (ret == AOP_TRUNCATED_PAGE) - goto find_page; - - /* - * prepare_write() may have instantiated a few blocks - * outside i_size. Trim these off again. - */ - if (sd->pos + this_len > isize) - vmtruncate(mapping->host, isize); - - goto out_ret; - } + ret = pagecache_write_begin(file, mapping, sd->pos, this_len, + AOP_FLAG_UNINTERRUPTIBLE, &page, &fsdata); + if (unlikely(ret)) + goto out; if (buf->page != page) { /* @@ -629,31 +596,9 @@ find_page: kunmap_atomic(dst, KM_USER1); buf->ops->unmap(pipe, buf, src); } - - ret = mapping->a_ops->commit_write(file, page, offset, offset+this_len); - if (ret) { - if (ret == AOP_TRUNCATED_PAGE) { - page_cache_release(page); - goto find_page; - } - if (ret < 0) - goto out; - /* - * Partial write has happened, so 'ret' already initialized by - * number of bytes written, Where is nothing we have to do here. - */ - } else - ret = this_len; - /* - * Return the number of bytes written and mark page as - * accessed, we are now done! - */ - mark_page_accessed(page); + ret = pagecache_write_end(file, mapping, sd->pos, this_len, this_len, + page, fsdata); out: - unlock_page(page); -out_release: - page_cache_release(page); -out_ret: return ret; } @@ -879,13 +824,18 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, { struct address_space *mapping = out->f_mapping; struct inode *inode = mapping->host; + int killsuid, killpriv; ssize_t ret; - int err; + int err = 0; - err = should_remove_suid(out->f_path.dentry); - if (unlikely(err)) { + killpriv = security_inode_need_killpriv(out->f_path.dentry); + killsuid = should_remove_suid(out->f_path.dentry); + if (unlikely(killsuid || killpriv)) { mutex_lock(&inode->i_mutex); - err = __remove_suid(out->f_path.dentry, err); + if (killpriv) + err = security_inode_killpriv(out->f_path.dentry); + if (!err && killsuid) + err = __remove_suid(out->f_path.dentry, killsuid); mutex_unlock(&inode->i_mutex); if (err) return err; @@ -1390,10 +1340,10 @@ static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf, if (copy_to_user(sd->u.userptr, src + buf->offset, sd->len)) ret = -EFAULT; + buf->ops->unmap(pipe, buf, src); out: if (ret > 0) sd->u.userptr += ret; - buf->ops->unmap(pipe, buf, src); return ret; } diff --git a/fs/super.c b/fs/super.c index fc8ebedc6bed..d28fde7e1cfb 100644 --- a/fs/super.c +++ b/fs/super.c @@ -40,10 +40,6 @@ #include <asm/uaccess.h> -void get_filesystem(struct file_system_type *fs); -void put_filesystem(struct file_system_type *fs); -struct file_system_type *get_fs_type(const char *name); - LIST_HEAD(super_blocks); DEFINE_SPINLOCK(sb_lock); @@ -67,6 +63,7 @@ static struct super_block *alloc_super(struct file_system_type *type) } INIT_LIST_HEAD(&s->s_dirty); INIT_LIST_HEAD(&s->s_io); + INIT_LIST_HEAD(&s->s_more_io); INIT_LIST_HEAD(&s->s_files); INIT_LIST_HEAD(&s->s_instances); INIT_HLIST_HEAD(&s->s_anon); @@ -335,21 +332,21 @@ struct super_block *sget(struct file_system_type *type, void *data) { struct super_block *s = NULL; - struct list_head *p; + struct super_block *old; int err; retry: spin_lock(&sb_lock); - if (test) list_for_each(p, &type->fs_supers) { - struct super_block *old; - old = list_entry(p, struct super_block, s_instances); - if (!test(old, data)) - continue; - if (!grab_super(old)) - goto retry; - if (s) - destroy_super(s); - return old; + if (test) { + list_for_each_entry(old, &type->fs_supers, s_instances) { + if (!test(old, data)) + continue; + if (!grab_super(old)) + goto retry; + if (s) + destroy_super(s); + return old; + } } if (!s) { spin_unlock(&sb_lock); @@ -947,9 +944,9 @@ do_kern_mount(const char *fstype, int flags, const char *name, void *data) return mnt; } -struct vfsmount *kern_mount(struct file_system_type *type) +struct vfsmount *kern_mount_data(struct file_system_type *type, void *data) { - return vfs_kern_mount(type, 0, type->name, NULL); + return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data); } -EXPORT_SYMBOL(kern_mount); +EXPORT_SYMBOL_GPL(kern_mount_data); diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index 5afe2a26f5d8..006fc64227dd 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c @@ -1,9 +1,15 @@ /* - * bin.c - binary file operations for sysfs. + * fs/sysfs/bin.c - sysfs binary file implementation * * Copyright (c) 2003 Patrick Mochel * Copyright (c) 2003 Matthew Wilcox * Copyright (c) 2004 Silicon Graphics, Inc. + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo <teheo@suse.de> + * + * This file is released under the GPLv2. + * + * Please see Documentation/filesystems/sysfs.txt for more information. */ #undef DEBUG @@ -14,9 +20,9 @@ #include <linux/kobject.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/mutex.h> #include <asm/uaccess.h> -#include <asm/semaphore.h> #include "sysfs.h" @@ -30,8 +36,8 @@ static int fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count) { struct sysfs_dirent *attr_sd = dentry->d_fsdata; - struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; - struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; + struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; + struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; int rc; /* need attr_sd for attr, its parent for kobj */ @@ -87,8 +93,8 @@ static int flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count) { struct sysfs_dirent *attr_sd = dentry->d_fsdata; - struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; - struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; + struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; + struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; int rc; /* need attr_sd for attr, its parent for kobj */ @@ -140,8 +146,8 @@ static int mmap(struct file *file, struct vm_area_struct *vma) { struct bin_buffer *bb = file->private_data; struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; - struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; - struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; + struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; + struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; int rc; mutex_lock(&bb->mutex); @@ -167,12 +173,12 @@ static int mmap(struct file *file, struct vm_area_struct *vma) static int open(struct inode * inode, struct file * file) { struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; - struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; + struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; struct bin_buffer *bb = NULL; int error; - /* need attr_sd for attr */ - if (!sysfs_get_active(attr_sd)) + /* binary file operations requires both @sd and its parent */ + if (!sysfs_get_active_two(attr_sd)) return -ENODEV; error = -EACCES; @@ -193,13 +199,12 @@ static int open(struct inode * inode, struct file * file) mutex_init(&bb->mutex); file->private_data = bb; - /* open succeeded, put active reference and pin attr_sd */ - sysfs_put_active(attr_sd); - sysfs_get(attr_sd); + /* open succeeded, put active references */ + sysfs_put_active_two(attr_sd); return 0; err_out: - sysfs_put_active(attr_sd); + sysfs_put_active_two(attr_sd); kfree(bb); return error; } @@ -211,7 +216,6 @@ static int release(struct inode * inode, struct file * file) if (bb->mmapped) sysfs_put_active_two(attr_sd); - sysfs_put(attr_sd); kfree(bb->buffer); kfree(bb); return 0; diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 83e76b3813c9..7a8ce9e98b32 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -1,5 +1,13 @@ /* - * dir.c - Operations for sysfs directories. + * fs/sysfs/dir.c - sysfs core and dir operation implementation + * + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo <teheo@suse.de> + * + * This file is released under the GPLv2. + * + * Please see Documentation/filesystems/sysfs.txt for more information. */ #undef DEBUG @@ -11,13 +19,14 @@ #include <linux/namei.h> #include <linux/idr.h> #include <linux/completion.h> -#include <asm/semaphore.h> +#include <linux/mutex.h> #include "sysfs.h" DEFINE_MUTEX(sysfs_mutex); -spinlock_t sysfs_assoc_lock = SPIN_LOCK_UNLOCKED; +DEFINE_MUTEX(sysfs_rename_mutex); +DEFINE_SPINLOCK(sysfs_assoc_lock); -static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(sysfs_ino_lock); static DEFINE_IDA(sysfs_ino_ida); /** @@ -25,18 +34,28 @@ static DEFINE_IDA(sysfs_ino_ida); * @sd: sysfs_dirent of interest * * Link @sd into its sibling list which starts from - * sd->s_parent->s_children. + * sd->s_parent->s_dir.children. * * Locking: * mutex_lock(sysfs_mutex) */ -void sysfs_link_sibling(struct sysfs_dirent *sd) +static void sysfs_link_sibling(struct sysfs_dirent *sd) { struct sysfs_dirent *parent_sd = sd->s_parent; + struct sysfs_dirent **pos; BUG_ON(sd->s_sibling); - sd->s_sibling = parent_sd->s_children; - parent_sd->s_children = sd; + + /* Store directory entries in order by ino. This allows + * readdir to properly restart without having to add a + * cursor into the s_dir.children list. + */ + for (pos = &parent_sd->s_dir.children; *pos; pos = &(*pos)->s_sibling) { + if (sd->s_ino < (*pos)->s_ino) + break; + } + sd->s_sibling = *pos; + *pos = sd; } /** @@ -44,16 +63,17 @@ void sysfs_link_sibling(struct sysfs_dirent *sd) * @sd: sysfs_dirent of interest * * Unlink @sd from its sibling list which starts from - * sd->s_parent->s_children. + * sd->s_parent->s_dir.children. * * Locking: * mutex_lock(sysfs_mutex) */ -void sysfs_unlink_sibling(struct sysfs_dirent *sd) +static void sysfs_unlink_sibling(struct sysfs_dirent *sd) { struct sysfs_dirent **pos; - for (pos = &sd->s_parent->s_children; *pos; pos = &(*pos)->s_sibling) { + for (pos = &sd->s_parent->s_dir.children; *pos; + pos = &(*pos)->s_sibling) { if (*pos == sd) { *pos = sd->s_sibling; sd->s_sibling = NULL; @@ -67,96 +87,38 @@ void sysfs_unlink_sibling(struct sysfs_dirent *sd) * @sd: sysfs_dirent of interest * * Get dentry for @sd. Dentry is looked up if currently not - * present. This function climbs sysfs_dirent tree till it - * reaches a sysfs_dirent with valid dentry attached and descends - * down from there looking up dentry for each step. + * present. This function descends from the root looking up + * dentry for each step. * * LOCKING: - * Kernel thread context (may sleep) + * mutex_lock(sysfs_rename_mutex) * * RETURNS: * Pointer to found dentry on success, ERR_PTR() value on error. */ struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd) { - struct sysfs_dirent *cur; - struct dentry *parent_dentry, *dentry; - int i, depth; - - /* Find the first parent which has valid s_dentry and get the - * dentry. - */ - mutex_lock(&sysfs_mutex); - restart0: - spin_lock(&sysfs_assoc_lock); - restart1: - spin_lock(&dcache_lock); + struct dentry *dentry = dget(sysfs_sb->s_root); - dentry = NULL; - depth = 0; - cur = sd; - while (!cur->s_dentry || !cur->s_dentry->d_inode) { - if (cur->s_flags & SYSFS_FLAG_REMOVED) { - dentry = ERR_PTR(-ENOENT); - depth = 0; - break; - } - cur = cur->s_parent; - depth++; - } - if (!IS_ERR(dentry)) - dentry = dget_locked(cur->s_dentry); + while (dentry->d_fsdata != sd) { + struct sysfs_dirent *cur; + struct dentry *parent; - spin_unlock(&dcache_lock); - spin_unlock(&sysfs_assoc_lock); - - /* from the found dentry, look up depth times */ - while (depth--) { - /* find and get depth'th ancestor */ - for (cur = sd, i = 0; cur && i < depth; i++) + /* find the first ancestor which hasn't been looked up */ + cur = sd; + while (cur->s_parent != dentry->d_fsdata) cur = cur->s_parent; - /* This can happen if tree structure was modified due - * to move/rename. Restart. - */ - if (i != depth) { - dput(dentry); - goto restart0; - } - - sysfs_get(cur); - - mutex_unlock(&sysfs_mutex); - /* look it up */ - parent_dentry = dentry; - dentry = lookup_one_len_kern(cur->s_name, parent_dentry, - strlen(cur->s_name)); - dput(parent_dentry); - - if (IS_ERR(dentry)) { - sysfs_put(cur); - return dentry; - } + parent = dentry; + mutex_lock(&parent->d_inode->i_mutex); + dentry = lookup_one_noperm(cur->s_name, parent); + mutex_unlock(&parent->d_inode->i_mutex); + dput(parent); - mutex_lock(&sysfs_mutex); - spin_lock(&sysfs_assoc_lock); - - /* This, again, can happen if tree structure has - * changed and we looked up the wrong thing. Restart. - */ - if (cur->s_dentry != dentry) { - dput(dentry); - sysfs_put(cur); - goto restart1; - } - - spin_unlock(&sysfs_assoc_lock); - - sysfs_put(cur); + if (IS_ERR(dentry)) + break; } - - mutex_unlock(&sysfs_mutex); return dentry; } @@ -319,7 +281,7 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) parent_sd = sd->s_parent; if (sysfs_type(sd) == SYSFS_KOBJ_LINK) - sysfs_put(sd->s_elem.symlink.target_sd); + sysfs_put(sd->s_symlink.target_sd); if (sysfs_type(sd) & SYSFS_COPY_NAME) kfree(sd->s_name); kfree(sd->s_iattr); @@ -335,22 +297,7 @@ static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) { struct sysfs_dirent * sd = dentry->d_fsdata; - if (sd) { - /* sd->s_dentry is protected with sysfs_assoc_lock. - * This allows sysfs_drop_dentry() to dereference it. - */ - spin_lock(&sysfs_assoc_lock); - - /* The dentry might have been deleted or another - * lookup could have happened updating sd->s_dentry to - * point the new dentry. Ignore if it isn't pointing - * to this dentry. - */ - if (sd->s_dentry == dentry) - sd->s_dentry = NULL; - spin_unlock(&sysfs_assoc_lock); - sysfs_put(sd); - } + sysfs_put(sd); iput(inode); } @@ -378,7 +325,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) atomic_set(&sd->s_count, 1); atomic_set(&sd->s_active, 0); - atomic_set(&sd->s_event, 1); sd->s_name = name; sd->s_mode = mode; @@ -393,30 +339,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) return NULL; } -/** - * sysfs_attach_dentry - associate sysfs_dirent with dentry - * @sd: target sysfs_dirent - * @dentry: dentry to associate - * - * Associate @sd with @dentry. This is protected by - * sysfs_assoc_lock to avoid race with sysfs_d_iput(). - * - * LOCKING: - * mutex_lock(sysfs_mutex) - */ -static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry) -{ - dentry->d_op = &sysfs_dentry_ops; - dentry->d_fsdata = sysfs_get(sd); - - /* protect sd->s_dentry against sysfs_d_iput */ - spin_lock(&sysfs_assoc_lock); - sd->s_dentry = dentry; - spin_unlock(&sysfs_assoc_lock); - - d_rehash(dentry); -} - static int sysfs_ilookup_test(struct inode *inode, void *arg) { struct sysfs_dirent *sd = arg; @@ -480,10 +402,8 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, * @sd: sysfs_dirent to be added * * Get @acxt->parent_sd and set sd->s_parent to it and increment - * nlink of parent inode if @sd is a directory. @sd is NOT - * linked into the children list of the parent. The caller - * should invoke sysfs_link_sibling() after this function - * completes if @sd needs to be on the children list. + * nlink of parent inode if @sd is a directory and link into the + * children list of the parent. * * This function should be called between calls to * sysfs_addrm_start() and sysfs_addrm_finish() and should be @@ -491,15 +411,30 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, * * LOCKING: * Determined by sysfs_addrm_start(). + * + * RETURNS: + * 0 on success, -EEXIST if entry with the given name already + * exists. */ -void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) +int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) { + if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) { + printk(KERN_WARNING "sysfs: duplicate filename '%s' " + "can not be created\n", sd->s_name); + WARN_ON(1); + return -EEXIST; + } + sd->s_parent = sysfs_get(acxt->parent_sd); if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode) inc_nlink(acxt->parent_inode); acxt->cnt++; + + sysfs_link_sibling(sd); + + return 0; } /** @@ -508,9 +443,7 @@ void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) * @sd: sysfs_dirent to be added * * Mark @sd removed and drop nlink of parent inode if @sd is a - * directory. @sd is NOT unlinked from the children list of the - * parent. The caller is repsonsible for removing @sd from the - * children list before calling this function. + * directory. @sd is unlinked from the children list. * * This function should be called between calls to * sysfs_addrm_start() and sysfs_addrm_finish() and should be @@ -521,7 +454,9 @@ void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) */ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) { - BUG_ON(sd->s_sibling || (sd->s_flags & SYSFS_FLAG_REMOVED)); + BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED); + + sysfs_unlink_sibling(sd); sd->s_flags |= SYSFS_FLAG_REMOVED; sd->s_sibling = acxt->removed; @@ -540,53 +475,49 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) * Drop dentry for @sd. @sd must have been unlinked from its * parent on entry to this function such that it can't be looked * up anymore. - * - * @sd->s_dentry which is protected with sysfs_assoc_lock points - * to the currently associated dentry but we're not holding a - * reference to it and racing with dput(). Grab dcache_lock and - * verify dentry before dropping it. If @sd->s_dentry is NULL or - * dput() beats us, no need to bother. */ static void sysfs_drop_dentry(struct sysfs_dirent *sd) { - struct dentry *dentry = NULL; struct inode *inode; + struct dentry *dentry; + + inode = ilookup(sysfs_sb, sd->s_ino); + if (!inode) + return; - /* We're not holding a reference to ->s_dentry dentry but the - * field will stay valid as long as sysfs_assoc_lock is held. + /* Drop any existing dentries associated with sd. + * + * For the dentry to be properly freed we need to grab a + * reference to the dentry under the dcache lock, unhash it, + * and then put it. The playing with the dentry count allows + * dput to immediately free the dentry if it is not in use. */ - spin_lock(&sysfs_assoc_lock); +repeat: spin_lock(&dcache_lock); - - /* drop dentry if it's there and dput() didn't kill it yet */ - if (sd->s_dentry && sd->s_dentry->d_inode) { - dentry = dget_locked(sd->s_dentry); + list_for_each_entry(dentry, &inode->i_dentry, d_alias) { + if (d_unhashed(dentry)) + continue; + dget_locked(dentry); spin_lock(&dentry->d_lock); __d_drop(dentry); spin_unlock(&dentry->d_lock); + spin_unlock(&dcache_lock); + dput(dentry); + goto repeat; } - spin_unlock(&dcache_lock); - spin_unlock(&sysfs_assoc_lock); - - /* dentries for shadowed inodes are pinned, unpin */ - if (dentry && sysfs_is_shadowed_inode(dentry->d_inode)) - dput(dentry); - dput(dentry); /* adjust nlink and update timestamp */ - inode = ilookup(sysfs_sb, sd->s_ino); - if (inode) { - mutex_lock(&inode->i_mutex); + mutex_lock(&inode->i_mutex); - inode->i_ctime = CURRENT_TIME; + inode->i_ctime = CURRENT_TIME; + drop_nlink(inode); + if (sysfs_type(sd) == SYSFS_DIR) drop_nlink(inode); - if (sysfs_type(sd) == SYSFS_DIR) - drop_nlink(inode); - mutex_unlock(&inode->i_mutex); - iput(inode); - } + mutex_unlock(&inode->i_mutex); + + iput(inode); } /** @@ -599,11 +530,8 @@ static void sysfs_drop_dentry(struct sysfs_dirent *sd) * * LOCKING: * All mutexes acquired by sysfs_addrm_start() are released. - * - * RETURNS: - * Number of added/removed sysfs_dirents since sysfs_addrm_start(). */ -int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) +void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) { /* release resources acquired by sysfs_addrm_start() */ mutex_unlock(&sysfs_mutex); @@ -629,8 +557,6 @@ int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) sysfs_deactivate(sd); sysfs_put(sd); } - - return acxt->cnt; } /** @@ -651,8 +577,8 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, { struct sysfs_dirent *sd; - for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) - if (sysfs_type(sd) && !strcmp(sd->s_name, name)) + for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling) + if (!strcmp(sd->s_name, name)) return sd; return NULL; } @@ -690,28 +616,25 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; struct sysfs_addrm_cxt acxt; struct sysfs_dirent *sd; + int rc; /* allocate */ sd = sysfs_new_dirent(name, mode, SYSFS_DIR); if (!sd) return -ENOMEM; - sd->s_elem.dir.kobj = kobj; + sd->s_dir.kobj = kobj; /* link in */ sysfs_addrm_start(&acxt, parent_sd); + rc = sysfs_add_one(&acxt, sd); + sysfs_addrm_finish(&acxt); - if (!sysfs_find_dirent(parent_sd, name)) { - sysfs_add_one(&acxt, sd); - sysfs_link_sibling(sd); - } - - if (!sysfs_addrm_finish(&acxt)) { + if (rc == 0) + *p_sd = sd; + else sysfs_put(sd); - return -EEXIST; - } - *p_sd = sd; - return 0; + return rc; } int sysfs_create_subdir(struct kobject *kobj, const char *name, @@ -723,24 +646,18 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name, /** * sysfs_create_dir - create a directory for an object. * @kobj: object we're creating directory for. - * @shadow_parent: parent object. */ -int sysfs_create_dir(struct kobject *kobj, - struct sysfs_dirent *shadow_parent_sd) +int sysfs_create_dir(struct kobject * kobj) { struct sysfs_dirent *parent_sd, *sd; int error = 0; BUG_ON(!kobj); - if (shadow_parent_sd) - parent_sd = shadow_parent_sd; - else if (kobj->parent) + if (kobj->parent) parent_sd = kobj->parent->sd; - else if (sysfs_mount && sysfs_mount->mnt_sb) - parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata; else - return -EFAULT; + parent_sd = &sysfs_root; error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd); if (!error) @@ -748,39 +665,20 @@ int sysfs_create_dir(struct kobject *kobj, return error; } -static int sysfs_count_nlink(struct sysfs_dirent *sd) -{ - struct sysfs_dirent *child; - int nr = 0; - - for (child = sd->s_children; child; child = child->s_sibling) - if (sysfs_type(child) == SYSFS_DIR) - nr++; - return nr + 2; -} - static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct dentry *ret = NULL; - struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata; - struct sysfs_dirent * sd; - struct bin_attribute *bin_attr; + struct sysfs_dirent *parent_sd = dentry->d_parent->d_fsdata; + struct sysfs_dirent *sd; struct inode *inode; - int found = 0; mutex_lock(&sysfs_mutex); - for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) { - if (sysfs_type(sd) && - !strcmp(sd->s_name, dentry->d_name.name)) { - found = 1; - break; - } - } + sd = sysfs_find_dirent(parent_sd, dentry->d_name.name); /* no such entry */ - if (!found) + if (!sd) goto out_unlock; /* attach dentry and inode */ @@ -790,33 +688,11 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, goto out_unlock; } - if (inode->i_state & I_NEW) { - /* initialize inode according to type */ - switch (sysfs_type(sd)) { - case SYSFS_DIR: - inode->i_op = &sysfs_dir_inode_operations; - inode->i_fop = &sysfs_dir_operations; - inode->i_nlink = sysfs_count_nlink(sd); - break; - case SYSFS_KOBJ_ATTR: - inode->i_size = PAGE_SIZE; - inode->i_fop = &sysfs_file_operations; - break; - case SYSFS_KOBJ_BIN_ATTR: - bin_attr = sd->s_elem.bin_attr.bin_attr; - inode->i_size = bin_attr->size; - inode->i_fop = &bin_fops; - break; - case SYSFS_KOBJ_LINK: - inode->i_op = &sysfs_symlink_inode_operations; - break; - default: - BUG(); - } - } - - sysfs_instantiate(dentry, inode); - sysfs_attach_dentry(sd, dentry); + /* instantiate and hash dentry */ + dentry->d_op = &sysfs_dentry_ops; + dentry->d_fsdata = sysfs_get(sd); + d_instantiate(dentry, inode); + d_rehash(dentry); out_unlock: mutex_unlock(&sysfs_mutex); @@ -833,7 +709,6 @@ static void remove_dir(struct sysfs_dirent *sd) struct sysfs_addrm_cxt acxt; sysfs_addrm_start(&acxt, sd->s_parent); - sysfs_unlink_sibling(sd); sysfs_remove_one(&acxt, sd); sysfs_addrm_finish(&acxt); } @@ -854,15 +729,13 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) pr_debug("sysfs %s: removing dir\n", dir_sd->s_name); sysfs_addrm_start(&acxt, dir_sd); - pos = &dir_sd->s_children; + pos = &dir_sd->s_dir.children; while (*pos) { struct sysfs_dirent *sd = *pos; - if (sysfs_type(sd) && sysfs_type(sd) != SYSFS_DIR) { - *pos = sd->s_sibling; - sd->s_sibling = NULL; + if (sysfs_type(sd) != SYSFS_DIR) sysfs_remove_one(&acxt, sd); - } else + else pos = &(*pos)->s_sibling; } sysfs_addrm_finish(&acxt); @@ -890,90 +763,68 @@ void sysfs_remove_dir(struct kobject * kobj) __sysfs_remove_dir(sd); } -int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd, - const char *new_name) +int sysfs_rename_dir(struct kobject * kobj, const char *new_name) { struct sysfs_dirent *sd = kobj->sd; - struct dentry *new_parent = NULL; + struct dentry *parent = NULL; struct dentry *old_dentry = NULL, *new_dentry = NULL; const char *dup_name = NULL; int error; - /* get dentries */ + mutex_lock(&sysfs_rename_mutex); + + error = 0; + if (strcmp(sd->s_name, new_name) == 0) + goto out; /* nothing to rename */ + + /* get the original dentry */ old_dentry = sysfs_get_dentry(sd); if (IS_ERR(old_dentry)) { error = PTR_ERR(old_dentry); - goto out_dput; - } - - new_parent = sysfs_get_dentry(new_parent_sd); - if (IS_ERR(new_parent)) { - error = PTR_ERR(new_parent); - goto out_dput; + goto out; } - /* lock new_parent and get dentry for new name */ - mutex_lock(&new_parent->d_inode->i_mutex); + parent = old_dentry->d_parent; - new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name)); - if (IS_ERR(new_dentry)) { - error = PTR_ERR(new_dentry); - goto out_unlock; - } + /* lock parent and get dentry for new name */ + mutex_lock(&parent->d_inode->i_mutex); + mutex_lock(&sysfs_mutex); - /* By allowing two different directories with the same - * d_parent we allow this routine to move between different - * shadows of the same directory - */ - error = -EINVAL; - if (old_dentry->d_parent->d_inode != new_parent->d_inode || - new_dentry->d_parent->d_inode != new_parent->d_inode || - old_dentry == new_dentry) + error = -EEXIST; + if (sysfs_find_dirent(sd->s_parent, new_name)) goto out_unlock; - error = -EEXIST; - if (new_dentry->d_inode) + error = -ENOMEM; + new_dentry = d_alloc_name(parent, new_name); + if (!new_dentry) goto out_unlock; /* rename kobject and sysfs_dirent */ error = -ENOMEM; new_name = dup_name = kstrdup(new_name, GFP_KERNEL); if (!new_name) - goto out_drop; + goto out_unlock; error = kobject_set_name(kobj, "%s", new_name); if (error) - goto out_drop; - - mutex_lock(&sysfs_mutex); + goto out_unlock; dup_name = sd->s_name; sd->s_name = new_name; - /* move under the new parent */ + /* rename */ d_add(new_dentry, NULL); - d_move(sd->s_dentry, new_dentry); - - sysfs_unlink_sibling(sd); - sysfs_get(new_parent_sd); - sysfs_put(sd->s_parent); - sd->s_parent = new_parent_sd; - sysfs_link_sibling(sd); - - mutex_unlock(&sysfs_mutex); + d_move(old_dentry, new_dentry); error = 0; - goto out_unlock; - - out_drop: - d_drop(new_dentry); out_unlock: - mutex_unlock(&new_parent->d_inode->i_mutex); - out_dput: + mutex_unlock(&sysfs_mutex); + mutex_unlock(&parent->d_inode->i_mutex); kfree(dup_name); - dput(new_parent); dput(old_dentry); dput(new_dentry); + out: + mutex_unlock(&sysfs_rename_mutex); return error; } @@ -985,96 +836,69 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) struct dentry *old_dentry = NULL, *new_dentry = NULL; int error; + mutex_lock(&sysfs_rename_mutex); BUG_ON(!sd->s_parent); new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root; + error = 0; + if (sd->s_parent == new_parent_sd) + goto out; /* nothing to move */ + /* get dentries */ old_dentry = sysfs_get_dentry(sd); if (IS_ERR(old_dentry)) { error = PTR_ERR(old_dentry); - goto out_dput; + goto out; } - old_parent = sd->s_parent->s_dentry; + old_parent = old_dentry->d_parent; new_parent = sysfs_get_dentry(new_parent_sd); if (IS_ERR(new_parent)) { error = PTR_ERR(new_parent); - goto out_dput; + goto out; } - if (old_parent->d_inode == new_parent->d_inode) { - error = 0; - goto out_dput; /* nothing to move */ - } again: mutex_lock(&old_parent->d_inode->i_mutex); if (!mutex_trylock(&new_parent->d_inode->i_mutex)) { mutex_unlock(&old_parent->d_inode->i_mutex); goto again; } + mutex_lock(&sysfs_mutex); - new_dentry = lookup_one_len(kobj->name, new_parent, strlen(kobj->name)); - if (IS_ERR(new_dentry)) { - error = PTR_ERR(new_dentry); + error = -EEXIST; + if (sysfs_find_dirent(new_parent_sd, sd->s_name)) goto out_unlock; - } else - error = 0; + + error = -ENOMEM; + new_dentry = d_alloc_name(new_parent, sd->s_name); + if (!new_dentry) + goto out_unlock; + + error = 0; d_add(new_dentry, NULL); - d_move(sd->s_dentry, new_dentry); + d_move(old_dentry, new_dentry); dput(new_dentry); /* Remove from old parent's list and insert into new parent's list. */ - mutex_lock(&sysfs_mutex); - sysfs_unlink_sibling(sd); sysfs_get(new_parent_sd); sysfs_put(sd->s_parent); sd->s_parent = new_parent_sd; sysfs_link_sibling(sd); - mutex_unlock(&sysfs_mutex); - out_unlock: + mutex_unlock(&sysfs_mutex); mutex_unlock(&new_parent->d_inode->i_mutex); mutex_unlock(&old_parent->d_inode->i_mutex); - out_dput: + out: dput(new_parent); dput(old_dentry); dput(new_dentry); + mutex_unlock(&sysfs_rename_mutex); return error; } -static int sysfs_dir_open(struct inode *inode, struct file *file) -{ - struct dentry * dentry = file->f_path.dentry; - struct sysfs_dirent * parent_sd = dentry->d_fsdata; - struct sysfs_dirent * sd; - - sd = sysfs_new_dirent("_DIR_", 0, 0); - if (sd) { - mutex_lock(&sysfs_mutex); - sd->s_parent = sysfs_get(parent_sd); - sysfs_link_sibling(sd); - mutex_unlock(&sysfs_mutex); - } - - file->private_data = sd; - return sd ? 0 : -ENOMEM; -} - -static int sysfs_dir_close(struct inode *inode, struct file *file) -{ - struct sysfs_dirent * cursor = file->private_data; - - mutex_lock(&sysfs_mutex); - sysfs_unlink_sibling(cursor); - mutex_unlock(&sysfs_mutex); - - release_sysfs_dirent(cursor); - - return 0; -} - /* Relationship between s_mode and the DT_xxx types */ static inline unsigned char dt_type(struct sysfs_dirent *sd) { @@ -1085,232 +909,51 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) { struct dentry *dentry = filp->f_path.dentry; struct sysfs_dirent * parent_sd = dentry->d_fsdata; - struct sysfs_dirent *cursor = filp->private_data; - struct sysfs_dirent **pos; + struct sysfs_dirent *pos; ino_t ino; - int i = filp->f_pos; - switch (i) { - case 0: - ino = parent_sd->s_ino; - if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) - break; + if (filp->f_pos == 0) { + ino = parent_sd->s_ino; + if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) == 0) filp->f_pos++; - i++; - /* fallthrough */ - case 1: - if (parent_sd->s_parent) - ino = parent_sd->s_parent->s_ino; - else - ino = parent_sd->s_ino; - if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0) - break; + } + if (filp->f_pos == 1) { + if (parent_sd->s_parent) + ino = parent_sd->s_parent->s_ino; + else + ino = parent_sd->s_ino; + if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0) filp->f_pos++; - i++; - /* fallthrough */ - default: - mutex_lock(&sysfs_mutex); - - pos = &parent_sd->s_children; - while (*pos != cursor) - pos = &(*pos)->s_sibling; - - /* unlink cursor */ - *pos = cursor->s_sibling; - - if (filp->f_pos == 2) - pos = &parent_sd->s_children; - - for ( ; *pos; pos = &(*pos)->s_sibling) { - struct sysfs_dirent *next = *pos; - const char * name; - int len; - - if (!sysfs_type(next)) - continue; - - name = next->s_name; - len = strlen(name); - ino = next->s_ino; - - if (filldir(dirent, name, len, filp->f_pos, ino, - dt_type(next)) < 0) - break; + } + if ((filp->f_pos > 1) && (filp->f_pos < INT_MAX)) { + mutex_lock(&sysfs_mutex); - filp->f_pos++; - } + /* Skip the dentries we have already reported */ + pos = parent_sd->s_dir.children; + while (pos && (filp->f_pos > pos->s_ino)) + pos = pos->s_sibling; - /* put cursor back in */ - cursor->s_sibling = *pos; - *pos = cursor; + for ( ; pos; pos = pos->s_sibling) { + const char * name; + int len; - mutex_unlock(&sysfs_mutex); - } - return 0; -} - -static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin) -{ - struct dentry * dentry = file->f_path.dentry; + name = pos->s_name; + len = strlen(name); + filp->f_pos = ino = pos->s_ino; - switch (origin) { - case 1: - offset += file->f_pos; - case 0: - if (offset >= 0) + if (filldir(dirent, name, len, filp->f_pos, ino, + dt_type(pos)) < 0) break; - default: - return -EINVAL; - } - if (offset != file->f_pos) { - mutex_lock(&sysfs_mutex); - - file->f_pos = offset; - if (file->f_pos >= 2) { - struct sysfs_dirent *sd = dentry->d_fsdata; - struct sysfs_dirent *cursor = file->private_data; - struct sysfs_dirent **pos; - loff_t n = file->f_pos - 2; - - sysfs_unlink_sibling(cursor); - - pos = &sd->s_children; - while (n && *pos) { - struct sysfs_dirent *next = *pos; - if (sysfs_type(next)) - n--; - pos = &(*pos)->s_sibling; - } - - cursor->s_sibling = *pos; - *pos = cursor; } - + if (!pos) + filp->f_pos = INT_MAX; mutex_unlock(&sysfs_mutex); } - - return offset; -} - - -/** - * sysfs_make_shadowed_dir - Setup so a directory can be shadowed - * @kobj: object we're creating shadow of. - */ - -int sysfs_make_shadowed_dir(struct kobject *kobj, - void * (*follow_link)(struct dentry *, struct nameidata *)) -{ - struct dentry *dentry; - struct inode *inode; - struct inode_operations *i_op; - - /* get dentry for @kobj->sd, dentry of a shadowed dir is pinned */ - dentry = sysfs_get_dentry(kobj->sd); - if (IS_ERR(dentry)) - return PTR_ERR(dentry); - - inode = dentry->d_inode; - if (inode->i_op != &sysfs_dir_inode_operations) { - dput(dentry); - return -EINVAL; - } - - i_op = kmalloc(sizeof(*i_op), GFP_KERNEL); - if (!i_op) - return -ENOMEM; - - memcpy(i_op, &sysfs_dir_inode_operations, sizeof(*i_op)); - i_op->follow_link = follow_link; - - /* Locking of inode->i_op? - * Since setting i_op is a single word write and they - * are atomic we should be ok here. - */ - inode->i_op = i_op; return 0; } -/** - * sysfs_create_shadow_dir - create a shadow directory for an object. - * @kobj: object we're creating directory for. - * - * sysfs_make_shadowed_dir must already have been called on this - * directory. - */ - -struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj) -{ - struct sysfs_dirent *parent_sd = kobj->sd->s_parent; - struct dentry *dir, *parent, *shadow; - struct inode *inode; - struct sysfs_dirent *sd; - struct sysfs_addrm_cxt acxt; - - dir = sysfs_get_dentry(kobj->sd); - if (IS_ERR(dir)) { - sd = (void *)dir; - goto out; - } - parent = dir->d_parent; - - inode = dir->d_inode; - sd = ERR_PTR(-EINVAL); - if (!sysfs_is_shadowed_inode(inode)) - goto out_dput; - - shadow = d_alloc(parent, &dir->d_name); - if (!shadow) - goto nomem; - - sd = sysfs_new_dirent("_SHADOW_", inode->i_mode, SYSFS_DIR); - if (!sd) - goto nomem; - sd->s_elem.dir.kobj = kobj; - - sysfs_addrm_start(&acxt, parent_sd); - - /* add but don't link into children list */ - sysfs_add_one(&acxt, sd); - - /* attach and instantiate dentry */ - sysfs_attach_dentry(sd, shadow); - d_instantiate(shadow, igrab(inode)); - inc_nlink(inode); /* tj: synchronization? */ - - sysfs_addrm_finish(&acxt); - - dget(shadow); /* Extra count - pin the dentry in core */ - - goto out_dput; - - nomem: - dput(shadow); - sd = ERR_PTR(-ENOMEM); - out_dput: - dput(dir); - out: - return sd; -} - -/** - * sysfs_remove_shadow_dir - remove an object's directory. - * @shadow_sd: sysfs_dirent of shadow directory - * - * The only thing special about this is that we remove any files in - * the directory before we remove the directory, and we've inlined - * what used to be sysfs_rmdir() below, instead of calling separately. - */ - -void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd) -{ - __sysfs_remove_dir(shadow_sd); -} const struct file_operations sysfs_dir_operations = { - .open = sysfs_dir_open, - .release = sysfs_dir_close, - .llseek = sysfs_dir_lseek, .read = generic_read_dir, .readdir = sysfs_readdir, }; diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 3e1cc062a740..d3be1e7fb48b 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -1,15 +1,22 @@ /* - * file.c - operations for regular (text) files. + * fs/sysfs/file.c - sysfs regular (text) file implementation + * + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo <teheo@suse.de> + * + * This file is released under the GPLv2. + * + * Please see Documentation/filesystems/sysfs.txt for more information. */ #include <linux/module.h> -#include <linux/fsnotify.h> #include <linux/kobject.h> #include <linux/namei.h> #include <linux/poll.h> #include <linux/list.h> +#include <linux/mutex.h> #include <asm/uaccess.h> -#include <asm/semaphore.h> #include "sysfs.h" @@ -50,14 +57,33 @@ static struct sysfs_ops subsys_sysfs_ops = { .store = subsys_attr_store, }; +/* + * There's one sysfs_buffer for each open file and one + * sysfs_open_dirent for each sysfs_dirent with one or more open + * files. + * + * filp->private_data points to sysfs_buffer and + * sysfs_dirent->s_attr.open points to sysfs_open_dirent. s_attr.open + * is protected by sysfs_open_dirent_lock. + */ +static spinlock_t sysfs_open_dirent_lock = SPIN_LOCK_UNLOCKED; + +struct sysfs_open_dirent { + atomic_t refcnt; + atomic_t event; + wait_queue_head_t poll; + struct list_head buffers; /* goes through sysfs_buffer.list */ +}; + struct sysfs_buffer { size_t count; loff_t pos; char * page; struct sysfs_ops * ops; - struct semaphore sem; + struct mutex mutex; int needs_read_fill; int event; + struct list_head list; }; /** @@ -74,7 +100,7 @@ struct sysfs_buffer { static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) { struct sysfs_dirent *attr_sd = dentry->d_fsdata; - struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; + struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; struct sysfs_ops * ops = buffer->ops; int ret = 0; ssize_t count; @@ -88,8 +114,8 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer if (!sysfs_get_active_two(attr_sd)) return -ENODEV; - buffer->event = atomic_read(&attr_sd->s_event); - count = ops->show(kobj, attr_sd->s_elem.attr.attr, buffer->page); + buffer->event = atomic_read(&attr_sd->s_attr.open->event); + count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page); sysfs_put_active_two(attr_sd); @@ -128,7 +154,7 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) struct sysfs_buffer * buffer = file->private_data; ssize_t retval = 0; - down(&buffer->sem); + mutex_lock(&buffer->mutex); if (buffer->needs_read_fill) { retval = fill_read_buffer(file->f_path.dentry,buffer); if (retval) @@ -139,7 +165,7 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) retval = simple_read_from_buffer(buf, count, ppos, buffer->page, buffer->count); out: - up(&buffer->sem); + mutex_unlock(&buffer->mutex); return retval; } @@ -189,7 +215,7 @@ static int flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count) { struct sysfs_dirent *attr_sd = dentry->d_fsdata; - struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; + struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; struct sysfs_ops * ops = buffer->ops; int rc; @@ -197,7 +223,7 @@ flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t if (!sysfs_get_active_two(attr_sd)) return -ENODEV; - rc = ops->store(kobj, attr_sd->s_elem.attr.attr, buffer->page, count); + rc = ops->store(kobj, attr_sd->s_attr.attr, buffer->page, count); sysfs_put_active_two(attr_sd); @@ -228,20 +254,102 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t struct sysfs_buffer * buffer = file->private_data; ssize_t len; - down(&buffer->sem); + mutex_lock(&buffer->mutex); len = fill_write_buffer(buffer, buf, count); if (len > 0) len = flush_write_buffer(file->f_path.dentry, buffer, len); if (len > 0) *ppos += len; - up(&buffer->sem); + mutex_unlock(&buffer->mutex); return len; } +/** + * sysfs_get_open_dirent - get or create sysfs_open_dirent + * @sd: target sysfs_dirent + * @buffer: sysfs_buffer for this instance of open + * + * If @sd->s_attr.open exists, increment its reference count; + * otherwise, create one. @buffer is chained to the buffers + * list. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +static int sysfs_get_open_dirent(struct sysfs_dirent *sd, + struct sysfs_buffer *buffer) +{ + struct sysfs_open_dirent *od, *new_od = NULL; + + retry: + spin_lock(&sysfs_open_dirent_lock); + + if (!sd->s_attr.open && new_od) { + sd->s_attr.open = new_od; + new_od = NULL; + } + + od = sd->s_attr.open; + if (od) { + atomic_inc(&od->refcnt); + list_add_tail(&buffer->list, &od->buffers); + } + + spin_unlock(&sysfs_open_dirent_lock); + + if (od) { + kfree(new_od); + return 0; + } + + /* not there, initialize a new one and retry */ + new_od = kmalloc(sizeof(*new_od), GFP_KERNEL); + if (!new_od) + return -ENOMEM; + + atomic_set(&new_od->refcnt, 0); + atomic_set(&new_od->event, 1); + init_waitqueue_head(&new_od->poll); + INIT_LIST_HEAD(&new_od->buffers); + goto retry; +} + +/** + * sysfs_put_open_dirent - put sysfs_open_dirent + * @sd: target sysfs_dirent + * @buffer: associated sysfs_buffer + * + * Put @sd->s_attr.open and unlink @buffer from the buffers list. + * If reference count reaches zero, disassociate and free it. + * + * LOCKING: + * None. + */ +static void sysfs_put_open_dirent(struct sysfs_dirent *sd, + struct sysfs_buffer *buffer) +{ + struct sysfs_open_dirent *od = sd->s_attr.open; + + spin_lock(&sysfs_open_dirent_lock); + + list_del(&buffer->list); + if (atomic_dec_and_test(&od->refcnt)) + sd->s_attr.open = NULL; + else + od = NULL; + + spin_unlock(&sysfs_open_dirent_lock); + + kfree(od); +} + static int sysfs_open_file(struct inode *inode, struct file *file) { struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; - struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; + struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; struct sysfs_buffer * buffer; struct sysfs_ops * ops = NULL; int error; @@ -294,33 +402,38 @@ static int sysfs_open_file(struct inode *inode, struct file *file) if (!buffer) goto err_out; - init_MUTEX(&buffer->sem); + mutex_init(&buffer->mutex); buffer->needs_read_fill = 1; buffer->ops = ops; file->private_data = buffer; - /* open succeeded, put active references and pin attr_sd */ + /* make sure we have open dirent struct */ + error = sysfs_get_open_dirent(attr_sd, buffer); + if (error) + goto err_free; + + /* open succeeded, put active references */ sysfs_put_active_two(attr_sd); - sysfs_get(attr_sd); return 0; + err_free: + kfree(buffer); err_out: sysfs_put_active_two(attr_sd); return error; } -static int sysfs_release(struct inode * inode, struct file * filp) +static int sysfs_release(struct inode *inode, struct file *filp) { - struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; + struct sysfs_dirent *sd = filp->f_path.dentry->d_fsdata; struct sysfs_buffer *buffer = filp->private_data; - sysfs_put(attr_sd); + sysfs_put_open_dirent(sd, buffer); + + if (buffer->page) + free_page((unsigned long)buffer->page); + kfree(buffer); - if (buffer) { - if (buffer->page) - free_page((unsigned long)buffer->page); - kfree(buffer); - } return 0; } @@ -335,24 +448,24 @@ static int sysfs_release(struct inode * inode, struct file * filp) * again will not get new data, or reset the state of 'poll'. * Reminder: this only works for attributes which actively support * it, and it is not possible to test an attribute from userspace - * to see if it supports poll (Nether 'poll' or 'select' return + * to see if it supports poll (Neither 'poll' nor 'select' return * an appropriate error code). When in doubt, set a suitable timeout value. */ static unsigned int sysfs_poll(struct file *filp, poll_table *wait) { struct sysfs_buffer * buffer = filp->private_data; struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; - struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; + struct sysfs_open_dirent *od = attr_sd->s_attr.open; /* need parent for the kobj, grab both */ if (!sysfs_get_active_two(attr_sd)) goto trigger; - poll_wait(filp, &kobj->poll, wait); + poll_wait(filp, &od->poll, wait); sysfs_put_active_two(attr_sd); - if (buffer->event != atomic_read(&attr_sd->s_event)) + if (buffer->event != atomic_read(&od->event)) goto trigger; return 0; @@ -373,8 +486,17 @@ void sysfs_notify(struct kobject *k, char *dir, char *attr) if (sd && attr) sd = sysfs_find_dirent(sd, attr); if (sd) { - atomic_inc(&sd->s_event); - wake_up_interruptible(&k->poll); + struct sysfs_open_dirent *od; + + spin_lock(&sysfs_open_dirent_lock); + + od = sd->s_attr.open; + if (od) { + atomic_inc(&od->event); + wake_up_interruptible(&od->poll); + } + + spin_unlock(&sysfs_open_dirent_lock); } mutex_unlock(&sysfs_mutex); @@ -397,25 +519,21 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG; struct sysfs_addrm_cxt acxt; struct sysfs_dirent *sd; + int rc; sd = sysfs_new_dirent(attr->name, mode, type); if (!sd) return -ENOMEM; - sd->s_elem.attr.attr = (void *)attr; + sd->s_attr.attr = (void *)attr; sysfs_addrm_start(&acxt, dir_sd); + rc = sysfs_add_one(&acxt, sd); + sysfs_addrm_finish(&acxt); - if (!sysfs_find_dirent(dir_sd, attr->name)) { - sysfs_add_one(&acxt, sd); - sysfs_link_sibling(sd); - } - - if (!sysfs_addrm_finish(&acxt)) { + if (rc) sysfs_put(sd); - return -EEXIST; - } - return 0; + return rc; } @@ -457,42 +575,6 @@ int sysfs_add_file_to_group(struct kobject *kobj, } EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); - -/** - * sysfs_update_file - update the modified timestamp on an object attribute. - * @kobj: object we're acting for. - * @attr: attribute descriptor. - */ -int sysfs_update_file(struct kobject * kobj, const struct attribute * attr) -{ - struct sysfs_dirent *victim_sd = NULL; - struct dentry *victim = NULL; - int rc; - - rc = -ENOENT; - victim_sd = sysfs_get_dirent(kobj->sd, attr->name); - if (!victim_sd) - goto out; - - victim = sysfs_get_dentry(victim_sd); - if (IS_ERR(victim)) { - rc = PTR_ERR(victim); - victim = NULL; - goto out; - } - - mutex_lock(&victim->d_inode->i_mutex); - victim->d_inode->i_mtime = CURRENT_TIME; - fsnotify_modify(victim); - mutex_unlock(&victim->d_inode->i_mutex); - rc = 0; - out: - dput(victim); - sysfs_put(victim_sd); - return rc; -} - - /** * sysfs_chmod_file - update the modified mode value on an object attribute. * @kobj: object we're acting for. @@ -513,7 +595,9 @@ int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) if (!victim_sd) goto out; + mutex_lock(&sysfs_rename_mutex); victim = sysfs_get_dentry(victim_sd); + mutex_unlock(&sysfs_rename_mutex); if (IS_ERR(victim)) { rc = PTR_ERR(victim); victim = NULL; @@ -521,10 +605,19 @@ int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) } inode = victim->d_inode; + mutex_lock(&inode->i_mutex); + newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; rc = notify_change(victim, &newattrs); + + if (rc == 0) { + mutex_lock(&sysfs_mutex); + victim_sd->s_mode = newattrs.ia_mode; + mutex_unlock(&sysfs_mutex); + } + mutex_unlock(&inode->i_mutex); out: dput(victim); @@ -632,4 +725,3 @@ EXPORT_SYMBOL_GPL(sysfs_schedule_callback); EXPORT_SYMBOL_GPL(sysfs_create_file); EXPORT_SYMBOL_GPL(sysfs_remove_file); -EXPORT_SYMBOL_GPL(sysfs_update_file); diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index f318b73c790c..d1972374655a 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -13,8 +13,6 @@ #include <linux/dcache.h> #include <linux/namei.h> #include <linux/err.h> -#include <linux/fs.h> -#include <asm/semaphore.h> #include "sysfs.h" diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 10d1b52899f1..d9262f74f94e 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -1,7 +1,11 @@ /* - * inode.c - basic inode and dentry operations. + * fs/sysfs/inode.c - basic sysfs inode and dentry operations * - * sysfs is Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo <teheo@suse.de> + * + * This file is released under the GPLv2. * * Please see Documentation/filesystems/sysfs.txt for more information. */ @@ -14,15 +18,14 @@ #include <linux/capability.h> #include <linux/errno.h> #include <linux/sched.h> -#include <asm/semaphore.h> #include "sysfs.h" extern struct super_block * sysfs_sb; static const struct address_space_operations sysfs_aops = { .readpage = simple_readpage, - .prepare_write = simple_prepare_write, - .commit_write = simple_commit_write + .write_begin = simple_write_begin, + .write_end = simple_write_end, }; static struct backing_dev_info sysfs_backing_dev_info = { @@ -34,14 +37,9 @@ static const struct inode_operations sysfs_inode_operations ={ .setattr = sysfs_setattr, }; -void sysfs_delete_inode(struct inode *inode) +int __init sysfs_inode_init(void) { - /* Free the shadowed directory inode operations */ - if (sysfs_is_shadowed_inode(inode)) { - kfree(inode->i_op); - inode->i_op = NULL; - } - return generic_delete_inode(inode); + return bdi_init(&sysfs_backing_dev_info); } int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) @@ -133,8 +131,22 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) */ static struct lock_class_key sysfs_inode_imutex_key; +static int sysfs_count_nlink(struct sysfs_dirent *sd) +{ + struct sysfs_dirent *child; + int nr = 0; + + for (child = sd->s_dir.children; child; child = child->s_sibling) + if (sysfs_type(child) == SYSFS_DIR) + nr++; + + return nr + 2; +} + static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) { + struct bin_attribute *bin_attr; + inode->i_blocks = 0; inode->i_mapping->a_ops = &sysfs_aops; inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; @@ -150,6 +162,32 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) set_inode_attr(inode, sd->s_iattr); } else set_default_inode_attr(inode, sd->s_mode); + + + /* initialize inode according to type */ + switch (sysfs_type(sd)) { + case SYSFS_DIR: + inode->i_op = &sysfs_dir_inode_operations; + inode->i_fop = &sysfs_dir_operations; + inode->i_nlink = sysfs_count_nlink(sd); + break; + case SYSFS_KOBJ_ATTR: + inode->i_size = PAGE_SIZE; + inode->i_fop = &sysfs_file_operations; + break; + case SYSFS_KOBJ_BIN_ATTR: + bin_attr = sd->s_bin_attr.bin_attr; + inode->i_size = bin_attr->size; + inode->i_fop = &bin_fops; + break; + case SYSFS_KOBJ_LINK: + inode->i_op = &sysfs_symlink_inode_operations; + break; + default: + BUG(); + } + + unlock_new_inode(inode); } /** @@ -177,50 +215,24 @@ struct inode * sysfs_get_inode(struct sysfs_dirent *sd) return inode; } -/** - * sysfs_instantiate - instantiate dentry - * @dentry: dentry to be instantiated - * @inode: inode associated with @sd - * - * Unlock @inode if locked and instantiate @dentry with @inode. - * - * LOCKING: - * None. - */ -void sysfs_instantiate(struct dentry *dentry, struct inode *inode) -{ - BUG_ON(!dentry || dentry->d_inode); - - if (inode->i_state & I_NEW) - unlock_new_inode(inode); - - d_instantiate(dentry, inode); -} - int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) { struct sysfs_addrm_cxt acxt; - struct sysfs_dirent **pos, *sd; + struct sysfs_dirent *sd; if (!dir_sd) return -ENOENT; sysfs_addrm_start(&acxt, dir_sd); - for (pos = &dir_sd->s_children; *pos; pos = &(*pos)->s_sibling) { - sd = *pos; - - if (!sysfs_type(sd)) - continue; - if (!strcmp(sd->s_name, name)) { - *pos = sd->s_sibling; - sd->s_sibling = NULL; - sysfs_remove_one(&acxt, sd); - break; - } - } + sd = sysfs_find_dirent(dir_sd, name); + if (sd) + sysfs_remove_one(&acxt, sd); + + sysfs_addrm_finish(&acxt); - if (sysfs_addrm_finish(&acxt)) + if (sd) return 0; - return -ENOENT; + else + return -ENOENT; } diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index fbc7b65fe262..74168266cd59 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -1,5 +1,13 @@ /* - * mount.c - operations for initializing and mounting sysfs. + * fs/sysfs/symlink.c - operations for initializing and mounting sysfs + * + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo <teheo@suse.de> + * + * This file is released under the GPLv2. + * + * Please see Documentation/filesystems/sysfs.txt for more information. */ #define DEBUG @@ -8,25 +16,25 @@ #include <linux/mount.h> #include <linux/pagemap.h> #include <linux/init.h> -#include <asm/semaphore.h> #include "sysfs.h" /* Random magic number */ #define SYSFS_MAGIC 0x62656572 -struct vfsmount *sysfs_mount; +static struct vfsmount *sysfs_mount; struct super_block * sysfs_sb = NULL; struct kmem_cache *sysfs_dir_cachep; static const struct super_operations sysfs_ops = { .statfs = simple_statfs, - .drop_inode = sysfs_delete_inode, + .drop_inode = generic_delete_inode, }; struct sysfs_dirent sysfs_root = { + .s_name = "", .s_count = ATOMIC_INIT(1), - .s_flags = SYSFS_ROOT, + .s_flags = SYSFS_DIR, .s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, .s_ino = 1, }; @@ -50,11 +58,6 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) return -ENOMEM; } - inode->i_op = &sysfs_dir_inode_operations; - inode->i_fop = &sysfs_dir_operations; - inc_nlink(inode); /* directory, account for "." */ - unlock_new_inode(inode); - /* instantiate and link root dentry */ root = d_alloc_root(inode); if (!root) { @@ -62,7 +65,6 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) iput(inode); return -ENOMEM; } - sysfs_root.s_dentry = root; root->d_fsdata = &sysfs_root; sb->s_root = root; return 0; @@ -77,7 +79,7 @@ static int sysfs_get_sb(struct file_system_type *fs_type, static struct file_system_type sysfs_fs_type = { .name = "sysfs", .get_sb = sysfs_get_sb, - .kill_sb = kill_litter_super, + .kill_sb = kill_anon_super, }; int __init sysfs_init(void) @@ -90,6 +92,10 @@ int __init sysfs_init(void) if (!sysfs_dir_cachep) goto out; + err = sysfs_inode_init(); + if (err) + goto out_err; + err = register_filesystem(&sysfs_fs_type); if (!err) { sysfs_mount = kern_mount(&sysfs_fs_type); diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 4ce687f0b5d0..3eac20c63c41 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -1,5 +1,13 @@ /* - * symlink.c - operations for sysfs symlinks. + * fs/sysfs/symlink.c - sysfs symlink implementation + * + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo <teheo@suse.de> + * + * This file is released under the GPLv2. + * + * Please see Documentation/filesystems/sysfs.txt for more information. */ #include <linux/fs.h> @@ -7,7 +15,7 @@ #include <linux/module.h> #include <linux/kobject.h> #include <linux/namei.h> -#include <asm/semaphore.h> +#include <linux/mutex.h> #include "sysfs.h" @@ -60,10 +68,9 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char BUG_ON(!name); - if (!kobj) { - if (sysfs_mount && sysfs_mount->mnt_sb) - parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata; - } else + if (!kobj) + parent_sd = &sysfs_root; + else parent_sd = kobj->sd; error = -EFAULT; @@ -87,20 +94,15 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char if (!sd) goto out_put; - sd->s_elem.symlink.target_sd = target_sd; + sd->s_symlink.target_sd = target_sd; target_sd = NULL; /* reference is now owned by the symlink */ sysfs_addrm_start(&acxt, parent_sd); + error = sysfs_add_one(&acxt, sd); + sysfs_addrm_finish(&acxt); - if (!sysfs_find_dirent(parent_sd, name)) { - sysfs_add_one(&acxt, sd); - sysfs_link_sibling(sd); - } - - if (!sysfs_addrm_finish(&acxt)) { - error = -EEXIST; + if (error) goto out_put; - } return 0; @@ -148,7 +150,7 @@ static int sysfs_getlink(struct dentry *dentry, char * path) { struct sysfs_dirent *sd = dentry->d_fsdata; struct sysfs_dirent *parent_sd = sd->s_parent; - struct sysfs_dirent *target_sd = sd->s_elem.symlink.target_sd; + struct sysfs_dirent *target_sd = sd->s_symlink.target_sd; int error; mutex_lock(&sysfs_mutex); diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 6b8c8d76d308..f8417988f6b0 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -1,20 +1,39 @@ +/* + * fs/sysfs/sysfs.h - sysfs internal header file + * + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo <teheo@suse.de> + * + * This file is released under the GPLv2. + */ + +struct sysfs_open_dirent; + +/* type-specific structures for sysfs_dirent->s_* union members */ struct sysfs_elem_dir { - struct kobject * kobj; + struct kobject *kobj; + /* children list starts here and goes through sd->s_sibling */ + struct sysfs_dirent *children; }; struct sysfs_elem_symlink { - struct sysfs_dirent * target_sd; + struct sysfs_dirent *target_sd; }; struct sysfs_elem_attr { - struct attribute * attr; + struct attribute *attr; + struct sysfs_open_dirent *open; }; struct sysfs_elem_bin_attr { - struct bin_attribute * bin_attr; + struct bin_attribute *bin_attr; }; /* + * sysfs_dirent - the building block of sysfs hierarchy. Each and + * every sysfs node is represented by single sysfs_dirent. + * * As long as s_count reference is held, the sysfs_dirent itself is * accessible. Dereferencing s_elem or any other outer entity * requires s_active reference. @@ -22,28 +41,43 @@ struct sysfs_elem_bin_attr { struct sysfs_dirent { atomic_t s_count; atomic_t s_active; - struct sysfs_dirent * s_parent; - struct sysfs_dirent * s_sibling; - struct sysfs_dirent * s_children; - const char * s_name; + struct sysfs_dirent *s_parent; + struct sysfs_dirent *s_sibling; + const char *s_name; union { - struct sysfs_elem_dir dir; - struct sysfs_elem_symlink symlink; - struct sysfs_elem_attr attr; - struct sysfs_elem_bin_attr bin_attr; - } s_elem; + struct sysfs_elem_dir s_dir; + struct sysfs_elem_symlink s_symlink; + struct sysfs_elem_attr s_attr; + struct sysfs_elem_bin_attr s_bin_attr; + }; unsigned int s_flags; - umode_t s_mode; ino_t s_ino; - struct dentry * s_dentry; - struct iattr * s_iattr; - atomic_t s_event; + umode_t s_mode; + struct iattr *s_iattr; }; -#define SD_DEACTIVATED_BIAS INT_MIN +#define SD_DEACTIVATED_BIAS INT_MIN + +#define SYSFS_TYPE_MASK 0x00ff +#define SYSFS_DIR 0x0001 +#define SYSFS_KOBJ_ATTR 0x0002 +#define SYSFS_KOBJ_BIN_ATTR 0x0004 +#define SYSFS_KOBJ_LINK 0x0008 +#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) + +#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK +#define SYSFS_FLAG_REMOVED 0x0200 + +static inline unsigned int sysfs_type(struct sysfs_dirent *sd) +{ + return sd->s_flags & SYSFS_TYPE_MASK; +} +/* + * Context structure to be used while adding/removing nodes. + */ struct sysfs_addrm_cxt { struct sysfs_dirent *parent_sd; struct inode *parent_inode; @@ -51,63 +85,47 @@ struct sysfs_addrm_cxt { int cnt; }; -extern struct vfsmount * sysfs_mount; +/* + * mount.c + */ extern struct sysfs_dirent sysfs_root; +extern struct super_block *sysfs_sb; extern struct kmem_cache *sysfs_dir_cachep; -extern struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd); -extern void sysfs_link_sibling(struct sysfs_dirent *sd); -extern void sysfs_unlink_sibling(struct sysfs_dirent *sd); -extern struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd); -extern void sysfs_put_active(struct sysfs_dirent *sd); -extern struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd); -extern void sysfs_put_active_two(struct sysfs_dirent *sd); -extern void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, - struct sysfs_dirent *parent_sd); -extern void sysfs_add_one(struct sysfs_addrm_cxt *acxt, - struct sysfs_dirent *sd); -extern void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, - struct sysfs_dirent *sd); -extern int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); - -extern void sysfs_delete_inode(struct inode *inode); -extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd); -extern void sysfs_instantiate(struct dentry *dentry, struct inode *inode); - -extern void release_sysfs_dirent(struct sysfs_dirent * sd); -extern struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, - const unsigned char *name); -extern struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, - const unsigned char *name); -extern struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, - int type); - -extern int sysfs_add_file(struct sysfs_dirent *dir_sd, - const struct attribute *attr, int type); -extern int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); -extern struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * name); - -extern int sysfs_create_subdir(struct kobject *kobj, const char *name, - struct sysfs_dirent **p_sd); -extern void sysfs_remove_subdir(struct sysfs_dirent *sd); - -extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); - -extern spinlock_t sysfs_assoc_lock; +/* + * dir.c + */ extern struct mutex sysfs_mutex; -extern struct super_block * sysfs_sb; +extern struct mutex sysfs_rename_mutex; +extern spinlock_t sysfs_assoc_lock; + extern const struct file_operations sysfs_dir_operations; -extern const struct file_operations sysfs_file_operations; -extern const struct file_operations bin_fops; extern const struct inode_operations sysfs_dir_inode_operations; -extern const struct inode_operations sysfs_symlink_inode_operations; - -static inline unsigned int sysfs_type(struct sysfs_dirent *sd) -{ - return sd->s_flags & SYSFS_TYPE_MASK; -} -static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd) +struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd); +struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd); +void sysfs_put_active(struct sysfs_dirent *sd); +struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd); +void sysfs_put_active_two(struct sysfs_dirent *sd); +void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, + struct sysfs_dirent *parent_sd); +int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); +void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); +void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); + +struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, + const unsigned char *name); +struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, + const unsigned char *name); +struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type); + +void release_sysfs_dirent(struct sysfs_dirent *sd); + +int sysfs_create_subdir(struct kobject *kobj, const char *name, + struct sysfs_dirent **p_sd); +void sysfs_remove_subdir(struct sysfs_dirent *sd); + +static inline struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd) { if (sd) { WARN_ON(!atomic_read(&sd->s_count)); @@ -116,13 +134,34 @@ static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd) return sd; } -static inline void sysfs_put(struct sysfs_dirent * sd) +static inline void sysfs_put(struct sysfs_dirent *sd) { if (sd && atomic_dec_and_test(&sd->s_count)) release_sysfs_dirent(sd); } -static inline int sysfs_is_shadowed_inode(struct inode *inode) -{ - return S_ISDIR(inode->i_mode) && inode->i_op->follow_link; -} +/* + * inode.c + */ +struct inode *sysfs_get_inode(struct sysfs_dirent *sd); +int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); +int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); +int sysfs_inode_init(void); + +/* + * file.c + */ +extern const struct file_operations sysfs_file_operations; + +int sysfs_add_file(struct sysfs_dirent *dir_sd, + const struct attribute *attr, int type); + +/* + * bin.c + */ +extern const struct file_operations bin_fops; + +/* + * symlink.c + */ +extern const struct inode_operations sysfs_symlink_inode_operations; diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c index e566b387fcf9..56f655254bfe 100644 --- a/fs/sysv/dir.c +++ b/fs/sysv/dir.c @@ -16,6 +16,7 @@ #include <linux/pagemap.h> #include <linux/highmem.h> #include <linux/smp_lock.h> +#include <linux/swap.h> #include "sysv.h" static int sysv_readdir(struct file *, void *, filldir_t); @@ -37,12 +38,17 @@ static inline unsigned long dir_pages(struct inode *inode) return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT; } -static int dir_commit_chunk(struct page *page, unsigned from, unsigned to) +static int dir_commit_chunk(struct page *page, loff_t pos, unsigned len) { - struct inode *dir = (struct inode *)page->mapping->host; + struct address_space *mapping = page->mapping; + struct inode *dir = mapping->host; int err = 0; - page->mapping->a_ops->commit_write(NULL, page, from, to); + block_write_end(NULL, mapping, pos, len, len, page, NULL); + if (pos+len > dir->i_size) { + i_size_write(dir, pos+len); + mark_inode_dirty(dir); + } if (IS_DIRSYNC(dir)) err = write_one_page(page, 1); else @@ -186,7 +192,7 @@ int sysv_add_link(struct dentry *dentry, struct inode *inode) unsigned long npages = dir_pages(dir); unsigned long n; char *kaddr; - unsigned from, to; + loff_t pos; int err; /* We take care of directory expansion in the same loop */ @@ -212,16 +218,17 @@ int sysv_add_link(struct dentry *dentry, struct inode *inode) return -EINVAL; got_it: - from = (char*)de - (char*)page_address(page); - to = from + SYSV_DIRSIZE; + pos = page_offset(page) + + (char*)de - (char*)page_address(page); lock_page(page); - err = page->mapping->a_ops->prepare_write(NULL, page, from, to); + err = __sysv_write_begin(NULL, page->mapping, pos, SYSV_DIRSIZE, + AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); if (err) goto out_unlock; memcpy (de->name, name, namelen); memset (de->name + namelen, 0, SYSV_DIRSIZE - namelen - 2); de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino); - err = dir_commit_chunk(page, from, to); + err = dir_commit_chunk(page, pos, SYSV_DIRSIZE); dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(dir); out_page: @@ -238,15 +245,15 @@ int sysv_delete_entry(struct sysv_dir_entry *de, struct page *page) struct address_space *mapping = page->mapping; struct inode *inode = (struct inode*)mapping->host; char *kaddr = (char*)page_address(page); - unsigned from = (char*)de - kaddr; - unsigned to = from + SYSV_DIRSIZE; + loff_t pos = page_offset(page) + (char *)de - kaddr; int err; lock_page(page); - err = mapping->a_ops->prepare_write(NULL, page, from, to); + err = __sysv_write_begin(NULL, mapping, pos, SYSV_DIRSIZE, + AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); BUG_ON(err); de->inode = 0; - err = dir_commit_chunk(page, from, to); + err = dir_commit_chunk(page, pos, SYSV_DIRSIZE); dir_put_page(page); inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; mark_inode_dirty(inode); @@ -263,12 +270,13 @@ int sysv_make_empty(struct inode *inode, struct inode *dir) if (!page) return -ENOMEM; - kmap(page); - err = mapping->a_ops->prepare_write(NULL, page, 0, 2 * SYSV_DIRSIZE); + err = __sysv_write_begin(NULL, mapping, 0, 2 * SYSV_DIRSIZE, + AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); if (err) { unlock_page(page); goto fail; } + kmap(page); base = (char*)page_address(page); memset(base, 0, PAGE_CACHE_SIZE); @@ -280,9 +288,9 @@ int sysv_make_empty(struct inode *inode, struct inode *dir) de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), dir->i_ino); strcpy(de->name,".."); + kunmap(page); err = dir_commit_chunk(page, 0, 2 * SYSV_DIRSIZE); fail: - kunmap(page); page_cache_release(page); return err; } @@ -336,16 +344,18 @@ not_empty: void sysv_set_link(struct sysv_dir_entry *de, struct page *page, struct inode *inode) { - struct inode *dir = (struct inode*)page->mapping->host; - unsigned from = (char *)de-(char*)page_address(page); - unsigned to = from + SYSV_DIRSIZE; + struct address_space *mapping = page->mapping; + struct inode *dir = mapping->host; + loff_t pos = page_offset(page) + + (char *)de-(char*)page_address(page); int err; lock_page(page); - err = page->mapping->a_ops->prepare_write(NULL, page, from, to); + err = __sysv_write_begin(NULL, mapping, pos, SYSV_DIRSIZE, + AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); BUG_ON(err); de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino); - err = dir_commit_chunk(page, from, to); + err = dir_commit_chunk(page, pos, SYSV_DIRSIZE); dir_put_page(page); dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(dir); diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index 7c4e5d302abb..81ec6c548c07 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -318,7 +318,7 @@ static void sysv_destroy_inode(struct inode *inode) kmem_cache_free(sysv_inode_cachep, SYSV_I(inode)); } -static void init_once(void *p, struct kmem_cache *cachep, unsigned long flags) +static void init_once(struct kmem_cache *cachep, void *p) { struct sysv_inode_info *si = (struct sysv_inode_info *)p; diff --git a/fs/sysv/itree.c b/fs/sysv/itree.c index f2bcccd1d6fc..f042eec464c2 100644 --- a/fs/sysv/itree.c +++ b/fs/sysv/itree.c @@ -453,23 +453,38 @@ static int sysv_writepage(struct page *page, struct writeback_control *wbc) { return block_write_full_page(page,get_block,wbc); } + static int sysv_readpage(struct file *file, struct page *page) { return block_read_full_page(page,get_block); } -static int sysv_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) + +int __sysv_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - return block_prepare_write(page,from,to,get_block); + return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + get_block); } + +static int sysv_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) +{ + *pagep = NULL; + return __sysv_write_begin(file, mapping, pos, len, flags, pagep, fsdata); +} + static sector_t sysv_bmap(struct address_space *mapping, sector_t block) { return generic_block_bmap(mapping,block,get_block); } + const struct address_space_operations sysv_aops = { .readpage = sysv_readpage, .writepage = sysv_writepage, .sync_page = block_sync_page, - .prepare_write = sysv_prepare_write, - .commit_write = generic_commit_write, + .write_begin = sysv_write_begin, + .write_end = generic_write_end, .bmap = sysv_bmap }; diff --git a/fs/sysv/sysv.h b/fs/sysv/sysv.h index 5b4fedf17cc4..64c03bdf06a5 100644 --- a/fs/sysv/sysv.h +++ b/fs/sysv/sysv.h @@ -136,6 +136,9 @@ extern unsigned long sysv_count_free_blocks(struct super_block *); /* itree.c */ extern void sysv_truncate(struct inode *); +extern int __sysv_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata); /* inode.c */ extern int sysv_write_inode(struct inode *, int); diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c index 87e87dcd3f9c..ab26176f6b91 100644 --- a/fs/udf/balloc.c +++ b/fs/udf/balloc.c @@ -689,7 +689,7 @@ static int udf_table_new_block(struct super_block *sb, uint32_t spread = 0xFFFFFFFF, nspread = 0xFFFFFFFF; uint32_t newblock = 0, adsize; uint32_t elen, goal_elen = 0; - kernel_lb_addr eloc, goal_eloc; + kernel_lb_addr eloc, uninitialized_var(goal_eloc); struct extent_position epos, goal_epos; int8_t etype; diff --git a/fs/udf/file.c b/fs/udf/file.c index 5d7a4ea27753..7c7a1b39d56c 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -76,36 +76,29 @@ static int udf_adinicb_writepage(struct page *page, struct writeback_control *wb return 0; } -static int udf_adinicb_prepare_write(struct file *file, struct page *page, - unsigned offset, unsigned to) +static int udf_adinicb_write_end(struct file *file, + struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) { - kmap(page); - return 0; -} - -static int udf_adinicb_commit_write(struct file *file, struct page *page, - unsigned offset, unsigned to) -{ - struct inode *inode = page->mapping->host; - char *kaddr = page_address(page); + struct inode *inode = mapping->host; + unsigned offset = pos & (PAGE_CACHE_SIZE - 1); + char *kaddr; + kaddr = kmap_atomic(page, KM_USER0); memcpy(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode) + offset, - kaddr + offset, to - offset); - mark_inode_dirty(inode); - SetPageUptodate(page); - kunmap(page); - /* only one page here */ - if (to > inode->i_size) - inode->i_size = to; - return 0; + kaddr + offset, copied); + kunmap_atomic(kaddr, KM_USER0); + + return simple_write_end(file, mapping, pos, len, copied, page, fsdata); } const struct address_space_operations udf_adinicb_aops = { .readpage = udf_adinicb_readpage, .writepage = udf_adinicb_writepage, .sync_page = block_sync_page, - .prepare_write = udf_adinicb_prepare_write, - .commit_write = udf_adinicb_commit_write, + .write_begin = simple_write_begin, + .write_end = udf_adinicb_write_end, }; static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 1652b2c665bb..6ff8151984cf 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -133,10 +133,13 @@ static int udf_readpage(struct file *file, struct page *page) return block_read_full_page(page, udf_get_block); } -static int udf_prepare_write(struct file *file, struct page *page, - unsigned from, unsigned to) +static int udf_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - return block_prepare_write(page, from, to, udf_get_block); + *pagep = NULL; + return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + udf_get_block); } static sector_t udf_bmap(struct address_space *mapping, sector_t block) @@ -148,8 +151,8 @@ const struct address_space_operations udf_aops = { .readpage = udf_readpage, .writepage = udf_writepage, .sync_page = block_sync_page, - .prepare_write = udf_prepare_write, - .commit_write = generic_commit_write, + .write_begin = udf_write_begin, + .write_end = generic_write_end, .bmap = udf_bmap, }; diff --git a/fs/udf/super.c b/fs/udf/super.c index c68a6e730b97..4360c7a05743 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -134,7 +134,7 @@ static void udf_destroy_inode(struct inode *inode) kmem_cache_free(udf_inode_cachep, UDF_I(inode)); } -static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags) +static void init_once(struct kmem_cache *cachep, void *foo) { struct udf_inode_info *ei = (struct udf_inode_info *)foo; @@ -913,8 +913,7 @@ static int udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table = udf_iget(sb, loc); if (!UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table) { - udf_debug("cannot load unallocSpaceTable (part %d)\n", - i); + udf_debug("cannot load unallocSpaceTable (part %d)\n", i); return 1; } UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_UNALLOC_TABLE; @@ -944,8 +943,7 @@ static int udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table = udf_iget(sb, loc); if (!UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table) { - udf_debug("cannot load freedSpaceTable (part %d)\n", - i); + udf_debug("cannot load freedSpaceTable (part %d)\n", i); return 1; } UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_FREED_TABLE; @@ -1293,19 +1291,16 @@ static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset) if (!UDF_SB_LASTBLOCK(sb)) { udf_debug("Unable to determine Lastblock (For " - "Virtual Partition)\n"); + "Virtual Partition)\n"); return 1; } for (j = 0; j < UDF_SB_NUMPARTS(sb); j++) { - if (j != i && UDF_SB_PARTVSN(sb, i) == - UDF_SB_PARTVSN(sb, j) && - UDF_SB_PARTNUM(sb, i) == - UDF_SB_PARTNUM(sb, j)) { + if (j != i && + UDF_SB_PARTVSN(sb, i) == UDF_SB_PARTVSN(sb, j) && + UDF_SB_PARTNUM(sb, i) == UDF_SB_PARTNUM(sb, j)) { ino.partitionReferenceNum = j; - ino.logicalBlockNum = - UDF_SB_LASTBLOCK(sb) - - UDF_SB_PARTROOT(sb, j); + ino.logicalBlockNum = UDF_SB_LASTBLOCK(sb) - UDF_SB_PARTROOT(sb, j); break; } } @@ -1318,9 +1313,9 @@ static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset) if (UDF_SB_PARTTYPE(sb, i) == UDF_VIRTUAL_MAP15) { UDF_SB_TYPEVIRT(sb, i).s_start_offset = - udf_ext0_offset(UDF_SB_VAT(sb)); + udf_ext0_offset(UDF_SB_VAT(sb)); UDF_SB_TYPEVIRT(sb, i).s_num_entries = - (UDF_SB_VAT(sb)->i_size - 36) >> 2; + (UDF_SB_VAT(sb)->i_size - 36) >> 2; } else if (UDF_SB_PARTTYPE(sb, i) == UDF_VIRTUAL_MAP20) { struct buffer_head *bh = NULL; uint32_t pos; @@ -1330,19 +1325,15 @@ static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset) if (!bh) return 1; UDF_SB_TYPEVIRT(sb, i).s_start_offset = - le16_to_cpu(((struct - virtualAllocationTable20 *)bh->b_data + - udf_ext0_offset(UDF_SB_VAT(sb)))-> - lengthHeader) + - udf_ext0_offset(UDF_SB_VAT(sb)); - UDF_SB_TYPEVIRT(sb, i).s_num_entries = - (UDF_SB_VAT(sb)->i_size - - UDF_SB_TYPEVIRT(sb, i).s_start_offset) >> 2; + le16_to_cpu(((struct virtualAllocationTable20 *)bh->b_data + + udf_ext0_offset(UDF_SB_VAT(sb)))->lengthHeader) + + udf_ext0_offset(UDF_SB_VAT(sb)); + UDF_SB_TYPEVIRT(sb, i).s_num_entries = (UDF_SB_VAT(sb)->i_size - + UDF_SB_TYPEVIRT(sb, i).s_start_offset) >> 2; brelse(bh); } UDF_SB_PARTROOT(sb, i) = udf_get_pblock(sb, 0, i, 0); - UDF_SB_PARTLEN(sb, i) = UDF_SB_PARTLEN(sb, - ino.partitionReferenceNum); + UDF_SB_PARTLEN(sb, i) = UDF_SB_PARTLEN(sb, ino.partitionReferenceNum); } } return 0; @@ -1357,21 +1348,17 @@ static void udf_open_lvid(struct super_block *sb) UDF_SB_LVIDIU(sb)->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; UDF_SB_LVIDIU(sb)->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; if (udf_time_to_stamp(&cpu_time, CURRENT_TIME)) - UDF_SB_LVID(sb)->recordingDateAndTime = - cpu_to_lets(cpu_time); + UDF_SB_LVID(sb)->recordingDateAndTime = cpu_to_lets(cpu_time); UDF_SB_LVID(sb)->integrityType = LVID_INTEGRITY_TYPE_OPEN; - UDF_SB_LVID(sb)->descTag.descCRC = - cpu_to_le16(udf_crc((char *)UDF_SB_LVID(sb) + sizeof(tag), - le16_to_cpu(UDF_SB_LVID(sb)->descTag. - descCRCLength), 0)); + UDF_SB_LVID(sb)->descTag.descCRC = cpu_to_le16(udf_crc((char *)UDF_SB_LVID(sb) + sizeof(tag), + le16_to_cpu(UDF_SB_LVID(sb)->descTag.descCRCLength), 0)); UDF_SB_LVID(sb)->descTag.tagChecksum = 0; for (i = 0; i < 16; i++) if (i != 4) UDF_SB_LVID(sb)->descTag.tagChecksum += - ((uint8_t *) & - (UDF_SB_LVID(sb)->descTag))[i]; + ((uint8_t *) &(UDF_SB_LVID(sb)->descTag))[i]; mark_buffer_dirty(UDF_SB_LVIDBH(sb)); } diff --git a/fs/udf/udftime.c b/fs/udf/udftime.c index 3fd80eb66af3..adcb87c2da7e 100644 --- a/fs/udf/udftime.c +++ b/fs/udf/udftime.c @@ -108,10 +108,10 @@ time_t *udf_stamp_to_time(time_t *dest, long *dest_usec, kernel_timestamp src) *dest = year_seconds[src.year - EPOCH_YEAR]; *dest -= offset * 60; - yday = ((__mon_yday[__isleap (src.year)] - [src.month - 1]) + (src.day - 1)); - *dest += ( ( (yday * 24) + src.hour ) * 60 + src.minute ) * 60 + src.second; - *dest_usec = src.centiseconds * 10000 + src.hundredsOfMicroseconds * 100 + src.microseconds; + yday = ((__mon_yday[__isleap(src.year)][src.month - 1]) + src.day - 1); + *dest += (((yday * 24) + src.hour) * 60 + src.minute) * 60 + src.second; + *dest_usec = src.centiseconds * 10000 + + src.hundredsOfMicroseconds * 100 + src.microseconds; return dest; } diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c index 841ac25fd950..f63a09ce8683 100644 --- a/fs/ufs/balloc.c +++ b/fs/ufs/balloc.c @@ -19,6 +19,7 @@ #include <linux/bitops.h> #include <asm/byteorder.h> +#include "ufs.h" #include "swab.h" #include "util.h" diff --git a/fs/ufs/cylinder.c b/fs/ufs/cylinder.c index 09c39e5e6386..2a815665644f 100644 --- a/fs/ufs/cylinder.c +++ b/fs/ufs/cylinder.c @@ -17,6 +17,7 @@ #include <asm/byteorder.h> +#include "ufs.h" #include "swab.h" #include "util.h" diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c index 154452172f43..30f8c2bb0c3e 100644 --- a/fs/ufs/dir.c +++ b/fs/ufs/dir.c @@ -19,7 +19,9 @@ #include <linux/time.h> #include <linux/fs.h> #include <linux/ufs_fs.h> +#include <linux/swap.h> +#include "ufs.h" #include "swab.h" #include "util.h" @@ -38,12 +40,18 @@ static inline int ufs_match(struct super_block *sb, int len, return !memcmp(name, de->d_name, len); } -static int ufs_commit_chunk(struct page *page, unsigned from, unsigned to) +static int ufs_commit_chunk(struct page *page, loff_t pos, unsigned len) { - struct inode *dir = page->mapping->host; + struct address_space *mapping = page->mapping; + struct inode *dir = mapping->host; int err = 0; + dir->i_version++; - page->mapping->a_ops->commit_write(NULL, page, from, to); + block_write_end(NULL, mapping, pos, len, len, page, NULL); + if (pos+len > dir->i_size) { + i_size_write(dir, pos+len); + mark_inode_dirty(dir); + } if (IS_DIRSYNC(dir)) err = write_one_page(page, 1); else @@ -81,16 +89,20 @@ ino_t ufs_inode_by_name(struct inode *dir, struct dentry *dentry) void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de, struct page *page, struct inode *inode) { - unsigned from = (char *) de - (char *) page_address(page); - unsigned to = from + fs16_to_cpu(dir->i_sb, de->d_reclen); + loff_t pos = page_offset(page) + + (char *) de - (char *) page_address(page); + unsigned len = fs16_to_cpu(dir->i_sb, de->d_reclen); int err; lock_page(page); - err = page->mapping->a_ops->prepare_write(NULL, page, from, to); + err = __ufs_write_begin(NULL, page->mapping, pos, len, + AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); BUG_ON(err); + de->d_ino = cpu_to_fs32(dir->i_sb, inode->i_ino); ufs_set_de_type(dir->i_sb, de, inode->i_mode); - err = ufs_commit_chunk(page, from, to); + + err = ufs_commit_chunk(page, pos, len); ufs_put_page(page); dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(dir); @@ -312,7 +324,7 @@ int ufs_add_link(struct dentry *dentry, struct inode *inode) unsigned long npages = ufs_dir_pages(dir); unsigned long n; char *kaddr; - unsigned from, to; + loff_t pos; int err; UFSD("ENTER, name %s, namelen %u\n", name, namelen); @@ -367,9 +379,10 @@ int ufs_add_link(struct dentry *dentry, struct inode *inode) return -EINVAL; got_it: - from = (char*)de - (char*)page_address(page); - to = from + rec_len; - err = page->mapping->a_ops->prepare_write(NULL, page, from, to); + pos = page_offset(page) + + (char*)de - (char*)page_address(page); + err = __ufs_write_begin(NULL, page->mapping, pos, rec_len, + AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); if (err) goto out_unlock; if (de->d_ino) { @@ -386,7 +399,7 @@ got_it: de->d_ino = cpu_to_fs32(sb, inode->i_ino); ufs_set_de_type(sb, de, inode->i_mode); - err = ufs_commit_chunk(page, from, to); + err = ufs_commit_chunk(page, pos, rec_len); dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(dir); @@ -509,6 +522,7 @@ int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir, char *kaddr = page_address(page); unsigned from = ((char*)dir - kaddr) & ~(UFS_SB(sb)->s_uspi->s_dirblksize - 1); unsigned to = ((char*)dir - kaddr) + fs16_to_cpu(sb, dir->d_reclen); + loff_t pos; struct ufs_dir_entry *pde = NULL; struct ufs_dir_entry *de = (struct ufs_dir_entry *) (kaddr + from); int err; @@ -532,13 +546,16 @@ int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir, } if (pde) from = (char*)pde - (char*)page_address(page); + + pos = page_offset(page) + from; lock_page(page); - err = mapping->a_ops->prepare_write(NULL, page, from, to); + err = __ufs_write_begin(NULL, mapping, pos, to - from, + AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); BUG_ON(err); if (pde) - pde->d_reclen = cpu_to_fs16(sb, to-from); + pde->d_reclen = cpu_to_fs16(sb, to - from); dir->d_ino = 0; - err = ufs_commit_chunk(page, from, to); + err = ufs_commit_chunk(page, pos, to - from); inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; mark_inode_dirty(inode); out: @@ -559,14 +576,15 @@ int ufs_make_empty(struct inode * inode, struct inode *dir) if (!page) return -ENOMEM; - kmap(page); - err = mapping->a_ops->prepare_write(NULL, page, 0, chunk_size); + + err = __ufs_write_begin(NULL, mapping, 0, chunk_size, + AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); if (err) { unlock_page(page); goto fail; } - + kmap(page); base = (char*)page_address(page); memset(base, 0, PAGE_CACHE_SIZE); @@ -584,10 +602,10 @@ int ufs_make_empty(struct inode * inode, struct inode *dir) de->d_reclen = cpu_to_fs16(sb, chunk_size - UFS_DIR_REC_LEN(1)); ufs_set_de_namlen(sb, de, 2); strcpy (de->d_name, ".."); + kunmap(page); err = ufs_commit_chunk(page, 0, chunk_size); fail: - kunmap(page); page_cache_release(page); return err; } diff --git a/fs/ufs/file.c b/fs/ufs/file.c index 6705d74c6d2d..a46c97bf023f 100644 --- a/fs/ufs/file.c +++ b/fs/ufs/file.c @@ -27,6 +27,9 @@ #include <linux/ufs_fs.h> #include <linux/buffer_head.h> /* for sync_mapping_buffers() */ +#include "ufs.h" + + static int ufs_sync_file(struct file *file, struct dentry *dentry, int datasync) { struct inode *inode = dentry->d_inode; diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c index c28a8b6f2feb..7e260bc0d94f 100644 --- a/fs/ufs/ialloc.c +++ b/fs/ufs/ialloc.c @@ -34,6 +34,7 @@ #include <linux/bitops.h> #include <asm/byteorder.h> +#include "ufs.h" #include "swab.h" #include "util.h" diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index f18b79122fa3..4320782761ae 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -38,6 +38,7 @@ #include <linux/smp_lock.h> #include <linux/buffer_head.h> +#include "ufs.h" #include "swab.h" #include "util.h" @@ -558,24 +559,39 @@ static int ufs_writepage(struct page *page, struct writeback_control *wbc) { return block_write_full_page(page,ufs_getfrag_block,wbc); } + static int ufs_readpage(struct file *file, struct page *page) { return block_read_full_page(page,ufs_getfrag_block); } -static int ufs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) + +int __ufs_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { - return block_prepare_write(page,from,to,ufs_getfrag_block); + return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + ufs_getfrag_block); } + +static int ufs_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) +{ + *pagep = NULL; + return __ufs_write_begin(file, mapping, pos, len, flags, pagep, fsdata); +} + static sector_t ufs_bmap(struct address_space *mapping, sector_t block) { return generic_block_bmap(mapping,block,ufs_getfrag_block); } + const struct address_space_operations ufs_aops = { .readpage = ufs_readpage, .writepage = ufs_writepage, .sync_page = block_sync_page, - .prepare_write = ufs_prepare_write, - .commit_write = generic_commit_write, + .write_begin = ufs_write_begin, + .write_end = generic_write_end, .bmap = ufs_bmap }; diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index a059ccd064ea..d8bfbee2fe2b 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -31,7 +31,7 @@ #include <linux/fs.h> #include <linux/ufs_fs.h> #include <linux/smp_lock.h> -#include "swab.h" /* will go away - see comment in mknod() */ +#include "ufs.h" #include "util.h" static inline int ufs_add_nondir(struct dentry *dentry, struct inode *inode) @@ -110,7 +110,6 @@ static int ufs_mknod (struct inode * dir, struct dentry *dentry, int mode, dev_t err = PTR_ERR(inode); if (!IS_ERR(inode)) { init_special_inode(inode, mode, rdev); - /* NOTE: that'll go when we get wide dev_t */ ufs_set_inode_dev(inode->i_sb, UFS_I(inode), rdev); mark_inode_dirty(inode); lock_kernel(); diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 38eb0b7a1f3d..584cf12cc40f 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -88,7 +88,10 @@ #include <linux/buffer_head.h> #include <linux/vfs.h> #include <linux/log2.h> +#include <linux/mount.h> +#include <linux/seq_file.h> +#include "ufs.h" #include "swab.h" #include "util.h" @@ -286,16 +289,28 @@ void ufs_warning (struct super_block * sb, const char * function, } enum { - Opt_type_old, Opt_type_sunx86, Opt_type_sun, Opt_type_44bsd, - Opt_type_ufs2, Opt_type_hp, Opt_type_nextstepcd, Opt_type_nextstep, - Opt_type_openstep, Opt_onerror_panic, Opt_onerror_lock, - Opt_onerror_umount, Opt_onerror_repair, Opt_err + Opt_type_old = UFS_MOUNT_UFSTYPE_OLD, + Opt_type_sunx86 = UFS_MOUNT_UFSTYPE_SUNx86, + Opt_type_sun = UFS_MOUNT_UFSTYPE_SUN, + Opt_type_sunos = UFS_MOUNT_UFSTYPE_SUNOS, + Opt_type_44bsd = UFS_MOUNT_UFSTYPE_44BSD, + Opt_type_ufs2 = UFS_MOUNT_UFSTYPE_UFS2, + Opt_type_hp = UFS_MOUNT_UFSTYPE_HP, + Opt_type_nextstepcd = UFS_MOUNT_UFSTYPE_NEXTSTEP_CD, + Opt_type_nextstep = UFS_MOUNT_UFSTYPE_NEXTSTEP, + Opt_type_openstep = UFS_MOUNT_UFSTYPE_OPENSTEP, + Opt_onerror_panic = UFS_MOUNT_ONERROR_PANIC, + Opt_onerror_lock = UFS_MOUNT_ONERROR_LOCK, + Opt_onerror_umount = UFS_MOUNT_ONERROR_UMOUNT, + Opt_onerror_repair = UFS_MOUNT_ONERROR_REPAIR, + Opt_err }; static match_table_t tokens = { {Opt_type_old, "ufstype=old"}, {Opt_type_sunx86, "ufstype=sunx86"}, {Opt_type_sun, "ufstype=sun"}, + {Opt_type_sunos, "ufstype=sunos"}, {Opt_type_44bsd, "ufstype=44bsd"}, {Opt_type_ufs2, "ufstype=ufs2"}, {Opt_type_ufs2, "ufstype=5xbsd"}, @@ -303,6 +318,7 @@ static match_table_t tokens = { {Opt_type_nextstepcd, "ufstype=nextstep-cd"}, {Opt_type_nextstep, "ufstype=nextstep"}, {Opt_type_openstep, "ufstype=openstep"}, +/*end of possible ufs types */ {Opt_onerror_panic, "onerror=panic"}, {Opt_onerror_lock, "onerror=lock"}, {Opt_onerror_umount, "onerror=umount"}, @@ -339,6 +355,10 @@ static int ufs_parse_options (char * options, unsigned * mount_options) ufs_clear_opt (*mount_options, UFSTYPE); ufs_set_opt (*mount_options, UFSTYPE_SUN); break; + case Opt_type_sunos: + ufs_clear_opt(*mount_options, UFSTYPE); + ufs_set_opt(*mount_options, UFSTYPE_SUNOS); + break; case Opt_type_44bsd: ufs_clear_opt (*mount_options, UFSTYPE); ufs_set_opt (*mount_options, UFSTYPE_44BSD); @@ -654,8 +674,8 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) ufs_set_opt (sbi->s_mount_opt, UFSTYPE_OLD); } - sbi->s_uspi = uspi = - kmalloc (sizeof(struct ufs_sb_private_info), GFP_KERNEL); + uspi = kzalloc(sizeof(struct ufs_sb_private_info), GFP_KERNEL); + sbi->s_uspi = uspi; if (!uspi) goto failed; uspi->s_dirblksize = UFS_SECTOR_SIZE; @@ -692,10 +712,22 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) uspi->s_fshift = 10; uspi->s_sbsize = super_block_size = 2048; uspi->s_sbbase = 0; - uspi->s_maxsymlinklen = 56; + uspi->s_maxsymlinklen = 0; /* Not supported on disk */ flags |= UFS_DE_OLD | UFS_UID_EFT | UFS_ST_SUN | UFS_CG_SUN; break; + case UFS_MOUNT_UFSTYPE_SUNOS: + UFSD(("ufstype=sunos\n")) + uspi->s_fsize = block_size = 1024; + uspi->s_fmask = ~(1024 - 1); + uspi->s_fshift = 10; + uspi->s_sbsize = 2048; + super_block_size = 2048; + uspi->s_sbbase = 0; + uspi->s_maxsymlinklen = 0; /* Not supported on disk */ + flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_SUNOS | UFS_CG_SUN; + break; + case UFS_MOUNT_UFSTYPE_SUNx86: UFSD("ufstype=sunx86\n"); uspi->s_fsize = block_size = 1024; @@ -703,7 +735,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) uspi->s_fshift = 10; uspi->s_sbsize = super_block_size = 2048; uspi->s_sbbase = 0; - uspi->s_maxsymlinklen = 56; + uspi->s_maxsymlinklen = 0; /* Not supported on disk */ flags |= UFS_DE_OLD | UFS_UID_EFT | UFS_ST_SUNx86 | UFS_CG_SUN; break; @@ -805,11 +837,18 @@ again: if (!ubh) goto failed; - usb1 = ubh_get_usb_first(uspi); usb2 = ubh_get_usb_second(uspi); usb3 = ubh_get_usb_third(uspi); + /* Sort out mod used on SunOS 4.1.3 for fs_state */ + uspi->s_postblformat = fs32_to_cpu(sb, usb3->fs_postblformat); + if (((flags & UFS_ST_MASK) == UFS_ST_SUNOS) && + (uspi->s_postblformat != UFS_42POSTBLFMT)) { + flags &= ~UFS_ST_MASK; + flags |= UFS_ST_SUN; + } + /* * Check ufs magic number */ @@ -894,18 +933,20 @@ magic_found: goto again; } - sbi->s_flags = flags;/*after that line some functions use s_flags*/ + /* Set sbi->s_flags here, used by ufs_get_fs_state() below */ + sbi->s_flags = flags; ufs_print_super_stuff(sb, usb1, usb2, usb3); /* * Check, if file system was correctly unmounted. * If not, make it read only. */ - if (((flags & UFS_ST_MASK) == UFS_ST_44BSD) || - ((flags & UFS_ST_MASK) == UFS_ST_OLD) || - (((flags & UFS_ST_MASK) == UFS_ST_SUN || - (flags & UFS_ST_MASK) == UFS_ST_SUNx86) && - (ufs_get_fs_state(sb, usb1, usb3) == (UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time))))) { + if ((((flags & UFS_ST_MASK) == UFS_ST_44BSD) || + ((flags & UFS_ST_MASK) == UFS_ST_OLD) || + ((flags & UFS_ST_MASK) == UFS_ST_SUN) || + ((flags & UFS_ST_MASK) == UFS_ST_SUNOS) || + ((flags & UFS_ST_MASK) == UFS_ST_SUNx86)) && + (ufs_get_fs_state(sb, usb1, usb3) == (UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time)))) { switch(usb1->fs_clean) { case UFS_FSCLEAN: UFSD("fs is clean\n"); @@ -995,7 +1036,6 @@ magic_found: uspi->s_contigsumsize = fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_contigsumsize); uspi->s_qbmask = ufs_get_fs_qbmask(sb, usb3); uspi->s_qfmask = ufs_get_fs_qfmask(sb, usb3); - uspi->s_postblformat = fs32_to_cpu(sb, usb3->fs_postblformat); uspi->s_nrpos = fs32_to_cpu(sb, usb3->fs_nrpos); uspi->s_postbloff = fs32_to_cpu(sb, usb3->fs_postbloff); uspi->s_rotbloff = fs32_to_cpu(sb, usb3->fs_rotbloff); @@ -1077,6 +1117,7 @@ static void ufs_write_super(struct super_block *sb) if (!(sb->s_flags & MS_RDONLY)) { usb1->fs_time = cpu_to_fs32(sb, get_seconds()); if ((flags & UFS_ST_MASK) == UFS_ST_SUN + || (flags & UFS_ST_MASK) == UFS_ST_SUNOS || (flags & UFS_ST_MASK) == UFS_ST_SUNx86) ufs_set_fs_state(sb, usb1, usb3, UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time)); @@ -1146,6 +1187,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) ufs_put_super_internal(sb); usb1->fs_time = cpu_to_fs32(sb, get_seconds()); if ((flags & UFS_ST_MASK) == UFS_ST_SUN + || (flags & UFS_ST_MASK) == UFS_ST_SUNOS || (flags & UFS_ST_MASK) == UFS_ST_SUNx86) ufs_set_fs_state(sb, usb1, usb3, UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time)); @@ -1162,6 +1204,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) return -EINVAL; #else if (ufstype != UFS_MOUNT_UFSTYPE_SUN && + ufstype != UFS_MOUNT_UFSTYPE_SUNOS && ufstype != UFS_MOUNT_UFSTYPE_44BSD && ufstype != UFS_MOUNT_UFSTYPE_SUNx86 && ufstype != UFS_MOUNT_UFSTYPE_UFS2) { @@ -1179,6 +1222,26 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) return 0; } +static int ufs_show_options(struct seq_file *seq, struct vfsmount *vfs) +{ + struct ufs_sb_info *sbi = UFS_SB(vfs->mnt_sb); + unsigned mval = sbi->s_mount_opt & UFS_MOUNT_UFSTYPE; + struct match_token *tp = tokens; + + while (tp->token != Opt_onerror_panic && tp->token != mval) + ++tp; + BUG_ON(tp->token == Opt_onerror_panic); + seq_printf(seq, ",%s", tp->pattern); + + mval = sbi->s_mount_opt & UFS_MOUNT_ONERROR; + while (tp->token != Opt_err && tp->token != mval) + ++tp; + BUG_ON(tp->token == Opt_err); + seq_printf(seq, ",%s", tp->pattern); + + return 0; +} + static int ufs_statfs(struct dentry *dentry, struct kstatfs *buf) { struct super_block *sb = dentry->d_sb; @@ -1232,7 +1295,7 @@ static void ufs_destroy_inode(struct inode *inode) kmem_cache_free(ufs_inode_cachep, UFS_I(inode)); } -static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(struct kmem_cache * cachep, void *foo) { struct ufs_inode_info *ei = (struct ufs_inode_info *) foo; @@ -1271,6 +1334,7 @@ static const struct super_operations ufs_super_ops = { .write_super = ufs_write_super, .statfs = ufs_statfs, .remount_fs = ufs_remount, + .show_options = ufs_show_options, #ifdef CONFIG_QUOTA .quota_read = ufs_quota_read, .quota_write = ufs_quota_write, diff --git a/fs/ufs/symlink.c b/fs/ufs/symlink.c index d8549f807e80..43ac10e75a4a 100644 --- a/fs/ufs/symlink.c +++ b/fs/ufs/symlink.c @@ -28,6 +28,8 @@ #include <linux/fs.h> #include <linux/namei.h> #include <linux/ufs_fs.h> +#include "ufs.h" + static void *ufs_follow_link(struct dentry *dentry, struct nameidata *nd) { diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c index 79c54c85fb58..311ded34c2b2 100644 --- a/fs/ufs/truncate.c +++ b/fs/ufs/truncate.c @@ -46,6 +46,7 @@ #include <linux/blkdev.h> #include <linux/sched.h> +#include "ufs.h" #include "swab.h" #include "util.h" diff --git a/fs/ufs/ufs.h b/fs/ufs/ufs.h new file mode 100644 index 000000000000..7faa4cd71a27 --- /dev/null +++ b/fs/ufs/ufs.h @@ -0,0 +1,157 @@ +#ifndef _UFS_UFS_H +#define _UFS_UFS_H 1 + +#define UFS_MAX_GROUP_LOADED 8 +#define UFS_CGNO_EMPTY ((unsigned)-1) + +struct ufs_sb_private_info; +struct ufs_cg_private_info; +struct ufs_csum; + +struct ufs_sb_info { + struct ufs_sb_private_info * s_uspi; + struct ufs_csum * s_csp; + unsigned s_bytesex; + unsigned s_flags; + struct buffer_head ** s_ucg; + struct ufs_cg_private_info * s_ucpi[UFS_MAX_GROUP_LOADED]; + unsigned s_cgno[UFS_MAX_GROUP_LOADED]; + unsigned short s_cg_loaded; + unsigned s_mount_opt; +}; + +struct ufs_inode_info { + union { + __fs32 i_data[15]; + __u8 i_symlink[4*15]; + __fs64 u2_i_data[15]; + } i_u1; + __u32 i_flags; + __u32 i_shadow; + __u32 i_unused1; + __u32 i_unused2; + __u32 i_oeftflag; + __u16 i_osync; + __u64 i_lastfrag; + __u32 i_dir_start_lookup; + struct inode vfs_inode; +}; + +/* mount options */ +#define UFS_MOUNT_ONERROR 0x0000000F +#define UFS_MOUNT_ONERROR_PANIC 0x00000001 +#define UFS_MOUNT_ONERROR_LOCK 0x00000002 +#define UFS_MOUNT_ONERROR_UMOUNT 0x00000004 +#define UFS_MOUNT_ONERROR_REPAIR 0x00000008 + +#define UFS_MOUNT_UFSTYPE 0x0000FFF0 +#define UFS_MOUNT_UFSTYPE_OLD 0x00000010 +#define UFS_MOUNT_UFSTYPE_44BSD 0x00000020 +#define UFS_MOUNT_UFSTYPE_SUN 0x00000040 +#define UFS_MOUNT_UFSTYPE_NEXTSTEP 0x00000080 +#define UFS_MOUNT_UFSTYPE_NEXTSTEP_CD 0x00000100 +#define UFS_MOUNT_UFSTYPE_OPENSTEP 0x00000200 +#define UFS_MOUNT_UFSTYPE_SUNx86 0x00000400 +#define UFS_MOUNT_UFSTYPE_HP 0x00000800 +#define UFS_MOUNT_UFSTYPE_UFS2 0x00001000 +#define UFS_MOUNT_UFSTYPE_SUNOS 0x00002000 + +#define ufs_clear_opt(o,opt) o &= ~UFS_MOUNT_##opt +#define ufs_set_opt(o,opt) o |= UFS_MOUNT_##opt +#define ufs_test_opt(o,opt) ((o) & UFS_MOUNT_##opt) + +/* + * Debug code + */ +#ifdef CONFIG_UFS_DEBUG +# define UFSD(f, a...) { \ + printk ("UFSD (%s, %d): %s:", \ + __FILE__, __LINE__, __FUNCTION__); \ + printk (f, ## a); \ + } +#else +# define UFSD(f, a...) /**/ +#endif + +/* balloc.c */ +extern void ufs_free_fragments (struct inode *, u64, unsigned); +extern void ufs_free_blocks (struct inode *, u64, unsigned); +extern u64 ufs_new_fragments(struct inode *, void *, u64, u64, + unsigned, int *, struct page *); + +/* cylinder.c */ +extern struct ufs_cg_private_info * ufs_load_cylinder (struct super_block *, unsigned); +extern void ufs_put_cylinder (struct super_block *, unsigned); + +/* dir.c */ +extern const struct inode_operations ufs_dir_inode_operations; +extern int ufs_add_link (struct dentry *, struct inode *); +extern ino_t ufs_inode_by_name(struct inode *, struct dentry *); +extern int ufs_make_empty(struct inode *, struct inode *); +extern struct ufs_dir_entry *ufs_find_entry(struct inode *, struct dentry *, struct page **); +extern int ufs_delete_entry(struct inode *, struct ufs_dir_entry *, struct page *); +extern int ufs_empty_dir (struct inode *); +extern struct ufs_dir_entry *ufs_dotdot(struct inode *, struct page **); +extern void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de, + struct page *page, struct inode *inode); + +/* file.c */ +extern const struct inode_operations ufs_file_inode_operations; +extern const struct file_operations ufs_file_operations; + +extern const struct address_space_operations ufs_aops; + +/* ialloc.c */ +extern void ufs_free_inode (struct inode *inode); +extern struct inode * ufs_new_inode (struct inode *, int); + +/* inode.c */ +extern void ufs_read_inode (struct inode *); +extern void ufs_put_inode (struct inode *); +extern int ufs_write_inode (struct inode *, int); +extern int ufs_sync_inode (struct inode *); +extern void ufs_delete_inode (struct inode *); +extern struct buffer_head * ufs_bread (struct inode *, unsigned, int, int *); +extern int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create); + +/* namei.c */ +extern const struct file_operations ufs_dir_operations; + +/* super.c */ +extern void ufs_warning (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4))); +extern void ufs_error (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4))); +extern void ufs_panic (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4))); + +/* symlink.c */ +extern const struct inode_operations ufs_fast_symlink_inode_operations; + +/* truncate.c */ +extern int ufs_truncate (struct inode *, loff_t); + +static inline struct ufs_sb_info *UFS_SB(struct super_block *sb) +{ + return sb->s_fs_info; +} + +static inline struct ufs_inode_info *UFS_I(struct inode *inode) +{ + return container_of(inode, struct ufs_inode_info, vfs_inode); +} + +/* + * Give cylinder group number for a file system block. + * Give cylinder group block number for a file system block. + */ +/* #define ufs_dtog(d) ((d) / uspi->s_fpg) */ +static inline u64 ufs_dtog(struct ufs_sb_private_info * uspi, u64 b) +{ + do_div(b, uspi->s_fpg); + return b; +} +/* #define ufs_dtogd(d) ((d) % uspi->s_fpg) */ +static inline u32 ufs_dtogd(struct ufs_sb_private_info * uspi, u64 b) +{ + return do_div(b, uspi->s_fpg); +} + +#endif /* _UFS_UFS_H */ diff --git a/fs/ufs/util.c b/fs/ufs/util.c index 84357f1ff0ec..410084dae389 100644 --- a/fs/ufs/util.c +++ b/fs/ufs/util.c @@ -11,6 +11,7 @@ #include <linux/ufs_fs.h> #include <linux/buffer_head.h> +#include "ufs.h" #include "swab.h" #include "util.h" diff --git a/fs/ufs/util.h b/fs/ufs/util.h index 06d344839c42..b26fc4dec1e7 100644 --- a/fs/ufs/util.h +++ b/fs/ufs/util.h @@ -38,6 +38,10 @@ ufs_get_fs_state(struct super_block *sb, struct ufs_super_block_first *usb1, struct ufs_super_block_third *usb3) { switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) { + case UFS_ST_SUNOS: + if (fs32_to_cpu(sb, usb3->fs_postblformat) == UFS_42POSTBLFMT) + return fs32_to_cpu(sb, usb1->fs_u0.fs_sun.fs_state); + /* Fall Through to UFS_ST_SUN */ case UFS_ST_SUN: return fs32_to_cpu(sb, usb3->fs_un2.fs_sun.fs_state); case UFS_ST_SUNx86: @@ -53,6 +57,12 @@ ufs_set_fs_state(struct super_block *sb, struct ufs_super_block_first *usb1, struct ufs_super_block_third *usb3, s32 value) { switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) { + case UFS_ST_SUNOS: + if (fs32_to_cpu(sb, usb3->fs_postblformat == UFS_42POSTBLFMT)) { + usb1->fs_u0.fs_sun.fs_state = cpu_to_fs32(sb, value); + break; + } + /* Fall Through to UFS_ST_SUN */ case UFS_ST_SUN: usb3->fs_un2.fs_sun.fs_state = cpu_to_fs32(sb, value); break; @@ -81,6 +91,7 @@ ufs_get_fs_qbmask(struct super_block *sb, struct ufs_super_block_third *usb3) __fs64 tmp; switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) { + case UFS_ST_SUNOS: case UFS_ST_SUN: ((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_sun.fs_qbmask[0]; ((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_sun.fs_qbmask[1]; @@ -104,6 +115,7 @@ ufs_get_fs_qfmask(struct super_block *sb, struct ufs_super_block_third *usb3) __fs64 tmp; switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) { + case UFS_ST_SUNOS: case UFS_ST_SUN: ((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_sun.fs_qfmask[0]; ((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_sun.fs_qfmask[1]; @@ -179,10 +191,12 @@ static inline u32 ufs_get_inode_uid(struct super_block *sb, struct ufs_inode *inode) { switch (UFS_SB(sb)->s_flags & UFS_UID_MASK) { - case UFS_UID_EFT: - return fs32_to_cpu(sb, inode->ui_u3.ui_sun.ui_uid); case UFS_UID_44BSD: return fs32_to_cpu(sb, inode->ui_u3.ui_44.ui_uid); + case UFS_UID_EFT: + if (inode->ui_u1.oldids.ui_suid == 0xFFFF) + return fs32_to_cpu(sb, inode->ui_u3.ui_sun.ui_uid); + /* Fall through */ default: return fs16_to_cpu(sb, inode->ui_u1.oldids.ui_suid); } @@ -192,24 +206,31 @@ static inline void ufs_set_inode_uid(struct super_block *sb, struct ufs_inode *inode, u32 value) { switch (UFS_SB(sb)->s_flags & UFS_UID_MASK) { - case UFS_UID_EFT: - inode->ui_u3.ui_sun.ui_uid = cpu_to_fs32(sb, value); - break; case UFS_UID_44BSD: inode->ui_u3.ui_44.ui_uid = cpu_to_fs32(sb, value); + inode->ui_u1.oldids.ui_suid = cpu_to_fs16(sb, value); + break; + case UFS_UID_EFT: + inode->ui_u3.ui_sun.ui_uid = cpu_to_fs32(sb, value); + if (value > 0xFFFF) + value = 0xFFFF; + /* Fall through */ + default: + inode->ui_u1.oldids.ui_suid = cpu_to_fs16(sb, value); break; } - inode->ui_u1.oldids.ui_suid = cpu_to_fs16(sb, value); } static inline u32 ufs_get_inode_gid(struct super_block *sb, struct ufs_inode *inode) { switch (UFS_SB(sb)->s_flags & UFS_UID_MASK) { - case UFS_UID_EFT: - return fs32_to_cpu(sb, inode->ui_u3.ui_sun.ui_gid); case UFS_UID_44BSD: return fs32_to_cpu(sb, inode->ui_u3.ui_44.ui_gid); + case UFS_UID_EFT: + if (inode->ui_u1.oldids.ui_suid == 0xFFFF) + return fs32_to_cpu(sb, inode->ui_u3.ui_sun.ui_gid); + /* Fall through */ default: return fs16_to_cpu(sb, inode->ui_u1.oldids.ui_sgid); } @@ -219,18 +240,26 @@ static inline void ufs_set_inode_gid(struct super_block *sb, struct ufs_inode *inode, u32 value) { switch (UFS_SB(sb)->s_flags & UFS_UID_MASK) { - case UFS_UID_EFT: - inode->ui_u3.ui_sun.ui_gid = cpu_to_fs32(sb, value); - break; case UFS_UID_44BSD: inode->ui_u3.ui_44.ui_gid = cpu_to_fs32(sb, value); + inode->ui_u1.oldids.ui_sgid = cpu_to_fs16(sb, value); + break; + case UFS_UID_EFT: + inode->ui_u3.ui_sun.ui_gid = cpu_to_fs32(sb, value); + if (value > 0xFFFF) + value = 0xFFFF; + /* Fall through */ + default: + inode->ui_u1.oldids.ui_sgid = cpu_to_fs16(sb, value); break; } - inode->ui_u1.oldids.ui_sgid = cpu_to_fs16(sb, value); } extern dev_t ufs_get_inode_dev(struct super_block *, struct ufs_inode_info *); extern void ufs_set_inode_dev(struct super_block *, struct ufs_inode_info *, dev_t); +extern int __ufs_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata); /* * These functions manipulate ufs buffers diff --git a/fs/utimes.c b/fs/utimes.c index 682eb63b20ad..b9912ecbee24 100644 --- a/fs/utimes.c +++ b/fs/utimes.c @@ -38,6 +38,14 @@ asmlinkage long sys_utime(char __user *filename, struct utimbuf __user *times) #endif +static bool nsec_valid(long nsec) +{ + if (nsec == UTIME_OMIT || nsec == UTIME_NOW) + return true; + + return nsec >= 0 && nsec <= 999999999; +} + /* If times==NULL, set access and modification to current time, * must be owner or have write permission. * Else, update from *times, must be owner or super user. @@ -52,6 +60,11 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags struct file *f = NULL; error = -EINVAL; + if (times && (!nsec_valid(times[0].tv_nsec) || + !nsec_valid(times[1].tv_nsec))) { + goto out; + } + if (flags & ~AT_SYMLINK_NOFOLLOW) goto out; diff --git a/fs/xfs/Makefile-linux-2.6 b/fs/xfs/Makefile-linux-2.6 index e7a9a83f0087..d1491aa7a0e2 100644 --- a/fs/xfs/Makefile-linux-2.6 +++ b/fs/xfs/Makefile-linux-2.6 @@ -49,7 +49,6 @@ xfs-y += xfs_alloc.o \ xfs_alloc_btree.o \ xfs_attr.o \ xfs_attr_leaf.o \ - xfs_behavior.o \ xfs_bit.o \ xfs_bmap.o \ xfs_bmap_btree.o \ @@ -108,13 +107,11 @@ xfs-y += $(addprefix $(XFS_LINUX)/, \ xfs_iops.o \ xfs_lrw.o \ xfs_super.o \ - xfs_vfs.o \ xfs_vnode.o) # Objects in support/ xfs-y += $(addprefix support/, \ debug.o \ - move.o \ uuid.o) xfs-$(CONFIG_XFS_TRACE) += support/ktrace.o diff --git a/fs/xfs/linux-2.6/kmem.h b/fs/xfs/linux-2.6/kmem.h index e6ea293f303c..5e9564902976 100644 --- a/fs/xfs/linux-2.6/kmem.h +++ b/fs/xfs/linux-2.6/kmem.h @@ -79,7 +79,7 @@ kmem_zone_init(int size, char *zone_name) static inline kmem_zone_t * kmem_zone_init_flags(int size, char *zone_name, unsigned long flags, - void (*construct)(void *, kmem_zone_t *, unsigned long)) + void (*construct)(kmem_zone_t *, void *)) { return kmem_cache_create(zone_name, size, 0, flags, construct); } diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 5f152f60d74d..2e34b104107c 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -37,6 +37,7 @@ #include "xfs_error.h" #include "xfs_rw.h" #include "xfs_iomap.h" +#include "xfs_vnodeops.h" #include <linux/mpage.h> #include <linux/pagevec.h> #include <linux/writeback.h> @@ -139,9 +140,11 @@ xfs_destroy_ioend( next = bh->b_private; bh->b_end_io(bh, !ioend->io_error); } - if (unlikely(ioend->io_error)) - vn_ioerror(ioend->io_vnode, ioend->io_error, __FILE__,__LINE__); - vn_iowake(ioend->io_vnode); + if (unlikely(ioend->io_error)) { + vn_ioerror(XFS_I(ioend->io_inode), ioend->io_error, + __FILE__,__LINE__); + } + vn_iowake(XFS_I(ioend->io_inode)); mempool_free(ioend, xfs_ioend_pool); } @@ -156,14 +159,10 @@ STATIC void xfs_setfilesize( xfs_ioend_t *ioend) { - xfs_inode_t *ip; + xfs_inode_t *ip = XFS_I(ioend->io_inode); xfs_fsize_t isize; xfs_fsize_t bsize; - ip = xfs_vtoi(ioend->io_vnode); - if (!ip) - return; - ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFREG); ASSERT(ioend->io_type != IOMAP_READ); @@ -181,7 +180,7 @@ xfs_setfilesize( ip->i_d.di_size = isize; ip->i_update_core = 1; ip->i_update_size = 1; - mark_inode_dirty_sync(vn_to_inode(ioend->io_vnode)); + mark_inode_dirty_sync(ioend->io_inode); } xfs_iunlock(ip, XFS_ILOCK_EXCL); @@ -227,12 +226,12 @@ xfs_end_bio_unwritten( { xfs_ioend_t *ioend = container_of(work, xfs_ioend_t, io_work); - bhv_vnode_t *vp = ioend->io_vnode; xfs_off_t offset = ioend->io_offset; size_t size = ioend->io_size; if (likely(!ioend->io_error)) { - bhv_vop_bmap(vp, offset, size, BMAPI_UNWRITTEN, NULL, NULL); + xfs_bmap(XFS_I(ioend->io_inode), offset, size, + BMAPI_UNWRITTEN, NULL, NULL); xfs_setfilesize(ioend); } xfs_destroy_ioend(ioend); @@ -275,10 +274,10 @@ xfs_alloc_ioend( ioend->io_error = 0; ioend->io_list = NULL; ioend->io_type = type; - ioend->io_vnode = vn_from_inode(inode); + ioend->io_inode = inode; ioend->io_buffer_head = NULL; ioend->io_buffer_tail = NULL; - atomic_inc(&ioend->io_vnode->v_iocount); + atomic_inc(&XFS_I(ioend->io_inode)->i_iocount); ioend->io_offset = 0; ioend->io_size = 0; @@ -302,12 +301,13 @@ xfs_map_blocks( xfs_iomap_t *mapp, int flags) { - bhv_vnode_t *vp = vn_from_inode(inode); + xfs_inode_t *ip = XFS_I(inode); int error, nmaps = 1; - error = bhv_vop_bmap(vp, offset, count, flags, mapp, &nmaps); + error = xfs_bmap(ip, offset, count, + flags, mapp, &nmaps); if (!error && (flags & (BMAPI_WRITE|BMAPI_ALLOCATE))) - VMODIFY(vp); + xfs_iflags_set(ip, XFS_IMODIFIED); return -error; } @@ -323,17 +323,13 @@ xfs_iomap_valid( /* * BIO completion handler for buffered IO. */ -STATIC int +STATIC void xfs_end_bio( struct bio *bio, - unsigned int bytes_done, int error) { xfs_ioend_t *ioend = bio->bi_private; - if (bio->bi_size) - return 1; - ASSERT(atomic_read(&bio->bi_cnt) >= 1); ioend->io_error = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : error; @@ -343,7 +339,6 @@ xfs_end_bio( bio_put(bio); xfs_finish_ioend(ioend, 0); - return 0; } STATIC void @@ -407,10 +402,9 @@ xfs_start_page_writeback( clear_page_dirty_for_io(page); set_page_writeback(page); unlock_page(page); - if (!buffers) { + /* If no buffers on the page are to be written, finish it here */ + if (!buffers) end_page_writeback(page); - wbc->pages_skipped++; /* We didn't write this page */ - } } static inline int bio_add_buffer(struct bio *bio, struct buffer_head *bh) @@ -503,7 +497,7 @@ xfs_cancel_ioend( unlock_buffer(bh); } while ((bh = next_bh) != NULL); - vn_iowake(ioend->io_vnode); + vn_iowake(XFS_I(ioend->io_inode)); mempool_free(ioend, xfs_ioend_pool); } while ((ioend = next) != NULL); } @@ -1243,10 +1237,7 @@ xfs_vm_writepages( struct address_space *mapping, struct writeback_control *wbc) { - struct bhv_vnode *vp = vn_from_inode(mapping->host); - - if (VN_TRUNC(vp)) - VUNTRUNCATE(vp); + xfs_iflags_clear(XFS_I(mapping->host), XFS_ITRUNCATED); return generic_writepages(mapping, wbc); } @@ -1323,7 +1314,6 @@ __xfs_get_blocks( int direct, bmapi_flags_t flags) { - bhv_vnode_t *vp = vn_from_inode(inode); xfs_iomap_t iomap; xfs_off_t offset; ssize_t size; @@ -1333,7 +1323,7 @@ __xfs_get_blocks( offset = (xfs_off_t)iblock << inode->i_blkbits; ASSERT(bh_result->b_size >= (1 << inode->i_blkbits)); size = bh_result->b_size; - error = bhv_vop_bmap(vp, offset, size, + error = xfs_bmap(XFS_I(inode), offset, size, create ? flags : BMAPI_READ, &iomap, &niomap); if (error) return -error; @@ -1481,13 +1471,13 @@ xfs_vm_direct_IO( { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; - bhv_vnode_t *vp = vn_from_inode(inode); xfs_iomap_t iomap; int maps = 1; int error; ssize_t ret; - error = bhv_vop_bmap(vp, offset, 0, BMAPI_DEVICE, &iomap, &maps); + error = xfs_bmap(XFS_I(inode), offset, 0, + BMAPI_DEVICE, &iomap, &maps); if (error) return -error; @@ -1513,13 +1503,18 @@ xfs_vm_direct_IO( } STATIC int -xfs_vm_prepare_write( +xfs_vm_write_begin( struct file *file, - struct page *page, - unsigned int from, - unsigned int to) + struct address_space *mapping, + loff_t pos, + unsigned len, + unsigned flags, + struct page **pagep, + void **fsdata) { - return block_prepare_write(page, from, to, xfs_get_blocks); + *pagep = NULL; + return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + xfs_get_blocks); } STATIC sector_t @@ -1528,12 +1523,13 @@ xfs_vm_bmap( sector_t block) { struct inode *inode = (struct inode *)mapping->host; - bhv_vnode_t *vp = vn_from_inode(inode); + struct xfs_inode *ip = XFS_I(inode); - vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); - bhv_vop_rwlock(vp, VRWLOCK_READ); - bhv_vop_flush_pages(vp, (xfs_off_t)0, -1, 0, FI_REMAPF); - bhv_vop_rwunlock(vp, VRWLOCK_READ); + vn_trace_entry(XFS_I(inode), __FUNCTION__, + (inst_t *)__return_address); + xfs_rwlock(ip, VRWLOCK_READ); + xfs_flush_pages(ip, (xfs_off_t)0, -1, 0, FI_REMAPF); + xfs_rwunlock(ip, VRWLOCK_READ); return generic_block_bmap(mapping, block, xfs_get_blocks); } @@ -1573,8 +1569,8 @@ const struct address_space_operations xfs_address_space_operations = { .sync_page = block_sync_page, .releasepage = xfs_vm_releasepage, .invalidatepage = xfs_vm_invalidatepage, - .prepare_write = xfs_vm_prepare_write, - .commit_write = generic_commit_write, + .write_begin = xfs_vm_write_begin, + .write_end = generic_write_end, .bmap = xfs_vm_bmap, .direct_IO = xfs_vm_direct_IO, .migratepage = buffer_migrate_page, diff --git a/fs/xfs/linux-2.6/xfs_aops.h b/fs/xfs/linux-2.6/xfs_aops.h index 2244e516b66a..3ba0631a3818 100644 --- a/fs/xfs/linux-2.6/xfs_aops.h +++ b/fs/xfs/linux-2.6/xfs_aops.h @@ -32,7 +32,7 @@ typedef struct xfs_ioend { unsigned int io_type; /* delalloc / unwritten */ int io_error; /* I/O error code */ atomic_t io_remaining; /* hold count */ - struct bhv_vnode *io_vnode; /* file being written to */ + struct inode *io_inode; /* file being written to */ struct buffer_head *io_buffer_head;/* buffer linked list head */ struct buffer_head *io_buffer_tail;/* buffer linked list tail */ size_t io_size; /* size of the extent */ diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index b0f0e58866de..b9c8589e05c2 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -187,6 +187,19 @@ free_address( { a_list_t *aentry; +#ifdef CONFIG_XEN + /* + * Xen needs to be able to make sure it can get an exclusive + * RO mapping of pages it wants to turn into a pagetable. If + * a newly allocated page is also still being vmap()ed by xfs, + * it will cause pagetable construction to fail. This is a + * quick workaround to always eagerly unmap pages so that Xen + * is happy. + */ + vunmap(addr); + return; +#endif + aentry = kmalloc(sizeof(a_list_t), GFP_NOWAIT); if (likely(aentry)) { spin_lock(&as_lock); @@ -997,7 +1010,18 @@ xfs_buf_iodone_work( xfs_buf_t *bp = container_of(work, xfs_buf_t, b_iodone_work); - if (bp->b_iodone) + /* + * We can get an EOPNOTSUPP to ordered writes. Here we clear the + * ordered flag and reissue them. Because we can't tell the higher + * layers directly that they should not issue ordered I/O anymore, they + * need to check if the ordered flag was cleared during I/O completion. + */ + if ((bp->b_error == EOPNOTSUPP) && + (bp->b_flags & (XBF_ORDERED|XBF_ASYNC)) == (XBF_ORDERED|XBF_ASYNC)) { + XB_TRACE(bp, "ordered_retry", bp->b_iodone); + bp->b_flags &= ~XBF_ORDERED; + xfs_buf_iorequest(bp); + } else if (bp->b_iodone) (*(bp->b_iodone))(bp); else if (bp->b_flags & XBF_ASYNC) xfs_buf_relse(bp); @@ -1103,19 +1127,15 @@ _xfs_buf_ioend( } } -STATIC int +STATIC void xfs_buf_bio_end_io( struct bio *bio, - unsigned int bytes_done, int error) { xfs_buf_t *bp = (xfs_buf_t *)bio->bi_private; unsigned int blocksize = bp->b_target->bt_bsize; struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; - if (bio->bi_size) - return 1; - if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) bp->b_error = EIO; @@ -1143,7 +1163,6 @@ xfs_buf_bio_end_io( _xfs_buf_ioend(bp, 1); bio_put(bio); - return 0; } STATIC void diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c index e3a5fedac1ba..3586c7a28d2c 100644 --- a/fs/xfs/linux-2.6/xfs_export.c +++ b/fs/xfs/linux-2.6/xfs_export.c @@ -17,12 +17,18 @@ */ #include "xfs.h" #include "xfs_types.h" -#include "xfs_dmapi.h" +#include "xfs_inum.h" #include "xfs_log.h" #include "xfs_trans.h" #include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dmapi.h" #include "xfs_mount.h" #include "xfs_export.h" +#include "xfs_vnodeops.h" +#include "xfs_bmap_btree.h" +#include "xfs_inode.h" +#include "xfs_vfsops.h" static struct dentry dotdot = { .d_name.name = "..", .d_name.len = 2, }; @@ -48,8 +54,8 @@ xfs_fs_decode_fh( struct dentry *de), void *context) { - xfs_fid2_t ifid; - xfs_fid2_t pfid; + xfs_fid_t ifid; + xfs_fid_t pfid; void *parent = NULL; int is64 = 0; __u32 *p = fh; @@ -96,9 +102,7 @@ xfs_fs_encode_fh( int len; int is64 = 0; #if XFS_BIG_INUMS - bhv_vfs_t *vfs = vfs_from_sb(inode->i_sb); - - if (!(vfs->vfs_flag & VFS_32BITINODES)) { + if (!(XFS_M(inode->i_sb)->m_flags & XFS_MOUNT_SMALL_INUMS)) { /* filesystem may contain 64bit inode numbers */ is64 = XFS_FILEID_TYPE_64FLAG; } @@ -138,10 +142,9 @@ xfs_fs_get_dentry( bhv_vnode_t *vp; struct inode *inode; struct dentry *result; - bhv_vfs_t *vfsp = vfs_from_sb(sb); int error; - error = bhv_vfs_vget(vfsp, &vp, (fid_t *)data); + error = xfs_vget(XFS_M(sb), &vp, data); if (error || vp == NULL) return ERR_PTR(-ESTALE) ; @@ -159,12 +162,11 @@ xfs_fs_get_parent( struct dentry *child) { int error; - bhv_vnode_t *vp, *cvp; + bhv_vnode_t *cvp; struct dentry *parent; cvp = NULL; - vp = vn_from_inode(child->d_inode); - error = bhv_vop_lookup(vp, &dotdot, &cvp, 0, NULL, NULL); + error = xfs_lookup(XFS_I(child->d_inode), &dotdot, &cvp); if (unlikely(error)) return ERR_PTR(-error); diff --git a/fs/xfs/linux-2.6/xfs_export.h b/fs/xfs/linux-2.6/xfs_export.h index e794ca4efc76..2f36071a86f7 100644 --- a/fs/xfs/linux-2.6/xfs_export.h +++ b/fs/xfs/linux-2.6/xfs_export.h @@ -71,13 +71,13 @@ xfs_fileid_length(int hasparent, int is64) /* * Decode encoded inode information (either for the inode itself - * or the parent) into an xfs_fid2_t structure. Advances and + * or the parent) into an xfs_fid_t structure. Advances and * returns the new data pointer */ static inline __u32 * -xfs_fileid_decode_fid2(__u32 *p, xfs_fid2_t *fid, int is64) +xfs_fileid_decode_fid2(__u32 *p, xfs_fid_t *fid, int is64) { - fid->fid_len = sizeof(xfs_fid2_t) - sizeof(fid->fid_len); + fid->fid_len = sizeof(xfs_fid_t) - sizeof(fid->fid_len); fid->fid_pad = 0; fid->fid_ino = *p++; #if XFS_BIG_INUMS diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index 0d4001eafd16..fb8dd34041eb 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c @@ -37,6 +37,7 @@ #include "xfs_error.h" #include "xfs_rw.h" #include "xfs_ioctl32.h" +#include "xfs_vnodeops.h" #include <linux/dcache.h> #include <linux/smp_lock.h> @@ -55,13 +56,12 @@ __xfs_file_read( loff_t pos) { struct file *file = iocb->ki_filp; - bhv_vnode_t *vp = vn_from_inode(file->f_path.dentry->d_inode); BUG_ON(iocb->ki_pos != pos); if (unlikely(file->f_flags & O_DIRECT)) ioflags |= IO_ISDIRECT; - return bhv_vop_read(vp, iocb, iov, nr_segs, &iocb->ki_pos, - ioflags, NULL); + return xfs_read(XFS_I(file->f_path.dentry->d_inode), iocb, iov, + nr_segs, &iocb->ki_pos, ioflags); } STATIC ssize_t @@ -93,14 +93,12 @@ __xfs_file_write( loff_t pos) { struct file *file = iocb->ki_filp; - struct inode *inode = file->f_mapping->host; - bhv_vnode_t *vp = vn_from_inode(inode); BUG_ON(iocb->ki_pos != pos); if (unlikely(file->f_flags & O_DIRECT)) ioflags |= IO_ISDIRECT; - return bhv_vop_write(vp, iocb, iov, nr_segs, &iocb->ki_pos, - ioflags, NULL); + return xfs_write(XFS_I(file->f_mapping->host), iocb, iov, nr_segs, + &iocb->ki_pos, ioflags); } STATIC ssize_t @@ -131,8 +129,8 @@ xfs_file_splice_read( size_t len, unsigned int flags) { - return bhv_vop_splice_read(vn_from_inode(infilp->f_path.dentry->d_inode), - infilp, ppos, pipe, len, flags, 0, NULL); + return xfs_splice_read(XFS_I(infilp->f_path.dentry->d_inode), + infilp, ppos, pipe, len, flags, 0); } STATIC ssize_t @@ -143,9 +141,8 @@ xfs_file_splice_read_invis( size_t len, unsigned int flags) { - return bhv_vop_splice_read(vn_from_inode(infilp->f_path.dentry->d_inode), - infilp, ppos, pipe, len, flags, IO_INVIS, - NULL); + return xfs_splice_read(XFS_I(infilp->f_path.dentry->d_inode), + infilp, ppos, pipe, len, flags, IO_INVIS); } STATIC ssize_t @@ -156,8 +153,8 @@ xfs_file_splice_write( size_t len, unsigned int flags) { - return bhv_vop_splice_write(vn_from_inode(outfilp->f_path.dentry->d_inode), - pipe, outfilp, ppos, len, flags, 0, NULL); + return xfs_splice_write(XFS_I(outfilp->f_path.dentry->d_inode), + pipe, outfilp, ppos, len, flags, 0); } STATIC ssize_t @@ -168,9 +165,8 @@ xfs_file_splice_write_invis( size_t len, unsigned int flags) { - return bhv_vop_splice_write(vn_from_inode(outfilp->f_path.dentry->d_inode), - pipe, outfilp, ppos, len, flags, IO_INVIS, - NULL); + return xfs_splice_write(XFS_I(outfilp->f_path.dentry->d_inode), + pipe, outfilp, ppos, len, flags, IO_INVIS); } STATIC int @@ -180,7 +176,7 @@ xfs_file_open( { if (!(filp->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS) return -EFBIG; - return -bhv_vop_open(vn_from_inode(inode), NULL); + return -xfs_open(XFS_I(inode)); } STATIC int @@ -188,11 +184,7 @@ xfs_file_release( struct inode *inode, struct file *filp) { - bhv_vnode_t *vp = vn_from_inode(inode); - - if (vp) - return -bhv_vop_release(vp); - return 0; + return -xfs_release(XFS_I(inode)); } STATIC int @@ -201,14 +193,13 @@ xfs_file_fsync( struct dentry *dentry, int datasync) { - bhv_vnode_t *vp = vn_from_inode(dentry->d_inode); int flags = FSYNC_WAIT; if (datasync) flags |= FSYNC_DATA; - if (VN_TRUNC(vp)) - VUNTRUNCATE(vp); - return -bhv_vop_fsync(vp, flags, NULL, (xfs_off_t)0, (xfs_off_t)-1); + xfs_iflags_clear(XFS_I(dentry->d_inode), XFS_ITRUNCATED); + return -xfs_fsync(XFS_I(dentry->d_inode), flags, + (xfs_off_t)0, (xfs_off_t)-1); } #ifdef CONFIG_XFS_DMAPI @@ -233,74 +224,30 @@ xfs_file_readdir( void *dirent, filldir_t filldir) { - int error = 0; - bhv_vnode_t *vp = vn_from_inode(filp->f_path.dentry->d_inode); - uio_t uio; - iovec_t iov; - int eof = 0; - caddr_t read_buf; - int namelen, size = 0; - size_t rlen = PAGE_CACHE_SIZE; - xfs_off_t start_offset, curr_offset; - xfs_dirent_t *dbp = NULL; - - /* Try fairly hard to get memory */ - do { - if ((read_buf = kmalloc(rlen, GFP_KERNEL))) - break; - rlen >>= 1; - } while (rlen >= 1024); - - if (read_buf == NULL) - return -ENOMEM; - - uio.uio_iov = &iov; - uio.uio_segflg = UIO_SYSSPACE; - curr_offset = filp->f_pos; - if (filp->f_pos != 0x7fffffff) - uio.uio_offset = filp->f_pos; - else - uio.uio_offset = 0xffffffff; - - while (!eof) { - uio.uio_resid = iov.iov_len = rlen; - iov.iov_base = read_buf; - uio.uio_iovcnt = 1; - - start_offset = uio.uio_offset; - - error = bhv_vop_readdir(vp, &uio, NULL, &eof); - if ((uio.uio_offset == start_offset) || error) { - size = 0; - break; - } - - size = rlen - uio.uio_resid; - dbp = (xfs_dirent_t *)read_buf; - while (size > 0) { - namelen = strlen(dbp->d_name); - - if (filldir(dirent, dbp->d_name, namelen, - (loff_t) curr_offset & 0x7fffffff, - (ino_t) dbp->d_ino, - DT_UNKNOWN)) { - goto done; - } - size -= dbp->d_reclen; - curr_offset = (loff_t)dbp->d_off /* & 0x7fffffff */; - dbp = (xfs_dirent_t *)((char *)dbp + dbp->d_reclen); - } - } -done: - if (!error) { - if (size == 0) - filp->f_pos = uio.uio_offset & 0x7fffffff; - else if (dbp) - filp->f_pos = curr_offset; - } + struct inode *inode = filp->f_path.dentry->d_inode; + xfs_inode_t *ip = XFS_I(inode); + int error; + size_t bufsize; + + /* + * The Linux API doesn't pass down the total size of the buffer + * we read into down to the filesystem. With the filldir concept + * it's not needed for correct information, but the XFS dir2 leaf + * code wants an estimate of the buffer size to calculate it's + * readahead window and size the buffers used for mapping to + * physical blocks. + * + * Try to give it an estimate that's good enough, maybe at some + * point we can change the ->readdir prototype to include the + * buffer size. + */ + bufsize = (size_t)min_t(loff_t, PAGE_SIZE, inode->i_size); - kfree(read_buf); - return -error; + error = xfs_readdir(ip, dirent, bufsize, + (xfs_off_t *)&filp->f_pos, filldir); + if (error) + return -error; + return 0; } STATIC int @@ -312,7 +259,7 @@ xfs_file_mmap( vma->vm_flags |= VM_CAN_NONLINEAR; #ifdef CONFIG_XFS_DMAPI - if (vn_from_inode(filp->f_path.dentry->d_inode)->v_vfsp->vfs_flag & VFS_DMI) + if (XFS_M(filp->f_path.dentry->d_inode->i_sb)->m_flags & XFS_MOUNT_DMAPI) vma->vm_ops = &xfs_dmapi_file_vm_ops; #endif /* CONFIG_XFS_DMAPI */ @@ -328,10 +275,9 @@ xfs_file_ioctl( { int error; struct inode *inode = filp->f_path.dentry->d_inode; - bhv_vnode_t *vp = vn_from_inode(inode); - error = bhv_vop_ioctl(vp, inode, filp, 0, cmd, (void __user *)p); - VMODIFY(vp); + error = xfs_ioctl(XFS_I(inode), filp, 0, cmd, (void __user *)p); + xfs_iflags_set(XFS_I(inode), XFS_IMODIFIED); /* NOTE: some of the ioctl's return positive #'s as a * byte count indicating success, such as @@ -350,10 +296,9 @@ xfs_file_ioctl_invis( { int error; struct inode *inode = filp->f_path.dentry->d_inode; - bhv_vnode_t *vp = vn_from_inode(inode); - error = bhv_vop_ioctl(vp, inode, filp, IO_INVIS, cmd, (void __user *)p); - VMODIFY(vp); + error = xfs_ioctl(XFS_I(inode), filp, IO_INVIS, cmd, (void __user *)p); + xfs_iflags_set(XFS_I(inode), XFS_IMODIFIED); /* NOTE: some of the ioctl's return positive #'s as a * byte count indicating success, such as @@ -371,16 +316,14 @@ xfs_vm_mprotect( struct vm_area_struct *vma, unsigned int newflags) { - bhv_vnode_t *vp = vn_from_inode(vma->vm_file->f_path.dentry->d_inode); + struct inode *inode = vma->vm_file->f_path.dentry->d_inode; + struct xfs_mount *mp = XFS_M(inode->i_sb); int error = 0; - if (vp->v_vfsp->vfs_flag & VFS_DMI) { + if (mp->m_flags & XFS_MOUNT_DMAPI) { if ((vma->vm_flags & VM_MAYSHARE) && - (newflags & VM_WRITE) && !(vma->vm_flags & VM_WRITE)) { - xfs_mount_t *mp = XFS_VFSTOM(vp->v_vfsp); - + (newflags & VM_WRITE) && !(vma->vm_flags & VM_WRITE)) error = XFS_SEND_MMAP(mp, vma, VM_WRITE); - } } return error; } @@ -397,18 +340,17 @@ STATIC int xfs_file_open_exec( struct inode *inode) { - bhv_vnode_t *vp = vn_from_inode(inode); + struct xfs_mount *mp = XFS_M(inode->i_sb); - if (unlikely(vp->v_vfsp->vfs_flag & VFS_DMI)) { - xfs_mount_t *mp = XFS_VFSTOM(vp->v_vfsp); - xfs_inode_t *ip = xfs_vtoi(vp); + if (unlikely(mp->m_flags & XFS_MOUNT_DMAPI)) { + if (DM_EVENT_ENABLED(XFS_I(inode), DM_EVENT_READ)) { + bhv_vnode_t *vp = vn_from_inode(inode); - if (!ip) - return -EINVAL; - if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ)) - return -XFS_SEND_DATA(mp, DM_EVENT_READ, vp, - 0, 0, 0, NULL); + return -XFS_SEND_DATA(mp, DM_EVENT_READ, + vp, 0, 0, 0, NULL); + } } + return 0; } #endif /* HAVE_FOP_OPEN_EXEC */ diff --git a/fs/xfs/linux-2.6/xfs_fs_subr.c b/fs/xfs/linux-2.6/xfs_fs_subr.c index 2eb87cd082af..ac6d34cc355d 100644 --- a/fs/xfs/linux-2.6/xfs_fs_subr.c +++ b/fs/xfs/linux-2.6/xfs_fs_subr.c @@ -16,66 +16,78 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "xfs.h" +#include "xfs_vnodeops.h" + +/* + * The following six includes are needed so that we can include + * xfs_inode.h. What a mess.. + */ +#include "xfs_bmap_btree.h" +#include "xfs_inum.h" +#include "xfs_dir2.h" +#include "xfs_dir2_sf.h" +#include "xfs_attr_sf.h" +#include "xfs_dinode.h" + +#include "xfs_inode.h" int fs_noerr(void) { return 0; } int fs_nosys(void) { return ENOSYS; } void fs_noval(void) { return; } void -fs_tosspages( - bhv_desc_t *bdp, +xfs_tosspages( + xfs_inode_t *ip, xfs_off_t first, xfs_off_t last, int fiopt) { - bhv_vnode_t *vp = BHV_TO_VNODE(bdp); - struct inode *ip = vn_to_inode(vp); + bhv_vnode_t *vp = XFS_ITOV(ip); + struct inode *inode = vn_to_inode(vp); if (VN_CACHED(vp)) - truncate_inode_pages(ip->i_mapping, first); + truncate_inode_pages(inode->i_mapping, first); } int -fs_flushinval_pages( - bhv_desc_t *bdp, +xfs_flushinval_pages( + xfs_inode_t *ip, xfs_off_t first, xfs_off_t last, int fiopt) { - bhv_vnode_t *vp = BHV_TO_VNODE(bdp); - struct inode *ip = vn_to_inode(vp); + bhv_vnode_t *vp = XFS_ITOV(ip); + struct inode *inode = vn_to_inode(vp); int ret = 0; if (VN_CACHED(vp)) { - if (VN_TRUNC(vp)) - VUNTRUNCATE(vp); - ret = filemap_write_and_wait(ip->i_mapping); + xfs_iflags_clear(ip, XFS_ITRUNCATED); + ret = filemap_write_and_wait(inode->i_mapping); if (!ret) - truncate_inode_pages(ip->i_mapping, first); + truncate_inode_pages(inode->i_mapping, first); } return ret; } int -fs_flush_pages( - bhv_desc_t *bdp, +xfs_flush_pages( + xfs_inode_t *ip, xfs_off_t first, xfs_off_t last, uint64_t flags, int fiopt) { - bhv_vnode_t *vp = BHV_TO_VNODE(bdp); - struct inode *ip = vn_to_inode(vp); + bhv_vnode_t *vp = XFS_ITOV(ip); + struct inode *inode = vn_to_inode(vp); int ret = 0; int ret2; if (VN_DIRTY(vp)) { - if (VN_TRUNC(vp)) - VUNTRUNCATE(vp); - ret = filemap_fdatawrite(ip->i_mapping); + xfs_iflags_clear(ip, XFS_ITRUNCATED); + ret = filemap_fdatawrite(inode->i_mapping); if (flags & XFS_B_ASYNC) return ret; - ret2 = filemap_fdatawait(ip->i_mapping); + ret2 = filemap_fdatawait(inode->i_mapping); if (!ret) ret = ret2; } diff --git a/fs/xfs/linux-2.6/xfs_fs_subr.h b/fs/xfs/linux-2.6/xfs_fs_subr.h index c1b53118a303..82bb19b2599e 100644 --- a/fs/xfs/linux-2.6/xfs_fs_subr.h +++ b/fs/xfs/linux-2.6/xfs_fs_subr.h @@ -18,12 +18,8 @@ #ifndef __XFS_FS_SUBR_H__ #define __XFS_FS_SUBR_H__ -struct cred; extern int fs_noerr(void); extern int fs_nosys(void); extern void fs_noval(void); -extern void fs_tosspages(bhv_desc_t *, xfs_off_t, xfs_off_t, int); -extern int fs_flushinval_pages(bhv_desc_t *, xfs_off_t, xfs_off_t, int); -extern int fs_flush_pages(bhv_desc_t *, xfs_off_t, xfs_off_t, uint64_t, int); #endif /* __XFS_FS_SUBR_H__ */ diff --git a/fs/xfs/linux-2.6/xfs_globals.c b/fs/xfs/linux-2.6/xfs_globals.c index 81565dea9af7..9febf9dc999d 100644 --- a/fs/xfs/linux-2.6/xfs_globals.c +++ b/fs/xfs/linux-2.6/xfs_globals.c @@ -20,11 +20,6 @@ #include "xfs_sysctl.h" /* - * System memory size - used to scale certain data structures in XFS. - */ -unsigned long xfs_physmem; - -/* * Tunable XFS parameters. xfs_params is required even when CONFIG_SYSCTL=n, * other XFS code uses these values. Times are measured in centisecs (i.e. * 100ths of a second). diff --git a/fs/xfs/linux-2.6/xfs_globals.h b/fs/xfs/linux-2.6/xfs_globals.h index e1a22bfcf865..2770b0085ee8 100644 --- a/fs/xfs/linux-2.6/xfs_globals.h +++ b/fs/xfs/linux-2.6/xfs_globals.h @@ -19,7 +19,6 @@ #define __XFS_GLOBALS_H__ extern uint64_t xfs_panic_mask; /* set to cause more panics */ -extern unsigned long xfs_physmem; extern struct cred *sys_cred; #endif /* __XFS_GLOBALS_H__ */ diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index 5917808abbd6..2b34bad48b07 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c @@ -47,6 +47,7 @@ #include "xfs_utils.h" #include "xfs_dfrag.h" #include "xfs_fsops.h" +#include "xfs_vnodeops.h" #include <linux/capability.h> #include <linux/dcache.h> @@ -137,7 +138,8 @@ xfs_find_handle( vp = vn_from_inode(inode); /* now we can grab the fsid */ - memcpy(&handle.ha_fsid, vp->v_vfsp->vfs_altfsid, sizeof(xfs_fsid_t)); + memcpy(&handle.ha_fsid, XFS_I(inode)->i_mount->m_fixedfsid, + sizeof(xfs_fsid_t)); hsize = sizeof(xfs_fsid_t); if (cmd != XFS_IOC_PATH_TO_FSHANDLE) { @@ -150,11 +152,11 @@ xfs_find_handle( lock_mode = xfs_ilock_map_shared(ip); /* fill in fid section of handle from inode */ - handle.ha_fid.xfs_fid_len = sizeof(xfs_fid_t) - - sizeof(handle.ha_fid.xfs_fid_len); - handle.ha_fid.xfs_fid_pad = 0; - handle.ha_fid.xfs_fid_gen = ip->i_d.di_gen; - handle.ha_fid.xfs_fid_ino = ip->i_ino; + handle.ha_fid.fid_len = sizeof(xfs_fid_t) - + sizeof(handle.ha_fid.fid_len); + handle.ha_fid.fid_pad = 0; + handle.ha_fid.fid_gen = ip->i_d.di_gen; + handle.ha_fid.fid_ino = ip->i_ino; xfs_iunlock_map_shared(ip, lock_mode); @@ -220,10 +222,10 @@ xfs_vget_fsop_handlereq( if (hlen < sizeof(*handlep)) memset(((char *)handlep) + hlen, 0, sizeof(*handlep) - hlen); if (hlen > sizeof(handlep->ha_fsid)) { - if (handlep->ha_fid.xfs_fid_len != - (hlen - sizeof(handlep->ha_fsid) - - sizeof(handlep->ha_fid.xfs_fid_len)) - || handlep->ha_fid.xfs_fid_pad) + if (handlep->ha_fid.fid_len != + (hlen - sizeof(handlep->ha_fsid) - + sizeof(handlep->ha_fid.fid_len)) || + handlep->ha_fid.fid_pad) return XFS_ERROR(EINVAL); } @@ -231,9 +233,9 @@ xfs_vget_fsop_handlereq( * Crack the handle, obtain the inode # & generation # */ xfid = (struct xfs_fid *)&handlep->ha_fid; - if (xfid->xfs_fid_len == sizeof(*xfid) - sizeof(xfid->xfs_fid_len)) { - ino = xfid->xfs_fid_ino; - igen = xfid->xfs_fid_gen; + if (xfid->fid_len == sizeof(*xfid) - sizeof(xfid->fid_len)) { + ino = xfid->fid_ino; + igen = xfid->fid_gen; } else { return XFS_ERROR(EINVAL); } @@ -349,19 +351,44 @@ xfs_open_by_handle( return new_fd; } +/* + * This is a copy from fs/namei.c:vfs_readlink(), except for removing it's + * unused first argument. + */ +STATIC int +do_readlink( + char __user *buffer, + int buflen, + const char *link) +{ + int len; + + len = PTR_ERR(link); + if (IS_ERR(link)) + goto out; + + len = strlen(link); + if (len > (unsigned) buflen) + len = buflen; + if (copy_to_user(buffer, link, len)) + len = -EFAULT; + out: + return len; +} + + STATIC int xfs_readlink_by_handle( xfs_mount_t *mp, void __user *arg, struct inode *parinode) { - int error; - struct iovec aiov; - struct uio auio; struct inode *inode; xfs_fsop_handlereq_t hreq; bhv_vnode_t *vp; __u32 olen; + void *link; + int error; if (!capable(CAP_SYS_ADMIN)) return -XFS_ERROR(EPERM); @@ -374,29 +401,31 @@ xfs_readlink_by_handle( /* Restrict this handle operation to symlinks only. */ if (!S_ISLNK(inode->i_mode)) { - VN_RELE(vp); - return -XFS_ERROR(EINVAL); + error = -XFS_ERROR(EINVAL); + goto out_iput; } if (copy_from_user(&olen, hreq.ohandlen, sizeof(__u32))) { - VN_RELE(vp); - return -XFS_ERROR(EFAULT); + error = -XFS_ERROR(EFAULT); + goto out_iput; } - aiov.iov_len = olen; - aiov.iov_base = hreq.ohandle; - auio.uio_iov = (struct kvec *)&aiov; - auio.uio_iovcnt = 1; - auio.uio_offset = 0; - auio.uio_segflg = UIO_USERSPACE; - auio.uio_resid = olen; + link = kmalloc(MAXPATHLEN+1, GFP_KERNEL); + if (!link) + goto out_iput; - error = bhv_vop_readlink(vp, &auio, IO_INVIS, NULL); - VN_RELE(vp); + error = -xfs_readlink(XFS_I(inode), link); if (error) - return -error; + goto out_kfree; + error = do_readlink(hreq.ohandle, olen, link); + if (error) + goto out_kfree; - return (olen - auio.uio_resid); + out_kfree: + kfree(link); + out_iput: + iput(inode); + return error; } STATIC int @@ -409,7 +438,6 @@ xfs_fssetdm_by_handle( struct fsdmidata fsd; xfs_fsop_setdm_handlereq_t dmhreq; struct inode *inode; - bhv_desc_t *bdp; bhv_vnode_t *vp; if (!capable(CAP_MKNOD)) @@ -431,8 +459,8 @@ xfs_fssetdm_by_handle( return -XFS_ERROR(EFAULT); } - bdp = bhv_base_unlocked(VN_BHV_HEAD(vp)); - error = xfs_set_dmattrs(bdp, fsd.fsd_dmevmask, fsd.fsd_dmstate, NULL); + error = xfs_set_dmattrs(xfs_vtoi(vp), + fsd.fsd_dmevmask, fsd.fsd_dmstate); VN_RELE(vp); if (error) @@ -470,8 +498,8 @@ xfs_attrlist_by_handle( goto out_vn_rele; cursor = (attrlist_cursor_kern_t *)&al_hreq.pos; - error = bhv_vop_attr_list(vp, kbuf, al_hreq.buflen, al_hreq.flags, - cursor, NULL); + error = xfs_attr_list(XFS_I(inode), kbuf, al_hreq.buflen, + al_hreq.flags, cursor); if (error) goto out_kfree; @@ -488,7 +516,7 @@ xfs_attrlist_by_handle( STATIC int xfs_attrmulti_attr_get( - bhv_vnode_t *vp, + struct inode *inode, char *name, char __user *ubuf, __uint32_t *len, @@ -503,7 +531,7 @@ xfs_attrmulti_attr_get( if (!kbuf) return ENOMEM; - error = bhv_vop_attr_get(vp, name, kbuf, len, flags, NULL); + error = xfs_attr_get(XFS_I(inode), name, kbuf, len, flags, NULL); if (error) goto out_kfree; @@ -517,7 +545,7 @@ xfs_attrmulti_attr_get( STATIC int xfs_attrmulti_attr_set( - bhv_vnode_t *vp, + struct inode *inode, char *name, const char __user *ubuf, __uint32_t len, @@ -526,9 +554,9 @@ xfs_attrmulti_attr_set( char *kbuf; int error = EFAULT; - if (IS_RDONLY(&vp->v_inode)) + if (IS_RDONLY(inode)) return -EROFS; - if (IS_IMMUTABLE(&vp->v_inode) || IS_APPEND(&vp->v_inode)) + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) return EPERM; if (len > XATTR_SIZE_MAX) return EINVAL; @@ -540,7 +568,7 @@ xfs_attrmulti_attr_set( if (copy_from_user(kbuf, ubuf, len)) goto out_kfree; - error = bhv_vop_attr_set(vp, name, kbuf, len, flags, NULL); + error = xfs_attr_set(XFS_I(inode), name, kbuf, len, flags); out_kfree: kfree(kbuf); @@ -549,15 +577,15 @@ xfs_attrmulti_attr_set( STATIC int xfs_attrmulti_attr_remove( - bhv_vnode_t *vp, + struct inode *inode, char *name, __uint32_t flags) { - if (IS_RDONLY(&vp->v_inode)) + if (IS_RDONLY(inode)) return -EROFS; - if (IS_IMMUTABLE(&vp->v_inode) || IS_APPEND(&vp->v_inode)) + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) return EPERM; - return bhv_vop_attr_remove(vp, name, flags, NULL); + return xfs_attr_remove(XFS_I(inode), name, flags); } STATIC int @@ -613,17 +641,17 @@ xfs_attrmulti_by_handle( switch (ops[i].am_opcode) { case ATTR_OP_GET: - ops[i].am_error = xfs_attrmulti_attr_get(vp, + ops[i].am_error = xfs_attrmulti_attr_get(inode, attr_name, ops[i].am_attrvalue, &ops[i].am_length, ops[i].am_flags); break; case ATTR_OP_SET: - ops[i].am_error = xfs_attrmulti_attr_set(vp, + ops[i].am_error = xfs_attrmulti_attr_set(inode, attr_name, ops[i].am_attrvalue, ops[i].am_length, ops[i].am_flags); break; case ATTR_OP_REMOVE: - ops[i].am_error = xfs_attrmulti_attr_remove(vp, + ops[i].am_error = xfs_attrmulti_attr_remove(inode, attr_name, ops[i].am_flags); break; default: @@ -649,7 +677,7 @@ xfs_attrmulti_by_handle( STATIC int xfs_ioc_space( - bhv_desc_t *bdp, + struct xfs_inode *ip, struct inode *inode, struct file *filp, int flags, @@ -681,37 +709,37 @@ xfs_ioc_xattr( void __user *arg); STATIC int +xfs_ioc_fsgetxattr( + xfs_inode_t *ip, + int attr, + void __user *arg); + +STATIC int xfs_ioc_getbmap( - bhv_desc_t *bdp, + struct xfs_inode *ip, int flags, unsigned int cmd, void __user *arg); STATIC int xfs_ioc_getbmapx( - bhv_desc_t *bdp, + struct xfs_inode *ip, void __user *arg); int xfs_ioctl( - bhv_desc_t *bdp, - struct inode *inode, + xfs_inode_t *ip, struct file *filp, int ioflags, unsigned int cmd, void __user *arg) { + struct inode *inode = filp->f_path.dentry->d_inode; + bhv_vnode_t *vp = vn_from_inode(inode); + xfs_mount_t *mp = ip->i_mount; int error; - bhv_vnode_t *vp; - xfs_inode_t *ip; - xfs_mount_t *mp; - vp = vn_from_inode(inode); - - vn_trace_entry(vp, "xfs_ioctl", (inst_t *)__return_address); - - ip = XFS_BHVTOI(bdp); - mp = ip->i_mount; + vn_trace_entry(XFS_I(inode), "xfs_ioctl", (inst_t *)__return_address); switch (cmd) { @@ -731,7 +759,7 @@ xfs_ioctl( !capable(CAP_SYS_ADMIN)) return -EPERM; - return xfs_ioc_space(bdp, inode, filp, ioflags, cmd, arg); + return xfs_ioc_space(ip, inode, filp, ioflags, cmd, arg); case XFS_IOC_DIOINFO: { struct dioattr da; @@ -761,11 +789,13 @@ xfs_ioctl( case XFS_IOC_GETVERSION: return put_user(inode->i_generation, (int __user *)arg); + case XFS_IOC_FSGETXATTR: + return xfs_ioc_fsgetxattr(ip, 0, arg); + case XFS_IOC_FSGETXATTRA: + return xfs_ioc_fsgetxattr(ip, 1, arg); case XFS_IOC_GETXFLAGS: case XFS_IOC_SETXFLAGS: - case XFS_IOC_FSGETXATTR: case XFS_IOC_FSSETXATTR: - case XFS_IOC_FSGETXATTRA: return xfs_ioc_xattr(vp, ip, filp, cmd, arg); case XFS_IOC_FSSETDM: { @@ -774,17 +804,17 @@ xfs_ioctl( if (copy_from_user(&dmi, arg, sizeof(dmi))) return -XFS_ERROR(EFAULT); - error = xfs_set_dmattrs(bdp, dmi.fsd_dmevmask, dmi.fsd_dmstate, - NULL); + error = xfs_set_dmattrs(ip, dmi.fsd_dmevmask, + dmi.fsd_dmstate); return -error; } case XFS_IOC_GETBMAP: case XFS_IOC_GETBMAPA: - return xfs_ioc_getbmap(bdp, ioflags, cmd, arg); + return xfs_ioc_getbmap(ip, ioflags, cmd, arg); case XFS_IOC_GETBMAPX: - return xfs_ioc_getbmapx(bdp, arg); + return xfs_ioc_getbmapx(ip, arg); case XFS_IOC_FD_TO_HANDLE: case XFS_IOC_PATH_TO_HANDLE: @@ -944,7 +974,7 @@ xfs_ioctl( if (!capable(CAP_SYS_ADMIN)) return -EPERM; - error = xfs_errortag_clearall(mp); + error = xfs_errortag_clearall(mp, 1); return -error; default: @@ -954,7 +984,7 @@ xfs_ioctl( STATIC int xfs_ioc_space( - bhv_desc_t *bdp, + struct xfs_inode *ip, struct inode *inode, struct file *filp, int ioflags, @@ -982,7 +1012,7 @@ xfs_ioc_space( if (ioflags & IO_INVIS) attr_flags |= ATTR_DMI; - error = xfs_change_file_space(bdp, cmd, &bf, filp->f_pos, + error = xfs_change_file_space(ip, cmd, &bf, filp->f_pos, NULL, attr_flags); return -error; } @@ -1140,6 +1170,42 @@ xfs_di2lxflags( } STATIC int +xfs_ioc_fsgetxattr( + xfs_inode_t *ip, + int attr, + void __user *arg) +{ + struct fsxattr fa; + + xfs_ilock(ip, XFS_ILOCK_SHARED); + fa.fsx_xflags = xfs_ip2xflags(ip); + fa.fsx_extsize = ip->i_d.di_extsize << ip->i_mount->m_sb.sb_blocklog; + fa.fsx_projid = ip->i_d.di_projid; + + if (attr) { + if (ip->i_afp) { + if (ip->i_afp->if_flags & XFS_IFEXTENTS) + fa.fsx_nextents = ip->i_afp->if_bytes / + sizeof(xfs_bmbt_rec_t); + else + fa.fsx_nextents = ip->i_d.di_anextents; + } else + fa.fsx_nextents = 0; + } else { + if (ip->i_df.if_flags & XFS_IFEXTENTS) + fa.fsx_nextents = ip->i_df.if_bytes / + sizeof(xfs_bmbt_rec_t); + else + fa.fsx_nextents = ip->i_d.di_nextents; + } + xfs_iunlock(ip, XFS_ILOCK_SHARED); + + if (copy_to_user(arg, &fa, sizeof(fa))) + return -EFAULT; + return 0; +} + +STATIC int xfs_ioc_xattr( bhv_vnode_t *vp, xfs_inode_t *ip, @@ -1158,27 +1224,6 @@ xfs_ioc_xattr( return -ENOMEM; switch (cmd) { - case XFS_IOC_FSGETXATTR: { - vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \ - XFS_AT_NEXTENTS | XFS_AT_PROJID; - error = bhv_vop_getattr(vp, vattr, 0, NULL); - if (unlikely(error)) { - error = -error; - break; - } - - fa.fsx_xflags = vattr->va_xflags; - fa.fsx_extsize = vattr->va_extsize; - fa.fsx_nextents = vattr->va_nextents; - fa.fsx_projid = vattr->va_projid; - - if (copy_to_user(arg, &fa, sizeof(fa))) { - error = -EFAULT; - break; - } - break; - } - case XFS_IOC_FSSETXATTR: { if (copy_from_user(&fa, arg, sizeof(fa))) { error = -EFAULT; @@ -1194,34 +1239,13 @@ xfs_ioc_xattr( vattr->va_extsize = fa.fsx_extsize; vattr->va_projid = fa.fsx_projid; - error = bhv_vop_setattr(vp, vattr, attr_flags, NULL); + error = xfs_setattr(ip, vattr, attr_flags, NULL); if (likely(!error)) __vn_revalidate(vp, vattr); /* update flags */ error = -error; break; } - case XFS_IOC_FSGETXATTRA: { - vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \ - XFS_AT_ANEXTENTS | XFS_AT_PROJID; - error = bhv_vop_getattr(vp, vattr, 0, NULL); - if (unlikely(error)) { - error = -error; - break; - } - - fa.fsx_xflags = vattr->va_xflags; - fa.fsx_extsize = vattr->va_extsize; - fa.fsx_nextents = vattr->va_anextents; - fa.fsx_projid = vattr->va_projid; - - if (copy_to_user(arg, &fa, sizeof(fa))) { - error = -EFAULT; - break; - } - break; - } - case XFS_IOC_GETXFLAGS: { flags = xfs_di2lxflags(ip->i_d.di_flags); if (copy_to_user(arg, &flags, sizeof(flags))) @@ -1250,7 +1274,7 @@ xfs_ioc_xattr( vattr->va_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip)); - error = bhv_vop_setattr(vp, vattr, attr_flags, NULL); + error = xfs_setattr(ip, vattr, attr_flags, NULL); if (likely(!error)) __vn_revalidate(vp, vattr); /* update flags */ error = -error; @@ -1268,7 +1292,7 @@ xfs_ioc_xattr( STATIC int xfs_ioc_getbmap( - bhv_desc_t *bdp, + struct xfs_inode *ip, int ioflags, unsigned int cmd, void __user *arg) @@ -1287,7 +1311,7 @@ xfs_ioc_getbmap( if (ioflags & IO_INVIS) iflags |= BMV_IF_NO_DMAPI_READ; - error = xfs_getbmap(bdp, &bm, (struct getbmap __user *)arg+1, iflags); + error = xfs_getbmap(ip, &bm, (struct getbmap __user *)arg+1, iflags); if (error) return -error; @@ -1298,7 +1322,7 @@ xfs_ioc_getbmap( STATIC int xfs_ioc_getbmapx( - bhv_desc_t *bdp, + struct xfs_inode *ip, void __user *arg) { struct getbmapx bmx; @@ -1325,7 +1349,7 @@ xfs_ioc_getbmapx( iflags |= BMV_IF_EXTENDED; - error = xfs_getbmap(bdp, &bm, (struct getbmapx __user *)arg+1, iflags); + error = xfs_getbmap(ip, &bm, (struct getbmapx __user *)arg+1, iflags); if (error) return -error; diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c index 42319d75aaab..0046bdd5b7f1 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl32.c +++ b/fs/xfs/linux-2.6/xfs_ioctl32.c @@ -43,6 +43,7 @@ #include "xfs_itable.h" #include "xfs_error.h" #include "xfs_dfrag.h" +#include "xfs_vnodeops.h" #define _NATIVE_IOC(cmd, type) \ _IOC(_IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), sizeof(type)) @@ -370,7 +371,6 @@ xfs_compat_ioctl( unsigned long arg) { struct inode *inode = file->f_path.dentry->d_inode; - bhv_vnode_t *vp = vn_from_inode(inode); int error; switch (cmd) { @@ -443,7 +443,7 @@ xfs_compat_ioctl( case XFS_IOC_FSBULKSTAT_SINGLE_32: case XFS_IOC_FSINUMBERS_32: cmd = _NATIVE_IOC(cmd, struct xfs_fsop_bulkreq); - return xfs_ioc_bulkstat_compat(XFS_BHVTOI(VNHEAD(vp))->i_mount, + return xfs_ioc_bulkstat_compat(XFS_I(inode)->i_mount, cmd, (void __user*)arg); case XFS_IOC_FD_TO_HANDLE_32: case XFS_IOC_PATH_TO_HANDLE_32: @@ -457,8 +457,8 @@ xfs_compat_ioctl( return -ENOIOCTLCMD; } - error = bhv_vop_ioctl(vp, inode, file, mode, cmd, (void __user *)arg); - VMODIFY(vp); + error = xfs_ioctl(XFS_I(inode), file, mode, cmd, (void __user *)arg); + xfs_iflags_set(XFS_I(inode), XFS_IMODIFIED); return error; } diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 0b5fa124bef2..ac50f8a37582 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -46,6 +46,7 @@ #include "xfs_attr.h" #include "xfs_buf_item.h" #include "xfs_utils.h" +#include "xfs_vnodeops.h" #include <linux/capability.h> #include <linux/xattr.h> @@ -53,22 +54,6 @@ #include <linux/security.h> /* - * Get a XFS inode from a given vnode. - */ -xfs_inode_t * -xfs_vtoi( - bhv_vnode_t *vp) -{ - bhv_desc_t *bdp; - - bdp = bhv_lookup_range(VN_BHV_HEAD(vp), - VNODE_POSITION_XFS, VNODE_POSITION_XFS); - if (unlikely(bdp == NULL)) - return NULL; - return XFS_BHVTOI(bdp); -} - -/* * Bring the atime in the XFS inode uptodate. * Used before logging the inode to disk or when the Linux inode goes away. */ @@ -80,9 +65,8 @@ xfs_synchronize_atime( vp = XFS_ITOV_NULL(ip); if (vp) { - struct inode *inode = &vp->v_inode; - ip->i_d.di_atime.t_sec = (__int32_t)inode->i_atime.tv_sec; - ip->i_d.di_atime.t_nsec = (__int32_t)inode->i_atime.tv_nsec; + ip->i_d.di_atime.t_sec = (__int32_t)vp->i_atime.tv_sec; + ip->i_d.di_atime.t_nsec = (__int32_t)vp->i_atime.tv_nsec; } } @@ -133,7 +117,7 @@ xfs_ichgtime( */ SYNCHRONIZE(); ip->i_update_core = 1; - if (!(inode->i_state & I_LOCK)) + if (!(inode->i_state & I_SYNC)) mark_inode_dirty_sync(inode); } @@ -185,7 +169,7 @@ xfs_ichgtime_fast( */ SYNCHRONIZE(); ip->i_update_core = 1; - if (!(inode->i_state & I_LOCK)) + if (!(inode->i_state & I_SYNC)) mark_inode_dirty_sync(inode); } @@ -195,18 +179,19 @@ xfs_ichgtime_fast( */ STATIC void xfs_validate_fields( - struct inode *ip, - bhv_vattr_t *vattr) + struct inode *inode) { - vattr->va_mask = XFS_AT_NLINK|XFS_AT_SIZE|XFS_AT_NBLOCKS; - if (!bhv_vop_getattr(vn_from_inode(ip), vattr, ATTR_LAZY, NULL)) { - ip->i_nlink = vattr->va_nlink; - ip->i_blocks = vattr->va_nblocks; - - /* we're under i_sem so i_size can't change under us */ - if (i_size_read(ip) != vattr->va_size) - i_size_write(ip, vattr->va_size); - } + struct xfs_inode *ip = XFS_I(inode); + loff_t size; + + inode->i_nlink = ip->i_d.di_nlink; + inode->i_blocks = + XFS_FSB_TO_BB(ip->i_mount, ip->i_d.di_nblocks + + ip->i_delayed_blks); + /* we're under i_sem so i_size can't change under us */ + size = XFS_ISIZE(ip); + if (i_size_read(inode) != size) + i_size_write(inode, size); } /* @@ -233,9 +218,10 @@ xfs_init_security( return -error; } - error = bhv_vop_attr_set(vp, name, value, length, ATTR_SECURE, NULL); + error = xfs_attr_set(XFS_I(ip), name, value, + length, ATTR_SECURE); if (!error) - VMODIFY(vp); + xfs_iflags_set(XFS_I(ip), XFS_IMODIFIED); kfree(name); kfree(value); @@ -256,7 +242,7 @@ xfs_has_fs_struct(struct task_struct *task) STATIC void xfs_cleanup_inode( - bhv_vnode_t *dvp, + struct inode *dir, bhv_vnode_t *vp, struct dentry *dentry, int mode) @@ -272,9 +258,9 @@ xfs_cleanup_inode( teardown.d_name = dentry->d_name; if (S_ISDIR(mode)) - bhv_vop_rmdir(dvp, &teardown, NULL); + xfs_rmdir(XFS_I(dir), &teardown); else - bhv_vop_remove(dvp, &teardown, NULL); + xfs_remove(XFS_I(dir), &teardown); VN_RELE(vp); } @@ -286,7 +272,6 @@ xfs_vn_mknod( dev_t rdev) { struct inode *ip; - bhv_vattr_t vattr = { 0 }; bhv_vnode_t *vp = NULL, *dvp = vn_from_inode(dir); xfs_acl_t *default_acl = NULL; attrexists_t test_default_acl = _ACL_DEFAULT_EXISTS; @@ -312,19 +297,14 @@ xfs_vn_mknod( if (IS_POSIXACL(dir) && !default_acl && xfs_has_fs_struct(current)) mode &= ~current->fs->umask; - vattr.va_mask = XFS_AT_TYPE|XFS_AT_MODE; - vattr.va_mode = mode; - switch (mode & S_IFMT) { case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK: - vattr.va_rdev = sysv_encode_dev(rdev); - vattr.va_mask |= XFS_AT_RDEV; - /*FALLTHROUGH*/ + rdev = sysv_encode_dev(rdev); case S_IFREG: - error = bhv_vop_create(dvp, dentry, &vattr, &vp, NULL); + error = xfs_create(XFS_I(dir), dentry, mode, rdev, &vp, NULL); break; case S_IFDIR: - error = bhv_vop_mkdir(dvp, dentry, &vattr, &vp, NULL); + error = xfs_mkdir(XFS_I(dir), dentry, mode, &vp, NULL); break; default: error = EINVAL; @@ -334,16 +314,16 @@ xfs_vn_mknod( if (unlikely(!error)) { error = xfs_init_security(vp, dir); if (error) - xfs_cleanup_inode(dvp, vp, dentry, mode); + xfs_cleanup_inode(dir, vp, dentry, mode); } if (unlikely(default_acl)) { if (!error) { - error = _ACL_INHERIT(vp, &vattr, default_acl); + error = _ACL_INHERIT(vp, mode, default_acl); if (!error) - VMODIFY(vp); + xfs_iflags_set(XFS_I(vp), XFS_IMODIFIED); else - xfs_cleanup_inode(dvp, vp, dentry, mode); + xfs_cleanup_inode(dir, vp, dentry, mode); } _ACL_FREE(default_acl); } @@ -355,9 +335,9 @@ xfs_vn_mknod( if (S_ISCHR(mode) || S_ISBLK(mode)) ip->i_rdev = rdev; else if (S_ISDIR(mode)) - xfs_validate_fields(ip, &vattr); + xfs_validate_fields(ip); d_instantiate(dentry, ip); - xfs_validate_fields(dir, &vattr); + xfs_validate_fields(dir); } return -error; } @@ -387,13 +367,13 @@ xfs_vn_lookup( struct dentry *dentry, struct nameidata *nd) { - bhv_vnode_t *vp = vn_from_inode(dir), *cvp; + bhv_vnode_t *cvp; int error; if (dentry->d_name.len >= MAXNAMELEN) return ERR_PTR(-ENAMETOOLONG); - error = bhv_vop_lookup(vp, dentry, &cvp, 0, NULL, NULL); + error = xfs_lookup(XFS_I(dir), dentry, &cvp); if (unlikely(error)) { if (unlikely(error != ENOENT)) return ERR_PTR(-error); @@ -411,22 +391,19 @@ xfs_vn_link( struct dentry *dentry) { struct inode *ip; /* inode of guy being linked to */ - bhv_vnode_t *tdvp; /* target directory for new name/link */ bhv_vnode_t *vp; /* vp of name being linked */ - bhv_vattr_t vattr; int error; ip = old_dentry->d_inode; /* inode being linked to */ - tdvp = vn_from_inode(dir); vp = vn_from_inode(ip); VN_HOLD(vp); - error = bhv_vop_link(tdvp, vp, dentry, NULL); + error = xfs_link(XFS_I(dir), vp, dentry); if (unlikely(error)) { VN_RELE(vp); } else { - VMODIFY(tdvp); - xfs_validate_fields(ip, &vattr); + xfs_iflags_set(XFS_I(dir), XFS_IMODIFIED); + xfs_validate_fields(ip); d_instantiate(dentry, ip); } return -error; @@ -438,17 +415,14 @@ xfs_vn_unlink( struct dentry *dentry) { struct inode *inode; - bhv_vnode_t *dvp; /* directory containing name to remove */ - bhv_vattr_t vattr; int error; inode = dentry->d_inode; - dvp = vn_from_inode(dir); - error = bhv_vop_remove(dvp, dentry, NULL); + error = xfs_remove(XFS_I(dir), dentry); if (likely(!error)) { - xfs_validate_fields(dir, &vattr); /* size needs update */ - xfs_validate_fields(inode, &vattr); + xfs_validate_fields(dir); /* size needs update */ + xfs_validate_fields(inode); } return -error; } @@ -460,28 +434,26 @@ xfs_vn_symlink( const char *symname) { struct inode *ip; - bhv_vattr_t va = { 0 }; - bhv_vnode_t *dvp; /* directory containing name of symlink */ bhv_vnode_t *cvp; /* used to lookup symlink to put in dentry */ int error; + mode_t mode; - dvp = vn_from_inode(dir); cvp = NULL; - va.va_mode = S_IFLNK | + mode = S_IFLNK | (irix_symlink_mode ? 0777 & ~current->fs->umask : S_IRWXUGO); - va.va_mask = XFS_AT_TYPE|XFS_AT_MODE; - error = bhv_vop_symlink(dvp, dentry, &va, (char *)symname, &cvp, NULL); + error = xfs_symlink(XFS_I(dir), dentry, (char *)symname, mode, + &cvp, NULL); if (likely(!error && cvp)) { error = xfs_init_security(cvp, dir); if (likely(!error)) { ip = vn_to_inode(cvp); d_instantiate(dentry, ip); - xfs_validate_fields(dir, &va); - xfs_validate_fields(ip, &va); + xfs_validate_fields(dir); + xfs_validate_fields(ip); } else { - xfs_cleanup_inode(dvp, cvp, dentry, 0); + xfs_cleanup_inode(dir, cvp, dentry, 0); } } return -error; @@ -493,14 +465,12 @@ xfs_vn_rmdir( struct dentry *dentry) { struct inode *inode = dentry->d_inode; - bhv_vnode_t *dvp = vn_from_inode(dir); - bhv_vattr_t vattr; int error; - error = bhv_vop_rmdir(dvp, dentry, NULL); + error = xfs_rmdir(XFS_I(dir), dentry); if (likely(!error)) { - xfs_validate_fields(inode, &vattr); - xfs_validate_fields(dir, &vattr); + xfs_validate_fields(inode); + xfs_validate_fields(dir); } return -error; } @@ -513,21 +483,18 @@ xfs_vn_rename( struct dentry *ndentry) { struct inode *new_inode = ndentry->d_inode; - bhv_vnode_t *fvp; /* from directory */ bhv_vnode_t *tvp; /* target directory */ - bhv_vattr_t vattr; int error; - fvp = vn_from_inode(odir); tvp = vn_from_inode(ndir); - error = bhv_vop_rename(fvp, odentry, tvp, ndentry, NULL); + error = xfs_rename(XFS_I(odir), odentry, tvp, ndentry); if (likely(!error)) { if (new_inode) - xfs_validate_fields(new_inode, &vattr); - xfs_validate_fields(odir, &vattr); + xfs_validate_fields(new_inode); + xfs_validate_fields(odir); if (ndir != odir) - xfs_validate_fields(ndir, &vattr); + xfs_validate_fields(ndir); } return -error; } @@ -542,50 +509,25 @@ xfs_vn_follow_link( struct dentry *dentry, struct nameidata *nd) { - bhv_vnode_t *vp; - uio_t *uio; - iovec_t iov; - int error; char *link; - - ASSERT(dentry); - ASSERT(nd); + int error = -ENOMEM; link = kmalloc(MAXPATHLEN+1, GFP_KERNEL); - if (!link) { - nd_set_link(nd, ERR_PTR(-ENOMEM)); - return NULL; - } - - uio = kmalloc(sizeof(uio_t), GFP_KERNEL); - if (!uio) { - kfree(link); - nd_set_link(nd, ERR_PTR(-ENOMEM)); - return NULL; - } - - vp = vn_from_inode(dentry->d_inode); - - iov.iov_base = link; - iov.iov_len = MAXPATHLEN; + if (!link) + goto out_err; - uio->uio_iov = &iov; - uio->uio_offset = 0; - uio->uio_segflg = UIO_SYSSPACE; - uio->uio_resid = MAXPATHLEN; - uio->uio_iovcnt = 1; - - error = bhv_vop_readlink(vp, uio, 0, NULL); - if (unlikely(error)) { - kfree(link); - link = ERR_PTR(-error); - } else { - link[MAXPATHLEN - uio->uio_resid] = '\0'; - } - kfree(uio); + error = -xfs_readlink(XFS_I(dentry->d_inode), link); + if (unlikely(error)) + goto out_kfree; nd_set_link(nd, link); return NULL; + + out_kfree: + kfree(link); + out_err: + nd_set_link(nd, ERR_PTR(error)); + return NULL; } STATIC void @@ -607,7 +549,7 @@ xfs_vn_permission( int mode, struct nameidata *nd) { - return -bhv_vop_access(vn_from_inode(inode), mode << 6, NULL); + return -xfs_access(XFS_I(inode), mode << 6, NULL); } #else #define xfs_vn_permission NULL @@ -620,11 +562,10 @@ xfs_vn_getattr( struct kstat *stat) { struct inode *inode = dentry->d_inode; - bhv_vnode_t *vp = vn_from_inode(inode); bhv_vattr_t vattr = { .va_mask = XFS_AT_STAT }; int error; - error = bhv_vop_getattr(vp, &vattr, ATTR_LAZY, NULL); + error = xfs_getattr(XFS_I(inode), &vattr, ATTR_LAZY); if (likely(!error)) { stat->size = i_size_read(inode); stat->dev = inode->i_sb->s_dev; @@ -652,7 +593,6 @@ xfs_vn_setattr( { struct inode *inode = dentry->d_inode; unsigned int ia_valid = attr->ia_valid; - bhv_vnode_t *vp = vn_from_inode(inode); bhv_vattr_t vattr = { 0 }; int flags = 0; int error; @@ -696,9 +636,9 @@ xfs_vn_setattr( flags |= ATTR_NONBLOCK; #endif - error = bhv_vop_setattr(vp, &vattr, flags, NULL); + error = xfs_setattr(XFS_I(inode), &vattr, flags, NULL); if (likely(!error)) - __vn_revalidate(vp, &vattr); + __vn_revalidate(vn_from_inode(inode), &vattr); return -error; } diff --git a/fs/xfs/linux-2.6/xfs_iops.h b/fs/xfs/linux-2.6/xfs_iops.h index 95a69398fce0..14d0deb7afff 100644 --- a/fs/xfs/linux-2.6/xfs_iops.h +++ b/fs/xfs/linux-2.6/xfs_iops.h @@ -26,11 +26,15 @@ extern const struct file_operations xfs_file_operations; extern const struct file_operations xfs_dir_file_operations; extern const struct file_operations xfs_invis_file_operations; -extern int xfs_ioctl(struct bhv_desc *, struct inode *, struct file *, - int, unsigned int, void __user *); struct xfs_inode; extern void xfs_ichgtime(struct xfs_inode *, int); extern void xfs_ichgtime_fast(struct xfs_inode *, struct inode *, int); +#define xfs_vtoi(vp) \ + ((struct xfs_inode *)vn_to_inode(vp)->i_private) + +#define XFS_I(inode) \ + ((struct xfs_inode *)(inode)->i_private) + #endif /* __XFS_IOPS_H__ */ diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h index 330c4ba9d404..dc3752de22da 100644 --- a/fs/xfs/linux-2.6/xfs_linux.h +++ b/fs/xfs/linux-2.6/xfs_linux.h @@ -51,7 +51,6 @@ #include <support/ktrace.h> #include <support/debug.h> -#include <support/move.h> #include <support/uuid.h> #include <linux/mm.h> @@ -75,6 +74,7 @@ #include <linux/cpu.h> #include <linux/notifier.h> #include <linux/delay.h> +#include <linux/log2.h> #include <asm/page.h> #include <asm/div64.h> @@ -83,7 +83,6 @@ #include <asm/byteorder.h> #include <asm/unaligned.h> -#include <xfs_behavior.h> #include <xfs_vfs.h> #include <xfs_cred.h> #include <xfs_vnode.h> diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c index 765ec16a6e39..d6a8dddb2268 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.c +++ b/fs/xfs/linux-2.6/xfs_lrw.c @@ -48,6 +48,7 @@ #include "xfs_buf_item.h" #include "xfs_utils.h" #include "xfs_iomap.h" +#include "xfs_vnodeops.h" #include <linux/capability.h> #include <linux/writeback.h> @@ -134,45 +135,34 @@ xfs_iozero( loff_t pos, /* offset in file */ size_t count) /* size of data to zero */ { - unsigned bytes; struct page *page; struct address_space *mapping; int status; mapping = ip->i_mapping; do { - unsigned long index, offset; + unsigned offset, bytes; + void *fsdata; offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */ - index = pos >> PAGE_CACHE_SHIFT; bytes = PAGE_CACHE_SIZE - offset; if (bytes > count) bytes = count; - status = -ENOMEM; - page = grab_cache_page(mapping, index); - if (!page) - break; - - status = mapping->a_ops->prepare_write(NULL, page, offset, - offset + bytes); + status = pagecache_write_begin(NULL, mapping, pos, bytes, + AOP_FLAG_UNINTERRUPTIBLE, + &page, &fsdata); if (status) - goto unlock; + break; zero_user_page(page, offset, bytes, KM_USER0); - status = mapping->a_ops->commit_write(NULL, page, offset, - offset + bytes); - if (!status) { - pos += bytes; - count -= bytes; - } - -unlock: - unlock_page(page); - page_cache_release(page); - if (status) - break; + status = pagecache_write_end(NULL, mapping, pos, bytes, bytes, + page, fsdata); + WARN_ON(status <= 0); /* can't return less than zero! */ + pos += bytes; + count -= bytes; + status = 0; } while (count); return (-status); @@ -180,27 +170,22 @@ unlock: ssize_t /* bytes read, or (-) error */ xfs_read( - bhv_desc_t *bdp, + xfs_inode_t *ip, struct kiocb *iocb, const struct iovec *iovp, unsigned int segs, loff_t *offset, - int ioflags, - cred_t *credp) + int ioflags) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; + bhv_vnode_t *vp = XFS_ITOV(ip); + xfs_mount_t *mp = ip->i_mount; size_t size = 0; ssize_t ret = 0; xfs_fsize_t n; - xfs_inode_t *ip; - xfs_mount_t *mp; - bhv_vnode_t *vp; unsigned long seg; - ip = XFS_BHVTOI(bdp); - vp = BHV_TO_VNODE(bdp); - mp = ip->i_mount; XFS_STATS_INC(xs_read_calls); @@ -245,13 +230,11 @@ xfs_read( mutex_lock(&inode->i_mutex); xfs_ilock(ip, XFS_IOLOCK_SHARED); - if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) && - !(ioflags & IO_INVIS)) { + if (DM_EVENT_ENABLED(ip, DM_EVENT_READ) && !(ioflags & IO_INVIS)) { bhv_vrwlock_t locktype = VRWLOCK_READ; int dmflags = FILP_DELAY_FLAG(file) | DM_SEM_FLAG_RD(ioflags); - ret = -XFS_SEND_DATA(mp, DM_EVENT_READ, - BHV_TO_VNODE(bdp), *offset, size, + ret = -XFS_SEND_DATA(mp, DM_EVENT_READ, vp, *offset, size, dmflags, &locktype); if (ret) { xfs_iunlock(ip, XFS_IOLOCK_SHARED); @@ -263,8 +246,9 @@ xfs_read( if (unlikely(ioflags & IO_ISDIRECT)) { if (VN_CACHED(vp)) - ret = bhv_vop_flushinval_pages(vp, ctooff(offtoct(*offset)), - -1, FI_REMAPF_LOCKED); + ret = xfs_flushinval_pages(ip, + ctooff(offtoct(*offset)), + -1, FI_REMAPF_LOCKED); mutex_unlock(&inode->i_mutex); if (ret) { xfs_iunlock(ip, XFS_IOLOCK_SHARED); @@ -288,16 +272,15 @@ xfs_read( ssize_t xfs_splice_read( - bhv_desc_t *bdp, + xfs_inode_t *ip, struct file *infilp, loff_t *ppos, struct pipe_inode_info *pipe, size_t count, int flags, - int ioflags, - cred_t *credp) + int ioflags) { - xfs_inode_t *ip = XFS_BHVTOI(bdp); + bhv_vnode_t *vp = XFS_ITOV(ip); xfs_mount_t *mp = ip->i_mount; ssize_t ret; @@ -307,13 +290,11 @@ xfs_splice_read( xfs_ilock(ip, XFS_IOLOCK_SHARED); - if (DM_EVENT_ENABLED(BHV_TO_VNODE(bdp)->v_vfsp, ip, DM_EVENT_READ) && - (!(ioflags & IO_INVIS))) { + if (DM_EVENT_ENABLED(ip, DM_EVENT_READ) && !(ioflags & IO_INVIS)) { bhv_vrwlock_t locktype = VRWLOCK_READ; int error; - error = XFS_SEND_DATA(mp, DM_EVENT_READ, BHV_TO_VNODE(bdp), - *ppos, count, + error = XFS_SEND_DATA(mp, DM_EVENT_READ, vp, *ppos, count, FILP_DELAY_FLAG(infilp), &locktype); if (error) { xfs_iunlock(ip, XFS_IOLOCK_SHARED); @@ -332,16 +313,15 @@ xfs_splice_read( ssize_t xfs_splice_write( - bhv_desc_t *bdp, + xfs_inode_t *ip, struct pipe_inode_info *pipe, struct file *outfilp, loff_t *ppos, size_t count, int flags, - int ioflags, - cred_t *credp) + int ioflags) { - xfs_inode_t *ip = XFS_BHVTOI(bdp); + bhv_vnode_t *vp = XFS_ITOV(ip); xfs_mount_t *mp = ip->i_mount; xfs_iocore_t *io = &ip->i_iocore; ssize_t ret; @@ -354,13 +334,11 @@ xfs_splice_write( xfs_ilock(ip, XFS_IOLOCK_EXCL); - if (DM_EVENT_ENABLED(BHV_TO_VNODE(bdp)->v_vfsp, ip, DM_EVENT_WRITE) && - (!(ioflags & IO_INVIS))) { + if (DM_EVENT_ENABLED(ip, DM_EVENT_WRITE) && !(ioflags & IO_INVIS)) { bhv_vrwlock_t locktype = VRWLOCK_WRITE; int error; - error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, BHV_TO_VNODE(bdp), - *ppos, count, + error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, vp, *ppos, count, FILP_DELAY_FLAG(outfilp), &locktype); if (error) { xfs_iunlock(ip, XFS_IOLOCK_EXCL); @@ -594,24 +572,22 @@ out_lock: ssize_t /* bytes written, or (-) error */ xfs_write( - bhv_desc_t *bdp, + struct xfs_inode *xip, struct kiocb *iocb, const struct iovec *iovp, unsigned int nsegs, loff_t *offset, - int ioflags, - cred_t *credp) + int ioflags) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; struct inode *inode = mapping->host; + bhv_vnode_t *vp = XFS_ITOV(xip); unsigned long segs = nsegs; - xfs_inode_t *xip; xfs_mount_t *mp; ssize_t ret = 0, error = 0; xfs_fsize_t isize, new_size; xfs_iocore_t *io; - bhv_vnode_t *vp; int iolock; int eventsent = 0; bhv_vrwlock_t locktype; @@ -621,9 +597,6 @@ xfs_write( XFS_STATS_INC(xs_write_calls); - vp = BHV_TO_VNODE(bdp); - xip = XFS_BHVTOI(bdp); - error = generic_segment_checks(iovp, &segs, &ocount, VERIFY_READ); if (error) return error; @@ -637,7 +610,7 @@ xfs_write( io = &xip->i_iocore; mp = io->io_mount; - vfs_wait_for_freeze(vp->v_vfsp, SB_FREEZE_WRITE); + xfs_wait_for_freeze(mp, SB_FREEZE_WRITE); if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; @@ -664,7 +637,7 @@ start: goto out_unlock_mutex; } - if ((DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_WRITE) && + if ((DM_EVENT_ENABLED(xip, DM_EVENT_WRITE) && !(ioflags & IO_INVIS) && !eventsent)) { int dmflags = FILP_DELAY_FLAG(file); @@ -733,7 +706,7 @@ start: */ if (pos > xip->i_size) { - error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, pos, xip->i_size); + error = xfs_zero_eof(vp, io, pos, xip->i_size); if (error) { xfs_iunlock(xip, XFS_ILOCK_EXCL); goto out_unlock_internal; @@ -769,7 +742,8 @@ retry: WARN_ON(need_i_mutex == 0); xfs_inval_cached_trace(io, pos, -1, ctooff(offtoct(pos)), -1); - error = bhv_vop_flushinval_pages(vp, ctooff(offtoct(pos)), + error = xfs_flushinval_pages(xip, + ctooff(offtoct(pos)), -1, FI_REMAPF_LOCKED); if (error) goto out_unlock_internal; @@ -816,11 +790,9 @@ retry: if (ret == -EIOCBQUEUED && !(ioflags & IO_ISAIO)) ret = wait_on_sync_kiocb(iocb); - if ((ret == -ENOSPC) && - DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_NOSPACE) && - !(ioflags & IO_INVIS)) { - - xfs_rwunlock(bdp, locktype); + if (ret == -ENOSPC && + DM_EVENT_ENABLED(xip, DM_EVENT_NOSPACE) && !(ioflags & IO_INVIS)) { + xfs_rwunlock(xip, locktype); if (need_i_mutex) mutex_unlock(&inode->i_mutex); error = XFS_SEND_NAMESP(xip->i_mount, DM_EVENT_NOSPACE, vp, @@ -828,7 +800,7 @@ retry: 0, 0, 0); /* Delay flag intentionally unused */ if (need_i_mutex) mutex_lock(&inode->i_mutex); - xfs_rwlock(bdp, locktype); + xfs_rwlock(xip, locktype); if (error) goto out_unlock_internal; pos = xip->i_size; @@ -855,20 +827,19 @@ retry: /* Handle various SYNC-type writes */ if ((file->f_flags & O_SYNC) || IS_SYNC(inode)) { - error = xfs_write_sync_logforce(mp, xip); - if (error) - goto out_unlock_internal; - - xfs_rwunlock(bdp, locktype); + int error2; + xfs_rwunlock(xip, locktype); if (need_i_mutex) mutex_unlock(&inode->i_mutex); - - error = sync_page_range(inode, mapping, pos, ret); + error2 = sync_page_range(inode, mapping, pos, ret); if (!error) - error = -ret; + error = error2; if (need_i_mutex) mutex_lock(&inode->i_mutex); - xfs_rwlock(bdp, locktype); + xfs_rwlock(xip, locktype); + error2 = xfs_write_sync_logforce(mp, xip); + if (!error) + error = error2; } out_unlock_internal: @@ -886,7 +857,7 @@ retry: xip->i_d.di_size = xip->i_size; xfs_iunlock(xip, XFS_ILOCK_EXCL); } - xfs_rwunlock(bdp, locktype); + xfs_rwunlock(xip, locktype); out_unlock_mutex: if (need_i_mutex) mutex_unlock(&inode->i_mutex); @@ -925,14 +896,14 @@ xfs_bdstrat_cb(struct xfs_buf *bp) int -xfs_bmap(bhv_desc_t *bdp, +xfs_bmap( + xfs_inode_t *ip, xfs_off_t offset, ssize_t count, int flags, xfs_iomap_t *iomapp, int *niomaps) { - xfs_inode_t *ip = XFS_BHVTOI(bdp); xfs_iocore_t *io = &ip->i_iocore; ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFREG); diff --git a/fs/xfs/linux-2.6/xfs_lrw.h b/fs/xfs/linux-2.6/xfs_lrw.h index 7c60a1eed88b..4b7747a828d9 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.h +++ b/fs/xfs/linux-2.6/xfs_lrw.h @@ -18,8 +18,6 @@ #ifndef __XFS_LRW_H__ #define __XFS_LRW_H__ -struct bhv_desc; -struct bhv_vnode; struct xfs_mount; struct xfs_iocore; struct xfs_inode; @@ -71,30 +69,11 @@ extern void xfs_inval_cached_trace(struct xfs_iocore *, #define xfs_inval_cached_trace(io, offset, len, first, last) #endif -/* - * Maximum count of bmaps used by read and write paths. - */ -#define XFS_MAX_RW_NBMAPS 4 - -extern int xfs_bmap(struct bhv_desc *, xfs_off_t, ssize_t, int, - struct xfs_iomap *, int *); extern int xfsbdstrat(struct xfs_mount *, struct xfs_buf *); extern int xfs_bdstrat_cb(struct xfs_buf *); extern int xfs_dev_is_read_only(struct xfs_mount *, char *); -extern int xfs_zero_eof(struct bhv_vnode *, struct xfs_iocore *, xfs_off_t, +extern int xfs_zero_eof(struct inode *, struct xfs_iocore *, xfs_off_t, xfs_fsize_t); -extern ssize_t xfs_read(struct bhv_desc *, struct kiocb *, - const struct iovec *, unsigned int, - loff_t *, int, struct cred *); -extern ssize_t xfs_write(struct bhv_desc *, struct kiocb *, - const struct iovec *, unsigned int, - loff_t *, int, struct cred *); -extern ssize_t xfs_splice_read(struct bhv_desc *, struct file *, loff_t *, - struct pipe_inode_info *, size_t, int, int, - struct cred *); -extern ssize_t xfs_splice_write(struct bhv_desc *, struct pipe_inode_info *, - struct file *, loff_t *, size_t, int, int, - struct cred *); #endif /* __XFS_LRW_H__ */ diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 491d1f4f202d..8cb63c60c048 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -46,6 +46,8 @@ #include "xfs_attr.h" #include "xfs_buf_item.h" #include "xfs_utils.h" +#include "xfs_vnodeops.h" +#include "xfs_vfsops.h" #include "xfs_version.h" #include <linux/namei.h> @@ -196,23 +198,20 @@ xfs_revalidate_inode( inode->i_flags |= S_NOATIME; else inode->i_flags &= ~S_NOATIME; - vp->v_flag &= ~VMODIFIED; + xfs_iflags_clear(ip, XFS_IMODIFIED); } void xfs_initialize_vnode( - bhv_desc_t *bdp, + struct xfs_mount *mp, bhv_vnode_t *vp, - bhv_desc_t *inode_bhv, - int unlock) + struct xfs_inode *ip) { - xfs_inode_t *ip = XFS_BHVTOI(inode_bhv); struct inode *inode = vn_to_inode(vp); - if (!inode_bhv->bd_vobj) { - vp->v_vfsp = bhvtovfs(bdp); - bhv_desc_init(inode_bhv, ip, vp, &xfs_vnodeops); - bhv_insert(VN_BHV_HEAD(vp), inode_bhv); + if (!ip->i_vnode) { + ip->i_vnode = vp; + inode->i_private = ip; } /* @@ -222,8 +221,8 @@ xfs_initialize_vnode( * second time once the inode is properly set up, and then we can * finish our work. */ - if (ip->i_d.di_mode != 0 && unlock && (inode->i_state & I_NEW)) { - xfs_revalidate_inode(XFS_BHVTOM(bdp), vp, ip); + if (ip->i_d.di_mode != 0 && (inode->i_state & I_NEW)) { + xfs_revalidate_inode(mp, vp, ip); xfs_set_inodeops(inode); xfs_iflags_clear(ip, XFS_INEW); @@ -356,9 +355,8 @@ xfs_fs_destroy_inode( STATIC void xfs_fs_inode_init_once( - void *vnode, kmem_zone_t *zonep, - unsigned long flags) + void *vnode) { inode_init_once(vn_to_inode((bhv_vnode_t *)vnode)); } @@ -410,19 +408,22 @@ xfs_fs_write_inode( struct inode *inode, int sync) { - bhv_vnode_t *vp = vn_from_inode(inode); int error = 0, flags = FLUSH_INODE; - if (vp) { - vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); - if (sync) { - filemap_fdatawait(inode->i_mapping); - flags |= FLUSH_SYNC; - } - error = bhv_vop_iflush(vp, flags); - if (error == EAGAIN) - error = sync? bhv_vop_iflush(vp, flags | FLUSH_LOG) : 0; + vn_trace_entry(XFS_I(inode), __FUNCTION__, + (inst_t *)__return_address); + if (sync) { + filemap_fdatawait(inode->i_mapping); + flags |= FLUSH_SYNC; } + error = xfs_inode_flush(XFS_I(inode), flags); + /* + * if we failed to write out the inode then mark + * it dirty again so we'll try again later. + */ + if (error) + mark_inode_dirty_sync(inode); + return -error; } @@ -430,35 +431,27 @@ STATIC void xfs_fs_clear_inode( struct inode *inode) { - bhv_vnode_t *vp = vn_from_inode(inode); - - vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); - - XFS_STATS_INC(vn_rele); - XFS_STATS_INC(vn_remove); - XFS_STATS_INC(vn_reclaim); - XFS_STATS_DEC(vn_active); + xfs_inode_t *ip = XFS_I(inode); /* - * This can happen because xfs_iget_core calls xfs_idestroy if we + * ip can be null when xfs_iget_core calls xfs_idestroy if we * find an inode with di_mode == 0 but without IGET_CREATE set. */ - if (VNHEAD(vp)) - bhv_vop_inactive(vp, NULL); - - VN_LOCK(vp); - vp->v_flag &= ~VMODIFIED; - VN_UNLOCK(vp, 0); - - if (VNHEAD(vp)) - if (bhv_vop_reclaim(vp)) - panic("%s: cannot reclaim 0x%p\n", __FUNCTION__, vp); - - ASSERT(VNHEAD(vp) == NULL); + if (ip) { + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); + + XFS_STATS_INC(vn_rele); + XFS_STATS_INC(vn_remove); + XFS_STATS_INC(vn_reclaim); + XFS_STATS_DEC(vn_active); + + xfs_inactive(ip); + xfs_iflags_clear(ip, XFS_IMODIFIED); + if (xfs_reclaim(ip)) + panic("%s: cannot reclaim 0x%p\n", __FUNCTION__, inode); + } -#ifdef XFS_VNODE_TRACE - ktrace_free(vp->v_trace); -#endif + ASSERT(XFS_I(inode) == NULL); } /* @@ -470,9 +463,9 @@ xfs_fs_clear_inode( */ STATIC void xfs_syncd_queue_work( - struct bhv_vfs *vfs, + struct xfs_mount *mp, void *data, - void (*syncer)(bhv_vfs_t *, void *)) + void (*syncer)(struct xfs_mount *, void *)) { struct bhv_vfs_sync_work *work; @@ -480,11 +473,11 @@ xfs_syncd_queue_work( INIT_LIST_HEAD(&work->w_list); work->w_syncer = syncer; work->w_data = data; - work->w_vfs = vfs; - spin_lock(&vfs->vfs_sync_lock); - list_add_tail(&work->w_list, &vfs->vfs_sync_list); - spin_unlock(&vfs->vfs_sync_lock); - wake_up_process(vfs->vfs_sync_task); + work->w_mount = mp; + spin_lock(&mp->m_sync_lock); + list_add_tail(&work->w_list, &mp->m_sync_list); + spin_unlock(&mp->m_sync_lock); + wake_up_process(mp->m_sync_task); } /* @@ -495,22 +488,22 @@ xfs_syncd_queue_work( */ STATIC void xfs_flush_inode_work( - bhv_vfs_t *vfs, - void *inode) + struct xfs_mount *mp, + void *arg) { - filemap_flush(((struct inode *)inode)->i_mapping); - iput((struct inode *)inode); + struct inode *inode = arg; + filemap_flush(inode->i_mapping); + iput(inode); } void xfs_flush_inode( xfs_inode_t *ip) { - struct inode *inode = vn_to_inode(XFS_ITOV(ip)); - struct bhv_vfs *vfs = XFS_MTOVFS(ip->i_mount); + struct inode *inode = ip->i_vnode; igrab(inode); - xfs_syncd_queue_work(vfs, inode, xfs_flush_inode_work); + xfs_syncd_queue_work(ip->i_mount, inode, xfs_flush_inode_work); delay(msecs_to_jiffies(500)); } @@ -520,11 +513,12 @@ xfs_flush_inode( */ STATIC void xfs_flush_device_work( - bhv_vfs_t *vfs, - void *inode) + struct xfs_mount *mp, + void *arg) { - sync_blockdev(vfs->vfs_super->s_bdev); - iput((struct inode *)inode); + struct inode *inode = arg; + sync_blockdev(mp->m_super->s_bdev); + iput(inode); } void @@ -532,35 +526,33 @@ xfs_flush_device( xfs_inode_t *ip) { struct inode *inode = vn_to_inode(XFS_ITOV(ip)); - struct bhv_vfs *vfs = XFS_MTOVFS(ip->i_mount); igrab(inode); - xfs_syncd_queue_work(vfs, inode, xfs_flush_device_work); + xfs_syncd_queue_work(ip->i_mount, inode, xfs_flush_device_work); delay(msecs_to_jiffies(500)); xfs_log_force(ip->i_mount, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC); } STATIC void -vfs_sync_worker( - bhv_vfs_t *vfsp, +xfs_sync_worker( + struct xfs_mount *mp, void *unused) { int error; - if (!(vfsp->vfs_flag & VFS_RDONLY)) - error = bhv_vfs_sync(vfsp, SYNC_FSDATA | SYNC_BDFLUSH | \ - SYNC_ATTR | SYNC_REFCACHE | SYNC_SUPER, - NULL); - vfsp->vfs_sync_seq++; - wake_up(&vfsp->vfs_wait_single_sync_task); + if (!(mp->m_flags & XFS_MOUNT_RDONLY)) + error = xfs_sync(mp, SYNC_FSDATA | SYNC_BDFLUSH | SYNC_ATTR | + SYNC_REFCACHE | SYNC_SUPER); + mp->m_sync_seq++; + wake_up(&mp->m_wait_single_sync_task); } STATIC int xfssyncd( void *arg) { + struct xfs_mount *mp = arg; long timeleft; - bhv_vfs_t *vfsp = (bhv_vfs_t *) arg; bhv_vfs_sync_work_t *work, *n; LIST_HEAD (tmp); @@ -570,31 +562,31 @@ xfssyncd( timeleft = schedule_timeout_interruptible(timeleft); /* swsusp */ try_to_freeze(); - if (kthread_should_stop() && list_empty(&vfsp->vfs_sync_list)) + if (kthread_should_stop() && list_empty(&mp->m_sync_list)) break; - spin_lock(&vfsp->vfs_sync_lock); + spin_lock(&mp->m_sync_lock); /* * We can get woken by laptop mode, to do a sync - * that's the (only!) case where the list would be * empty with time remaining. */ - if (!timeleft || list_empty(&vfsp->vfs_sync_list)) { + if (!timeleft || list_empty(&mp->m_sync_list)) { if (!timeleft) timeleft = xfs_syncd_centisecs * msecs_to_jiffies(10); - INIT_LIST_HEAD(&vfsp->vfs_sync_work.w_list); - list_add_tail(&vfsp->vfs_sync_work.w_list, - &vfsp->vfs_sync_list); + INIT_LIST_HEAD(&mp->m_sync_work.w_list); + list_add_tail(&mp->m_sync_work.w_list, + &mp->m_sync_list); } - list_for_each_entry_safe(work, n, &vfsp->vfs_sync_list, w_list) + list_for_each_entry_safe(work, n, &mp->m_sync_list, w_list) list_move(&work->w_list, &tmp); - spin_unlock(&vfsp->vfs_sync_lock); + spin_unlock(&mp->m_sync_lock); list_for_each_entry_safe(work, n, &tmp, w_list) { - (*work->w_syncer)(vfsp, work->w_data); + (*work->w_syncer)(mp, work->w_data); list_del(&work->w_list); - if (work == &vfsp->vfs_sync_work) + if (work == &mp->m_sync_work) continue; kmem_free(work, sizeof(struct bhv_vfs_sync_work)); } @@ -603,41 +595,19 @@ xfssyncd( return 0; } -STATIC int -xfs_fs_start_syncd( - bhv_vfs_t *vfsp) -{ - vfsp->vfs_sync_work.w_syncer = vfs_sync_worker; - vfsp->vfs_sync_work.w_vfs = vfsp; - vfsp->vfs_sync_task = kthread_run(xfssyncd, vfsp, "xfssyncd"); - if (IS_ERR(vfsp->vfs_sync_task)) - return -PTR_ERR(vfsp->vfs_sync_task); - return 0; -} - -STATIC void -xfs_fs_stop_syncd( - bhv_vfs_t *vfsp) -{ - kthread_stop(vfsp->vfs_sync_task); -} - STATIC void xfs_fs_put_super( struct super_block *sb) { - bhv_vfs_t *vfsp = vfs_from_sb(sb); + struct xfs_mount *mp = XFS_M(sb); int error; - xfs_fs_stop_syncd(vfsp); - bhv_vfs_sync(vfsp, SYNC_ATTR | SYNC_DELWRI, NULL); - error = bhv_vfs_unmount(vfsp, 0, NULL); - if (error) { + kthread_stop(mp->m_sync_task); + + xfs_sync(mp, SYNC_ATTR | SYNC_DELWRI); + error = xfs_unmount(mp, 0, NULL); + if (error) printk("XFS: unmount got error=%d\n", error); - printk("%s: vfs=0x%p left dangling!\n", __FUNCTION__, vfsp); - } else { - vfs_deallocate(vfsp); - } } STATIC void @@ -645,7 +615,7 @@ xfs_fs_write_super( struct super_block *sb) { if (!(sb->s_flags & MS_RDONLY)) - bhv_vfs_sync(vfs_from_sb(sb), SYNC_FSDATA, NULL); + xfs_sync(XFS_M(sb), SYNC_FSDATA); sb->s_dirt = 0; } @@ -654,11 +624,23 @@ xfs_fs_sync_super( struct super_block *sb, int wait) { - bhv_vfs_t *vfsp = vfs_from_sb(sb); + struct xfs_mount *mp = XFS_M(sb); int error; int flags; - if (unlikely(sb->s_frozen == SB_FREEZE_WRITE)) { + /* + * Treat a sync operation like a freeze. This is to work + * around a race in sync_inodes() which works in two phases + * - an asynchronous flush, which can write out an inode + * without waiting for file size updates to complete, and a + * synchronous flush, which wont do anything because the + * async flush removed the inode's dirty flag. Also + * sync_inodes() will not see any files that just have + * outstanding transactions to be flushed because we don't + * dirty the Linux inode until after the transaction I/O + * completes. + */ + if (wait || unlikely(sb->s_frozen == SB_FREEZE_WRITE)) { /* * First stage of freeze - no more writers will make progress * now we are here, so we flush delwri and delalloc buffers @@ -669,28 +651,28 @@ xfs_fs_sync_super( */ flags = SYNC_DATA_QUIESCE; } else - flags = SYNC_FSDATA | (wait ? SYNC_WAIT : 0); + flags = SYNC_FSDATA; - error = bhv_vfs_sync(vfsp, flags, NULL); + error = xfs_sync(mp, flags); sb->s_dirt = 0; if (unlikely(laptop_mode)) { - int prev_sync_seq = vfsp->vfs_sync_seq; + int prev_sync_seq = mp->m_sync_seq; /* * The disk must be active because we're syncing. * We schedule xfssyncd now (now that the disk is * active) instead of later (when it might not be). */ - wake_up_process(vfsp->vfs_sync_task); + wake_up_process(mp->m_sync_task); /* * We have to wait for the sync iteration to complete. * If we don't, the disk activity caused by the sync * will come after the sync is completed, and that * triggers another sync from laptop mode. */ - wait_event(vfsp->vfs_wait_single_sync_task, - vfsp->vfs_sync_seq != prev_sync_seq); + wait_event(mp->m_wait_single_sync_task, + mp->m_sync_seq != prev_sync_seq); } return -error; @@ -701,7 +683,7 @@ xfs_fs_statfs( struct dentry *dentry, struct kstatfs *statp) { - return -bhv_vfs_statvfs(vfs_from_sb(dentry->d_sb), statp, + return -xfs_statvfs(XFS_M(dentry->d_sb), statp, vn_from_inode(dentry->d_inode)); } @@ -711,13 +693,13 @@ xfs_fs_remount( int *flags, char *options) { - bhv_vfs_t *vfsp = vfs_from_sb(sb); + struct xfs_mount *mp = XFS_M(sb); struct xfs_mount_args *args = xfs_args_allocate(sb, 0); int error; - error = bhv_vfs_parseargs(vfsp, options, args, 1); + error = xfs_parseargs(mp, options, args, 1); if (!error) - error = bhv_vfs_mntupdate(vfsp, flags, args); + error = xfs_mntupdate(mp, flags, args); kmem_free(args, sizeof(*args)); return -error; } @@ -726,7 +708,7 @@ STATIC void xfs_fs_lockfs( struct super_block *sb) { - bhv_vfs_freeze(vfs_from_sb(sb)); + xfs_freeze(XFS_M(sb)); } STATIC int @@ -734,7 +716,7 @@ xfs_fs_show_options( struct seq_file *m, struct vfsmount *mnt) { - return -bhv_vfs_showargs(vfs_from_sb(mnt->mnt_sb), m); + return -xfs_showargs(XFS_M(mnt->mnt_sb), m); } STATIC int @@ -742,7 +724,7 @@ xfs_fs_quotasync( struct super_block *sb, int type) { - return -bhv_vfs_quotactl(vfs_from_sb(sb), Q_XQUOTASYNC, 0, NULL); + return -XFS_QM_QUOTACTL(XFS_M(sb), Q_XQUOTASYNC, 0, NULL); } STATIC int @@ -750,7 +732,7 @@ xfs_fs_getxstate( struct super_block *sb, struct fs_quota_stat *fqs) { - return -bhv_vfs_quotactl(vfs_from_sb(sb), Q_XGETQSTAT, 0, (caddr_t)fqs); + return -XFS_QM_QUOTACTL(XFS_M(sb), Q_XGETQSTAT, 0, (caddr_t)fqs); } STATIC int @@ -759,7 +741,7 @@ xfs_fs_setxstate( unsigned int flags, int op) { - return -bhv_vfs_quotactl(vfs_from_sb(sb), op, 0, (caddr_t)&flags); + return -XFS_QM_QUOTACTL(XFS_M(sb), op, 0, (caddr_t)&flags); } STATIC int @@ -769,7 +751,7 @@ xfs_fs_getxquota( qid_t id, struct fs_disk_quota *fdq) { - return -bhv_vfs_quotactl(vfs_from_sb(sb), + return -XFS_QM_QUOTACTL(XFS_M(sb), (type == USRQUOTA) ? Q_XGETQUOTA : ((type == GRPQUOTA) ? Q_XGETGQUOTA : Q_XGETPQUOTA), id, (caddr_t)fdq); @@ -782,7 +764,7 @@ xfs_fs_setxquota( qid_t id, struct fs_disk_quota *fdq) { - return -bhv_vfs_quotactl(vfs_from_sb(sb), + return -XFS_QM_QUOTACTL(XFS_M(sb), (type == USRQUOTA) ? Q_XSETQLIM : ((type == GRPQUOTA) ? Q_XSETGQLIM : Q_XSETPQLIM), id, (caddr_t)fdq); @@ -794,32 +776,38 @@ xfs_fs_fill_super( void *data, int silent) { - struct bhv_vnode *rootvp; - struct bhv_vfs *vfsp = vfs_allocate(sb); + struct inode *rootvp; + struct xfs_mount *mp = NULL; struct xfs_mount_args *args = xfs_args_allocate(sb, silent); struct kstatfs statvfs; int error; - bhv_insert_all_vfsops(vfsp); + mp = xfs_mount_init(); - error = bhv_vfs_parseargs(vfsp, (char *)data, args, 0); - if (error) { - bhv_remove_all_vfsops(vfsp, 1); + INIT_LIST_HEAD(&mp->m_sync_list); + spin_lock_init(&mp->m_sync_lock); + init_waitqueue_head(&mp->m_wait_single_sync_task); + + mp->m_super = sb; + sb->s_fs_info = mp; + + if (sb->s_flags & MS_RDONLY) + mp->m_flags |= XFS_MOUNT_RDONLY; + + error = xfs_parseargs(mp, (char *)data, args, 0); + if (error) goto fail_vfsop; - } sb_min_blocksize(sb, BBSIZE); sb->s_export_op = &xfs_export_operations; sb->s_qcop = &xfs_quotactl_operations; sb->s_op = &xfs_super_operations; - error = bhv_vfs_mount(vfsp, args, NULL); - if (error) { - bhv_remove_all_vfsops(vfsp, 1); + error = xfs_mount(mp, args, NULL); + if (error) goto fail_vfsop; - } - error = bhv_vfs_statvfs(vfsp, &statvfs, NULL); + error = xfs_statvfs(mp, &statvfs, NULL); if (error) goto fail_unmount; @@ -831,7 +819,7 @@ xfs_fs_fill_super( sb->s_time_gran = 1; set_posix_acl_flag(sb); - error = bhv_vfs_root(vfsp, &rootvp); + error = xfs_root(mp, &rootvp); if (error) goto fail_unmount; @@ -844,9 +832,17 @@ xfs_fs_fill_super( error = EINVAL; goto fail_vnrele; } - if ((error = xfs_fs_start_syncd(vfsp))) + + mp->m_sync_work.w_syncer = xfs_sync_worker; + mp->m_sync_work.w_mount = mp; + mp->m_sync_task = kthread_run(xfssyncd, mp, "xfssyncd"); + if (IS_ERR(mp->m_sync_task)) { + error = -PTR_ERR(mp->m_sync_task); goto fail_vnrele; - vn_trace_exit(rootvp, __FUNCTION__, (inst_t *)__return_address); + } + + vn_trace_exit(XFS_I(sb->s_root->d_inode), __FUNCTION__, + (inst_t *)__return_address); kmem_free(args, sizeof(*args)); return 0; @@ -860,10 +856,9 @@ fail_vnrele: } fail_unmount: - bhv_vfs_unmount(vfsp, 0, NULL); + xfs_unmount(mp, 0, NULL); fail_vfsop: - vfs_deallocate(vfsp); kmem_free(args, sizeof(*args)); return -error; } @@ -915,15 +910,11 @@ STATIC int __init init_xfs_fs( void ) { int error; - struct sysinfo si; static char message[] __initdata = KERN_INFO \ XFS_VERSION_STRING " with " XFS_BUILD_OPTIONS " enabled\n"; printk(message); - si_meminfo(&si); - xfs_physmem = si.totalram; - ktrace_init(64); error = xfs_init_zones(); diff --git a/fs/xfs/linux-2.6/xfs_super.h b/fs/xfs/linux-2.6/xfs_super.h index 201cc3273c84..c78c23310fe8 100644 --- a/fs/xfs/linux-2.6/xfs_super.h +++ b/fs/xfs/linux-2.6/xfs_super.h @@ -107,7 +107,8 @@ struct block_device; extern __uint64_t xfs_max_file_offset(unsigned int); -extern void xfs_initialize_vnode(bhv_desc_t *, bhv_vnode_t *, bhv_desc_t *, int); +extern void xfs_initialize_vnode(struct xfs_mount *mp, bhv_vnode_t *vp, + struct xfs_inode *ip); extern void xfs_flush_inode(struct xfs_inode *); extern void xfs_flush_device(struct xfs_inode *); @@ -119,4 +120,6 @@ extern void xfs_blkdev_issue_flush(struct xfs_buftarg *); extern struct export_operations xfs_export_operations; +#define XFS_M(sb) ((struct xfs_mount *)((sb)->s_fs_info)) + #endif /* __XFS_SUPER_H__ */ diff --git a/fs/xfs/linux-2.6/xfs_vfs.c b/fs/xfs/linux-2.6/xfs_vfs.c deleted file mode 100644 index 6145e8bd0be2..000000000000 --- a/fs/xfs/linux-2.6/xfs_vfs.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_inum.h" -#include "xfs_log.h" -#include "xfs_clnt.h" -#include "xfs_trans.h" -#include "xfs_sb.h" -#include "xfs_ag.h" -#include "xfs_dir2.h" -#include "xfs_imap.h" -#include "xfs_alloc.h" -#include "xfs_dmapi.h" -#include "xfs_mount.h" -#include "xfs_quota.h" - -int -vfs_mount( - struct bhv_desc *bdp, - struct xfs_mount_args *args, - struct cred *cr) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_mount) - next = BHV_NEXT(next); - return ((*bhvtovfsops(next)->vfs_mount)(next, args, cr)); -} - -int -vfs_parseargs( - struct bhv_desc *bdp, - char *s, - struct xfs_mount_args *args, - int f) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_parseargs) - next = BHV_NEXT(next); - return ((*bhvtovfsops(next)->vfs_parseargs)(next, s, args, f)); -} - -int -vfs_showargs( - struct bhv_desc *bdp, - struct seq_file *m) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_showargs) - next = BHV_NEXT(next); - return ((*bhvtovfsops(next)->vfs_showargs)(next, m)); -} - -int -vfs_unmount( - struct bhv_desc *bdp, - int fl, - struct cred *cr) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_unmount) - next = BHV_NEXT(next); - return ((*bhvtovfsops(next)->vfs_unmount)(next, fl, cr)); -} - -int -vfs_mntupdate( - struct bhv_desc *bdp, - int *fl, - struct xfs_mount_args *args) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_mntupdate) - next = BHV_NEXT(next); - return ((*bhvtovfsops(next)->vfs_mntupdate)(next, fl, args)); -} - -int -vfs_root( - struct bhv_desc *bdp, - struct bhv_vnode **vpp) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_root) - next = BHV_NEXT(next); - return ((*bhvtovfsops(next)->vfs_root)(next, vpp)); -} - -int -vfs_statvfs( - struct bhv_desc *bdp, - bhv_statvfs_t *statp, - struct bhv_vnode *vp) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_statvfs) - next = BHV_NEXT(next); - return ((*bhvtovfsops(next)->vfs_statvfs)(next, statp, vp)); -} - -int -vfs_sync( - struct bhv_desc *bdp, - int fl, - struct cred *cr) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_sync) - next = BHV_NEXT(next); - return ((*bhvtovfsops(next)->vfs_sync)(next, fl, cr)); -} - -int -vfs_vget( - struct bhv_desc *bdp, - struct bhv_vnode **vpp, - struct fid *fidp) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_vget) - next = BHV_NEXT(next); - return ((*bhvtovfsops(next)->vfs_vget)(next, vpp, fidp)); -} - -int -vfs_dmapiops( - struct bhv_desc *bdp, - caddr_t addr) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_dmapiops) - next = BHV_NEXT(next); - return ((*bhvtovfsops(next)->vfs_dmapiops)(next, addr)); -} - -int -vfs_quotactl( - struct bhv_desc *bdp, - int cmd, - int id, - caddr_t addr) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_quotactl) - next = BHV_NEXT(next); - return ((*bhvtovfsops(next)->vfs_quotactl)(next, cmd, id, addr)); -} - -void -vfs_init_vnode( - struct bhv_desc *bdp, - struct bhv_vnode *vp, - struct bhv_desc *bp, - int unlock) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_init_vnode) - next = BHV_NEXT(next); - ((*bhvtovfsops(next)->vfs_init_vnode)(next, vp, bp, unlock)); -} - -void -vfs_force_shutdown( - struct bhv_desc *bdp, - int fl, - char *file, - int line) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_force_shutdown) - next = BHV_NEXT(next); - ((*bhvtovfsops(next)->vfs_force_shutdown)(next, fl, file, line)); -} - -void -vfs_freeze( - struct bhv_desc *bdp) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_freeze) - next = BHV_NEXT(next); - ((*bhvtovfsops(next)->vfs_freeze)(next)); -} - -bhv_vfs_t * -vfs_allocate( - struct super_block *sb) -{ - struct bhv_vfs *vfsp; - - vfsp = kmem_zalloc(sizeof(bhv_vfs_t), KM_SLEEP); - bhv_head_init(VFS_BHVHEAD(vfsp), "vfs"); - INIT_LIST_HEAD(&vfsp->vfs_sync_list); - spin_lock_init(&vfsp->vfs_sync_lock); - init_waitqueue_head(&vfsp->vfs_wait_single_sync_task); - - vfsp->vfs_super = sb; - sb->s_fs_info = vfsp; - - if (sb->s_flags & MS_RDONLY) - vfsp->vfs_flag |= VFS_RDONLY; - - return vfsp; -} - -bhv_vfs_t * -vfs_from_sb( - struct super_block *sb) -{ - return (bhv_vfs_t *)sb->s_fs_info; -} - -void -vfs_deallocate( - struct bhv_vfs *vfsp) -{ - bhv_head_destroy(VFS_BHVHEAD(vfsp)); - kmem_free(vfsp, sizeof(bhv_vfs_t)); -} - -void -vfs_insertops( - struct bhv_vfs *vfsp, - struct bhv_module_vfsops *vfsops) -{ - struct bhv_desc *bdp; - - bdp = kmem_alloc(sizeof(struct bhv_desc), KM_SLEEP); - bhv_desc_init(bdp, NULL, vfsp, vfsops); - bhv_insert(&vfsp->vfs_bh, bdp); -} - -void -vfs_insertbhv( - struct bhv_vfs *vfsp, - struct bhv_desc *bdp, - struct bhv_vfsops *vfsops, - void *mount) -{ - bhv_desc_init(bdp, mount, vfsp, vfsops); - bhv_insert_initial(&vfsp->vfs_bh, bdp); -} - -void -bhv_remove_vfsops( - struct bhv_vfs *vfsp, - int pos) -{ - struct bhv_desc *bhv; - - bhv = bhv_lookup_range(&vfsp->vfs_bh, pos, pos); - if (!bhv) - return; - bhv_remove(&vfsp->vfs_bh, bhv); - kmem_free(bhv, sizeof(*bhv)); -} - -void -bhv_remove_all_vfsops( - struct bhv_vfs *vfsp, - int freebase) -{ - struct xfs_mount *mp; - - bhv_remove_vfsops(vfsp, VFS_POSITION_QM); - bhv_remove_vfsops(vfsp, VFS_POSITION_DM); - if (!freebase) - return; - mp = XFS_VFSTOM(vfsp); - VFS_REMOVEBHV(vfsp, &mp->m_bhv); - xfs_mount_free(mp, 0); -} - -void -bhv_insert_all_vfsops( - struct bhv_vfs *vfsp) -{ - struct xfs_mount *mp; - - mp = xfs_mount_init(); - vfs_insertbhv(vfsp, &mp->m_bhv, &xfs_vfsops, mp); - vfs_insertdmapi(vfsp); - vfs_insertquota(vfsp); -} diff --git a/fs/xfs/linux-2.6/xfs_vfs.h b/fs/xfs/linux-2.6/xfs_vfs.h index dca3481aaafa..4da03a4e3520 100644 --- a/fs/xfs/linux-2.6/xfs_vfs.h +++ b/fs/xfs/linux-2.6/xfs_vfs.h @@ -21,68 +21,25 @@ #include <linux/vfs.h> #include "xfs_fs.h" -struct bhv_vfs; -struct bhv_vnode; +struct inode; struct fid; struct cred; struct seq_file; struct super_block; +struct xfs_inode; +struct xfs_mount; struct xfs_mount_args; typedef struct kstatfs bhv_statvfs_t; typedef struct bhv_vfs_sync_work { struct list_head w_list; - struct bhv_vfs *w_vfs; + struct xfs_mount *w_mount; void *w_data; /* syncer routine argument */ - void (*w_syncer)(struct bhv_vfs *, void *); + void (*w_syncer)(struct xfs_mount *, void *); } bhv_vfs_sync_work_t; -typedef struct bhv_vfs { - u_int vfs_flag; /* flags */ - xfs_fsid_t vfs_fsid; /* file system ID */ - xfs_fsid_t *vfs_altfsid; /* An ID fixed for life of FS */ - bhv_head_t vfs_bh; /* head of vfs behavior chain */ - struct super_block *vfs_super; /* generic superblock pointer */ - struct task_struct *vfs_sync_task; /* generalised sync thread */ - bhv_vfs_sync_work_t vfs_sync_work; /* work item for VFS_SYNC */ - struct list_head vfs_sync_list; /* sync thread work item list */ - spinlock_t vfs_sync_lock; /* work item list lock */ - int vfs_sync_seq; /* sync thread generation no. */ - wait_queue_head_t vfs_wait_single_sync_task; -} bhv_vfs_t; - -#define bhvtovfs(bdp) ( (struct bhv_vfs *)BHV_VOBJ(bdp) ) -#define bhvtovfsops(bdp) ( (struct bhv_vfsops *)BHV_OPS(bdp) ) -#define VFS_BHVHEAD(vfs) ( &(vfs)->vfs_bh ) -#define VFS_REMOVEBHV(vfs, bdp) ( bhv_remove(VFS_BHVHEAD(vfs), bdp) ) - -#define VFS_POSITION_BASE BHV_POSITION_BASE /* chain bottom */ -#define VFS_POSITION_TOP BHV_POSITION_TOP /* chain top */ -#define VFS_POSITION_INVALID BHV_POSITION_INVALID /* invalid pos. num */ - -typedef enum { - VFS_BHV_UNKNOWN, /* not specified */ - VFS_BHV_XFS, /* xfs */ - VFS_BHV_DM, /* data migration */ - VFS_BHV_QM, /* quota manager */ - VFS_BHV_IO, /* IO path */ - VFS_BHV_END /* housekeeping end-of-range */ -} bhv_vfs_type_t; - -#define VFS_POSITION_XFS (BHV_POSITION_BASE) -#define VFS_POSITION_DM (VFS_POSITION_BASE+10) -#define VFS_POSITION_QM (VFS_POSITION_BASE+20) -#define VFS_POSITION_IO (VFS_POSITION_BASE+30) - -#define VFS_RDONLY 0x0001 /* read-only vfs */ -#define VFS_GRPID 0x0002 /* group-ID assigned from directory */ -#define VFS_DMI 0x0004 /* filesystem has the DMI enabled */ -/* ---- VFS_UMOUNT ---- 0x0008 -- unneeded, fixed via kthread APIs */ -#define VFS_32BITINODES 0x0010 /* do not use inums above 32 bits */ -#define VFS_END 0x0010 /* max flag */ - #define SYNC_ATTR 0x0001 /* sync attributes */ #define SYNC_CLOSE 0x0002 /* close file system down */ #define SYNC_DELWRI 0x0004 /* look at delayed writes */ @@ -115,118 +72,7 @@ typedef enum { #define SHUTDOWN_REMOTE_REQ 0x0010 /* shutdown came from remote cell */ #define SHUTDOWN_DEVICE_REQ 0x0020 /* failed all paths to the device */ -typedef int (*vfs_mount_t)(bhv_desc_t *, - struct xfs_mount_args *, struct cred *); -typedef int (*vfs_parseargs_t)(bhv_desc_t *, char *, - struct xfs_mount_args *, int); -typedef int (*vfs_showargs_t)(bhv_desc_t *, struct seq_file *); -typedef int (*vfs_unmount_t)(bhv_desc_t *, int, struct cred *); -typedef int (*vfs_mntupdate_t)(bhv_desc_t *, int *, - struct xfs_mount_args *); -typedef int (*vfs_root_t)(bhv_desc_t *, struct bhv_vnode **); -typedef int (*vfs_statvfs_t)(bhv_desc_t *, bhv_statvfs_t *, - struct bhv_vnode *); -typedef int (*vfs_sync_t)(bhv_desc_t *, int, struct cred *); -typedef int (*vfs_vget_t)(bhv_desc_t *, struct bhv_vnode **, struct fid *); -typedef int (*vfs_dmapiops_t)(bhv_desc_t *, caddr_t); -typedef int (*vfs_quotactl_t)(bhv_desc_t *, int, int, caddr_t); -typedef void (*vfs_init_vnode_t)(bhv_desc_t *, - struct bhv_vnode *, bhv_desc_t *, int); -typedef void (*vfs_force_shutdown_t)(bhv_desc_t *, int, char *, int); -typedef void (*vfs_freeze_t)(bhv_desc_t *); - -typedef struct bhv_vfsops { - bhv_position_t vf_position; /* behavior chain position */ - vfs_mount_t vfs_mount; /* mount file system */ - vfs_parseargs_t vfs_parseargs; /* parse mount options */ - vfs_showargs_t vfs_showargs; /* unparse mount options */ - vfs_unmount_t vfs_unmount; /* unmount file system */ - vfs_mntupdate_t vfs_mntupdate; /* update file system options */ - vfs_root_t vfs_root; /* get root vnode */ - vfs_statvfs_t vfs_statvfs; /* file system statistics */ - vfs_sync_t vfs_sync; /* flush files */ - vfs_vget_t vfs_vget; /* get vnode from fid */ - vfs_dmapiops_t vfs_dmapiops; /* data migration */ - vfs_quotactl_t vfs_quotactl; /* disk quota */ - vfs_init_vnode_t vfs_init_vnode; /* initialize a new vnode */ - vfs_force_shutdown_t vfs_force_shutdown; /* crash and burn */ - vfs_freeze_t vfs_freeze; /* freeze fs for snapshot */ -} bhv_vfsops_t; - -/* - * Virtual filesystem operations, operating from head bhv. - */ -#define VFSHEAD(v) ((v)->vfs_bh.bh_first) -#define bhv_vfs_mount(v, ma,cr) vfs_mount(VFSHEAD(v), ma,cr) -#define bhv_vfs_parseargs(v, o,ma,f) vfs_parseargs(VFSHEAD(v), o,ma,f) -#define bhv_vfs_showargs(v, m) vfs_showargs(VFSHEAD(v), m) -#define bhv_vfs_unmount(v, f,cr) vfs_unmount(VFSHEAD(v), f,cr) -#define bhv_vfs_mntupdate(v, fl,args) vfs_mntupdate(VFSHEAD(v), fl,args) -#define bhv_vfs_root(v, vpp) vfs_root(VFSHEAD(v), vpp) -#define bhv_vfs_statvfs(v, sp,vp) vfs_statvfs(VFSHEAD(v), sp,vp) -#define bhv_vfs_sync(v, flag,cr) vfs_sync(VFSHEAD(v), flag,cr) -#define bhv_vfs_vget(v, vpp,fidp) vfs_vget(VFSHEAD(v), vpp,fidp) -#define bhv_vfs_dmapiops(v, p) vfs_dmapiops(VFSHEAD(v), p) -#define bhv_vfs_quotactl(v, c,id,p) vfs_quotactl(VFSHEAD(v), c,id,p) -#define bhv_vfs_init_vnode(v, vp,b,ul) vfs_init_vnode(VFSHEAD(v), vp,b,ul) -#define bhv_vfs_force_shutdown(v,u,f,l) vfs_force_shutdown(VFSHEAD(v), u,f,l) -#define bhv_vfs_freeze(v) vfs_freeze(VFSHEAD(v)) - -/* - * Virtual filesystem operations, operating from next bhv. - */ -#define bhv_next_vfs_mount(b, ma,cr) vfs_mount(b, ma,cr) -#define bhv_next_vfs_parseargs(b, o,ma,f) vfs_parseargs(b, o,ma,f) -#define bhv_next_vfs_showargs(b, m) vfs_showargs(b, m) -#define bhv_next_vfs_unmount(b, f,cr) vfs_unmount(b, f,cr) -#define bhv_next_vfs_mntupdate(b, fl,args) vfs_mntupdate(b, fl, args) -#define bhv_next_vfs_root(b, vpp) vfs_root(b, vpp) -#define bhv_next_vfs_statvfs(b, sp,vp) vfs_statvfs(b, sp,vp) -#define bhv_next_vfs_sync(b, flag,cr) vfs_sync(b, flag,cr) -#define bhv_next_vfs_vget(b, vpp,fidp) vfs_vget(b, vpp,fidp) -#define bhv_next_vfs_dmapiops(b, p) vfs_dmapiops(b, p) -#define bhv_next_vfs_quotactl(b, c,id,p) vfs_quotactl(b, c,id,p) -#define bhv_next_vfs_init_vnode(b, vp,b2,ul) vfs_init_vnode(b, vp,b2,ul) -#define bhv_next_force_shutdown(b, fl,f,l) vfs_force_shutdown(b, fl,f,l) -#define bhv_next_vfs_freeze(b) vfs_freeze(b) - -extern int vfs_mount(bhv_desc_t *, struct xfs_mount_args *, struct cred *); -extern int vfs_parseargs(bhv_desc_t *, char *, struct xfs_mount_args *, int); -extern int vfs_showargs(bhv_desc_t *, struct seq_file *); -extern int vfs_unmount(bhv_desc_t *, int, struct cred *); -extern int vfs_mntupdate(bhv_desc_t *, int *, struct xfs_mount_args *); -extern int vfs_root(bhv_desc_t *, struct bhv_vnode **); -extern int vfs_statvfs(bhv_desc_t *, bhv_statvfs_t *, struct bhv_vnode *); -extern int vfs_sync(bhv_desc_t *, int, struct cred *); -extern int vfs_vget(bhv_desc_t *, struct bhv_vnode **, struct fid *); -extern int vfs_dmapiops(bhv_desc_t *, caddr_t); -extern int vfs_quotactl(bhv_desc_t *, int, int, caddr_t); -extern void vfs_init_vnode(bhv_desc_t *, struct bhv_vnode *, bhv_desc_t *, int); -extern void vfs_force_shutdown(bhv_desc_t *, int, char *, int); -extern void vfs_freeze(bhv_desc_t *); - -#define vfs_test_for_freeze(vfs) ((vfs)->vfs_super->s_frozen) -#define vfs_wait_for_freeze(vfs,l) vfs_check_frozen((vfs)->vfs_super, (l)) - -typedef struct bhv_module_vfsops { - struct bhv_vfsops bhv_common; - void * bhv_custom; -} bhv_module_vfsops_t; - -#define vfs_bhv_lookup(v, id) (bhv_lookup_range(&(v)->vfs_bh, (id), (id))) -#define vfs_bhv_custom(b) (((bhv_module_vfsops_t*)BHV_OPS(b))->bhv_custom) -#define vfs_bhv_set_custom(b,o) ((b)->bhv_custom = (void *)(o)) -#define vfs_bhv_clr_custom(b) ((b)->bhv_custom = NULL) - -extern bhv_vfs_t *vfs_allocate(struct super_block *); -extern bhv_vfs_t *vfs_from_sb(struct super_block *); -extern void vfs_deallocate(bhv_vfs_t *); -extern void vfs_insertbhv(bhv_vfs_t *, bhv_desc_t *, bhv_vfsops_t *, void *); - -extern void vfs_insertops(bhv_vfs_t *, bhv_module_vfsops_t *); - -extern void bhv_insert_all_vfsops(struct bhv_vfs *); -extern void bhv_remove_all_vfsops(struct bhv_vfs *, int); -extern void bhv_remove_vfsops(struct bhv_vfs *, int); +#define xfs_test_for_freeze(mp) ((mp)->m_super->s_frozen) +#define xfs_wait_for_freeze(mp,l) vfs_check_frozen((mp)->m_super, (l)) #endif /* __XFS_VFS_H__ */ diff --git a/fs/xfs/linux-2.6/xfs_vnode.c b/fs/xfs/linux-2.6/xfs_vnode.c index ada24baf88de..814169fd7e1e 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.c +++ b/fs/xfs/linux-2.6/xfs_vnode.c @@ -16,9 +16,21 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "xfs.h" +#include "xfs_vnodeops.h" +#include "xfs_bmap_btree.h" +#include "xfs_inode.h" + +/* + * And this gunk is needed for xfs_mount.h" + */ +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_dmapi.h" +#include "xfs_inum.h" +#include "xfs_ag.h" +#include "xfs_mount.h" -uint64_t vn_generation; /* vnode generation number */ -DEFINE_SPINLOCK(vnumber_lock); /* * Dedicated vnode inactive/reclaim sync semaphores. @@ -39,19 +51,19 @@ vn_init(void) void vn_iowait( - bhv_vnode_t *vp) + xfs_inode_t *ip) { - wait_queue_head_t *wq = vptosync(vp); + wait_queue_head_t *wq = vptosync(ip); - wait_event(*wq, (atomic_read(&vp->v_iocount) == 0)); + wait_event(*wq, (atomic_read(&ip->i_iocount) == 0)); } void vn_iowake( - bhv_vnode_t *vp) + xfs_inode_t *ip) { - if (atomic_dec_and_test(&vp->v_iocount)) - wake_up(vptosync(vp)); + if (atomic_dec_and_test(&ip->i_iocount)) + wake_up(vptosync(ip)); } /* @@ -61,13 +73,13 @@ vn_iowake( */ void vn_ioerror( - bhv_vnode_t *vp, + xfs_inode_t *ip, int error, char *f, int l) { if (unlikely(error == -ENODEV)) - bhv_vfs_force_shutdown(vp->v_vfsp, SHUTDOWN_DEVICE_REQ, f, l); + xfs_do_force_shutdown(ip->i_mount, SHUTDOWN_DEVICE_REQ, f, l); } bhv_vnode_t * @@ -79,27 +91,8 @@ vn_initialize( XFS_STATS_INC(vn_active); XFS_STATS_INC(vn_alloc); - vp->v_flag = VMODIFIED; - spinlock_init(&vp->v_lock, "v_lock"); - - spin_lock(&vnumber_lock); - if (!++vn_generation) /* v_number shouldn't be zero */ - vn_generation++; - vp->v_number = vn_generation; - spin_unlock(&vnumber_lock); - ASSERT(VN_CACHED(vp) == 0); - /* Initialize the first behavior and the behavior chain head. */ - vn_bhv_head_init(VN_BHV_HEAD(vp), "vnode"); - - atomic_set(&vp->v_iocount, 0); - -#ifdef XFS_VNODE_TRACE - vp->v_trace = ktrace_alloc(VNODE_TRACE_SIZE, KM_SLEEP); -#endif /* XFS_VNODE_TRACE */ - - vn_trace_exit(vp, __FUNCTION__, (inst_t *)__return_address); return vp; } @@ -150,12 +143,12 @@ __vn_revalidate( { int error; - vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); + vn_trace_entry(xfs_vtoi(vp), __FUNCTION__, (inst_t *)__return_address); vattr->va_mask = XFS_AT_STAT | XFS_AT_XFLAGS; - error = bhv_vop_getattr(vp, vattr, 0, NULL); + error = xfs_getattr(xfs_vtoi(vp), vattr, 0); if (likely(!error)) { vn_revalidate_core(vp, vattr); - VUNMODIFY(vp); + xfs_iflags_clear(xfs_vtoi(vp), XFS_IMODIFIED); } return -error; } @@ -180,24 +173,35 @@ vn_hold( XFS_STATS_INC(vn_hold); - VN_LOCK(vp); inode = igrab(vn_to_inode(vp)); ASSERT(inode); - VN_UNLOCK(vp, 0); return vp; } #ifdef XFS_VNODE_TRACE -#define KTRACE_ENTER(vp, vk, s, line, ra) \ - ktrace_enter( (vp)->v_trace, \ +/* + * Reference count of Linux inode if present, -1 if the xfs_inode + * has no associated Linux inode. + */ +static inline int xfs_icount(struct xfs_inode *ip) +{ + bhv_vnode_t *vp = XFS_ITOV_NULL(ip); + + if (vp) + return vn_count(vp); + return -1; +} + +#define KTRACE_ENTER(ip, vk, s, line, ra) \ + ktrace_enter( (ip)->i_trace, \ /* 0 */ (void *)(__psint_t)(vk), \ /* 1 */ (void *)(s), \ /* 2 */ (void *)(__psint_t) line, \ -/* 3 */ (void *)(__psint_t)(vn_count(vp)), \ +/* 3 */ (void *)(__psint_t)xfs_icount(ip), \ /* 4 */ (void *)(ra), \ -/* 5 */ (void *)(__psunsigned_t)(vp)->v_flag, \ +/* 5 */ NULL, \ /* 6 */ (void *)(__psint_t)current_cpu(), \ /* 7 */ (void *)(__psint_t)current_pid(), \ /* 8 */ (void *)__return_address, \ @@ -207,32 +211,32 @@ vn_hold( * Vnode tracing code. */ void -vn_trace_entry(bhv_vnode_t *vp, const char *func, inst_t *ra) +vn_trace_entry(xfs_inode_t *ip, const char *func, inst_t *ra) { - KTRACE_ENTER(vp, VNODE_KTRACE_ENTRY, func, 0, ra); + KTRACE_ENTER(ip, VNODE_KTRACE_ENTRY, func, 0, ra); } void -vn_trace_exit(bhv_vnode_t *vp, const char *func, inst_t *ra) +vn_trace_exit(xfs_inode_t *ip, const char *func, inst_t *ra) { - KTRACE_ENTER(vp, VNODE_KTRACE_EXIT, func, 0, ra); + KTRACE_ENTER(ip, VNODE_KTRACE_EXIT, func, 0, ra); } void -vn_trace_hold(bhv_vnode_t *vp, char *file, int line, inst_t *ra) +vn_trace_hold(xfs_inode_t *ip, char *file, int line, inst_t *ra) { - KTRACE_ENTER(vp, VNODE_KTRACE_HOLD, file, line, ra); + KTRACE_ENTER(ip, VNODE_KTRACE_HOLD, file, line, ra); } void -vn_trace_ref(bhv_vnode_t *vp, char *file, int line, inst_t *ra) +vn_trace_ref(xfs_inode_t *ip, char *file, int line, inst_t *ra) { - KTRACE_ENTER(vp, VNODE_KTRACE_REF, file, line, ra); + KTRACE_ENTER(ip, VNODE_KTRACE_REF, file, line, ra); } void -vn_trace_rele(bhv_vnode_t *vp, char *file, int line, inst_t *ra) +vn_trace_rele(xfs_inode_t *ip, char *file, int line, inst_t *ra) { - KTRACE_ENTER(vp, VNODE_KTRACE_RELE, file, line, ra); + KTRACE_ENTER(ip, VNODE_KTRACE_RELE, file, line, ra); } #endif /* XFS_VNODE_TRACE */ diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h index 5742d65f0785..55fb46948589 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.h +++ b/fs/xfs/linux-2.6/xfs_vnode.h @@ -18,84 +18,31 @@ #ifndef __XFS_VNODE_H__ #define __XFS_VNODE_H__ -struct uio; struct file; -struct bhv_vfs; struct bhv_vattr; struct xfs_iomap; struct attrlist_cursor_kern; typedef struct dentry bhv_vname_t; typedef __u64 bhv_vnumber_t; +typedef struct inode bhv_vnode_t; -typedef enum bhv_vflags { - VMODIFIED = 0x08, /* XFS inode state possibly differs */ - /* to the Linux inode state. */ - VTRUNCATED = 0x40, /* truncated down so flush-on-close */ -} bhv_vflags_t; - -/* - * MP locking protocols: - * v_flag, v_vfsp VN_LOCK/VN_UNLOCK - */ -typedef struct bhv_vnode { - bhv_vflags_t v_flag; /* vnode flags (see above) */ - bhv_vfs_t *v_vfsp; /* ptr to containing VFS */ - bhv_vnumber_t v_number; /* in-core vnode number */ - bhv_head_t v_bh; /* behavior head */ - spinlock_t v_lock; /* VN_LOCK/VN_UNLOCK */ - atomic_t v_iocount; /* outstanding I/O count */ -#ifdef XFS_VNODE_TRACE - struct ktrace *v_trace; /* trace header structure */ -#endif - struct inode v_inode; /* Linux inode */ - /* inode MUST be last */ -} bhv_vnode_t; - -#define VN_ISLNK(vp) S_ISLNK((vp)->v_inode.i_mode) -#define VN_ISREG(vp) S_ISREG((vp)->v_inode.i_mode) -#define VN_ISDIR(vp) S_ISDIR((vp)->v_inode.i_mode) -#define VN_ISCHR(vp) S_ISCHR((vp)->v_inode.i_mode) -#define VN_ISBLK(vp) S_ISBLK((vp)->v_inode.i_mode) - -#define VNODE_POSITION_BASE BHV_POSITION_BASE /* chain bottom */ -#define VNODE_POSITION_TOP BHV_POSITION_TOP /* chain top */ -#define VNODE_POSITION_INVALID BHV_POSITION_INVALID /* invalid pos. num */ - -typedef enum { - VN_BHV_UNKNOWN, /* not specified */ - VN_BHV_XFS, /* xfs */ - VN_BHV_DM, /* data migration */ - VN_BHV_QM, /* quota manager */ - VN_BHV_IO, /* IO path */ - VN_BHV_END /* housekeeping end-of-range */ -} vn_bhv_t; - -#define VNODE_POSITION_XFS (VNODE_POSITION_BASE) -#define VNODE_POSITION_DM (VNODE_POSITION_BASE+10) -#define VNODE_POSITION_QM (VNODE_POSITION_BASE+20) -#define VNODE_POSITION_IO (VNODE_POSITION_BASE+30) - -/* - * Macros for dealing with the behavior descriptor inside of the vnode. - */ -#define BHV_TO_VNODE(bdp) ((bhv_vnode_t *)BHV_VOBJ(bdp)) -#define BHV_TO_VNODE_NULL(bdp) ((bhv_vnode_t *)BHV_VOBJNULL(bdp)) - -#define VN_BHV_HEAD(vp) ((bhv_head_t *)(&((vp)->v_bh))) -#define vn_bhv_head_init(bhp,name) bhv_head_init(bhp,name) -#define vn_bhv_remove(bhp,bdp) bhv_remove(bhp,bdp) +#define VN_ISLNK(vp) S_ISLNK((vp)->i_mode) +#define VN_ISREG(vp) S_ISREG((vp)->i_mode) +#define VN_ISDIR(vp) S_ISDIR((vp)->i_mode) +#define VN_ISCHR(vp) S_ISCHR((vp)->i_mode) +#define VN_ISBLK(vp) S_ISBLK((vp)->i_mode) /* * Vnode to Linux inode mapping. */ -static inline struct bhv_vnode *vn_from_inode(struct inode *inode) +static inline bhv_vnode_t *vn_from_inode(struct inode *inode) { - return container_of(inode, bhv_vnode_t, v_inode); + return inode; } -static inline struct inode *vn_to_inode(struct bhv_vnode *vnode) +static inline struct inode *vn_to_inode(bhv_vnode_t *vnode) { - return &vnode->v_inode; + return vnode; } /* @@ -111,7 +58,7 @@ typedef enum bhv_vrwlock { } bhv_vrwlock_t; /* - * Return values for bhv_vop_inactive. A return value of + * Return values for xfs_inactive. A return value of * VN_INACTIVE_NOCACHE implies that the file system behavior * has disassociated its state and bhv_desc_t from the vnode. */ @@ -119,193 +66,6 @@ typedef enum bhv_vrwlock { #define VN_INACTIVE_NOCACHE 1 /* - * Values for the cmd code given to vop_vnode_change. - */ -typedef enum bhv_vchange { - VCHANGE_FLAGS_FRLOCKS = 0, - VCHANGE_FLAGS_ENF_LOCKING = 1, - VCHANGE_FLAGS_TRUNCATED = 2, - VCHANGE_FLAGS_PAGE_DIRTY = 3, - VCHANGE_FLAGS_IOEXCL_COUNT = 4 -} bhv_vchange_t; - -typedef int (*vop_open_t)(bhv_desc_t *, struct cred *); -typedef ssize_t (*vop_read_t)(bhv_desc_t *, struct kiocb *, - const struct iovec *, unsigned int, - loff_t *, int, struct cred *); -typedef ssize_t (*vop_write_t)(bhv_desc_t *, struct kiocb *, - const struct iovec *, unsigned int, - loff_t *, int, struct cred *); -typedef ssize_t (*vop_splice_read_t)(bhv_desc_t *, struct file *, loff_t *, - struct pipe_inode_info *, size_t, int, int, - struct cred *); -typedef ssize_t (*vop_splice_write_t)(bhv_desc_t *, struct pipe_inode_info *, - struct file *, loff_t *, size_t, int, int, - struct cred *); -typedef int (*vop_ioctl_t)(bhv_desc_t *, struct inode *, struct file *, - int, unsigned int, void __user *); -typedef int (*vop_getattr_t)(bhv_desc_t *, struct bhv_vattr *, int, - struct cred *); -typedef int (*vop_setattr_t)(bhv_desc_t *, struct bhv_vattr *, int, - struct cred *); -typedef int (*vop_access_t)(bhv_desc_t *, int, struct cred *); -typedef int (*vop_lookup_t)(bhv_desc_t *, bhv_vname_t *, bhv_vnode_t **, - int, bhv_vnode_t *, struct cred *); -typedef int (*vop_create_t)(bhv_desc_t *, bhv_vname_t *, struct bhv_vattr *, - bhv_vnode_t **, struct cred *); -typedef int (*vop_remove_t)(bhv_desc_t *, bhv_vname_t *, struct cred *); -typedef int (*vop_link_t)(bhv_desc_t *, bhv_vnode_t *, bhv_vname_t *, - struct cred *); -typedef int (*vop_rename_t)(bhv_desc_t *, bhv_vname_t *, bhv_vnode_t *, - bhv_vname_t *, struct cred *); -typedef int (*vop_mkdir_t)(bhv_desc_t *, bhv_vname_t *, struct bhv_vattr *, - bhv_vnode_t **, struct cred *); -typedef int (*vop_rmdir_t)(bhv_desc_t *, bhv_vname_t *, struct cred *); -typedef int (*vop_readdir_t)(bhv_desc_t *, struct uio *, struct cred *, - int *); -typedef int (*vop_symlink_t)(bhv_desc_t *, bhv_vname_t *, struct bhv_vattr*, - char *, bhv_vnode_t **, struct cred *); -typedef int (*vop_readlink_t)(bhv_desc_t *, struct uio *, int, - struct cred *); -typedef int (*vop_fsync_t)(bhv_desc_t *, int, struct cred *, - xfs_off_t, xfs_off_t); -typedef int (*vop_inactive_t)(bhv_desc_t *, struct cred *); -typedef int (*vop_fid2_t)(bhv_desc_t *, struct fid *); -typedef int (*vop_release_t)(bhv_desc_t *); -typedef int (*vop_rwlock_t)(bhv_desc_t *, bhv_vrwlock_t); -typedef void (*vop_rwunlock_t)(bhv_desc_t *, bhv_vrwlock_t); -typedef int (*vop_bmap_t)(bhv_desc_t *, xfs_off_t, ssize_t, int, - struct xfs_iomap *, int *); -typedef int (*vop_reclaim_t)(bhv_desc_t *); -typedef int (*vop_attr_get_t)(bhv_desc_t *, const char *, char *, int *, - int, struct cred *); -typedef int (*vop_attr_set_t)(bhv_desc_t *, const char *, char *, int, - int, struct cred *); -typedef int (*vop_attr_remove_t)(bhv_desc_t *, const char *, - int, struct cred *); -typedef int (*vop_attr_list_t)(bhv_desc_t *, char *, int, int, - struct attrlist_cursor_kern *, struct cred *); -typedef void (*vop_link_removed_t)(bhv_desc_t *, bhv_vnode_t *, int); -typedef void (*vop_vnode_change_t)(bhv_desc_t *, bhv_vchange_t, __psint_t); -typedef void (*vop_ptossvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int); -typedef int (*vop_pflushinvalvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int); -typedef int (*vop_pflushvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, - uint64_t, int); -typedef int (*vop_iflush_t)(bhv_desc_t *, int); - - -typedef struct bhv_vnodeops { - bhv_position_t vn_position; /* position within behavior chain */ - vop_open_t vop_open; - vop_read_t vop_read; - vop_write_t vop_write; - vop_splice_read_t vop_splice_read; - vop_splice_write_t vop_splice_write; - vop_ioctl_t vop_ioctl; - vop_getattr_t vop_getattr; - vop_setattr_t vop_setattr; - vop_access_t vop_access; - vop_lookup_t vop_lookup; - vop_create_t vop_create; - vop_remove_t vop_remove; - vop_link_t vop_link; - vop_rename_t vop_rename; - vop_mkdir_t vop_mkdir; - vop_rmdir_t vop_rmdir; - vop_readdir_t vop_readdir; - vop_symlink_t vop_symlink; - vop_readlink_t vop_readlink; - vop_fsync_t vop_fsync; - vop_inactive_t vop_inactive; - vop_fid2_t vop_fid2; - vop_rwlock_t vop_rwlock; - vop_rwunlock_t vop_rwunlock; - vop_bmap_t vop_bmap; - vop_reclaim_t vop_reclaim; - vop_attr_get_t vop_attr_get; - vop_attr_set_t vop_attr_set; - vop_attr_remove_t vop_attr_remove; - vop_attr_list_t vop_attr_list; - vop_link_removed_t vop_link_removed; - vop_vnode_change_t vop_vnode_change; - vop_ptossvp_t vop_tosspages; - vop_pflushinvalvp_t vop_flushinval_pages; - vop_pflushvp_t vop_flush_pages; - vop_release_t vop_release; - vop_iflush_t vop_iflush; -} bhv_vnodeops_t; - -/* - * Virtual node operations, operating from head bhv. - */ -#define VNHEAD(vp) ((vp)->v_bh.bh_first) -#define VOP(op, vp) (*((bhv_vnodeops_t *)VNHEAD(vp)->bd_ops)->op) -#define bhv_vop_open(vp, cr) VOP(vop_open, vp)(VNHEAD(vp),cr) -#define bhv_vop_read(vp,file,iov,segs,offset,ioflags,cr) \ - VOP(vop_read, vp)(VNHEAD(vp),file,iov,segs,offset,ioflags,cr) -#define bhv_vop_write(vp,file,iov,segs,offset,ioflags,cr) \ - VOP(vop_write, vp)(VNHEAD(vp),file,iov,segs,offset,ioflags,cr) -#define bhv_vop_splice_read(vp,f,o,pipe,cnt,fl,iofl,cr) \ - VOP(vop_splice_read, vp)(VNHEAD(vp),f,o,pipe,cnt,fl,iofl,cr) -#define bhv_vop_splice_write(vp,f,o,pipe,cnt,fl,iofl,cr) \ - VOP(vop_splice_write, vp)(VNHEAD(vp),f,o,pipe,cnt,fl,iofl,cr) -#define bhv_vop_bmap(vp,of,sz,rw,b,n) \ - VOP(vop_bmap, vp)(VNHEAD(vp),of,sz,rw,b,n) -#define bhv_vop_getattr(vp, vap,f,cr) \ - VOP(vop_getattr, vp)(VNHEAD(vp), vap,f,cr) -#define bhv_vop_setattr(vp, vap,f,cr) \ - VOP(vop_setattr, vp)(VNHEAD(vp), vap,f,cr) -#define bhv_vop_access(vp, mode,cr) VOP(vop_access, vp)(VNHEAD(vp), mode,cr) -#define bhv_vop_lookup(vp,d,vpp,f,rdir,cr) \ - VOP(vop_lookup, vp)(VNHEAD(vp),d,vpp,f,rdir,cr) -#define bhv_vop_create(dvp,d,vap,vpp,cr) \ - VOP(vop_create, dvp)(VNHEAD(dvp),d,vap,vpp,cr) -#define bhv_vop_remove(dvp,d,cr) VOP(vop_remove, dvp)(VNHEAD(dvp),d,cr) -#define bhv_vop_link(dvp,fvp,d,cr) VOP(vop_link, dvp)(VNHEAD(dvp),fvp,d,cr) -#define bhv_vop_rename(fvp,fnm,tdvp,tnm,cr) \ - VOP(vop_rename, fvp)(VNHEAD(fvp),fnm,tdvp,tnm,cr) -#define bhv_vop_mkdir(dp,d,vap,vpp,cr) \ - VOP(vop_mkdir, dp)(VNHEAD(dp),d,vap,vpp,cr) -#define bhv_vop_rmdir(dp,d,cr) VOP(vop_rmdir, dp)(VNHEAD(dp),d,cr) -#define bhv_vop_readdir(vp,uiop,cr,eofp) \ - VOP(vop_readdir, vp)(VNHEAD(vp),uiop,cr,eofp) -#define bhv_vop_symlink(dvp,d,vap,tnm,vpp,cr) \ - VOP(vop_symlink, dvp)(VNHEAD(dvp),d,vap,tnm,vpp,cr) -#define bhv_vop_readlink(vp,uiop,fl,cr) \ - VOP(vop_readlink, vp)(VNHEAD(vp),uiop,fl,cr) -#define bhv_vop_fsync(vp,f,cr,b,e) VOP(vop_fsync, vp)(VNHEAD(vp),f,cr,b,e) -#define bhv_vop_inactive(vp,cr) VOP(vop_inactive, vp)(VNHEAD(vp),cr) -#define bhv_vop_release(vp) VOP(vop_release, vp)(VNHEAD(vp)) -#define bhv_vop_fid2(vp,fidp) VOP(vop_fid2, vp)(VNHEAD(vp),fidp) -#define bhv_vop_rwlock(vp,i) VOP(vop_rwlock, vp)(VNHEAD(vp),i) -#define bhv_vop_rwlock_try(vp,i) VOP(vop_rwlock, vp)(VNHEAD(vp),i) -#define bhv_vop_rwunlock(vp,i) VOP(vop_rwunlock, vp)(VNHEAD(vp),i) -#define bhv_vop_frlock(vp,c,fl,flags,offset,fr) \ - VOP(vop_frlock, vp)(VNHEAD(vp),c,fl,flags,offset,fr) -#define bhv_vop_reclaim(vp) VOP(vop_reclaim, vp)(VNHEAD(vp)) -#define bhv_vop_attr_get(vp, name, val, vallenp, fl, cred) \ - VOP(vop_attr_get, vp)(VNHEAD(vp),name,val,vallenp,fl,cred) -#define bhv_vop_attr_set(vp, name, val, vallen, fl, cred) \ - VOP(vop_attr_set, vp)(VNHEAD(vp),name,val,vallen,fl,cred) -#define bhv_vop_attr_remove(vp, name, flags, cred) \ - VOP(vop_attr_remove, vp)(VNHEAD(vp),name,flags,cred) -#define bhv_vop_attr_list(vp, buf, buflen, fl, cursor, cred) \ - VOP(vop_attr_list, vp)(VNHEAD(vp),buf,buflen,fl,cursor,cred) -#define bhv_vop_link_removed(vp, dvp, linkzero) \ - VOP(vop_link_removed, vp)(VNHEAD(vp), dvp, linkzero) -#define bhv_vop_vnode_change(vp, cmd, val) \ - VOP(vop_vnode_change, vp)(VNHEAD(vp), cmd, val) -#define bhv_vop_toss_pages(vp, first, last, fiopt) \ - VOP(vop_tosspages, vp)(VNHEAD(vp), first, last, fiopt) -#define bhv_vop_flushinval_pages(vp, first, last, fiopt) \ - VOP(vop_flushinval_pages, vp)(VNHEAD(vp),first,last,fiopt) -#define bhv_vop_flush_pages(vp, first, last, flags, fiopt) \ - VOP(vop_flush_pages, vp)(VNHEAD(vp),first,last,flags,fiopt) -#define bhv_vop_ioctl(vp, inode, filp, fl, cmd, arg) \ - VOP(vop_ioctl, vp)(VNHEAD(vp),inode,filp,fl,cmd,arg) -#define bhv_vop_iflush(vp, flags) VOP(vop_iflush, vp)(VNHEAD(vp), flags) - -/* * Flags for read/write calls - same values as IRIX */ #define IO_ISAIO 0x00001 /* don't wait for completion */ @@ -428,16 +188,19 @@ typedef struct bhv_vattr { extern void vn_init(void); extern bhv_vnode_t *vn_initialize(struct inode *); -extern int vn_revalidate(struct bhv_vnode *); -extern int __vn_revalidate(struct bhv_vnode *, bhv_vattr_t *); -extern void vn_revalidate_core(struct bhv_vnode *, bhv_vattr_t *); - -extern void vn_iowait(struct bhv_vnode *vp); -extern void vn_iowake(struct bhv_vnode *vp); +extern int vn_revalidate(bhv_vnode_t *); +extern int __vn_revalidate(bhv_vnode_t *, bhv_vattr_t *); +extern void vn_revalidate_core(bhv_vnode_t *, bhv_vattr_t *); -extern void vn_ioerror(struct bhv_vnode *vp, int error, char *f, int l); +/* + * Yeah, these don't take vnode anymore at all, all this should be + * cleaned up at some point. + */ +extern void vn_iowait(struct xfs_inode *ip); +extern void vn_iowake(struct xfs_inode *ip); +extern void vn_ioerror(struct xfs_inode *ip, int error, char *f, int l); -static inline int vn_count(struct bhv_vnode *vp) +static inline int vn_count(bhv_vnode_t *vp) { return atomic_read(&vn_to_inode(vp)->i_count); } @@ -445,21 +208,21 @@ static inline int vn_count(struct bhv_vnode *vp) /* * Vnode reference counting functions (and macros for compatibility). */ -extern bhv_vnode_t *vn_hold(struct bhv_vnode *); +extern bhv_vnode_t *vn_hold(bhv_vnode_t *); #if defined(XFS_VNODE_TRACE) #define VN_HOLD(vp) \ ((void)vn_hold(vp), \ - vn_trace_hold(vp, __FILE__, __LINE__, (inst_t *)__return_address)) + vn_trace_hold(xfs_vtoi(vp), __FILE__, __LINE__, (inst_t *)__return_address)) #define VN_RELE(vp) \ - (vn_trace_rele(vp, __FILE__, __LINE__, (inst_t *)__return_address), \ + (vn_trace_rele(xfs_vtoi(vp), __FILE__, __LINE__, (inst_t *)__return_address), \ iput(vn_to_inode(vp))) #else #define VN_HOLD(vp) ((void)vn_hold(vp)) #define VN_RELE(vp) (iput(vn_to_inode(vp))) #endif -static inline struct bhv_vnode *vn_grab(struct bhv_vnode *vp) +static inline bhv_vnode_t *vn_grab(bhv_vnode_t *vp) { struct inode *inode = igrab(vn_to_inode(vp)); return inode ? vn_from_inode(inode) : NULL; @@ -473,43 +236,14 @@ static inline struct bhv_vnode *vn_grab(struct bhv_vnode *vp) #define VNAME_TO_VNODE(dentry) (vn_from_inode((dentry)->d_inode)) /* - * Vnode spinlock manipulation. - */ -#define VN_LOCK(vp) mutex_spinlock(&(vp)->v_lock) -#define VN_UNLOCK(vp, s) mutex_spinunlock(&(vp)->v_lock, s) - -STATIC_INLINE void vn_flagset(struct bhv_vnode *vp, uint flag) -{ - spin_lock(&vp->v_lock); - vp->v_flag |= flag; - spin_unlock(&vp->v_lock); -} - -STATIC_INLINE uint vn_flagclr(struct bhv_vnode *vp, uint flag) -{ - uint cleared; - - spin_lock(&vp->v_lock); - cleared = (vp->v_flag & flag); - vp->v_flag &= ~flag; - spin_unlock(&vp->v_lock); - return cleared; -} - -#define VMODIFY(vp) vn_flagset(vp, VMODIFIED) -#define VUNMODIFY(vp) vn_flagclr(vp, VMODIFIED) -#define VTRUNCATE(vp) vn_flagset(vp, VTRUNCATED) -#define VUNTRUNCATE(vp) vn_flagclr(vp, VTRUNCATED) - -/* * Dealing with bad inodes */ -static inline void vn_mark_bad(struct bhv_vnode *vp) +static inline void vn_mark_bad(bhv_vnode_t *vp) { make_bad_inode(vn_to_inode(vp)); } -static inline int VN_BAD(struct bhv_vnode *vp) +static inline int VN_BAD(bhv_vnode_t *vp) { return is_bad_inode(vn_to_inode(vp)); } @@ -519,18 +253,18 @@ static inline int VN_BAD(struct bhv_vnode *vp) */ static inline void vn_atime_to_bstime(bhv_vnode_t *vp, xfs_bstime_t *bs_atime) { - bs_atime->tv_sec = vp->v_inode.i_atime.tv_sec; - bs_atime->tv_nsec = vp->v_inode.i_atime.tv_nsec; + bs_atime->tv_sec = vp->i_atime.tv_sec; + bs_atime->tv_nsec = vp->i_atime.tv_nsec; } static inline void vn_atime_to_timespec(bhv_vnode_t *vp, struct timespec *ts) { - *ts = vp->v_inode.i_atime; + *ts = vp->i_atime; } static inline void vn_atime_to_time_t(bhv_vnode_t *vp, time_t *tt) { - *tt = vp->v_inode.i_atime.tv_sec; + *tt = vp->i_atime.tv_sec; } /* @@ -540,7 +274,6 @@ static inline void vn_atime_to_time_t(bhv_vnode_t *vp, time_t *tt) #define VN_CACHED(vp) (vn_to_inode(vp)->i_mapping->nrpages) #define VN_DIRTY(vp) mapping_tagged(vn_to_inode(vp)->i_mapping, \ PAGECACHE_TAG_DIRTY) -#define VN_TRUNC(vp) ((vp)->v_flag & VTRUNCATED) /* * Flags to vop_setattr/getattr. @@ -572,21 +305,17 @@ static inline void vn_atime_to_time_t(bhv_vnode_t *vp, time_t *tt) #define VNODE_KTRACE_REF 4 #define VNODE_KTRACE_RELE 5 -extern void vn_trace_entry(struct bhv_vnode *, const char *, inst_t *); -extern void vn_trace_exit(struct bhv_vnode *, const char *, inst_t *); -extern void vn_trace_hold(struct bhv_vnode *, char *, int, inst_t *); -extern void vn_trace_ref(struct bhv_vnode *, char *, int, inst_t *); -extern void vn_trace_rele(struct bhv_vnode *, char *, int, inst_t *); - -#define VN_TRACE(vp) \ - vn_trace_ref(vp, __FILE__, __LINE__, (inst_t *)__return_address) +extern void vn_trace_entry(struct xfs_inode *, const char *, inst_t *); +extern void vn_trace_exit(struct xfs_inode *, const char *, inst_t *); +extern void vn_trace_hold(struct xfs_inode *, char *, int, inst_t *); +extern void vn_trace_ref(struct xfs_inode *, char *, int, inst_t *); +extern void vn_trace_rele(struct xfs_inode *, char *, int, inst_t *); #else #define vn_trace_entry(a,b,c) #define vn_trace_exit(a,b,c) #define vn_trace_hold(a,b,c,d) #define vn_trace_ref(a,b,c,d) #define vn_trace_rele(a,b,c,d) -#define VN_TRACE(vp) #endif #endif /* __XFS_VNODE_H__ */ diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index 6ff0f4de1630..b5f91281b707 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c @@ -288,45 +288,6 @@ xfs_qm_rele_quotafs_ref( } /* - * This is called at mount time from xfs_mountfs to initialize the quotainfo - * structure and start the global quota manager (xfs_Gqm) if it hasn't done - * so already. Note that the superblock has not been read in yet. - */ -void -xfs_qm_mount_quotainit( - xfs_mount_t *mp, - uint flags) -{ - /* - * User, projects or group quotas has to be on. - */ - ASSERT(flags & (XFSMNT_UQUOTA | XFSMNT_PQUOTA | XFSMNT_GQUOTA)); - - /* - * Initialize the flags in the mount structure. From this point - * onwards we look at m_qflags to figure out if quotas's ON/OFF, etc. - * Note that we enforce nothing if accounting is off. - * ie. XFSMNT_*QUOTA must be ON for XFSMNT_*QUOTAENF. - * It isn't necessary to take the quotaoff lock to do this; this is - * called from mount. - */ - if (flags & XFSMNT_UQUOTA) { - mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE); - if (flags & XFSMNT_UQUOTAENF) - mp->m_qflags |= XFS_UQUOTA_ENFD; - } - if (flags & XFSMNT_GQUOTA) { - mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE); - if (flags & XFSMNT_GQUOTAENF) - mp->m_qflags |= XFS_OQUOTA_ENFD; - } else if (flags & XFSMNT_PQUOTA) { - mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE); - if (flags & XFSMNT_PQUOTAENF) - mp->m_qflags |= XFS_OQUOTA_ENFD; - } -} - -/* * Just destroy the quotainfo structure. */ void @@ -1039,7 +1000,7 @@ xfs_qm_dqdetach( int xfs_qm_sync( xfs_mount_t *mp, - short flags) + int flags) { int recl, restarts; xfs_dquot_t *dqp; @@ -1717,7 +1678,6 @@ xfs_qm_get_rtblks( xfs_extnum_t idx; /* extent record index */ xfs_ifork_t *ifp; /* inode fork pointer */ xfs_extnum_t nextents; /* number of extent entries */ - xfs_bmbt_rec_t *ep; /* pointer to an extent entry */ int error; ASSERT(XFS_IS_REALTIME_INODE(ip)); @@ -1728,10 +1688,8 @@ xfs_qm_get_rtblks( } rtblks = 0; nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); - for (idx = 0; idx < nextents; idx++) { - ep = xfs_iext_get_ext(ifp, idx); - rtblks += xfs_bmbt_get_blockcount(ep); - } + for (idx = 0; idx < nextents; idx++) + rtblks += xfs_bmbt_get_blockcount(xfs_iext_get_ext(ifp, idx)); *O_rtblks = (xfs_qcnt_t)rtblks; return 0; } @@ -2459,8 +2417,7 @@ xfs_qm_vop_dqalloc( lockflags = XFS_ILOCK_EXCL; xfs_ilock(ip, lockflags); - if ((flags & XFS_QMOPT_INHERIT) && - XFS_INHERIT_GID(ip, XFS_MTOVFS(mp))) + if ((flags & XFS_QMOPT_INHERIT) && XFS_INHERIT_GID(ip)) gid = ip->i_d.di_gid; /* diff --git a/fs/xfs/quota/xfs_qm.h b/fs/xfs/quota/xfs_qm.h index 689407de0a20..23ccaa5fceaf 100644 --- a/fs/xfs/quota/xfs_qm.h +++ b/fs/xfs/quota/xfs_qm.h @@ -166,12 +166,11 @@ typedef struct xfs_dquot_acct { extern void xfs_qm_destroy_quotainfo(xfs_mount_t *); extern int xfs_qm_mount_quotas(xfs_mount_t *, int); -extern void xfs_qm_mount_quotainit(xfs_mount_t *, uint); extern int xfs_qm_quotacheck(xfs_mount_t *); extern void xfs_qm_unmount_quotadestroy(xfs_mount_t *); extern int xfs_qm_unmount_quotas(xfs_mount_t *); extern int xfs_qm_write_sb_changes(xfs_mount_t *, __int64_t); -extern int xfs_qm_sync(xfs_mount_t *, short); +extern int xfs_qm_sync(xfs_mount_t *, int); /* dquot stuff */ extern boolean_t xfs_qm_dqalloc_incore(xfs_dquot_t **); @@ -199,7 +198,8 @@ extern void xfs_qm_freelist_unlink(xfs_dquot_t *); extern int xfs_qm_freelist_lock_nowait(xfs_qm_t *); /* system call interface */ -extern int xfs_qm_quotactl(bhv_desc_t *, int, int, xfs_caddr_t); +extern int xfs_qm_quotactl(struct xfs_mount *, int, int, + xfs_caddr_t); #ifdef DEBUG extern int xfs_qm_internalqcheck(xfs_mount_t *); diff --git a/fs/xfs/quota/xfs_qm_bhv.c b/fs/xfs/quota/xfs_qm_bhv.c index d2cdb8a2aad6..97bb32937585 100644 --- a/fs/xfs/quota/xfs_qm_bhv.c +++ b/fs/xfs/quota/xfs_qm_bhv.c @@ -48,172 +48,13 @@ #include "xfs_buf_item.h" #include "xfs_qm.h" -#define MNTOPT_QUOTA "quota" /* disk quotas (user) */ -#define MNTOPT_NOQUOTA "noquota" /* no quotas */ -#define MNTOPT_USRQUOTA "usrquota" /* user quota enabled */ -#define MNTOPT_GRPQUOTA "grpquota" /* group quota enabled */ -#define MNTOPT_PRJQUOTA "prjquota" /* project quota enabled */ -#define MNTOPT_UQUOTA "uquota" /* user quota (IRIX variant) */ -#define MNTOPT_GQUOTA "gquota" /* group quota (IRIX variant) */ -#define MNTOPT_PQUOTA "pquota" /* project quota (IRIX variant) */ -#define MNTOPT_UQUOTANOENF "uqnoenforce"/* user quota limit enforcement */ -#define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */ -#define MNTOPT_PQUOTANOENF "pqnoenforce"/* project quota limit enforcement */ -#define MNTOPT_QUOTANOENF "qnoenforce" /* same as uqnoenforce */ -STATIC int -xfs_qm_parseargs( - struct bhv_desc *bhv, - char *options, - struct xfs_mount_args *args, - int update) -{ - size_t length; - char *local_options = options; - char *this_char; - int error; - int referenced = update; - - while ((this_char = strsep(&local_options, ",")) != NULL) { - length = strlen(this_char); - if (local_options) - length++; - - if (!strcmp(this_char, MNTOPT_NOQUOTA)) { - args->flags &= ~(XFSMNT_UQUOTAENF|XFSMNT_UQUOTA); - args->flags &= ~(XFSMNT_GQUOTAENF|XFSMNT_GQUOTA); - referenced = update; - } else if (!strcmp(this_char, MNTOPT_QUOTA) || - !strcmp(this_char, MNTOPT_UQUOTA) || - !strcmp(this_char, MNTOPT_USRQUOTA)) { - args->flags |= XFSMNT_UQUOTA | XFSMNT_UQUOTAENF; - referenced = 1; - } else if (!strcmp(this_char, MNTOPT_QUOTANOENF) || - !strcmp(this_char, MNTOPT_UQUOTANOENF)) { - args->flags |= XFSMNT_UQUOTA; - args->flags &= ~XFSMNT_UQUOTAENF; - referenced = 1; - } else if (!strcmp(this_char, MNTOPT_PQUOTA) || - !strcmp(this_char, MNTOPT_PRJQUOTA)) { - args->flags |= XFSMNT_PQUOTA | XFSMNT_PQUOTAENF; - referenced = 1; - } else if (!strcmp(this_char, MNTOPT_PQUOTANOENF)) { - args->flags |= XFSMNT_PQUOTA; - args->flags &= ~XFSMNT_PQUOTAENF; - referenced = 1; - } else if (!strcmp(this_char, MNTOPT_GQUOTA) || - !strcmp(this_char, MNTOPT_GRPQUOTA)) { - args->flags |= XFSMNT_GQUOTA | XFSMNT_GQUOTAENF; - referenced = 1; - } else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) { - args->flags |= XFSMNT_GQUOTA; - args->flags &= ~XFSMNT_GQUOTAENF; - referenced = 1; - } else { - if (local_options) - *(local_options-1) = ','; - continue; - } - - while (length--) - *this_char++ = ','; - } - - if ((args->flags & XFSMNT_GQUOTA) && (args->flags & XFSMNT_PQUOTA)) { - cmn_err(CE_WARN, - "XFS: cannot mount with both project and group quota"); - return XFS_ERROR(EINVAL); - } - - error = bhv_next_vfs_parseargs(BHV_NEXT(bhv), options, args, update); - if (!error && !referenced) - bhv_remove_vfsops(bhvtovfs(bhv), VFS_POSITION_QM); - return error; -} - -STATIC int -xfs_qm_showargs( - struct bhv_desc *bhv, - struct seq_file *m) -{ - struct bhv_vfs *vfsp = bhvtovfs(bhv); - struct xfs_mount *mp = XFS_VFSTOM(vfsp); - - if (mp->m_qflags & XFS_UQUOTA_ACCT) { - (mp->m_qflags & XFS_UQUOTA_ENFD) ? - seq_puts(m, "," MNTOPT_USRQUOTA) : - seq_puts(m, "," MNTOPT_UQUOTANOENF); - } - - if (mp->m_qflags & XFS_PQUOTA_ACCT) { - (mp->m_qflags & XFS_OQUOTA_ENFD) ? - seq_puts(m, "," MNTOPT_PRJQUOTA) : - seq_puts(m, "," MNTOPT_PQUOTANOENF); - } - - if (mp->m_qflags & XFS_GQUOTA_ACCT) { - (mp->m_qflags & XFS_OQUOTA_ENFD) ? - seq_puts(m, "," MNTOPT_GRPQUOTA) : - seq_puts(m, "," MNTOPT_GQUOTANOENF); - } - - if (!(mp->m_qflags & XFS_ALL_QUOTA_ACCT)) - seq_puts(m, "," MNTOPT_NOQUOTA); - - return bhv_next_vfs_showargs(BHV_NEXT(bhv), m); -} - -STATIC int -xfs_qm_mount( - struct bhv_desc *bhv, - struct xfs_mount_args *args, - struct cred *cr) -{ - struct bhv_vfs *vfsp = bhvtovfs(bhv); - struct xfs_mount *mp = XFS_VFSTOM(vfsp); - - if (args->flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA | XFSMNT_PQUOTA)) - xfs_qm_mount_quotainit(mp, args->flags); - return bhv_next_vfs_mount(BHV_NEXT(bhv), args, cr); -} - -/* - * Directory tree accounting is implemented using project quotas, where - * the project identifier is inherited from parent directories. - * A statvfs (df, etc.) of a directory that is using project quota should - * return a statvfs of the project, not the entire filesystem. - * This makes such trees appear as if they are filesystems in themselves. - */ -STATIC int -xfs_qm_statvfs( - struct bhv_desc *bhv, +STATIC void +xfs_fill_statvfs_from_dquot( bhv_statvfs_t *statp, - struct bhv_vnode *vnode) + xfs_disk_dquot_t *dp) { - xfs_mount_t *mp; - xfs_inode_t *ip; - xfs_dquot_t *dqp; - xfs_disk_dquot_t *dp; __uint64_t limit; - int error; - - error = bhv_next_vfs_statvfs(BHV_NEXT(bhv), statp, vnode); - if (error || !vnode) - return error; - - mp = xfs_vfstom(bhvtovfs(bhv)); - ip = xfs_vtoi(vnode); - - if (!(ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)) - return 0; - if (!(mp->m_qflags & XFS_PQUOTA_ACCT)) - return 0; - if (!(mp->m_qflags & XFS_OQUOTA_ENFD)) - return 0; - - if (xfs_qm_dqget(mp, NULL, ip->i_d.di_projid, XFS_DQ_PROJ, 0, &dqp)) - return 0; - dp = &dqp->q_core; limit = dp->d_blk_softlimit ? be64_to_cpu(dp->d_blk_softlimit) : @@ -234,37 +75,35 @@ xfs_qm_statvfs( (statp->f_files > be64_to_cpu(dp->d_icount)) ? (statp->f_ffree - be64_to_cpu(dp->d_icount)) : 0; } - - xfs_qm_dqput(dqp); - return 0; } -STATIC int -xfs_qm_syncall( - struct bhv_desc *bhv, - int flags, - cred_t *credp) + +/* + * Directory tree accounting is implemented using project quotas, where + * the project identifier is inherited from parent directories. + * A statvfs (df, etc.) of a directory that is using project quota should + * return a statvfs of the project, not the entire filesystem. + * This makes such trees appear as if they are filesystems in themselves. + */ +STATIC void +xfs_qm_statvfs( + xfs_inode_t *ip, + bhv_statvfs_t *statp) { - struct bhv_vfs *vfsp = bhvtovfs(bhv); - struct xfs_mount *mp = XFS_VFSTOM(vfsp); - int error; + xfs_mount_t *mp = ip->i_mount; + xfs_dquot_t *dqp; - /* - * Get the Quota Manager to flush the dquots. - */ - if (XFS_IS_QUOTA_ON(mp)) { - if ((error = xfs_qm_sync(mp, flags))) { - /* - * If we got an IO error, we will be shutting down. - * So, there's nothing more for us to do here. - */ - ASSERT(error != EIO || XFS_FORCED_SHUTDOWN(mp)); - if (XFS_FORCED_SHUTDOWN(mp)) { - return XFS_ERROR(error); - } - } + if (!(ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) || + !((mp->m_qflags & (XFS_PQUOTA_ACCT|XFS_OQUOTA_ENFD))) == + (XFS_PQUOTA_ACCT|XFS_OQUOTA_ENFD)) + return; + + if (!xfs_qm_dqget(mp, NULL, ip->i_d.di_projid, XFS_DQ_PROJ, 0, &dqp)) { + xfs_disk_dquot_t *dp = &dqp->q_core; + + xfs_fill_statvfs_from_dquot(statp, dp); + xfs_qm_dqput(dqp); } - return bhv_next_vfs_sync(BHV_NEXT(bhv), flags, credp); } STATIC int @@ -382,7 +221,7 @@ xfs_qm_dqrele_null( } -static struct xfs_qmops xfs_qmcore_xfs = { +struct xfs_qmops xfs_qmcore_xfs = { .xfs_qminit = xfs_qm_newmount, .xfs_qmdone = xfs_qm_unmount_quotadestroy, .xfs_qmmount = xfs_qm_endmount, @@ -396,36 +235,24 @@ static struct xfs_qmops xfs_qmcore_xfs = { .xfs_dqvoprename = xfs_qm_vop_rename_dqattach, .xfs_dqvopchown = xfs_qm_vop_chown, .xfs_dqvopchownresv = xfs_qm_vop_chown_reserve, + .xfs_dqstatvfs = xfs_qm_statvfs, + .xfs_dqsync = xfs_qm_sync, + .xfs_quotactl = xfs_qm_quotactl, .xfs_dqtrxops = &xfs_trans_dquot_ops, }; - -struct bhv_module_vfsops xfs_qmops = { { - BHV_IDENTITY_INIT(VFS_BHV_QM, VFS_POSITION_QM), - .vfs_parseargs = xfs_qm_parseargs, - .vfs_showargs = xfs_qm_showargs, - .vfs_mount = xfs_qm_mount, - .vfs_statvfs = xfs_qm_statvfs, - .vfs_sync = xfs_qm_syncall, - .vfs_quotactl = xfs_qm_quotactl, }, -}; - +EXPORT_SYMBOL(xfs_qmcore_xfs); void __init xfs_qm_init(void) { - static char message[] __initdata = - KERN_INFO "SGI XFS Quota Management subsystem\n"; - - printk(message); + printk(KERN_INFO "SGI XFS Quota Management subsystem\n"); mutex_init(&xfs_Gqm_lock); - vfs_bhv_set_custom(&xfs_qmops, &xfs_qmcore_xfs); xfs_qm_init_procfs(); } void __exit xfs_qm_exit(void) { - vfs_bhv_clr_custom(&xfs_qmops); xfs_qm_cleanup_procfs(); if (qm_dqzone) kmem_zone_destroy(qm_dqzone); diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c index 2df67fd913e5..ad5579d4eac4 100644 --- a/fs/xfs/quota/xfs_qm_syscalls.c +++ b/fs/xfs/quota/xfs_qm_syscalls.c @@ -81,18 +81,13 @@ STATIC void xfs_qm_export_dquot(xfs_mount_t *, xfs_disk_dquot_t *, */ int xfs_qm_quotactl( - struct bhv_desc *bdp, + xfs_mount_t *mp, int cmd, int id, xfs_caddr_t addr) { - xfs_mount_t *mp; - bhv_vfs_t *vfsp; int error; - vfsp = bhvtovfs(bdp); - mp = XFS_VFSTOM(vfsp); - ASSERT(addr != NULL || cmd == Q_XQUOTASYNC); /* @@ -105,7 +100,7 @@ xfs_qm_quotactl( */ if (XFS_IS_QUOTA_ON(mp)) return XFS_ERROR(EINVAL); - if (vfsp->vfs_flag & VFS_RDONLY) + if (mp->m_flags & XFS_MOUNT_RDONLY) return XFS_ERROR(EROFS); return (xfs_qm_scall_trunc_qfiles(mp, xfs_qm_import_qtype_flags(*(uint *)addr))); @@ -121,13 +116,13 @@ xfs_qm_quotactl( * QUOTAON - enabling quota enforcement. * Quota accounting must be turned on at mount time. */ - if (vfsp->vfs_flag & VFS_RDONLY) + if (mp->m_flags & XFS_MOUNT_RDONLY) return XFS_ERROR(EROFS); return (xfs_qm_scall_quotaon(mp, xfs_qm_import_flags(*(uint *)addr))); case Q_XQUOTAOFF: - if (vfsp->vfs_flag & VFS_RDONLY) + if (mp->m_flags & XFS_MOUNT_RDONLY) return XFS_ERROR(EROFS); break; @@ -143,7 +138,7 @@ xfs_qm_quotactl( switch (cmd) { case Q_XQUOTAOFF: - if (vfsp->vfs_flag & VFS_RDONLY) + if (mp->m_flags & XFS_MOUNT_RDONLY) return XFS_ERROR(EROFS); error = xfs_qm_scall_quotaoff(mp, xfs_qm_import_flags(*(uint *)addr), @@ -164,19 +159,19 @@ xfs_qm_quotactl( break; case Q_XSETQLIM: - if (vfsp->vfs_flag & VFS_RDONLY) + if (mp->m_flags & XFS_MOUNT_RDONLY) return XFS_ERROR(EROFS); error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_USER, (fs_disk_quota_t *)addr); break; case Q_XSETGQLIM: - if (vfsp->vfs_flag & VFS_RDONLY) + if (mp->m_flags & XFS_MOUNT_RDONLY) return XFS_ERROR(EROFS); error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_GROUP, (fs_disk_quota_t *)addr); break; case Q_XSETPQLIM: - if (vfsp->vfs_flag & VFS_RDONLY) + if (mp->m_flags & XFS_MOUNT_RDONLY) return XFS_ERROR(EROFS); error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_PROJ, (fs_disk_quota_t *)addr); diff --git a/fs/xfs/support/move.c b/fs/xfs/support/move.c deleted file mode 100644 index ac8617ca3909..000000000000 --- a/fs/xfs/support/move.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include <xfs.h> - -/* Read from kernel buffer at src to user/kernel buffer defined - * by the uio structure. Advance the pointer in the uio struct - * as we go. - */ -int -xfs_uio_read(caddr_t src, size_t len, struct uio *uio) -{ - size_t count; - - if (!len || !uio->uio_resid) - return 0; - - count = uio->uio_iov->iov_len; - if (!count) - return 0; - if (count > len) - count = len; - - if (uio->uio_segflg == UIO_USERSPACE) { - if (copy_to_user(uio->uio_iov->iov_base, src, count)) - return EFAULT; - } else { - ASSERT(uio->uio_segflg == UIO_SYSSPACE); - memcpy(uio->uio_iov->iov_base, src, count); - } - - uio->uio_iov->iov_base = (void*)((char*)uio->uio_iov->iov_base + count); - uio->uio_iov->iov_len -= count; - uio->uio_offset += count; - uio->uio_resid -= count; - return 0; -} diff --git a/fs/xfs/support/move.h b/fs/xfs/support/move.h deleted file mode 100644 index 324e413deadd..000000000000 --- a/fs/xfs/support/move.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Portions Copyright (c) 1982, 1986, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#ifndef __XFS_SUPPORT_MOVE_H__ -#define __XFS_SUPPORT_MOVE_H__ - -#include <linux/uio.h> -#include <asm/uaccess.h> - -/* Segment flag values. */ -enum uio_seg { - UIO_USERSPACE, /* from user data space */ - UIO_SYSSPACE, /* from system space */ -}; - -struct uio { - struct kvec *uio_iov; /* pointer to array of iovecs */ - int uio_iovcnt; /* number of iovecs in array */ - xfs_off_t uio_offset; /* offset in file this uio corresponds to */ - int uio_resid; /* residual i/o count */ - enum uio_seg uio_segflg; /* see above */ -}; - -typedef struct uio uio_t; -typedef struct kvec iovec_t; - -extern int xfs_uio_read (caddr_t, size_t, uio_t *); - -#endif /* __XFS_SUPPORT_MOVE_H__ */ diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c index 4ca4beb7bb54..5bfb66f33caf 100644 --- a/fs/xfs/xfs_acl.c +++ b/fs/xfs/xfs_acl.c @@ -32,6 +32,7 @@ #include "xfs_btree.h" #include "xfs_acl.h" #include "xfs_attr.h" +#include "xfs_vnodeops.h" #include <linux/capability.h> #include <linux/posix_acl_xattr.h> @@ -241,7 +242,7 @@ xfs_acl_vget( bhv_vattr_t va; va.va_mask = XFS_AT_MODE; - error = bhv_vop_getattr(vp, &va, 0, sys_cred); + error = xfs_getattr(xfs_vtoi(vp), &va, 0); if (error) goto out; xfs_acl_sync_mode(va.va_mode, xfs_acl); @@ -265,9 +266,10 @@ xfs_acl_vremove( VN_HOLD(vp); error = xfs_acl_allow_set(vp, kind); if (!error) { - error = bhv_vop_attr_remove(vp, kind == _ACL_TYPE_DEFAULT? + error = xfs_attr_remove(xfs_vtoi(vp), + kind == _ACL_TYPE_DEFAULT? SGI_ACL_DEFAULT: SGI_ACL_FILE, - ATTR_ROOT, sys_cred); + ATTR_ROOT); if (error == ENOATTR) error = 0; /* 'scool */ } @@ -370,17 +372,18 @@ xfs_acl_allow_set( bhv_vnode_t *vp, int kind) { + xfs_inode_t *ip = xfs_vtoi(vp); bhv_vattr_t va; int error; - if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND)) + if (vp->i_flags & (S_IMMUTABLE|S_APPEND)) return EPERM; if (kind == _ACL_TYPE_DEFAULT && !VN_ISDIR(vp)) return ENOTDIR; - if (vp->v_vfsp->vfs_flag & VFS_RDONLY) + if (vp->i_sb->s_flags & MS_RDONLY) return EROFS; va.va_mask = XFS_AT_UID; - error = bhv_vop_getattr(vp, &va, 0, NULL); + error = xfs_getattr(ip, &va, 0); if (error) return error; if (va.va_uid != current->fsuid && !capable(CAP_FOWNER)) @@ -613,7 +616,8 @@ xfs_acl_get_attr( ASSERT((flags & ATTR_KERNOVAL) ? (aclp == NULL) : 1); flags |= ATTR_ROOT; - *error = bhv_vop_attr_get(vp, kind == _ACL_TYPE_ACCESS ? + *error = xfs_attr_get(xfs_vtoi(vp), + kind == _ACL_TYPE_ACCESS ? SGI_ACL_FILE : SGI_ACL_DEFAULT, (char *)aclp, &len, flags, sys_cred); if (*error || (flags & ATTR_KERNOVAL)) @@ -651,9 +655,10 @@ xfs_acl_set_attr( INT_SET(newace->ae_perm, ARCH_CONVERT, ace->ae_perm); } INT_SET(newacl->acl_cnt, ARCH_CONVERT, aclp->acl_cnt); - *error = bhv_vop_attr_set(vp, kind == _ACL_TYPE_ACCESS ? + *error = xfs_attr_set(xfs_vtoi(vp), + kind == _ACL_TYPE_ACCESS ? SGI_ACL_FILE: SGI_ACL_DEFAULT, - (char *)newacl, len, ATTR_ROOT, sys_cred); + (char *)newacl, len, ATTR_ROOT); _ACL_FREE(newacl); } @@ -675,7 +680,7 @@ xfs_acl_vtoacl( if (!error) { /* Got the ACL, need the mode... */ va.va_mask = XFS_AT_MODE; - error = bhv_vop_getattr(vp, &va, 0, sys_cred); + error = xfs_getattr(xfs_vtoi(vp), &va, 0); } if (error) @@ -699,7 +704,7 @@ xfs_acl_vtoacl( int xfs_acl_inherit( bhv_vnode_t *vp, - bhv_vattr_t *vap, + mode_t mode, xfs_acl_t *pdaclp) { xfs_acl_t *cacl; @@ -727,7 +732,7 @@ xfs_acl_inherit( return ENOMEM; memcpy(cacl, pdaclp, sizeof(xfs_acl_t)); - xfs_acl_filter_mode(vap->va_mode, cacl); + xfs_acl_filter_mode(mode, cacl); xfs_acl_setmode(vp, cacl, &basicperms); /* @@ -773,7 +778,7 @@ xfs_acl_setmode( * mode. The m:: bits take precedence over the g:: bits. */ va.va_mask = XFS_AT_MODE; - error = bhv_vop_getattr(vp, &va, 0, sys_cred); + error = xfs_getattr(xfs_vtoi(vp), &va, 0); if (error) return error; @@ -807,7 +812,7 @@ xfs_acl_setmode( if (gap && nomask) va.va_mode |= gap->ae_perm << 3; - return bhv_vop_setattr(vp, &va, 0, sys_cred); + return xfs_setattr(xfs_vtoi(vp), &va, 0, sys_cred); } /* diff --git a/fs/xfs/xfs_acl.h b/fs/xfs/xfs_acl.h index f853cf1a6270..34b7d3391299 100644 --- a/fs/xfs/xfs_acl.h +++ b/fs/xfs/xfs_acl.h @@ -50,7 +50,6 @@ typedef struct xfs_acl { #ifdef CONFIG_XFS_POSIX_ACL struct vattr; -struct bhv_vnode; struct xfs_inode; extern struct kmem_zone *xfs_acl_zone; @@ -58,20 +57,20 @@ extern struct kmem_zone *xfs_acl_zone; (zone) = kmem_zone_init(sizeof(xfs_acl_t), (name)) #define xfs_acl_zone_destroy(zone) kmem_zone_destroy(zone) -extern int xfs_acl_inherit(struct bhv_vnode *, struct bhv_vattr *, xfs_acl_t *); +extern int xfs_acl_inherit(bhv_vnode_t *, mode_t mode, xfs_acl_t *); extern int xfs_acl_iaccess(struct xfs_inode *, mode_t, cred_t *); -extern int xfs_acl_vtoacl(struct bhv_vnode *, xfs_acl_t *, xfs_acl_t *); -extern int xfs_acl_vhasacl_access(struct bhv_vnode *); -extern int xfs_acl_vhasacl_default(struct bhv_vnode *); -extern int xfs_acl_vset(struct bhv_vnode *, void *, size_t, int); -extern int xfs_acl_vget(struct bhv_vnode *, void *, size_t, int); -extern int xfs_acl_vremove(struct bhv_vnode *, int); +extern int xfs_acl_vtoacl(bhv_vnode_t *, xfs_acl_t *, xfs_acl_t *); +extern int xfs_acl_vhasacl_access(bhv_vnode_t *); +extern int xfs_acl_vhasacl_default(bhv_vnode_t *); +extern int xfs_acl_vset(bhv_vnode_t *, void *, size_t, int); +extern int xfs_acl_vget(bhv_vnode_t *, void *, size_t, int); +extern int xfs_acl_vremove(bhv_vnode_t *, int); #define _ACL_TYPE_ACCESS 1 #define _ACL_TYPE_DEFAULT 2 #define _ACL_PERM_INVALID(perm) ((perm) & ~(ACL_READ|ACL_WRITE|ACL_EXECUTE)) -#define _ACL_INHERIT(c,v,d) (xfs_acl_inherit(c,v,d)) +#define _ACL_INHERIT(c,m,d) (xfs_acl_inherit(c,m,d)) #define _ACL_GET_ACCESS(pv,pa) (xfs_acl_vtoacl(pv,pa,NULL) == 0) #define _ACL_GET_DEFAULT(pv,pd) (xfs_acl_vtoacl(pv,NULL,pd) == 0) #define _ACL_ACCESS_EXISTS xfs_acl_vhasacl_access @@ -91,7 +90,7 @@ extern int xfs_acl_vremove(struct bhv_vnode *, int); #define xfs_acl_vhasacl_default(v) (0) #define _ACL_ALLOC(a) (1) /* successfully allocate nothing */ #define _ACL_FREE(a) ((void)0) -#define _ACL_INHERIT(c,v,d) (0) +#define _ACL_INHERIT(c,m,d) (0) #define _ACL_GET_ACCESS(pv,pa) (0) #define _ACL_GET_DEFAULT(pv,pd) (0) #define _ACL_ACCESS_EXISTS (NULL) diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h index 51c09c114a20..9381b0360c4b 100644 --- a/fs/xfs/xfs_ag.h +++ b/fs/xfs/xfs_ag.h @@ -197,6 +197,10 @@ typedef struct xfs_perag #endif xfs_perag_busy_t *pagb_list; /* unstable blocks */ atomic_t pagf_fstrms; /* # of filestreams active in this AG */ + + int pag_ici_init; /* incore inode cache initialised */ + rwlock_t pag_ici_lock; /* incore inode lock */ + struct radix_tree_root pag_ici_root; /* incore inode cache root */ } xfs_perag_t; #define XFS_AG_MAXLEVELS(mp) ((mp)->m_ag_maxlevels) diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index 7ce44a7b88a2..93fa64dd1be6 100644 --- a/fs/xfs/xfs_attr.c +++ b/fs/xfs/xfs_attr.c @@ -49,6 +49,7 @@ #include "xfs_trans_space.h" #include "xfs_acl.h" #include "xfs_rw.h" +#include "xfs_vnodeops.h" /* * xfs_attr.c @@ -156,10 +157,14 @@ xfs_attr_fetch(xfs_inode_t *ip, const char *name, int namelen, } int -xfs_attr_get(bhv_desc_t *bdp, const char *name, char *value, int *valuelenp, - int flags, struct cred *cred) +xfs_attr_get( + xfs_inode_t *ip, + const char *name, + char *value, + int *valuelenp, + int flags, + cred_t *cred) { - xfs_inode_t *ip = XFS_BHVTOI(bdp); int error, namelen; XFS_STATS_INC(xs_attr_get); @@ -417,10 +422,13 @@ out: } int -xfs_attr_set(bhv_desc_t *bdp, const char *name, char *value, int valuelen, int flags, - struct cred *cred) +xfs_attr_set( + xfs_inode_t *dp, + const char *name, + char *value, + int valuelen, + int flags) { - xfs_inode_t *dp; int namelen; namelen = strlen(name); @@ -429,7 +437,6 @@ xfs_attr_set(bhv_desc_t *bdp, const char *name, char *value, int valuelen, int f XFS_STATS_INC(xs_attr_set); - dp = XFS_BHVTOI(bdp); if (XFS_FORCED_SHUTDOWN(dp->i_mount)) return (EIO); @@ -563,10 +570,12 @@ out: } int -xfs_attr_remove(bhv_desc_t *bdp, const char *name, int flags, struct cred *cred) +xfs_attr_remove( + xfs_inode_t *dp, + const char *name, + int flags) { - xfs_inode_t *dp; - int namelen; + int namelen; namelen = strlen(name); if (namelen >= MAXNAMELEN) @@ -574,7 +583,6 @@ xfs_attr_remove(bhv_desc_t *bdp, const char *name, int flags, struct cred *cred) XFS_STATS_INC(xs_attr_remove); - dp = XFS_BHVTOI(bdp); if (XFS_FORCED_SHUTDOWN(dp->i_mount)) return (EIO); @@ -702,11 +710,14 @@ xfs_attr_kern_list_sizes(xfs_attr_list_context_t *context, attrnames_t *namesp, * success. */ int -xfs_attr_list(bhv_desc_t *bdp, char *buffer, int bufsize, int flags, - attrlist_cursor_kern_t *cursor, struct cred *cred) +xfs_attr_list( + xfs_inode_t *dp, + char *buffer, + int bufsize, + int flags, + attrlist_cursor_kern_t *cursor) { xfs_attr_list_context_t context; - xfs_inode_t *dp; int error; XFS_STATS_INC(xs_attr_list); @@ -731,7 +742,7 @@ xfs_attr_list(bhv_desc_t *bdp, char *buffer, int bufsize, int flags, /* * Initialize the output buffer. */ - context.dp = dp = XFS_BHVTOI(bdp); + context.dp = dp; context.cursor = cursor; context.count = 0; context.dupcnt = 0; @@ -2502,7 +2513,7 @@ STATIC int attr_generic_set( bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) { - return -bhv_vop_attr_set(vp, name, data, size, xflags, NULL); + return -xfs_attr_set(xfs_vtoi(vp), name, data, size, xflags); } STATIC int @@ -2511,7 +2522,8 @@ attr_generic_get( { int error, asize = size; - error = bhv_vop_attr_get(vp, name, data, &asize, xflags, NULL); + error = xfs_attr_get(xfs_vtoi(vp), name, data, + &asize, xflags, NULL); if (!error) return asize; return -error; @@ -2521,7 +2533,7 @@ STATIC int attr_generic_remove( bhv_vnode_t *vp, char *name, int xflags) { - return -bhv_vop_attr_remove(vp, name, xflags, NULL); + return -xfs_attr_remove(xfs_vtoi(vp), name, xflags); } STATIC int @@ -2576,7 +2588,7 @@ attr_generic_list( attrlist_cursor_kern_t cursor = { 0 }; int error; - error = bhv_vop_attr_list(vp, data, size, xflags, &cursor, NULL); + error = xfs_attr_list(xfs_vtoi(vp), data, size, xflags, &cursor); if (error > 0) return -error; *result = -error; diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h index 783977d3ea71..786eba3121c4 100644 --- a/fs/xfs/xfs_attr.h +++ b/fs/xfs/xfs_attr.h @@ -36,14 +36,13 @@ *========================================================================*/ struct cred; -struct bhv_vnode; struct xfs_attr_list_context; -typedef int (*attrset_t)(struct bhv_vnode *, char *, void *, size_t, int); -typedef int (*attrget_t)(struct bhv_vnode *, char *, void *, size_t, int); -typedef int (*attrremove_t)(struct bhv_vnode *, char *, int); -typedef int (*attrexists_t)(struct bhv_vnode *); -typedef int (*attrcapable_t)(struct bhv_vnode *, struct cred *); +typedef int (*attrset_t)(bhv_vnode_t *, char *, void *, size_t, int); +typedef int (*attrget_t)(bhv_vnode_t *, char *, void *, size_t, int); +typedef int (*attrremove_t)(bhv_vnode_t *, char *, int); +typedef int (*attrexists_t)(bhv_vnode_t *); +typedef int (*attrcapable_t)(bhv_vnode_t *, struct cred *); typedef struct attrnames { char * attr_name; @@ -64,7 +63,7 @@ extern struct attrnames attr_trusted; extern struct attrnames *attr_namespaces[ATTR_NAMECOUNT]; extern attrnames_t *attr_lookup_namespace(char *, attrnames_t **, int); -extern int attr_generic_list(struct bhv_vnode *, void *, size_t, int, ssize_t *); +extern int attr_generic_list(bhv_vnode_t *, void *, size_t, int, ssize_t *); #define ATTR_DONTFOLLOW 0x0001 /* -- unused, from IRIX -- */ #define ATTR_ROOT 0x0002 /* use attrs in root (trusted) namespace */ @@ -159,12 +158,8 @@ struct xfs_da_args; /* * Overall external interface routines. */ -int xfs_attr_get(bhv_desc_t *, const char *, char *, int *, int, struct cred *); -int xfs_attr_set(bhv_desc_t *, const char *, char *, int, int, struct cred *); int xfs_attr_set_int(struct xfs_inode *, const char *, int, char *, int, int); -int xfs_attr_remove(bhv_desc_t *, const char *, int, struct cred *); int xfs_attr_remove_int(struct xfs_inode *, const char *, int, int); -int xfs_attr_list(bhv_desc_t *, char *, int, int, struct attrlist_cursor_kern *, struct cred *); int xfs_attr_list_int(struct xfs_attr_list_context *); int xfs_attr_inactive(struct xfs_inode *dp); diff --git a/fs/xfs/xfs_behavior.c b/fs/xfs/xfs_behavior.c deleted file mode 100644 index 0dc17219d412..000000000000 --- a/fs/xfs/xfs_behavior.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" - -/* - * Source file used to associate/disassociate behaviors with virtualized - * objects. See xfs_behavior.h for more information about behaviors, etc. - * - * The implementation is split between functions in this file and macros - * in xfs_behavior.h. - */ - -/* - * Insert a new behavior descriptor into a behavior chain. - * - * The behavior chain is ordered based on the 'position' number which - * lives in the first field of the ops vector (higher numbers first). - * - * Attempts to insert duplicate ops result in an EINVAL return code. - * Otherwise, return 0 to indicate success. - */ -int -bhv_insert(bhv_head_t *bhp, bhv_desc_t *bdp) -{ - bhv_desc_t *curdesc, *prev; - int position; - - /* - * Validate the position value of the new behavior. - */ - position = BHV_POSITION(bdp); - ASSERT(position >= BHV_POSITION_BASE && position <= BHV_POSITION_TOP); - - /* - * Find location to insert behavior. Check for duplicates. - */ - prev = NULL; - for (curdesc = bhp->bh_first; - curdesc != NULL; - curdesc = curdesc->bd_next) { - - /* Check for duplication. */ - if (curdesc->bd_ops == bdp->bd_ops) { - ASSERT(0); - return EINVAL; - } - - /* Find correct position */ - if (position >= BHV_POSITION(curdesc)) { - ASSERT(position != BHV_POSITION(curdesc)); - break; /* found it */ - } - - prev = curdesc; - } - - if (prev == NULL) { - /* insert at front of chain */ - bdp->bd_next = bhp->bh_first; - bhp->bh_first = bdp; - } else { - /* insert after prev */ - bdp->bd_next = prev->bd_next; - prev->bd_next = bdp; - } - - return 0; -} - -/* - * Remove a behavior descriptor from a position in a behavior chain; - * the position is guaranteed not to be the first position. - * Should only be called by the bhv_remove() macro. - */ -void -bhv_remove_not_first(bhv_head_t *bhp, bhv_desc_t *bdp) -{ - bhv_desc_t *curdesc, *prev; - - ASSERT(bhp->bh_first != NULL); - ASSERT(bhp->bh_first->bd_next != NULL); - - prev = bhp->bh_first; - for (curdesc = bhp->bh_first->bd_next; - curdesc != NULL; - curdesc = curdesc->bd_next) { - - if (curdesc == bdp) - break; /* found it */ - prev = curdesc; - } - - ASSERT(curdesc == bdp); - prev->bd_next = bdp->bd_next; /* remove from after prev */ -} - -/* - * Looks for the first behavior within a specified range of positions. - * Return the associated behavior descriptor. Or NULL, if none found. - */ -bhv_desc_t * -bhv_lookup_range(bhv_head_t *bhp, int low, int high) -{ - bhv_desc_t *curdesc; - - for (curdesc = bhp->bh_first; - curdesc != NULL; - curdesc = curdesc->bd_next) { - - int position = BHV_POSITION(curdesc); - - if (position <= high) { - if (position >= low) - return curdesc; - return NULL; - } - } - - return NULL; -} - -/* - * Return the base behavior in the chain, or NULL if the chain - * is empty. - * - * The caller has not read locked the behavior chain, so acquire the - * lock before traversing the chain. - */ -bhv_desc_t * -bhv_base(bhv_head_t *bhp) -{ - bhv_desc_t *curdesc; - - for (curdesc = bhp->bh_first; - curdesc != NULL; - curdesc = curdesc->bd_next) { - - if (curdesc->bd_next == NULL) { - return curdesc; - } - } - - return NULL; -} - -void -bhv_head_init( - bhv_head_t *bhp, - char *name) -{ - bhp->bh_first = NULL; -} - -void -bhv_insert_initial( - bhv_head_t *bhp, - bhv_desc_t *bdp) -{ - ASSERT(bhp->bh_first == NULL); - (bhp)->bh_first = bdp; -} - -void -bhv_head_destroy( - bhv_head_t *bhp) -{ - ASSERT(bhp->bh_first == NULL); -} diff --git a/fs/xfs/xfs_behavior.h b/fs/xfs/xfs_behavior.h deleted file mode 100644 index e7ca1fed955a..000000000000 --- a/fs/xfs/xfs_behavior.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_BEHAVIOR_H__ -#define __XFS_BEHAVIOR_H__ - -/* - * Header file used to associate behaviors with virtualized objects. - * - * A virtualized object is an internal, virtualized representation of - * OS entities such as persistent files, processes, or sockets. Examples - * of virtualized objects include vnodes, vprocs, and vsockets. Often - * a virtualized object is referred to simply as an "object." - * - * A behavior is essentially an implementation layer associated with - * an object. Multiple behaviors for an object are chained together, - * the order of chaining determining the order of invocation. Each - * behavior of a given object implements the same set of interfaces - * (e.g., the VOP interfaces). - * - * Behaviors may be dynamically inserted into an object's behavior chain, - * such that the addition is transparent to consumers that already have - * references to the object. Typically, a given behavior will be inserted - * at a particular location in the behavior chain. Insertion of new - * behaviors is synchronized with operations-in-progress (oip's) so that - * the oip's always see a consistent view of the chain. - * - * The term "interposition" is used to refer to the act of inserting - * a behavior such that it interposes on (i.e., is inserted in front - * of) a particular other behavior. A key example of this is when a - * system implementing distributed single system image wishes to - * interpose a distribution layer (providing distributed coherency) - * in front of an object that is otherwise only accessed locally. - * - * Note that the traditional vnode/inode combination is simply a virtualized - * object that has exactly one associated behavior. - * - * Behavior synchronization is logic which is necessary under certain - * circumstances that there is no conflict between ongoing operations - * traversing the behavior chain and those dynamically modifying the - * behavior chain. Because behavior synchronization adds extra overhead - * to virtual operation invocation, we want to restrict, as much as - * we can, the requirement for this extra code, to those situations - * in which it is truly necessary. - * - * Behavior synchronization is needed whenever there's at least one class - * of object in the system for which: - * 1) multiple behaviors for a given object are supported, - * -- AND -- - * 2a) insertion of a new behavior can happen dynamically at any time during - * the life of an active object, - * -- AND -- - * 3a) insertion of a new behavior needs to synchronize with existing - * ops-in-progress. - * -- OR -- - * 3b) multiple different behaviors can be dynamically inserted at - * any time during the life of an active object - * -- OR -- - * 3c) removal of a behavior can occur at any time during the life of - * an active object. - * -- OR -- - * 2b) removal of a behavior can occur at any time during the life of an - * active object - * - */ - -/* - * Behavior head. Head of the chain of behaviors. - * Contained within each virtualized object data structure. - */ -typedef struct bhv_head { - struct bhv_desc *bh_first; /* first behavior in chain */ -} bhv_head_t; - -/* - * Behavior descriptor. Descriptor associated with each behavior. - * Contained within the behavior's private data structure. - */ -typedef struct bhv_desc { - void *bd_pdata; /* private data for this behavior */ - void *bd_vobj; /* virtual object associated with */ - void *bd_ops; /* ops for this behavior */ - struct bhv_desc *bd_next; /* next behavior in chain */ -} bhv_desc_t; - -/* - * Behavior identity field. A behavior's identity determines the position - * where it lives within a behavior chain, and it's always the first field - * of the behavior's ops vector. The optional id field further identifies the - * subsystem responsible for the behavior. - */ -typedef struct bhv_identity { - __u16 bi_id; /* owning subsystem id */ - __u16 bi_position; /* position in chain */ -} bhv_identity_t; - -typedef bhv_identity_t bhv_position_t; - -#define BHV_IDENTITY_INIT(id,pos) {id, pos} -#define BHV_IDENTITY_INIT_POSITION(pos) BHV_IDENTITY_INIT(0, pos) - -/* - * Define boundaries of position values. - */ -#define BHV_POSITION_INVALID 0 /* invalid position number */ -#define BHV_POSITION_BASE 1 /* base (last) implementation layer */ -#define BHV_POSITION_TOP 63 /* top (first) implementation layer */ - -/* - * Plumbing macros. - */ -#define BHV_HEAD_FIRST(bhp) (ASSERT((bhp)->bh_first), (bhp)->bh_first) -#define BHV_NEXT(bdp) (ASSERT((bdp)->bd_next), (bdp)->bd_next) -#define BHV_NEXTNULL(bdp) ((bdp)->bd_next) -#define BHV_VOBJ(bdp) (ASSERT((bdp)->bd_vobj), (bdp)->bd_vobj) -#define BHV_VOBJNULL(bdp) ((bdp)->bd_vobj) -#define BHV_PDATA(bdp) (bdp)->bd_pdata -#define BHV_OPS(bdp) (bdp)->bd_ops -#define BHV_IDENTITY(bdp) ((bhv_identity_t *)(bdp)->bd_ops) -#define BHV_POSITION(bdp) (BHV_IDENTITY(bdp)->bi_position) - -extern void bhv_head_init(bhv_head_t *, char *); -extern void bhv_head_destroy(bhv_head_t *); -extern int bhv_insert(bhv_head_t *, bhv_desc_t *); -extern void bhv_insert_initial(bhv_head_t *, bhv_desc_t *); - -/* - * Initialize a new behavior descriptor. - * Arguments: - * bdp - pointer to behavior descriptor - * pdata - pointer to behavior's private data - * vobj - pointer to associated virtual object - * ops - pointer to ops for this behavior - */ -#define bhv_desc_init(bdp, pdata, vobj, ops) \ - { \ - (bdp)->bd_pdata = pdata; \ - (bdp)->bd_vobj = vobj; \ - (bdp)->bd_ops = ops; \ - (bdp)->bd_next = NULL; \ - } - -/* - * Remove a behavior descriptor from a behavior chain. - */ -#define bhv_remove(bhp, bdp) \ - { \ - if ((bhp)->bh_first == (bdp)) { \ - /* \ - * Remove from front of chain. \ - * Atomic wrt oip's. \ - */ \ - (bhp)->bh_first = (bdp)->bd_next; \ - } else { \ - /* remove from non-front of chain */ \ - bhv_remove_not_first(bhp, bdp); \ - } \ - (bdp)->bd_vobj = NULL; \ - } - -/* - * Behavior module prototypes. - */ -extern void bhv_remove_not_first(bhv_head_t *bhp, bhv_desc_t *bdp); -extern bhv_desc_t * bhv_lookup_range(bhv_head_t *bhp, int low, int high); -extern bhv_desc_t * bhv_base(bhv_head_t *bhp); - -/* No bhv locking on Linux */ -#define bhv_base_unlocked bhv_base - -#endif /* __XFS_BEHAVIOR_H__ */ diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 94b5c5fe2681..2e9b34b7344b 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c @@ -53,6 +53,7 @@ #include "xfs_trans_space.h" #include "xfs_buf_item.h" #include "xfs_filestream.h" +#include "xfs_vnodeops.h" #ifdef DEBUG @@ -248,7 +249,7 @@ xfs_bmap_local_to_extents( * Else, *lastxp will be set to the index of the found * entry; *gotp will contain the entry. */ -STATIC xfs_bmbt_rec_t * /* pointer to found extent entry */ +STATIC xfs_bmbt_rec_host_t * /* pointer to found extent entry */ xfs_bmap_search_extents( xfs_inode_t *ip, /* incore inode pointer */ xfs_fileoff_t bno, /* block number searched for */ @@ -273,21 +274,6 @@ xfs_bmap_isaeof( #ifdef XFS_BMAP_TRACE /* - * Add a bmap trace buffer entry. Base routine for the others. - */ -STATIC void -xfs_bmap_trace_addentry( - int opcode, /* operation */ - const char *fname, /* function name */ - char *desc, /* operation description */ - xfs_inode_t *ip, /* incore inode pointer */ - xfs_extnum_t idx, /* index of entry(ies) */ - xfs_extnum_t cnt, /* count of entries, 1 or 2 */ - xfs_bmbt_rec_t *r1, /* first record */ - xfs_bmbt_rec_t *r2, /* second record or null */ - int whichfork); /* data or attr fork */ - -/* * Add bmap trace entry prior to a call to xfs_iext_remove. */ STATIC void @@ -714,7 +700,7 @@ xfs_bmap_add_extent_delay_real( { xfs_btree_cur_t *cur; /* btree cursor */ int diff; /* temp value */ - xfs_bmbt_rec_t *ep; /* extent entry for idx */ + xfs_bmbt_rec_host_t *ep; /* extent entry for idx */ int error; /* error return value */ int i; /* temp state */ xfs_ifork_t *ifp; /* inode fork pointer */ @@ -1270,7 +1256,7 @@ xfs_bmap_add_extent_unwritten_real( xfs_extdelta_t *delta) /* Change made to incore extents */ { xfs_btree_cur_t *cur; /* btree cursor */ - xfs_bmbt_rec_t *ep; /* extent entry for idx */ + xfs_bmbt_rec_host_t *ep; /* extent entry for idx */ int error; /* error return value */ int i; /* temp state */ xfs_ifork_t *ifp; /* inode fork pointer */ @@ -1823,7 +1809,7 @@ xfs_bmap_add_extent_hole_delay( xfs_extdelta_t *delta, /* Change made to incore extents */ int rsvd) /* OK to allocate reserved blocks */ { - xfs_bmbt_rec_t *ep; /* extent record for idx */ + xfs_bmbt_rec_host_t *ep; /* extent record for idx */ xfs_ifork_t *ifp; /* inode fork pointer */ xfs_bmbt_irec_t left; /* left neighbor extent entry */ xfs_filblks_t newlen=0; /* new indirect size */ @@ -2012,7 +1998,7 @@ xfs_bmap_add_extent_hole_real( xfs_extdelta_t *delta, /* Change made to incore extents */ int whichfork) /* data or attr fork */ { - xfs_bmbt_rec_t *ep; /* pointer to extent entry ins. point */ + xfs_bmbt_rec_host_t *ep; /* pointer to extent entry ins. point */ int error; /* error return value */ int i; /* temp state */ xfs_ifork_t *ifp; /* inode fork pointer */ @@ -3070,7 +3056,7 @@ xfs_bmap_del_extent( xfs_fileoff_t del_endoff; /* first offset past del */ int delay; /* current block is delayed allocated */ int do_fx; /* free extent at end of routine */ - xfs_bmbt_rec_t *ep; /* current extent entry pointer */ + xfs_bmbt_rec_host_t *ep; /* current extent entry pointer */ int error; /* error return value */ int flags; /* inode logging flags */ xfs_bmbt_irec_t got; /* current extent entry */ @@ -3418,7 +3404,7 @@ xfs_bmap_extents_to_btree( xfs_bmbt_rec_t *arp; /* child record pointer */ xfs_bmbt_block_t *block; /* btree root block */ xfs_btree_cur_t *cur; /* bmap btree cursor */ - xfs_bmbt_rec_t *ep; /* extent record pointer */ + xfs_bmbt_rec_host_t *ep; /* extent record pointer */ int error; /* error return value */ xfs_extnum_t i, cnt; /* extent record index */ xfs_ifork_t *ifp; /* inode fork pointer */ @@ -3507,8 +3493,8 @@ xfs_bmap_extents_to_btree( for (cnt = i = 0; i < nextents; i++) { ep = xfs_iext_get_ext(ifp, i); if (!ISNULLSTARTBLOCK(xfs_bmbt_get_startblock(ep))) { - arp->l0 = INT_GET(ep->l0, ARCH_CONVERT); - arp->l1 = INT_GET(ep->l1, ARCH_CONVERT); + arp->l0 = cpu_to_be64(ep->l0); + arp->l1 = cpu_to_be64(ep->l1); arp++; cnt++; } } @@ -3590,7 +3576,7 @@ xfs_bmap_local_to_extents( if (ifp->if_bytes) { xfs_alloc_arg_t args; /* allocation arguments */ xfs_buf_t *bp; /* buffer for extent block */ - xfs_bmbt_rec_t *ep; /* extent record pointer */ + xfs_bmbt_rec_host_t *ep;/* extent record pointer */ args.tp = tp; args.mp = ip->i_mount; @@ -3655,7 +3641,7 @@ done: * entry (null if none). Else, *lastxp will be set to the index * of the found entry; *gotp will contain the entry. */ -xfs_bmbt_rec_t * /* pointer to found extent entry */ +xfs_bmbt_rec_host_t * /* pointer to found extent entry */ xfs_bmap_search_multi_extents( xfs_ifork_t *ifp, /* inode fork pointer */ xfs_fileoff_t bno, /* block number searched for */ @@ -3664,7 +3650,7 @@ xfs_bmap_search_multi_extents( xfs_bmbt_irec_t *gotp, /* out: extent entry found */ xfs_bmbt_irec_t *prevp) /* out: previous extent entry found */ { - xfs_bmbt_rec_t *ep; /* extent record pointer */ + xfs_bmbt_rec_host_t *ep; /* extent record pointer */ xfs_extnum_t lastx; /* last extent index */ /* @@ -3706,7 +3692,7 @@ xfs_bmap_search_multi_extents( * Else, *lastxp will be set to the index of the found * entry; *gotp will contain the entry. */ -STATIC xfs_bmbt_rec_t * /* pointer to found extent entry */ +STATIC xfs_bmbt_rec_host_t * /* pointer to found extent entry */ xfs_bmap_search_extents( xfs_inode_t *ip, /* incore inode pointer */ xfs_fileoff_t bno, /* block number searched for */ @@ -3717,7 +3703,7 @@ xfs_bmap_search_extents( xfs_bmbt_irec_t *prevp) /* out: previous extent entry found */ { xfs_ifork_t *ifp; /* inode fork pointer */ - xfs_bmbt_rec_t *ep; /* extent record pointer */ + xfs_bmbt_rec_host_t *ep; /* extent record pointer */ XFS_STATS_INC(xs_look_exlist); ifp = XFS_IFORK_PTR(ip, fork); @@ -3757,11 +3743,11 @@ xfs_bmap_trace_addentry( xfs_inode_t *ip, /* incore inode pointer */ xfs_extnum_t idx, /* index of entry(ies) */ xfs_extnum_t cnt, /* count of entries, 1 or 2 */ - xfs_bmbt_rec_t *r1, /* first record */ - xfs_bmbt_rec_t *r2, /* second record or null */ + xfs_bmbt_rec_host_t *r1, /* first record */ + xfs_bmbt_rec_host_t *r2, /* second record or null */ int whichfork) /* data or attr fork */ { - xfs_bmbt_rec_t tr2; + xfs_bmbt_rec_host_t tr2; ASSERT(cnt == 1 || cnt == 2); ASSERT(r1 != NULL); @@ -3842,8 +3828,8 @@ xfs_bmap_trace_insert( xfs_bmbt_irec_t *r2, /* inserted record 2 or null */ int whichfork) /* data or attr fork */ { - xfs_bmbt_rec_t tr1; /* compressed record 1 */ - xfs_bmbt_rec_t tr2; /* compressed record 2 if needed */ + xfs_bmbt_rec_host_t tr1; /* compressed record 1 */ + xfs_bmbt_rec_host_t tr2; /* compressed record 2 if needed */ xfs_bmbt_set_all(&tr1, r1); if (cnt == 2) { @@ -4316,7 +4302,6 @@ xfs_bmap_first_unused( xfs_fileoff_t *first_unused, /* unused block */ int whichfork) /* data or attr fork */ { - xfs_bmbt_rec_t *ep; /* pointer to an extent entry */ int error; /* error return value */ int idx; /* extent record index */ xfs_ifork_t *ifp; /* inode fork pointer */ @@ -4340,7 +4325,7 @@ xfs_bmap_first_unused( lowest = *first_unused; nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); for (idx = 0, lastaddr = 0, max = lowest; idx < nextents; idx++) { - ep = xfs_iext_get_ext(ifp, idx); + xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, idx); off = xfs_bmbt_get_startoff(ep); /* * See if the hole before this extent will work. @@ -4371,7 +4356,7 @@ xfs_bmap_last_before( { xfs_fileoff_t bno; /* input file offset */ int eof; /* hit end of file */ - xfs_bmbt_rec_t *ep; /* pointer to last extent */ + xfs_bmbt_rec_host_t *ep; /* pointer to last extent */ int error; /* error return value */ xfs_bmbt_irec_t got; /* current extent value */ xfs_ifork_t *ifp; /* inode fork pointer */ @@ -4417,7 +4402,7 @@ xfs_bmap_last_offset( xfs_fileoff_t *last_block, /* last block */ int whichfork) /* data or attr fork */ { - xfs_bmbt_rec_t *ep; /* pointer to last extent */ + xfs_bmbt_rec_host_t *ep; /* pointer to last extent */ int error; /* error return value */ xfs_ifork_t *ifp; /* inode fork pointer */ xfs_extnum_t nextents; /* number of extent entries */ @@ -4454,7 +4439,7 @@ xfs_bmap_one_block( xfs_inode_t *ip, /* incore inode */ int whichfork) /* data or attr fork */ { - xfs_bmbt_rec_t *ep; /* ptr to fork's extent */ + xfs_bmbt_rec_host_t *ep; /* ptr to fork's extent */ xfs_ifork_t *ifp; /* inode fork pointer */ int rval; /* return value */ xfs_bmbt_irec_t s; /* internal version of extent */ @@ -4549,7 +4534,7 @@ xfs_bmap_read_extents( * Loop over all leaf nodes. Copy information to the extent records. */ for (;;) { - xfs_bmbt_rec_t *frp, *trp; + xfs_bmbt_rec_t *frp; xfs_fsblock_t nextbno; xfs_extnum_t num_recs; xfs_extnum_t start; @@ -4581,9 +4566,9 @@ xfs_bmap_read_extents( frp = XFS_BTREE_REC_ADDR(xfs_bmbt, block, 1); start = i; for (j = 0; j < num_recs; j++, i++, frp++) { - trp = xfs_iext_get_ext(ifp, i); - trp->l0 = INT_GET(frp->l0, ARCH_CONVERT); - trp->l1 = INT_GET(frp->l1, ARCH_CONVERT); + xfs_bmbt_rec_host_t *trp = xfs_iext_get_ext(ifp, i); + trp->l0 = be64_to_cpu(frp->l0); + trp->l1 = be64_to_cpu(frp->l1); } if (exntf == XFS_EXTFMT_NOSTATE) { /* @@ -4631,7 +4616,7 @@ xfs_bmap_trace_exlist( xfs_extnum_t cnt, /* count of entries in the list */ int whichfork) /* data or attr fork */ { - xfs_bmbt_rec_t *ep; /* current extent record */ + xfs_bmbt_rec_host_t *ep; /* current extent record */ xfs_extnum_t idx; /* extent record index */ xfs_ifork_t *ifp; /* inode fork pointer */ xfs_bmbt_irec_t s; /* file extent record */ @@ -4727,7 +4712,7 @@ xfs_bmapi( xfs_btree_cur_t *cur; /* bmap btree cursor */ xfs_fileoff_t end; /* end of mapped file region */ int eof; /* we've hit the end of extents */ - xfs_bmbt_rec_t *ep; /* extent record pointer */ + xfs_bmbt_rec_host_t *ep; /* extent record pointer */ int error; /* error return */ xfs_bmbt_irec_t got; /* current file extent record */ xfs_ifork_t *ifp; /* inode fork pointer */ @@ -5378,7 +5363,7 @@ xfs_bunmapi( xfs_btree_cur_t *cur; /* bmap btree cursor */ xfs_bmbt_irec_t del; /* extent being deleted */ int eof; /* is deleting at eof */ - xfs_bmbt_rec_t *ep; /* extent record pointer */ + xfs_bmbt_rec_host_t *ep; /* extent record pointer */ int error; /* error return value */ xfs_extnum_t extno; /* extent number in list */ xfs_bmbt_irec_t got; /* current extent record */ @@ -5743,11 +5728,44 @@ error0: } /* + * returns 1 for success, 0 if we failed to map the extent. + */ +STATIC int +xfs_getbmapx_fix_eof_hole( + xfs_inode_t *ip, /* xfs incore inode pointer */ + struct getbmap *out, /* output structure */ + int prealloced, /* this is a file with + * preallocated data space */ + __int64_t end, /* last block requested */ + xfs_fsblock_t startblock) +{ + __int64_t fixlen; + xfs_mount_t *mp; /* file system mount point */ + + if (startblock == HOLESTARTBLOCK) { + mp = ip->i_mount; + out->bmv_block = -1; + fixlen = XFS_FSB_TO_BB(mp, XFS_B_TO_FSB(mp, ip->i_size)); + fixlen -= out->bmv_offset; + if (prealloced && out->bmv_offset + out->bmv_length == end) { + /* Came to hole at EOF. Trim it. */ + if (fixlen <= 0) + return 0; + out->bmv_length = fixlen; + } + } else { + out->bmv_block = XFS_FSB_TO_DB(ip, startblock); + } + + return 1; +} + +/* * Fcntl interface to xfs_bmapi. */ int /* error code */ xfs_getbmap( - bhv_desc_t *bdp, /* XFS behavior descriptor*/ + xfs_inode_t *ip, struct getbmap *bmv, /* user bmap structure */ void __user *ap, /* pointer to user's array */ int interface) /* interface flags */ @@ -5756,7 +5774,6 @@ xfs_getbmap( int error; /* return value */ __int64_t fixlen; /* length for -1 case */ int i; /* extent number */ - xfs_inode_t *ip; /* xfs incore inode pointer */ bhv_vnode_t *vp; /* corresponding vnode */ int lock; /* lock state */ xfs_bmbt_irec_t *map; /* buffer for user's data */ @@ -5774,8 +5791,7 @@ xfs_getbmap( int bmapi_flags; /* flags for xfs_bmapi */ __int32_t oflags; /* getbmapx bmv_oflags field */ - vp = BHV_TO_VNODE(bdp); - ip = XFS_BHVTOI(bdp); + vp = XFS_ITOV(ip); mp = ip->i_mount; whichfork = interface & BMV_IF_ATTRFORK ? XFS_ATTR_FORK : XFS_DATA_FORK; @@ -5794,10 +5810,9 @@ xfs_getbmap( * could misinterpret holes in a DMAPI file as true holes, * when in fact they may represent offline user data. */ - if ( (interface & BMV_IF_NO_DMAPI_READ) == 0 - && DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) - && whichfork == XFS_DATA_FORK) { - + if ((interface & BMV_IF_NO_DMAPI_READ) == 0 && + DM_EVENT_ENABLED(ip, DM_EVENT_READ) && + whichfork == XFS_DATA_FORK) { error = XFS_SEND_DATA(mp, DM_EVENT_READ, vp, 0, 0, 0, NULL); if (error) return XFS_ERROR(error); @@ -5854,7 +5869,8 @@ xfs_getbmap( if (whichfork == XFS_DATA_FORK && (ip->i_delayed_blks || ip->i_size > ip->i_d.di_size)) { /* xfs_fsize_t last_byte = xfs_file_last_byte(ip); */ - error = bhv_vop_flush_pages(vp, (xfs_off_t)0, -1, 0, FI_REMAPF); + error = xfs_flush_pages(ip, (xfs_off_t)0, + -1, 0, FI_REMAPF); } ASSERT(whichfork == XFS_ATTR_FORK || ip->i_delayed_blks == 0); @@ -5904,18 +5920,15 @@ xfs_getbmap( out.bmv_length = XFS_FSB_TO_BB(mp, map[i].br_blockcount); ASSERT(map[i].br_startblock != DELAYSTARTBLOCK); if (map[i].br_startblock == HOLESTARTBLOCK && - ((prealloced && out.bmv_offset + out.bmv_length == bmvend) || - whichfork == XFS_ATTR_FORK )) { - /* - * came to hole at end of file or the end of - attribute fork - */ + whichfork == XFS_ATTR_FORK) { + /* came to the end of attribute fork */ goto unlock_and_return; } else { - out.bmv_block = - (map[i].br_startblock == HOLESTARTBLOCK) ? - -1 : - XFS_FSB_TO_DB(ip, map[i].br_startblock); + if (!xfs_getbmapx_fix_eof_hole(ip, &out, + prealloced, bmvend, + map[i].br_startblock)) { + goto unlock_and_return; + } /* return either getbmap/getbmapx structure. */ if (interface & BMV_IF_EXTENDED) { @@ -5974,7 +5987,7 @@ xfs_bmap_isaeof( { int error; /* error return value */ xfs_ifork_t *ifp; /* inode fork pointer */ - xfs_bmbt_rec_t *lastrec; /* extent record pointer */ + xfs_bmbt_rec_host_t *lastrec; /* extent record pointer */ xfs_extnum_t nextents; /* number of file extents */ xfs_bmbt_irec_t s; /* expanded extent record */ @@ -6018,7 +6031,7 @@ xfs_bmap_eof( xfs_fsblock_t blockcount; /* extent block count */ int error; /* error return value */ xfs_ifork_t *ifp; /* inode fork pointer */ - xfs_bmbt_rec_t *lastrec; /* extent record pointer */ + xfs_bmbt_rec_host_t *lastrec; /* extent record pointer */ xfs_extnum_t nextents; /* number of file extents */ xfs_fileoff_t startoff; /* extent starting file offset */ @@ -6465,10 +6478,9 @@ xfs_bmap_count_leaves( int *count) { int b; - xfs_bmbt_rec_t *frp; for (b = 0; b < numrecs; b++) { - frp = xfs_iext_get_ext(ifp, idx + b); + xfs_bmbt_rec_host_t *frp = xfs_iext_get_ext(ifp, idx + b); *count += xfs_bmbt_get_blockcount(frp); } return 0; diff --git a/fs/xfs/xfs_bmap.h b/fs/xfs/xfs_bmap.h index 524b1c9d5246..68267d75ff19 100644 --- a/fs/xfs/xfs_bmap.h +++ b/fs/xfs/xfs_bmap.h @@ -335,7 +335,7 @@ xfs_bunmapi( */ int /* error code */ xfs_getbmap( - bhv_desc_t *bdp, /* XFS behavior descriptor*/ + xfs_inode_t *ip, struct getbmap *bmv, /* user bmap structure */ void __user *ap, /* pointer to user's array */ int iflags); /* interface flags */ @@ -378,7 +378,7 @@ xfs_check_nostate_extents( * entry (null if none). Else, *lastxp will be set to the index * of the found entry; *gotp will contain the entry. */ -xfs_bmbt_rec_t * +xfs_bmbt_rec_host_t * xfs_bmap_search_multi_extents(struct xfs_ifork *, xfs_fileoff_t, int *, xfs_extnum_t *, xfs_bmbt_irec_t *, xfs_bmbt_irec_t *); diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c index 89b891f51cfb..32b49ec00fb5 100644 --- a/fs/xfs/xfs_bmap_btree.c +++ b/fs/xfs/xfs_bmap_btree.c @@ -260,13 +260,14 @@ xfs_bmbt_trace_cursor( char *s, int line) { - xfs_bmbt_rec_t r; + xfs_bmbt_rec_host_t r; xfs_bmbt_set_all(&r, &cur->bc_rec.b); xfs_bmbt_trace_enter(func, cur, s, XFS_BMBT_KTRACE_CUR, line, (cur->bc_nlevels << 24) | (cur->bc_private.b.flags << 16) | cur->bc_private.b.allocated, - INT_GET(r.l0, ARCH_CONVERT) >> 32, (int)INT_GET(r.l0, ARCH_CONVERT), INT_GET(r.l1, ARCH_CONVERT) >> 32, (int)INT_GET(r.l1, ARCH_CONVERT), + r.l0 >> 32, (int)r.l0, + r.l1 >> 32, (int)r.l1, (unsigned long)cur->bc_bufs[0], (unsigned long)cur->bc_bufs[1], (unsigned long)cur->bc_bufs[2], (unsigned long)cur->bc_bufs[3], (cur->bc_ptrs[0] << 16) | cur->bc_ptrs[1], @@ -383,7 +384,7 @@ xfs_bmbt_delrec( if (ptr < numrecs) { memmove(&kp[ptr - 1], &kp[ptr], (numrecs - ptr) * sizeof(*kp)); - memmove(&pp[ptr - 1], &pp[ptr], /* INT_: direct copy */ + memmove(&pp[ptr - 1], &pp[ptr], (numrecs - ptr) * sizeof(*pp)); xfs_bmbt_log_ptrs(cur, bp, ptr, numrecs - 1); xfs_bmbt_log_keys(cur, bp, ptr, numrecs - 1); @@ -815,7 +816,7 @@ xfs_bmbt_insrec( #endif memmove(&kp[ptr], &kp[ptr - 1], (numrecs - ptr + 1) * sizeof(*kp)); - memmove(&pp[ptr], &pp[ptr - 1], /* INT_: direct copy */ + memmove(&pp[ptr], &pp[ptr - 1], (numrecs - ptr + 1) * sizeof(*pp)); #ifdef DEBUG if ((error = xfs_btree_check_lptr(cur, *bnop, level))) { @@ -1250,7 +1251,7 @@ xfs_bmbt_lshift( return error; } #endif - *lpp = *rpp; /* INT_: direct copy */ + *lpp = *rpp; xfs_bmbt_log_ptrs(cur, lbp, lrecs, lrecs); } else { lrp = XFS_BMAP_REC_IADDR(left, lrecs, cur); @@ -1388,7 +1389,7 @@ xfs_bmbt_rshift( } #endif *rkp = *lkp; - *rpp = *lpp; /* INT_: direct copy */ + *rpp = *lpp; xfs_bmbt_log_keys(cur, rbp, 1, be16_to_cpu(right->bb_numrecs) + 1); xfs_bmbt_log_ptrs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs) + 1); } else { @@ -1826,7 +1827,7 @@ __xfs_bmbt_get_all( void xfs_bmbt_get_all( - xfs_bmbt_rec_t *r, + xfs_bmbt_rec_host_t *r, xfs_bmbt_irec_t *s) { __xfs_bmbt_get_all(r->l0, r->l1, s); @@ -1862,7 +1863,7 @@ xfs_bmbt_get_block( */ xfs_filblks_t xfs_bmbt_get_blockcount( - xfs_bmbt_rec_t *r) + xfs_bmbt_rec_host_t *r) { return (xfs_filblks_t)(r->l1 & XFS_MASK64LO(21)); } @@ -1872,7 +1873,7 @@ xfs_bmbt_get_blockcount( */ xfs_fsblock_t xfs_bmbt_get_startblock( - xfs_bmbt_rec_t *r) + xfs_bmbt_rec_host_t *r) { #if XFS_BIG_BLKNOS return (((xfs_fsblock_t)r->l0 & XFS_MASK64LO(9)) << 43) | @@ -1896,7 +1897,7 @@ xfs_bmbt_get_startblock( */ xfs_fileoff_t xfs_bmbt_get_startoff( - xfs_bmbt_rec_t *r) + xfs_bmbt_rec_host_t *r) { return ((xfs_fileoff_t)r->l0 & XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; @@ -1904,7 +1905,7 @@ xfs_bmbt_get_startoff( xfs_exntst_t xfs_bmbt_get_state( - xfs_bmbt_rec_t *r) + xfs_bmbt_rec_host_t *r) { int ext_flag; @@ -1913,19 +1914,13 @@ xfs_bmbt_get_state( ext_flag); } -#ifndef XFS_NATIVE_HOST /* Endian flipping versions of the bmbt extraction functions */ void xfs_bmbt_disk_get_all( xfs_bmbt_rec_t *r, xfs_bmbt_irec_t *s) { - __uint64_t l0, l1; - - l0 = INT_GET(r->l0, ARCH_CONVERT); - l1 = INT_GET(r->l1, ARCH_CONVERT); - - __xfs_bmbt_get_all(l0, l1, s); + __xfs_bmbt_get_all(be64_to_cpu(r->l0), be64_to_cpu(r->l1), s); } /* @@ -1935,7 +1930,7 @@ xfs_filblks_t xfs_bmbt_disk_get_blockcount( xfs_bmbt_rec_t *r) { - return (xfs_filblks_t)(INT_GET(r->l1, ARCH_CONVERT) & XFS_MASK64LO(21)); + return (xfs_filblks_t)(be64_to_cpu(r->l1) & XFS_MASK64LO(21)); } /* @@ -1945,11 +1940,9 @@ xfs_fileoff_t xfs_bmbt_disk_get_startoff( xfs_bmbt_rec_t *r) { - return ((xfs_fileoff_t)INT_GET(r->l0, ARCH_CONVERT) & + return ((xfs_fileoff_t)be64_to_cpu(r->l0) & XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; } -#endif /* XFS_NATIVE_HOST */ - /* * Increment cursor by one record at the level. @@ -2290,185 +2283,131 @@ xfs_bmbt_newroot( } /* - * Set all the fields in a bmap extent record from the uncompressed form. - */ -void -xfs_bmbt_set_all( - xfs_bmbt_rec_t *r, - xfs_bmbt_irec_t *s) -{ - int extent_flag; - - ASSERT((s->br_state == XFS_EXT_NORM) || - (s->br_state == XFS_EXT_UNWRITTEN)); - extent_flag = (s->br_state == XFS_EXT_NORM) ? 0 : 1; - ASSERT((s->br_startoff & XFS_MASK64HI(9)) == 0); - ASSERT((s->br_blockcount & XFS_MASK64HI(43)) == 0); -#if XFS_BIG_BLKNOS - ASSERT((s->br_startblock & XFS_MASK64HI(12)) == 0); - r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) | - ((xfs_bmbt_rec_base_t)s->br_startoff << 9) | - ((xfs_bmbt_rec_base_t)s->br_startblock >> 43); - r->l1 = ((xfs_bmbt_rec_base_t)s->br_startblock << 21) | - ((xfs_bmbt_rec_base_t)s->br_blockcount & - (xfs_bmbt_rec_base_t)XFS_MASK64LO(21)); -#else /* !XFS_BIG_BLKNOS */ - if (ISNULLSTARTBLOCK(s->br_startblock)) { - r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) | - ((xfs_bmbt_rec_base_t)s->br_startoff << 9) | - (xfs_bmbt_rec_base_t)XFS_MASK64LO(9); - r->l1 = XFS_MASK64HI(11) | - ((xfs_bmbt_rec_base_t)s->br_startblock << 21) | - ((xfs_bmbt_rec_base_t)s->br_blockcount & - (xfs_bmbt_rec_base_t)XFS_MASK64LO(21)); - } else { - r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) | - ((xfs_bmbt_rec_base_t)s->br_startoff << 9); - r->l1 = ((xfs_bmbt_rec_base_t)s->br_startblock << 21) | - ((xfs_bmbt_rec_base_t)s->br_blockcount & - (xfs_bmbt_rec_base_t)XFS_MASK64LO(21)); - } -#endif /* XFS_BIG_BLKNOS */ -} - -/* * Set all the fields in a bmap extent record from the arguments. */ void xfs_bmbt_set_allf( - xfs_bmbt_rec_t *r, - xfs_fileoff_t o, - xfs_fsblock_t b, - xfs_filblks_t c, - xfs_exntst_t v) + xfs_bmbt_rec_host_t *r, + xfs_fileoff_t startoff, + xfs_fsblock_t startblock, + xfs_filblks_t blockcount, + xfs_exntst_t state) { - int extent_flag; + int extent_flag = (state == XFS_EXT_NORM) ? 0 : 1; + + ASSERT(state == XFS_EXT_NORM || state == XFS_EXT_UNWRITTEN); + ASSERT((startoff & XFS_MASK64HI(64-BMBT_STARTOFF_BITLEN)) == 0); + ASSERT((blockcount & XFS_MASK64HI(64-BMBT_BLOCKCOUNT_BITLEN)) == 0); - ASSERT((v == XFS_EXT_NORM) || (v == XFS_EXT_UNWRITTEN)); - extent_flag = (v == XFS_EXT_NORM) ? 0 : 1; - ASSERT((o & XFS_MASK64HI(64-BMBT_STARTOFF_BITLEN)) == 0); - ASSERT((c & XFS_MASK64HI(64-BMBT_BLOCKCOUNT_BITLEN)) == 0); #if XFS_BIG_BLKNOS - ASSERT((b & XFS_MASK64HI(64-BMBT_STARTBLOCK_BITLEN)) == 0); + ASSERT((startblock & XFS_MASK64HI(64-BMBT_STARTBLOCK_BITLEN)) == 0); + r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) | - ((xfs_bmbt_rec_base_t)o << 9) | - ((xfs_bmbt_rec_base_t)b >> 43); - r->l1 = ((xfs_bmbt_rec_base_t)b << 21) | - ((xfs_bmbt_rec_base_t)c & + ((xfs_bmbt_rec_base_t)startoff << 9) | + ((xfs_bmbt_rec_base_t)startblock >> 43); + r->l1 = ((xfs_bmbt_rec_base_t)startblock << 21) | + ((xfs_bmbt_rec_base_t)blockcount & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21)); #else /* !XFS_BIG_BLKNOS */ - if (ISNULLSTARTBLOCK(b)) { + if (ISNULLSTARTBLOCK(startblock)) { r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) | - ((xfs_bmbt_rec_base_t)o << 9) | + ((xfs_bmbt_rec_base_t)startoff << 9) | (xfs_bmbt_rec_base_t)XFS_MASK64LO(9); r->l1 = XFS_MASK64HI(11) | - ((xfs_bmbt_rec_base_t)b << 21) | - ((xfs_bmbt_rec_base_t)c & + ((xfs_bmbt_rec_base_t)startblock << 21) | + ((xfs_bmbt_rec_base_t)blockcount & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21)); } else { r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) | - ((xfs_bmbt_rec_base_t)o << 9); - r->l1 = ((xfs_bmbt_rec_base_t)b << 21) | - ((xfs_bmbt_rec_base_t)c & + ((xfs_bmbt_rec_base_t)startoff << 9); + r->l1 = ((xfs_bmbt_rec_base_t)startblock << 21) | + ((xfs_bmbt_rec_base_t)blockcount & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21)); } #endif /* XFS_BIG_BLKNOS */ } -#ifndef XFS_NATIVE_HOST /* * Set all the fields in a bmap extent record from the uncompressed form. */ void -xfs_bmbt_disk_set_all( - xfs_bmbt_rec_t *r, - xfs_bmbt_irec_t *s) +xfs_bmbt_set_all( + xfs_bmbt_rec_host_t *r, + xfs_bmbt_irec_t *s) { - int extent_flag; - - ASSERT((s->br_state == XFS_EXT_NORM) || - (s->br_state == XFS_EXT_UNWRITTEN)); - extent_flag = (s->br_state == XFS_EXT_NORM) ? 0 : 1; - ASSERT((s->br_startoff & XFS_MASK64HI(9)) == 0); - ASSERT((s->br_blockcount & XFS_MASK64HI(43)) == 0); -#if XFS_BIG_BLKNOS - ASSERT((s->br_startblock & XFS_MASK64HI(12)) == 0); - INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | - ((xfs_bmbt_rec_base_t)s->br_startoff << 9) | - ((xfs_bmbt_rec_base_t)s->br_startblock >> 43)); - INT_SET(r->l1, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)s->br_startblock << 21) | - ((xfs_bmbt_rec_base_t)s->br_blockcount & - (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); -#else /* !XFS_BIG_BLKNOS */ - if (ISNULLSTARTBLOCK(s->br_startblock)) { - INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | - ((xfs_bmbt_rec_base_t)s->br_startoff << 9) | - (xfs_bmbt_rec_base_t)XFS_MASK64LO(9)); - INT_SET(r->l1, ARCH_CONVERT, XFS_MASK64HI(11) | - ((xfs_bmbt_rec_base_t)s->br_startblock << 21) | - ((xfs_bmbt_rec_base_t)s->br_blockcount & - (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); - } else { - INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | - ((xfs_bmbt_rec_base_t)s->br_startoff << 9)); - INT_SET(r->l1, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)s->br_startblock << 21) | - ((xfs_bmbt_rec_base_t)s->br_blockcount & - (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); - } -#endif /* XFS_BIG_BLKNOS */ + xfs_bmbt_set_allf(r, s->br_startoff, s->br_startblock, + s->br_blockcount, s->br_state); } + /* * Set all the fields in a disk format bmap extent record from the arguments. */ void xfs_bmbt_disk_set_allf( - xfs_bmbt_rec_t *r, - xfs_fileoff_t o, - xfs_fsblock_t b, - xfs_filblks_t c, - xfs_exntst_t v) + xfs_bmbt_rec_t *r, + xfs_fileoff_t startoff, + xfs_fsblock_t startblock, + xfs_filblks_t blockcount, + xfs_exntst_t state) { - int extent_flag; + int extent_flag = (state == XFS_EXT_NORM) ? 0 : 1; + + ASSERT(state == XFS_EXT_NORM || state == XFS_EXT_UNWRITTEN); + ASSERT((startoff & XFS_MASK64HI(64-BMBT_STARTOFF_BITLEN)) == 0); + ASSERT((blockcount & XFS_MASK64HI(64-BMBT_BLOCKCOUNT_BITLEN)) == 0); - ASSERT((v == XFS_EXT_NORM) || (v == XFS_EXT_UNWRITTEN)); - extent_flag = (v == XFS_EXT_NORM) ? 0 : 1; - ASSERT((o & XFS_MASK64HI(64-BMBT_STARTOFF_BITLEN)) == 0); - ASSERT((c & XFS_MASK64HI(64-BMBT_BLOCKCOUNT_BITLEN)) == 0); #if XFS_BIG_BLKNOS - ASSERT((b & XFS_MASK64HI(64-BMBT_STARTBLOCK_BITLEN)) == 0); - INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | - ((xfs_bmbt_rec_base_t)o << 9) | - ((xfs_bmbt_rec_base_t)b >> 43)); - INT_SET(r->l1, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)b << 21) | - ((xfs_bmbt_rec_base_t)c & - (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); + ASSERT((startblock & XFS_MASK64HI(64-BMBT_STARTBLOCK_BITLEN)) == 0); + + r->l0 = cpu_to_be64( + ((xfs_bmbt_rec_base_t)extent_flag << 63) | + ((xfs_bmbt_rec_base_t)startoff << 9) | + ((xfs_bmbt_rec_base_t)startblock >> 43)); + r->l1 = cpu_to_be64( + ((xfs_bmbt_rec_base_t)startblock << 21) | + ((xfs_bmbt_rec_base_t)blockcount & + (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); #else /* !XFS_BIG_BLKNOS */ - if (ISNULLSTARTBLOCK(b)) { - INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | - ((xfs_bmbt_rec_base_t)o << 9) | - (xfs_bmbt_rec_base_t)XFS_MASK64LO(9)); - INT_SET(r->l1, ARCH_CONVERT, XFS_MASK64HI(11) | - ((xfs_bmbt_rec_base_t)b << 21) | - ((xfs_bmbt_rec_base_t)c & + if (ISNULLSTARTBLOCK(startblock)) { + r->l0 = cpu_to_be64( + ((xfs_bmbt_rec_base_t)extent_flag << 63) | + ((xfs_bmbt_rec_base_t)startoff << 9) | + (xfs_bmbt_rec_base_t)XFS_MASK64LO(9)); + r->l1 = cpu_to_be64(XFS_MASK64HI(11) | + ((xfs_bmbt_rec_base_t)startblock << 21) | + ((xfs_bmbt_rec_base_t)blockcount & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); } else { - INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | - ((xfs_bmbt_rec_base_t)o << 9)); - INT_SET(r->l1, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)b << 21) | - ((xfs_bmbt_rec_base_t)c & - (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); + r->l0 = cpu_to_be64( + ((xfs_bmbt_rec_base_t)extent_flag << 63) | + ((xfs_bmbt_rec_base_t)startoff << 9)); + r->l1 = cpu_to_be64( + ((xfs_bmbt_rec_base_t)startblock << 21) | + ((xfs_bmbt_rec_base_t)blockcount & + (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); } #endif /* XFS_BIG_BLKNOS */ } -#endif /* XFS_NATIVE_HOST */ + +/* + * Set all the fields in a bmap extent record from the uncompressed form. + */ +void +xfs_bmbt_disk_set_all( + xfs_bmbt_rec_t *r, + xfs_bmbt_irec_t *s) +{ + xfs_bmbt_disk_set_allf(r, s->br_startoff, s->br_startblock, + s->br_blockcount, s->br_state); +} /* * Set the blockcount field in a bmap extent record. */ void xfs_bmbt_set_blockcount( - xfs_bmbt_rec_t *r, + xfs_bmbt_rec_host_t *r, xfs_filblks_t v) { ASSERT((v & XFS_MASK64HI(43)) == 0); @@ -2481,7 +2420,7 @@ xfs_bmbt_set_blockcount( */ void xfs_bmbt_set_startblock( - xfs_bmbt_rec_t *r, + xfs_bmbt_rec_host_t *r, xfs_fsblock_t v) { #if XFS_BIG_BLKNOS @@ -2509,7 +2448,7 @@ xfs_bmbt_set_startblock( */ void xfs_bmbt_set_startoff( - xfs_bmbt_rec_t *r, + xfs_bmbt_rec_host_t *r, xfs_fileoff_t v) { ASSERT((v & XFS_MASK64HI(9)) == 0); @@ -2523,7 +2462,7 @@ xfs_bmbt_set_startoff( */ void xfs_bmbt_set_state( - xfs_bmbt_rec_t *r, + xfs_bmbt_rec_host_t *r, xfs_exntst_t v) { ASSERT(v == XFS_EXT_NORM || v == XFS_EXT_UNWRITTEN); @@ -2624,10 +2563,8 @@ xfs_check_nostate_extents( xfs_extnum_t idx, xfs_extnum_t num) { - xfs_bmbt_rec_t *ep; - for (; num > 0; num--, idx++) { - ep = xfs_iext_get_ext(ifp, idx); + xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, idx); if ((ep->l0 >> (64 - BMBT_EXNTFLAG_BITLEN)) != 0) { ASSERT(0); diff --git a/fs/xfs/xfs_bmap_btree.h b/fs/xfs/xfs_bmap_btree.h index a77b1b753d0c..2d950e975918 100644 --- a/fs/xfs/xfs_bmap_btree.h +++ b/fs/xfs/xfs_bmap_btree.h @@ -35,45 +35,16 @@ typedef struct xfs_bmdr_block { /* * Bmap btree record and extent descriptor. - * For 32-bit kernels, - * l0:31 is an extent flag (value 1 indicates non-normal). - * l0:0-30 and l1:9-31 are startoff. - * l1:0-8, l2:0-31, and l3:21-31 are startblock. - * l3:0-20 are blockcount. - * For 64-bit kernels, * l0:63 is an extent flag (value 1 indicates non-normal). * l0:9-62 are startoff. * l0:0-8 and l1:21-63 are startblock. * l1:0-20 are blockcount. */ - -#ifndef XFS_NATIVE_HOST - -#define BMBT_TOTAL_BITLEN 128 /* 128 bits, 16 bytes */ -#define BMBT_EXNTFLAG_BITOFF 0 #define BMBT_EXNTFLAG_BITLEN 1 -#define BMBT_STARTOFF_BITOFF (BMBT_EXNTFLAG_BITOFF + BMBT_EXNTFLAG_BITLEN) #define BMBT_STARTOFF_BITLEN 54 -#define BMBT_STARTBLOCK_BITOFF (BMBT_STARTOFF_BITOFF + BMBT_STARTOFF_BITLEN) #define BMBT_STARTBLOCK_BITLEN 52 -#define BMBT_BLOCKCOUNT_BITOFF \ - (BMBT_STARTBLOCK_BITOFF + BMBT_STARTBLOCK_BITLEN) -#define BMBT_BLOCKCOUNT_BITLEN (BMBT_TOTAL_BITLEN - BMBT_BLOCKCOUNT_BITOFF) - -#else - -#define BMBT_TOTAL_BITLEN 128 /* 128 bits, 16 bytes */ -#define BMBT_EXNTFLAG_BITOFF 63 -#define BMBT_EXNTFLAG_BITLEN 1 -#define BMBT_STARTOFF_BITOFF (BMBT_EXNTFLAG_BITOFF - BMBT_STARTOFF_BITLEN) -#define BMBT_STARTOFF_BITLEN 54 -#define BMBT_STARTBLOCK_BITOFF 85 /* 128 - 43 (other 9 is in first word) */ -#define BMBT_STARTBLOCK_BITLEN 52 -#define BMBT_BLOCKCOUNT_BITOFF 64 /* Start of second 64 bit container */ #define BMBT_BLOCKCOUNT_BITLEN 21 -#endif /* XFS_NATIVE_HOST */ - #define BMBT_USE_64 1 @@ -83,12 +54,16 @@ typedef struct xfs_bmbt_rec_32 } xfs_bmbt_rec_32_t; typedef struct xfs_bmbt_rec_64 { - __uint64_t l0, l1; + __be64 l0, l1; } xfs_bmbt_rec_64_t; typedef __uint64_t xfs_bmbt_rec_base_t; /* use this for casts */ typedef xfs_bmbt_rec_64_t xfs_bmbt_rec_t, xfs_bmdr_rec_t; +typedef struct xfs_bmbt_rec_host { + __uint64_t l0, l1; +} xfs_bmbt_rec_host_t; + /* * Values and macros for delayed-allocation startblock fields. */ @@ -281,23 +256,17 @@ extern ktrace_t *xfs_bmbt_trace_buf; extern void xfs_bmdr_to_bmbt(xfs_bmdr_block_t *, int, xfs_bmbt_block_t *, int); extern int xfs_bmbt_decrement(struct xfs_btree_cur *, int, int *); extern int xfs_bmbt_delete(struct xfs_btree_cur *, int *); -extern void xfs_bmbt_get_all(xfs_bmbt_rec_t *r, xfs_bmbt_irec_t *s); +extern void xfs_bmbt_get_all(xfs_bmbt_rec_host_t *r, xfs_bmbt_irec_t *s); extern xfs_bmbt_block_t *xfs_bmbt_get_block(struct xfs_btree_cur *cur, int, struct xfs_buf **bpp); -extern xfs_filblks_t xfs_bmbt_get_blockcount(xfs_bmbt_rec_t *r); -extern xfs_fsblock_t xfs_bmbt_get_startblock(xfs_bmbt_rec_t *r); -extern xfs_fileoff_t xfs_bmbt_get_startoff(xfs_bmbt_rec_t *r); -extern xfs_exntst_t xfs_bmbt_get_state(xfs_bmbt_rec_t *r); +extern xfs_filblks_t xfs_bmbt_get_blockcount(xfs_bmbt_rec_host_t *r); +extern xfs_fsblock_t xfs_bmbt_get_startblock(xfs_bmbt_rec_host_t *r); +extern xfs_fileoff_t xfs_bmbt_get_startoff(xfs_bmbt_rec_host_t *r); +extern xfs_exntst_t xfs_bmbt_get_state(xfs_bmbt_rec_host_t *r); -#ifndef XFS_NATIVE_HOST extern void xfs_bmbt_disk_get_all(xfs_bmbt_rec_t *r, xfs_bmbt_irec_t *s); extern xfs_filblks_t xfs_bmbt_disk_get_blockcount(xfs_bmbt_rec_t *r); extern xfs_fileoff_t xfs_bmbt_disk_get_startoff(xfs_bmbt_rec_t *r); -#else -#define xfs_bmbt_disk_get_all(r, s) xfs_bmbt_get_all(r, s) -#define xfs_bmbt_disk_get_blockcount(r) xfs_bmbt_get_blockcount(r) -#define xfs_bmbt_disk_get_startoff(r) xfs_bmbt_get_startoff(r) -#endif /* XFS_NATIVE_HOST */ extern int xfs_bmbt_increment(struct xfs_btree_cur *, int, int *); extern int xfs_bmbt_insert(struct xfs_btree_cur *, int *); @@ -315,22 +284,17 @@ extern int xfs_bmbt_lookup_ge(struct xfs_btree_cur *, xfs_fileoff_t, */ extern int xfs_bmbt_newroot(struct xfs_btree_cur *cur, int *lflags, int *stat); -extern void xfs_bmbt_set_all(xfs_bmbt_rec_t *r, xfs_bmbt_irec_t *s); -extern void xfs_bmbt_set_allf(xfs_bmbt_rec_t *r, xfs_fileoff_t o, +extern void xfs_bmbt_set_all(xfs_bmbt_rec_host_t *r, xfs_bmbt_irec_t *s); +extern void xfs_bmbt_set_allf(xfs_bmbt_rec_host_t *r, xfs_fileoff_t o, xfs_fsblock_t b, xfs_filblks_t c, xfs_exntst_t v); -extern void xfs_bmbt_set_blockcount(xfs_bmbt_rec_t *r, xfs_filblks_t v); -extern void xfs_bmbt_set_startblock(xfs_bmbt_rec_t *r, xfs_fsblock_t v); -extern void xfs_bmbt_set_startoff(xfs_bmbt_rec_t *r, xfs_fileoff_t v); -extern void xfs_bmbt_set_state(xfs_bmbt_rec_t *r, xfs_exntst_t v); +extern void xfs_bmbt_set_blockcount(xfs_bmbt_rec_host_t *r, xfs_filblks_t v); +extern void xfs_bmbt_set_startblock(xfs_bmbt_rec_host_t *r, xfs_fsblock_t v); +extern void xfs_bmbt_set_startoff(xfs_bmbt_rec_host_t *r, xfs_fileoff_t v); +extern void xfs_bmbt_set_state(xfs_bmbt_rec_host_t *r, xfs_exntst_t v); -#ifndef XFS_NATIVE_HOST extern void xfs_bmbt_disk_set_all(xfs_bmbt_rec_t *r, xfs_bmbt_irec_t *s); extern void xfs_bmbt_disk_set_allf(xfs_bmbt_rec_t *r, xfs_fileoff_t o, xfs_fsblock_t b, xfs_filblks_t c, xfs_exntst_t v); -#else -#define xfs_bmbt_disk_set_all(r, s) xfs_bmbt_set_all(r, s) -#define xfs_bmbt_disk_set_allf(r, o, b, c, v) xfs_bmbt_set_allf(r, o, b, c, v) -#endif /* XFS_NATIVE_HOST */ extern void xfs_bmbt_to_bmdr(xfs_bmbt_block_t *, int, xfs_bmdr_block_t *, int); extern int xfs_bmbt_update(struct xfs_btree_cur *, xfs_fileoff_t, diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index b0667cb27d66..c8f2c2886fe4 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c @@ -23,6 +23,7 @@ #include "xfs_inum.h" #include "xfs_trans.h" #include "xfs_sb.h" +#include "xfs_ag.h" #include "xfs_dmapi.h" #include "xfs_mount.h" #include "xfs_buf_item.h" diff --git a/fs/xfs/xfs_clnt.h b/fs/xfs/xfs_clnt.h index f89196cb08d2..d16c1b971074 100644 --- a/fs/xfs/xfs_clnt.h +++ b/fs/xfs/xfs_clnt.h @@ -89,7 +89,6 @@ struct xfs_mount_args { #define XFSMNT_IDELETE 0x08000000 /* inode cluster delete */ #define XFSMNT_SWALLOC 0x10000000 /* turn on stripe width * allocation */ -#define XFSMNT_IHASHSIZE 0x20000000 /* inode hash table size */ #define XFSMNT_DIRSYNC 0x40000000 /* sync creat,link,unlink,rename * symlink,mkdir,rmdir,mknod */ #define XFSMNT_FLAGS2 0x80000000 /* more flags set in flags2 */ diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c index de35d18cc002..584f1ae85cd9 100644 --- a/fs/xfs/xfs_dfrag.c +++ b/fs/xfs/xfs_dfrag.c @@ -42,6 +42,7 @@ #include "xfs_dfrag.h" #include "xfs_error.h" #include "xfs_rw.h" +#include "xfs_vnodeops.h" /* * Syssgi interface for swapext @@ -199,7 +200,8 @@ xfs_swap_extents( if (VN_CACHED(tvp) != 0) { xfs_inval_cached_trace(&tip->i_iocore, 0, -1, 0, -1); - error = bhv_vop_flushinval_pages(tvp, 0, -1, FI_REMAPF_LOCKED); + error = xfs_flushinval_pages(tip, 0, -1, + FI_REMAPF_LOCKED); if (error) goto error0; } @@ -265,7 +267,7 @@ xfs_swap_extents( * fields change. */ - bhv_vop_toss_pages(vp, 0, -1, FI_REMAPF); + xfs_tosspages(ip, 0, -1, FI_REMAPF); tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT); if ((error = xfs_trans_reserve(tp, 0, diff --git a/fs/xfs/xfs_dinode.h b/fs/xfs/xfs_dinode.h index fefd0116bac9..dedd713574e1 100644 --- a/fs/xfs/xfs_dinode.h +++ b/fs/xfs/xfs_dinode.h @@ -34,41 +34,41 @@ struct xfs_mount; * because we only need the core part in the in-core inode. */ typedef struct xfs_timestamp { - __int32_t t_sec; /* timestamp seconds */ - __int32_t t_nsec; /* timestamp nanoseconds */ + __be32 t_sec; /* timestamp seconds */ + __be32 t_nsec; /* timestamp nanoseconds */ } xfs_timestamp_t; /* * Note: Coordinate changes to this structure with the XFS_DI_* #defines - * below and the offsets table in xfs_ialloc_log_di(). + * below, the offsets table in xfs_ialloc_log_di() and struct xfs_icdinode + * in xfs_inode.h. */ -typedef struct xfs_dinode_core -{ - __uint16_t di_magic; /* inode magic # = XFS_DINODE_MAGIC */ - __uint16_t di_mode; /* mode and type of file */ - __int8_t di_version; /* inode version */ - __int8_t di_format; /* format of di_c data */ - __uint16_t di_onlink; /* old number of links to file */ - __uint32_t di_uid; /* owner's user id */ - __uint32_t di_gid; /* owner's group id */ - __uint32_t di_nlink; /* number of links to file */ - __uint16_t di_projid; /* owner's project id */ - __uint8_t di_pad[8]; /* unused, zeroed space */ - __uint16_t di_flushiter; /* incremented on flush */ +typedef struct xfs_dinode_core { + __be16 di_magic; /* inode magic # = XFS_DINODE_MAGIC */ + __be16 di_mode; /* mode and type of file */ + __u8 di_version; /* inode version */ + __u8 di_format; /* format of di_c data */ + __be16 di_onlink; /* old number of links to file */ + __be32 di_uid; /* owner's user id */ + __be32 di_gid; /* owner's group id */ + __be32 di_nlink; /* number of links to file */ + __be16 di_projid; /* owner's project id */ + __u8 di_pad[8]; /* unused, zeroed space */ + __be16 di_flushiter; /* incremented on flush */ xfs_timestamp_t di_atime; /* time last accessed */ xfs_timestamp_t di_mtime; /* time last modified */ xfs_timestamp_t di_ctime; /* time created/inode modified */ - xfs_fsize_t di_size; /* number of bytes in file */ - xfs_drfsbno_t di_nblocks; /* # of direct & btree blocks used */ - xfs_extlen_t di_extsize; /* basic/minimum extent size for file */ - xfs_extnum_t di_nextents; /* number of extents in data fork */ - xfs_aextnum_t di_anextents; /* number of extents in attribute fork*/ - __uint8_t di_forkoff; /* attr fork offs, <<3 for 64b align */ - __int8_t di_aformat; /* format of attr fork's data */ - __uint32_t di_dmevmask; /* DMIG event mask */ - __uint16_t di_dmstate; /* DMIG state info */ - __uint16_t di_flags; /* random flags, XFS_DIFLAG_... */ - __uint32_t di_gen; /* generation number */ + __be64 di_size; /* number of bytes in file */ + __be64 di_nblocks; /* # of direct & btree blocks used */ + __be32 di_extsize; /* basic/minimum extent size for file */ + __be32 di_nextents; /* number of extents in data fork */ + __be16 di_anextents; /* number of extents in attribute fork*/ + __u8 di_forkoff; /* attr fork offs, <<3 for 64b align */ + __s8 di_aformat; /* format of attr fork's data */ + __be32 di_dmevmask; /* DMIG event mask */ + __be16 di_dmstate; /* DMIG state info */ + __be16 di_flags; /* random flags, XFS_DIFLAG_... */ + __be32 di_gen; /* generation number */ } xfs_dinode_core_t; #define DI_MAX_FLUSH 0xffff @@ -81,13 +81,13 @@ typedef struct xfs_dinode * sure to update the macros like XFS_LITINO below and * XFS_BMAP_RBLOCK_DSIZE in xfs_bmap_btree.h. */ - xfs_agino_t di_next_unlinked;/* agi unlinked list ptr */ + __be32 di_next_unlinked;/* agi unlinked list ptr */ union { xfs_bmdr_block_t di_bmbt; /* btree root block */ xfs_bmbt_rec_32_t di_bmx[1]; /* extent list */ xfs_dir2_sf_t di_dir2sf; /* shortform directory v2 */ char di_c[1]; /* local contents */ - xfs_dev_t di_dev; /* device for S_IFCHR/S_IFBLK */ + __be32 di_dev; /* device for S_IFCHR/S_IFBLK */ uuid_t di_muuid; /* mount point value */ char di_symlink[1]; /* local symbolic link */ } di_u; @@ -175,8 +175,7 @@ typedef enum xfs_dinode_fmt #define XFS_CFORK_Q_DISK(dcp) ((dcp)->di_forkoff != 0) #define XFS_CFORK_BOFF(dcp) ((int)((dcp)->di_forkoff << 3)) -#define XFS_CFORK_BOFF_DISK(dcp) \ - ((int)(INT_GET((dcp)->di_forkoff, ARCH_CONVERT) << 3)) +#define XFS_CFORK_BOFF_DISK(dcp) ((int)((dcp)->di_forkoff << 3)) #define XFS_CFORK_DSIZE_DISK(dcp,mp) \ (XFS_CFORK_Q_DISK(dcp) ? XFS_CFORK_BOFF_DISK(dcp) : XFS_LITINO(mp)) @@ -225,8 +224,8 @@ typedef enum xfs_dinode_fmt #define XFS_CFORK_NEXTENTS_DISK(dcp,w) \ ((w) == XFS_DATA_FORK ? \ - INT_GET((dcp)->di_nextents, ARCH_CONVERT) : \ - INT_GET((dcp)->di_anextents, ARCH_CONVERT)) + be32_to_cpu((dcp)->di_nextents) : \ + be16_to_cpu((dcp)->di_anextents)) #define XFS_CFORK_NEXTENTS(dcp,w) \ ((w) == XFS_DATA_FORK ? (dcp)->di_nextents : (dcp)->di_anextents) #define XFS_DFORK_NEXTENTS(dip,w) XFS_CFORK_NEXTENTS_DISK(&(dip)->di_core, w) diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c index 29e091914df4..b0f1ee8fcb90 100644 --- a/fs/xfs/xfs_dir2.c +++ b/fs/xfs/xfs_dir2.c @@ -43,8 +43,6 @@ #include "xfs_dir2_trace.h" #include "xfs_error.h" -static int xfs_dir2_put_dirent64_direct(xfs_dir2_put_args_t *pa); -static int xfs_dir2_put_dirent64_uio(xfs_dir2_put_args_t *pa); void xfs_dir_mount( @@ -293,47 +291,33 @@ xfs_dir_removename( * Read a directory. */ int -xfs_dir_getdents( - xfs_trans_t *tp, +xfs_readdir( xfs_inode_t *dp, - uio_t *uio, /* caller's buffer control */ - int *eofp) /* out: eof reached */ + void *dirent, + size_t bufsize, + xfs_off_t *offset, + filldir_t filldir) { - int alignment; /* alignment required for ABI */ - xfs_dirent_t *dbp; /* malloc'ed buffer */ - xfs_dir2_put_t put; /* entry formatting routine */ int rval; /* return value */ int v; /* type-checking value */ + vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); + + if (XFS_FORCED_SHUTDOWN(dp->i_mount)) + return XFS_ERROR(EIO); + ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); XFS_STATS_INC(xs_dir_getdents); - /* - * If our caller has given us a single contiguous aligned memory buffer, - * just work directly within that buffer. If it's in user memory, - * lock it down first. - */ - alignment = sizeof(xfs_off_t) - 1; - if ((uio->uio_iovcnt == 1) && - (((__psint_t)uio->uio_iov[0].iov_base & alignment) == 0) && - ((uio->uio_iov[0].iov_len & alignment) == 0)) { - dbp = NULL; - put = xfs_dir2_put_dirent64_direct; - } else { - dbp = kmem_alloc(sizeof(*dbp) + MAXNAMELEN, KM_SLEEP); - put = xfs_dir2_put_dirent64_uio; - } - *eofp = 0; if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) - rval = xfs_dir2_sf_getdents(dp, uio, eofp, dbp, put); - else if ((rval = xfs_dir2_isblock(tp, dp, &v))) + rval = xfs_dir2_sf_getdents(dp, dirent, offset, filldir); + else if ((rval = xfs_dir2_isblock(NULL, dp, &v))) ; else if (v) - rval = xfs_dir2_block_getdents(tp, dp, uio, eofp, dbp, put); + rval = xfs_dir2_block_getdents(dp, dirent, offset, filldir); else - rval = xfs_dir2_leaf_getdents(tp, dp, uio, eofp, dbp, put); - if (dbp != NULL) - kmem_free(dbp, sizeof(*dbp) + MAXNAMELEN); + rval = xfs_dir2_leaf_getdents(dp, dirent, bufsize, offset, + filldir); return rval; } @@ -613,77 +597,6 @@ xfs_dir2_isleaf( } /* - * Getdents put routine for 64-bit ABI, direct form. - */ -static int -xfs_dir2_put_dirent64_direct( - xfs_dir2_put_args_t *pa) -{ - xfs_dirent_t *idbp; /* dirent pointer */ - iovec_t *iovp; /* io vector */ - int namelen; /* entry name length */ - int reclen; /* entry total length */ - uio_t *uio; /* I/O control */ - - namelen = pa->namelen; - reclen = DIRENTSIZE(namelen); - uio = pa->uio; - /* - * Won't fit in the remaining space. - */ - if (reclen > uio->uio_resid) { - pa->done = 0; - return 0; - } - iovp = uio->uio_iov; - idbp = (xfs_dirent_t *)iovp->iov_base; - iovp->iov_base = (char *)idbp + reclen; - iovp->iov_len -= reclen; - uio->uio_resid -= reclen; - idbp->d_reclen = reclen; - idbp->d_ino = pa->ino; - idbp->d_off = pa->cook; - idbp->d_name[namelen] = '\0'; - pa->done = 1; - memcpy(idbp->d_name, pa->name, namelen); - return 0; -} - -/* - * Getdents put routine for 64-bit ABI, uio form. - */ -static int -xfs_dir2_put_dirent64_uio( - xfs_dir2_put_args_t *pa) -{ - xfs_dirent_t *idbp; /* dirent pointer */ - int namelen; /* entry name length */ - int reclen; /* entry total length */ - int rval; /* return value */ - uio_t *uio; /* I/O control */ - - namelen = pa->namelen; - reclen = DIRENTSIZE(namelen); - uio = pa->uio; - /* - * Won't fit in the remaining space. - */ - if (reclen > uio->uio_resid) { - pa->done = 0; - return 0; - } - idbp = pa->dbp; - idbp->d_reclen = reclen; - idbp->d_ino = pa->ino; - idbp->d_off = pa->cook; - idbp->d_name[namelen] = '\0'; - memcpy(idbp->d_name, pa->name, namelen); - rval = xfs_uio_read((caddr_t)idbp, reclen, uio); - pa->done = (rval == 0); - return rval; -} - -/* * Remove the given block from the directory. * This routine is used for data and free blocks, leaf/node are done * by xfs_da_shrink_inode. diff --git a/fs/xfs/xfs_dir2.h b/fs/xfs/xfs_dir2.h index 86560b6f794c..b265197e74cf 100644 --- a/fs/xfs/xfs_dir2.h +++ b/fs/xfs/xfs_dir2.h @@ -60,21 +60,6 @@ typedef __uint32_t xfs_dir2_db_t; typedef xfs_off_t xfs_dir2_off_t; /* - * For getdents, argument struct for put routines. - */ -typedef int (*xfs_dir2_put_t)(struct xfs_dir2_put_args *pa); -typedef struct xfs_dir2_put_args { - xfs_off_t cook; /* cookie of (next) entry */ - xfs_intino_t ino; /* inode number */ - xfs_dirent_t *dbp; /* buffer pointer */ - char *name; /* directory entry name */ - int namelen; /* length of name */ - int done; /* output: set if value was stored */ - xfs_dir2_put_t put; /* put function ptr (i/o) */ - struct uio *uio; /* uio control structure */ -} xfs_dir2_put_args_t; - -/* * Generic directory interface routines */ extern void xfs_dir_startup(void); @@ -92,8 +77,6 @@ extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp, char *name, int namelen, xfs_ino_t ino, xfs_fsblock_t *first, struct xfs_bmap_free *flist, xfs_extlen_t tot); -extern int xfs_dir_getdents(struct xfs_trans *tp, struct xfs_inode *dp, - uio_t *uio, int *eofp); extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp, char *name, int namelen, xfs_ino_t inum, xfs_fsblock_t *first, diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c index e4df1aaae2a2..c171767e242a 100644 --- a/fs/xfs/xfs_dir2_block.c +++ b/fs/xfs/xfs_dir2_block.c @@ -22,6 +22,7 @@ #include "xfs_inum.h" #include "xfs_trans.h" #include "xfs_sb.h" +#include "xfs_ag.h" #include "xfs_dir2.h" #include "xfs_dmapi.h" #include "xfs_mount.h" @@ -432,12 +433,10 @@ xfs_dir2_block_addname( */ int /* error */ xfs_dir2_block_getdents( - xfs_trans_t *tp, /* transaction (NULL) */ xfs_inode_t *dp, /* incore inode */ - uio_t *uio, /* caller's buffer control */ - int *eofp, /* eof reached? (out) */ - xfs_dirent_t *dbp, /* caller's buffer */ - xfs_dir2_put_t put) /* abi's formatting function */ + void *dirent, + xfs_off_t *offset, + filldir_t filldir) { xfs_dir2_block_t *block; /* directory block structure */ xfs_dabuf_t *bp; /* buffer for block */ @@ -447,31 +446,32 @@ xfs_dir2_block_getdents( char *endptr; /* end of the data entries */ int error; /* error return value */ xfs_mount_t *mp; /* filesystem mount point */ - xfs_dir2_put_args_t p; /* arg package for put rtn */ char *ptr; /* current data entry */ int wantoff; /* starting block offset */ + xfs_ino_t ino; + xfs_off_t cook; mp = dp->i_mount; /* * If the block number in the offset is out of range, we're done. */ - if (xfs_dir2_dataptr_to_db(mp, uio->uio_offset) > mp->m_dirdatablk) { - *eofp = 1; + if (xfs_dir2_dataptr_to_db(mp, *offset) > mp->m_dirdatablk) { return 0; } /* * Can't read the block, give up, else get dabuf in bp. */ - if ((error = - xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &bp, XFS_DATA_FORK))) { + error = xfs_da_read_buf(NULL, dp, mp->m_dirdatablk, -1, + &bp, XFS_DATA_FORK); + if (error) return error; - } + ASSERT(bp != NULL); /* * Extract the byte offset we start at from the seek pointer. * We'll skip entries before this. */ - wantoff = xfs_dir2_dataptr_to_off(mp, uio->uio_offset); + wantoff = xfs_dir2_dataptr_to_off(mp, *offset); block = bp->data; xfs_dir2_data_check(dp, bp); /* @@ -480,9 +480,7 @@ xfs_dir2_block_getdents( btp = xfs_dir2_block_tail_p(mp, block); ptr = (char *)block->u; endptr = (char *)xfs_dir2_block_leaf_p(btp); - p.dbp = dbp; - p.put = put; - p.uio = uio; + /* * Loop over the data portion of the block. * Each object is a real entry (dep) or an unused one (dup). @@ -508,33 +506,24 @@ xfs_dir2_block_getdents( */ if ((char *)dep - (char *)block < wantoff) continue; - /* - * Set up argument structure for put routine. - */ - p.namelen = dep->namelen; - p.cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, + cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, ptr - (char *)block); - p.ino = be64_to_cpu(dep->inumber); + ino = be64_to_cpu(dep->inumber); #if XFS_BIG_INUMS - p.ino += mp->m_inoadd; + ino += mp->m_inoadd; #endif - p.name = (char *)dep->name; - - /* - * Put the entry in the caller's buffer. - */ - error = p.put(&p); /* * If it didn't fit, set the final offset to here & return. */ - if (!p.done) { - uio->uio_offset = - xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, + if (filldir(dirent, dep->name, dep->namelen, cook, + ino, DT_UNKNOWN)) { + *offset = xfs_dir2_db_off_to_dataptr(mp, + mp->m_dirdatablk, (char *)dep - (char *)block); - xfs_da_brelse(tp, bp); - return error; + xfs_da_brelse(NULL, bp); + return 0; } } @@ -542,13 +531,8 @@ xfs_dir2_block_getdents( * Reached the end of the block. * Set the offset to a non-existent block 1 and return. */ - *eofp = 1; - - uio->uio_offset = - xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0); - - xfs_da_brelse(tp, bp); - + *offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0); + xfs_da_brelse(NULL, bp); return 0; } diff --git a/fs/xfs/xfs_dir2_block.h b/fs/xfs/xfs_dir2_block.h index e7c2606161e9..10e689676382 100644 --- a/fs/xfs/xfs_dir2_block.h +++ b/fs/xfs/xfs_dir2_block.h @@ -80,9 +80,8 @@ xfs_dir2_block_leaf_p(xfs_dir2_block_tail_t *btp) * Function declarations. */ extern int xfs_dir2_block_addname(struct xfs_da_args *args); -extern int xfs_dir2_block_getdents(struct xfs_trans *tp, struct xfs_inode *dp, - struct uio *uio, int *eofp, - struct xfs_dirent *dbp, xfs_dir2_put_t put); +extern int xfs_dir2_block_getdents(struct xfs_inode *dp, void *dirent, + xfs_off_t *offset, filldir_t filldir); extern int xfs_dir2_block_lookup(struct xfs_da_args *args); extern int xfs_dir2_block_removename(struct xfs_da_args *args); extern int xfs_dir2_block_replace(struct xfs_da_args *args); diff --git a/fs/xfs/xfs_dir2_data.c b/fs/xfs/xfs_dir2_data.c index 7ebe295bd6d3..d2452699e9b1 100644 --- a/fs/xfs/xfs_dir2_data.c +++ b/fs/xfs/xfs_dir2_data.c @@ -22,6 +22,7 @@ #include "xfs_inum.h" #include "xfs_trans.h" #include "xfs_sb.h" +#include "xfs_ag.h" #include "xfs_dir2.h" #include "xfs_dmapi.h" #include "xfs_mount.h" diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c index 1b73c9ad646a..e7c12fa1303e 100644 --- a/fs/xfs/xfs_dir2_leaf.c +++ b/fs/xfs/xfs_dir2_leaf.c @@ -749,12 +749,11 @@ xfs_dir2_leaf_compact_x1( */ int /* error */ xfs_dir2_leaf_getdents( - xfs_trans_t *tp, /* transaction pointer */ xfs_inode_t *dp, /* incore directory inode */ - uio_t *uio, /* I/O control & vectors */ - int *eofp, /* out: reached end of dir */ - xfs_dirent_t *dbp, /* caller's buffer */ - xfs_dir2_put_t put) /* ABI formatting routine */ + void *dirent, + size_t bufsize, + xfs_off_t *offset, + filldir_t filldir) { xfs_dabuf_t *bp; /* data block buffer */ int byteoff; /* offset in current block */ @@ -763,7 +762,6 @@ xfs_dir2_leaf_getdents( xfs_dir2_data_t *data; /* data block structure */ xfs_dir2_data_entry_t *dep; /* data entry */ xfs_dir2_data_unused_t *dup; /* unused entry */ - int eof; /* reached end of directory */ int error = 0; /* error return value */ int i; /* temporary loop index */ int j; /* temporary loop index */ @@ -776,46 +774,38 @@ xfs_dir2_leaf_getdents( xfs_mount_t *mp; /* filesystem mount point */ xfs_dir2_off_t newoff; /* new curoff after new blk */ int nmap; /* mappings to ask xfs_bmapi */ - xfs_dir2_put_args_t *p; /* formatting arg bundle */ char *ptr = NULL; /* pointer to current data */ int ra_current; /* number of read-ahead blks */ int ra_index; /* *map index for read-ahead */ int ra_offset; /* map entry offset for ra */ int ra_want; /* readahead count wanted */ + xfs_ino_t ino; /* * If the offset is at or past the largest allowed value, - * give up right away, return eof. + * give up right away. */ - if (uio->uio_offset >= XFS_DIR2_MAX_DATAPTR) { - *eofp = 1; + if (*offset >= XFS_DIR2_MAX_DATAPTR) return 0; - } + mp = dp->i_mount; - /* - * Setup formatting arguments. - */ - p = kmem_alloc(sizeof(*p), KM_SLEEP); - p->dbp = dbp; - p->put = put; - p->uio = uio; + /* * Set up to bmap a number of blocks based on the caller's * buffer size, the directory block size, and the filesystem * block size. */ - map_size = - howmany(uio->uio_resid + mp->m_dirblksize, - mp->m_sb.sb_blocksize); + map_size = howmany(bufsize + mp->m_dirblksize, mp->m_sb.sb_blocksize); map = kmem_alloc(map_size * sizeof(*map), KM_SLEEP); map_valid = ra_index = ra_offset = ra_current = map_blocks = 0; bp = NULL; - eof = 1; + /* * Inside the loop we keep the main offset value as a byte offset * in the directory file. */ - curoff = xfs_dir2_dataptr_to_byte(mp, uio->uio_offset); + curoff = xfs_dir2_dataptr_to_byte(mp, *offset); + /* * Force this conversion through db so we truncate the offset * down to get the start of the data block. @@ -836,7 +826,7 @@ xfs_dir2_leaf_getdents( * take it out of the mapping. */ if (bp) { - xfs_da_brelse(tp, bp); + xfs_da_brelse(NULL, bp); bp = NULL; map_blocks -= mp->m_dirblkfsbs; /* @@ -862,8 +852,9 @@ xfs_dir2_leaf_getdents( /* * Recalculate the readahead blocks wanted. */ - ra_want = howmany(uio->uio_resid + mp->m_dirblksize, + ra_want = howmany(bufsize + mp->m_dirblksize, mp->m_sb.sb_blocksize) - 1; + /* * If we don't have as many as we want, and we haven't * run out of data blocks, get some more mappings. @@ -876,7 +867,7 @@ xfs_dir2_leaf_getdents( * we already have in the table. */ nmap = map_size - map_valid; - error = xfs_bmapi(tp, dp, + error = xfs_bmapi(NULL, dp, map_off, xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET) - map_off, @@ -939,7 +930,7 @@ xfs_dir2_leaf_getdents( * mapping. */ curdb = xfs_dir2_da_to_db(mp, map->br_startoff); - error = xfs_da_read_buf(tp, dp, map->br_startoff, + error = xfs_da_read_buf(NULL, dp, map->br_startoff, map->br_blockcount >= mp->m_dirblkfsbs ? XFS_FSB_TO_DADDR(mp, map->br_startblock) : -1, @@ -982,7 +973,7 @@ xfs_dir2_leaf_getdents( * is a very rare case. */ else if (i > ra_current) { - (void)xfs_da_reada_buf(tp, dp, + (void)xfs_da_reada_buf(NULL, dp, map[ra_index].br_startoff + ra_offset, XFS_DATA_FORK); ra_current = i; @@ -1089,46 +1080,39 @@ xfs_dir2_leaf_getdents( */ dep = (xfs_dir2_data_entry_t *)ptr; - p->namelen = dep->namelen; - - length = xfs_dir2_data_entsize(p->namelen); - - p->cook = xfs_dir2_byte_to_dataptr(mp, curoff + length); + length = xfs_dir2_data_entsize(dep->namelen); - p->ino = be64_to_cpu(dep->inumber); + ino = be64_to_cpu(dep->inumber); #if XFS_BIG_INUMS - p->ino += mp->m_inoadd; + ino += mp->m_inoadd; #endif - p->name = (char *)dep->name; - - error = p->put(p); /* * Won't fit. Return to caller. */ - if (!p->done) { - eof = 0; + if (filldir(dirent, dep->name, dep->namelen, + xfs_dir2_byte_to_dataptr(mp, curoff + length), + ino, DT_UNKNOWN)) break; - } + /* * Advance to next entry in the block. */ ptr += length; curoff += length; + bufsize -= length; } /* * All done. Set output offset value to current offset. */ - *eofp = eof; if (curoff > xfs_dir2_dataptr_to_byte(mp, XFS_DIR2_MAX_DATAPTR)) - uio->uio_offset = XFS_DIR2_MAX_DATAPTR; + *offset = XFS_DIR2_MAX_DATAPTR; else - uio->uio_offset = xfs_dir2_byte_to_dataptr(mp, curoff); + *offset = xfs_dir2_byte_to_dataptr(mp, curoff); kmem_free(map, map_size * sizeof(*map)); - kmem_free(p, sizeof(*p)); if (bp) - xfs_da_brelse(tp, bp); + xfs_da_brelse(NULL, bp); return error; } diff --git a/fs/xfs/xfs_dir2_leaf.h b/fs/xfs/xfs_dir2_leaf.h index 70c97f3f815e..6c9539f06987 100644 --- a/fs/xfs/xfs_dir2_leaf.h +++ b/fs/xfs/xfs_dir2_leaf.h @@ -232,9 +232,9 @@ extern void xfs_dir2_leaf_compact(struct xfs_da_args *args, extern void xfs_dir2_leaf_compact_x1(struct xfs_dabuf *bp, int *indexp, int *lowstalep, int *highstalep, int *lowlogp, int *highlogp); -extern int xfs_dir2_leaf_getdents(struct xfs_trans *tp, struct xfs_inode *dp, - struct uio *uio, int *eofp, - struct xfs_dirent *dbp, xfs_dir2_put_t put); +extern int xfs_dir2_leaf_getdents(struct xfs_inode *dp, void *dirent, + size_t bufsize, xfs_off_t *offset, + filldir_t filldir); extern int xfs_dir2_leaf_init(struct xfs_da_args *args, xfs_dir2_db_t bno, struct xfs_dabuf **bpp, int magic); extern void xfs_dir2_leaf_log_ents(struct xfs_trans *tp, struct xfs_dabuf *bp, diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c index 91c61d9632c8..eb18e399e836 100644 --- a/fs/xfs/xfs_dir2_node.c +++ b/fs/xfs/xfs_dir2_node.c @@ -22,6 +22,7 @@ #include "xfs_inum.h" #include "xfs_trans.h" #include "xfs_sb.h" +#include "xfs_ag.h" #include "xfs_dir2.h" #include "xfs_dmapi.h" #include "xfs_mount.h" diff --git a/fs/xfs/xfs_dir2_sf.c b/fs/xfs/xfs_dir2_sf.c index 38fc4f22b76d..182c70315ad1 100644 --- a/fs/xfs/xfs_dir2_sf.c +++ b/fs/xfs/xfs_dir2_sf.c @@ -22,6 +22,7 @@ #include "xfs_inum.h" #include "xfs_trans.h" #include "xfs_sb.h" +#include "xfs_ag.h" #include "xfs_dir2.h" #include "xfs_dmapi.h" #include "xfs_mount.h" @@ -695,19 +696,18 @@ xfs_dir2_sf_create( int /* error */ xfs_dir2_sf_getdents( xfs_inode_t *dp, /* incore directory inode */ - uio_t *uio, /* caller's buffer control */ - int *eofp, /* eof reached? (out) */ - xfs_dirent_t *dbp, /* caller's buffer */ - xfs_dir2_put_t put) /* abi's formatting function */ + void *dirent, + xfs_off_t *offset, + filldir_t filldir) { - int error; /* error return value */ int i; /* shortform entry number */ xfs_mount_t *mp; /* filesystem mount point */ xfs_dir2_dataptr_t off; /* current entry's offset */ - xfs_dir2_put_args_t p; /* arg package for put rtn */ xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ xfs_dir2_sf_t *sfp; /* shortform structure */ - xfs_off_t dir_offset; + xfs_dir2_dataptr_t dot_offset; + xfs_dir2_dataptr_t dotdot_offset; + xfs_ino_t ino; mp = dp->i_mount; @@ -720,8 +720,6 @@ xfs_dir2_sf_getdents( return XFS_ERROR(EIO); } - dir_offset = uio->uio_offset; - ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); ASSERT(dp->i_df.if_u1.if_data != NULL); @@ -732,108 +730,78 @@ xfs_dir2_sf_getdents( /* * If the block number in the offset is out of range, we're done. */ - if (xfs_dir2_dataptr_to_db(mp, dir_offset) > mp->m_dirdatablk) { - *eofp = 1; + if (xfs_dir2_dataptr_to_db(mp, *offset) > mp->m_dirdatablk) return 0; - } /* - * Set up putargs structure. + * Precalculate offsets for . and .. as we will always need them. + * + * XXX(hch): the second argument is sometimes 0 and sometimes + * mp->m_dirdatablk. */ - p.dbp = dbp; - p.put = put; - p.uio = uio; + dot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, + XFS_DIR2_DATA_DOT_OFFSET); + dotdot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, + XFS_DIR2_DATA_DOTDOT_OFFSET); + /* * Put . entry unless we're starting past it. */ - if (dir_offset <= - xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, - XFS_DIR2_DATA_DOT_OFFSET)) { - p.cook = xfs_dir2_db_off_to_dataptr(mp, 0, - XFS_DIR2_DATA_DOTDOT_OFFSET); - p.ino = dp->i_ino; + if (*offset <= dot_offset) { + ino = dp->i_ino; #if XFS_BIG_INUMS - p.ino += mp->m_inoadd; + ino += mp->m_inoadd; #endif - p.name = "."; - p.namelen = 1; - - error = p.put(&p); - - if (!p.done) { - uio->uio_offset = - xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, - XFS_DIR2_DATA_DOT_OFFSET); - return error; + if (filldir(dirent, ".", 1, dotdot_offset, ino, DT_DIR)) { + *offset = dot_offset; + return 0; } } /* * Put .. entry unless we're starting past it. */ - if (dir_offset <= - xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, - XFS_DIR2_DATA_DOTDOT_OFFSET)) { - p.cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, - XFS_DIR2_DATA_FIRST_OFFSET); - p.ino = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent); + if (*offset <= dotdot_offset) { + off = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, + XFS_DIR2_DATA_FIRST_OFFSET); + ino = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent); #if XFS_BIG_INUMS - p.ino += mp->m_inoadd; + ino += mp->m_inoadd; #endif - p.name = ".."; - p.namelen = 2; - - error = p.put(&p); - - if (!p.done) { - uio->uio_offset = - xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, - XFS_DIR2_DATA_DOTDOT_OFFSET); - return error; + if (filldir(dirent, "..", 2, off, ino, DT_DIR)) { + *offset = dotdot_offset; + return 0; } } /* * Loop while there are more entries and put'ing works. */ - for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); - i < sfp->hdr.count; - i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) { - + sfep = xfs_dir2_sf_firstentry(sfp); + for (i = 0; i < sfp->hdr.count; i++) { off = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, xfs_dir2_sf_get_offset(sfep)); - if (dir_offset > off) + if (*offset > off) { + sfep = xfs_dir2_sf_nextentry(sfp, sfep); continue; + } - p.namelen = sfep->namelen; - - p.cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, - xfs_dir2_sf_get_offset(sfep) + - xfs_dir2_data_entsize(p.namelen)); - - p.ino = xfs_dir2_sf_get_inumber(sfp, xfs_dir2_sf_inumberp(sfep)); + ino = xfs_dir2_sf_get_inumber(sfp, xfs_dir2_sf_inumberp(sfep)); #if XFS_BIG_INUMS - p.ino += mp->m_inoadd; + ino += mp->m_inoadd; #endif - p.name = (char *)sfep->name; - - error = p.put(&p); - if (!p.done) { - uio->uio_offset = off; - return error; + if (filldir(dirent, sfep->name, sfep->namelen, + off + xfs_dir2_data_entsize(sfep->namelen), + ino, DT_UNKNOWN)) { + *offset = off; + return 0; } + sfep = xfs_dir2_sf_nextentry(sfp, sfep); } - /* - * They all fit. - */ - *eofp = 1; - - uio->uio_offset = - xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0); - + *offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0); return 0; } diff --git a/fs/xfs/xfs_dir2_sf.h b/fs/xfs/xfs_dir2_sf.h index 11e503209afa..005629d702d2 100644 --- a/fs/xfs/xfs_dir2_sf.h +++ b/fs/xfs/xfs_dir2_sf.h @@ -169,9 +169,8 @@ extern int xfs_dir2_block_to_sf(struct xfs_da_args *args, struct xfs_dabuf *bp, int size, xfs_dir2_sf_hdr_t *sfhp); extern int xfs_dir2_sf_addname(struct xfs_da_args *args); extern int xfs_dir2_sf_create(struct xfs_da_args *args, xfs_ino_t pino); -extern int xfs_dir2_sf_getdents(struct xfs_inode *dp, struct uio *uio, - int *eofp, struct xfs_dirent *dbp, - xfs_dir2_put_t put); +extern int xfs_dir2_sf_getdents(struct xfs_inode *dp, void *dirent, + xfs_off_t *offset, filldir_t filldir); extern int xfs_dir2_sf_lookup(struct xfs_da_args *args); extern int xfs_dir2_sf_removename(struct xfs_da_args *args); extern int xfs_dir2_sf_replace(struct xfs_da_args *args); diff --git a/fs/xfs/xfs_dmapi.h b/fs/xfs/xfs_dmapi.h index adc3d251240d..f71784ab6a60 100644 --- a/fs/xfs/xfs_dmapi.h +++ b/fs/xfs/xfs_dmapi.h @@ -67,17 +67,15 @@ typedef enum { #define HAVE_DM_RIGHT_T /* Defines for determining if an event message should be sent. */ -#define DM_EVENT_ENABLED(vfsp, ip, event) ( \ - unlikely ((vfsp)->vfs_flag & VFS_DMI) && \ +#ifdef HAVE_DMAPI +#define DM_EVENT_ENABLED(ip, event) ( \ + unlikely ((ip)->i_mount->m_flags & XFS_MOUNT_DMAPI) && \ ( ((ip)->i_d.di_dmevmask & (1 << event)) || \ ((ip)->i_mount->m_dmevmask & (1 << event)) ) \ ) - -#define DM_EVENT_ENABLED_IO(vfsp, io, event) ( \ - unlikely ((vfsp)->vfs_flag & VFS_DMI) && \ - ( ((io)->io_dmevmask & (1 << event)) || \ - ((io)->io_mount->m_dmevmask & (1 << event)) ) \ - ) +#else +#define DM_EVENT_ENABLED(ip, event) (0) +#endif #define DM_XFS_VALID_FS_EVENTS ( \ (1 << DM_EVENT_PREUNMOUNT) | \ @@ -170,7 +168,4 @@ typedef enum { DM_FLAGS_NDELAY : 0) #define AT_DELAY_FLAG(f) ((f&ATTR_NONBLOCK) ? DM_FLAGS_NDELAY : 0) - -extern struct bhv_module_vfsops xfs_dmops; - #endif /* __XFS_DMAPI_H__ */ diff --git a/fs/xfs/xfs_dmops.c b/fs/xfs/xfs_dmops.c index 1e4a35ddf7f9..a1e55fb9d5dd 100644 --- a/fs/xfs/xfs_dmops.c +++ b/fs/xfs/xfs_dmops.c @@ -19,18 +19,38 @@ #include "xfs_fs.h" #include "xfs_types.h" #include "xfs_log.h" -#include "xfs_inum.h" #include "xfs_trans.h" #include "xfs_sb.h" -#include "xfs_ag.h" -#include "xfs_dir2.h" #include "xfs_dmapi.h" +#include "xfs_inum.h" +#include "xfs_ag.h" #include "xfs_mount.h" +#include "xfs_clnt.h" -xfs_dmops_t xfs_dmcore_stub = { + +static struct xfs_dmops xfs_dmcore_stub = { .xfs_send_data = (xfs_send_data_t)fs_nosys, .xfs_send_mmap = (xfs_send_mmap_t)fs_noerr, .xfs_send_destroy = (xfs_send_destroy_t)fs_nosys, .xfs_send_namesp = (xfs_send_namesp_t)fs_nosys, - .xfs_send_unmount = (xfs_send_unmount_t)fs_noval, + .xfs_send_mount = (xfs_send_mount_t)fs_nosys, + .xfs_send_unmount = (xfs_send_unmount_t)fs_noerr, }; + +int +xfs_dmops_get(struct xfs_mount *mp, struct xfs_mount_args *args) +{ + if (args->flags & XFSMNT_DMAPI) { + cmn_err(CE_WARN, + "XFS: dmapi support not available in this kernel."); + return EINVAL; + } + + mp->m_dm_ops = &xfs_dmcore_stub; + return 0; +} + +void +xfs_dmops_put(struct xfs_mount *mp) +{ +} diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c index 8c4331631337..a4634d94e561 100644 --- a/fs/xfs/xfs_error.c +++ b/fs/xfs/xfs_error.c @@ -22,6 +22,7 @@ #include "xfs_inum.h" #include "xfs_trans.h" #include "xfs_sb.h" +#include "xfs_ag.h" #include "xfs_dir2.h" #include "xfs_dmapi.h" #include "xfs_mount.h" @@ -132,10 +133,14 @@ xfs_errortag_add(int error_tag, xfs_mount_t *mp) } int -xfs_errortag_clearall_umount(int64_t fsid, char *fsname, int loud) +xfs_errortag_clearall(xfs_mount_t *mp, int loud) { - int i; + int64_t fsid; int cleared = 0; + int i; + + memcpy(&fsid, mp->m_fixedfsid, sizeof(xfs_fsid_t)); + for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) { if ((fsid == 0LL || xfs_etest_fsid[i] == fsid) && @@ -154,20 +159,10 @@ xfs_errortag_clearall_umount(int64_t fsid, char *fsname, int loud) if (loud || cleared) cmn_err(CE_WARN, "Cleared all XFS error tags for filesystem \"%s\"", - fsname); + mp->m_fsname); return 0; } - -int -xfs_errortag_clearall(xfs_mount_t *mp) -{ - int64_t fsid; - - memcpy(&fsid, mp->m_fixedfsid, sizeof(xfs_fsid_t)); - - return xfs_errortag_clearall_umount(fsid, mp->m_fsname, 1); -} #endif /* DEBUG || INDUCE_IO_ERROR */ static void diff --git a/fs/xfs/xfs_error.h b/fs/xfs/xfs_error.h index 5599ada456a1..10e9d9619ae5 100644 --- a/fs/xfs/xfs_error.h +++ b/fs/xfs/xfs_error.h @@ -144,12 +144,11 @@ extern void xfs_error_test_init(void); #endif /* __ANSI_CPP__ */ extern int xfs_errortag_add(int error_tag, xfs_mount_t *mp); -extern int xfs_errortag_clearall(xfs_mount_t *mp); -extern int xfs_errortag_clearall_umount(int64_t fsid, char *fsname, int loud); +extern int xfs_errortag_clearall(xfs_mount_t *mp, int loud); #else #define XFS_TEST_ERROR(expr, mp, tag, rf) (expr) #define xfs_errortag_add(tag, mp) (ENOSYS) -#define xfs_errortag_clearall(mp) (ENOSYS) +#define xfs_errortag_clearall(mp, loud) (ENOSYS) #endif /* (DEBUG || INDUCE_IO_ERROR) */ /* diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index 3b14427ee123..f938a51be81b 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -23,6 +23,7 @@ #include "xfs_trans.h" #include "xfs_buf_item.h" #include "xfs_sb.h" +#include "xfs_ag.h" #include "xfs_dmapi.h" #include "xfs_mount.h" #include "xfs_trans_priv.h" diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h index ec3c9c27e0de..aab966276517 100644 --- a/fs/xfs/xfs_fs.h +++ b/fs/xfs/xfs_fs.h @@ -389,30 +389,13 @@ typedef struct xfs_fsop_attrmulti_handlereq { */ typedef struct { __u32 val[2]; } xfs_fsid_t; /* file system id type */ - -#ifndef HAVE_FID -#define MAXFIDSZ 46 - -typedef struct fid { - __u16 fid_len; /* length of data in bytes */ - unsigned char fid_data[MAXFIDSZ]; /* data (fid_len worth) */ -} fid_t; -#endif - typedef struct xfs_fid { - __u16 xfs_fid_len; /* length of remainder */ - __u16 xfs_fid_pad; - __u32 xfs_fid_gen; /* generation number */ - __u64 xfs_fid_ino; /* 64 bits inode number */ + __u16 fid_len; /* length of remainder */ + __u16 fid_pad; + __u32 fid_gen; /* generation number */ + __u64 fid_ino; /* 64 bits inode number */ } xfs_fid_t; -typedef struct xfs_fid2 { - __u16 fid_len; /* length of remainder */ - __u16 fid_pad; /* padding, must be zero */ - __u32 fid_gen; /* generation number */ - __u64 fid_ino; /* inode number */ -} xfs_fid2_t; - typedef struct xfs_handle { union { __s64 align; /* force alignment of ha_fid */ @@ -422,9 +405,9 @@ typedef struct xfs_handle { } xfs_handle_t; #define ha_fsid ha_u._ha_fsid -#define XFS_HSIZE(handle) (((char *) &(handle).ha_fid.xfs_fid_pad \ +#define XFS_HSIZE(handle) (((char *) &(handle).ha_fid.fid_pad \ - (char *) &(handle)) \ - + (handle).ha_fid.xfs_fid_len) + + (handle).ha_fid.fid_len) /* * Flags for going down operation diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index 432e82347ed6..c92d5b821029 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -136,7 +136,6 @@ xfs_growfs_data_private( xfs_rfsblock_t nfree; xfs_agnumber_t oagcount; int pct; - xfs_sb_t *sbp; xfs_trans_t *tp; nb = in->newblocks; @@ -175,7 +174,7 @@ xfs_growfs_data_private( memset(&mp->m_perag[oagcount], 0, (nagcount - oagcount) * sizeof(xfs_perag_t)); mp->m_flags |= XFS_MOUNT_32BITINODES; - nagimax = xfs_initialize_perag(XFS_MTOVFS(mp), mp, nagcount); + nagimax = xfs_initialize_perag(mp, nagcount); up_write(&mp->m_peraglock); } tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS); @@ -377,8 +376,7 @@ xfs_growfs_data_private( error, agno); break; } - sbp = XFS_BUF_TO_SBP(bp); - xfs_xlatesb(sbp, &mp->m_sb, -1, XFS_SB_ALL_BITS); + xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb, XFS_SB_ALL_BITS); /* * If we get an error writing out the alternate superblocks, * just issue a warning and continue. The real work is @@ -435,10 +433,10 @@ xfs_growfs_data( xfs_growfs_data_t *in) { int error; - if (!cpsema(&mp->m_growlock)) + if (!mutex_trylock(&mp->m_growlock)) return XFS_ERROR(EWOULDBLOCK); error = xfs_growfs_data_private(mp, in); - vsema(&mp->m_growlock); + mutex_unlock(&mp->m_growlock); return error; } @@ -448,10 +446,10 @@ xfs_growfs_log( xfs_growfs_log_t *in) { int error; - if (!cpsema(&mp->m_growlock)) + if (!mutex_trylock(&mp->m_growlock)) return XFS_ERROR(EWOULDBLOCK); error = xfs_growfs_log_private(mp, in); - vsema(&mp->m_growlock); + mutex_unlock(&mp->m_growlock); return error; } @@ -628,8 +626,7 @@ xfs_fs_goingdown( { switch (inflags) { case XFS_FSOP_GOING_FLAGS_DEFAULT: { - struct bhv_vfs *vfsp = XFS_MTOVFS(mp); - struct super_block *sb = freeze_bdev(vfsp->vfs_super->s_bdev); + struct super_block *sb = freeze_bdev(mp->m_super->s_bdev); if (sb && !IS_ERR(sb)) { xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT); diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index f943368c9b93..1409c2d61c11 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c @@ -293,9 +293,9 @@ xfs_ialloc_ag_alloc( xfs_biozero(fbuf, 0, ninodes << args.mp->m_sb.sb_inodelog); for (i = 0; i < ninodes; i++) { free = XFS_MAKE_IPTR(args.mp, fbuf, i); - INT_SET(free->di_core.di_magic, ARCH_CONVERT, XFS_DINODE_MAGIC); - INT_SET(free->di_core.di_version, ARCH_CONVERT, version); - INT_SET(free->di_next_unlinked, ARCH_CONVERT, NULLAGINO); + free->di_core.di_magic = cpu_to_be16(XFS_DINODE_MAGIC); + free->di_core.di_version = version; + free->di_next_unlinked = cpu_to_be32(NULLAGINO); xfs_ialloc_log_di(tp, fbuf, i, XFS_DI_CORE_BITS | XFS_DI_NEXT_UNLINKED); } diff --git a/fs/xfs/xfs_ialloc.h b/fs/xfs/xfs_ialloc.h index 97f4040931ca..4e30ec1d13bc 100644 --- a/fs/xfs/xfs_ialloc.h +++ b/fs/xfs/xfs_ialloc.h @@ -30,14 +30,9 @@ struct xfs_trans; #define XFS_IALLOC_BLOCKS(mp) (mp)->m_ialloc_blks /* - * For small block file systems, move inodes in clusters of this size. - * When we don't have a lot of memory, however, we go a bit smaller - * to reduce the number of AGI and ialloc btree blocks we need to keep - * around for xfs_dilocate(). We choose which one to use in - * xfs_mount_int(). + * Move inodes in clusters of this size. */ #define XFS_INODE_BIG_CLUSTER_SIZE 8192 -#define XFS_INODE_SMALL_CLUSTER_SIZE 4096 #define XFS_INODE_CLUSTER_SIZE(mp) (mp)->m_inode_cluster_size /* diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index 114433a22baa..488836e204a3 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c @@ -40,131 +40,13 @@ #include "xfs_utils.h" /* - * Initialize the inode hash table for the newly mounted file system. - * Choose an initial table size based on user specified value, else - * use a simple algorithm using the maximum number of inodes as an - * indicator for table size, and clamp it between one and some large - * number of pages. - */ -void -xfs_ihash_init(xfs_mount_t *mp) -{ - __uint64_t icount; - uint i; - - if (!mp->m_ihsize) { - icount = mp->m_maxicount ? mp->m_maxicount : - (mp->m_sb.sb_dblocks << mp->m_sb.sb_inopblog); - mp->m_ihsize = 1 << max_t(uint, 8, - (xfs_highbit64(icount) + 1) / 2); - mp->m_ihsize = min_t(uint, mp->m_ihsize, - (64 * NBPP) / sizeof(xfs_ihash_t)); - } - - mp->m_ihash = kmem_zalloc_greedy(&mp->m_ihsize, - NBPC * sizeof(xfs_ihash_t), - mp->m_ihsize * sizeof(xfs_ihash_t), - KM_SLEEP | KM_MAYFAIL | KM_LARGE); - mp->m_ihsize /= sizeof(xfs_ihash_t); - for (i = 0; i < mp->m_ihsize; i++) - rwlock_init(&(mp->m_ihash[i].ih_lock)); -} - -/* - * Free up structures allocated by xfs_ihash_init, at unmount time. - */ -void -xfs_ihash_free(xfs_mount_t *mp) -{ - kmem_free(mp->m_ihash, mp->m_ihsize * sizeof(xfs_ihash_t)); - mp->m_ihash = NULL; -} - -/* - * Initialize the inode cluster hash table for the newly mounted file system. - * Its size is derived from the ihash table size. - */ -void -xfs_chash_init(xfs_mount_t *mp) -{ - uint i; - - mp->m_chsize = max_t(uint, 1, mp->m_ihsize / - (XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog)); - mp->m_chsize = min_t(uint, mp->m_chsize, mp->m_ihsize); - mp->m_chash = (xfs_chash_t *)kmem_zalloc(mp->m_chsize - * sizeof(xfs_chash_t), - KM_SLEEP | KM_LARGE); - for (i = 0; i < mp->m_chsize; i++) { - spinlock_init(&mp->m_chash[i].ch_lock,"xfshash"); - } -} - -/* - * Free up structures allocated by xfs_chash_init, at unmount time. - */ -void -xfs_chash_free(xfs_mount_t *mp) -{ - int i; - - for (i = 0; i < mp->m_chsize; i++) { - spinlock_destroy(&mp->m_chash[i].ch_lock); - } - - kmem_free(mp->m_chash, mp->m_chsize*sizeof(xfs_chash_t)); - mp->m_chash = NULL; -} - -/* - * Try to move an inode to the front of its hash list if possible - * (and if its not there already). Called right after obtaining - * the list version number and then dropping the read_lock on the - * hash list in question (which is done right after looking up the - * inode in question...). - */ -STATIC void -xfs_ihash_promote( - xfs_ihash_t *ih, - xfs_inode_t *ip, - ulong version) -{ - xfs_inode_t *iq; - - if ((ip->i_prevp != &ih->ih_next) && write_trylock(&ih->ih_lock)) { - if (likely(version == ih->ih_version)) { - /* remove from list */ - if ((iq = ip->i_next)) { - iq->i_prevp = ip->i_prevp; - } - *ip->i_prevp = iq; - - /* insert at list head */ - iq = ih->ih_next; - iq->i_prevp = &ip->i_next; - ip->i_next = iq; - ip->i_prevp = &ih->ih_next; - ih->ih_next = ip; - } - write_unlock(&ih->ih_lock); - } -} - -/* * Look up an inode by number in the given file system. - * The inode is looked up in the hash table for the file system - * represented by the mount point parameter mp. Each bucket of - * the hash table is guarded by an individual semaphore. - * - * If the inode is found in the hash table, its corresponding vnode - * is obtained with a call to vn_get(). This call takes care of - * coordination with the reclamation of the inode and vnode. Note - * that the vmap structure is filled in while holding the hash lock. - * This gives us the state of the inode/vnode when we found it and - * is used for coordination in vn_get(). + * The inode is looked up in the cache held in each AG. + * If the inode is found in the cache, attach it to the provided + * vnode. * - * If it is not in core, read it in from the file system's device and - * add the inode into the hash table. + * If it is not in core, read it in from the file system's device, + * add it to the cache and attach the provided vnode. * * The inode is locked according to the value of the lock_flags parameter. * This flag parameter indicates how and if the inode's IO lock and inode lock @@ -192,274 +74,241 @@ xfs_iget_core( xfs_inode_t **ipp, xfs_daddr_t bno) { - xfs_ihash_t *ih; xfs_inode_t *ip; xfs_inode_t *iq; bhv_vnode_t *inode_vp; - ulong version; int error; - /* REFERENCED */ - xfs_chash_t *ch; - xfs_chashlist_t *chl, *chlnew; - SPLDECL(s); + xfs_icluster_t *icl, *new_icl = NULL; + unsigned long first_index, mask; + xfs_perag_t *pag; + xfs_agino_t agino; + + /* the radix tree exists only in inode capable AGs */ + if (XFS_INO_TO_AGNO(mp, ino) >= mp->m_maxagi) + return EINVAL; + + /* get the perag structure and ensure that it's inode capable */ + pag = xfs_get_perag(mp, ino); + if (!pag->pagi_inodeok) + return EINVAL; + ASSERT(pag->pag_ici_init); + agino = XFS_INO_TO_AGINO(mp, ino); +again: + read_lock(&pag->pag_ici_lock); + ip = radix_tree_lookup(&pag->pag_ici_root, agino); - ih = XFS_IHASH(mp, ino); + if (ip != NULL) { + /* + * If INEW is set this inode is being set up + * we need to pause and try again. + */ + if (xfs_iflags_test(ip, XFS_INEW)) { + read_unlock(&pag->pag_ici_lock); + delay(1); + XFS_STATS_INC(xs_ig_frecycle); -again: - read_lock(&ih->ih_lock); + goto again; + } - for (ip = ih->ih_next; ip != NULL; ip = ip->i_next) { - if (ip->i_ino == ino) { + inode_vp = XFS_ITOV_NULL(ip); + if (inode_vp == NULL) { /* - * If INEW is set this inode is being set up + * If IRECLAIM is set this inode is + * on its way out of the system, * we need to pause and try again. */ - if (xfs_iflags_test(ip, XFS_INEW)) { - read_unlock(&ih->ih_lock); + if (xfs_iflags_test(ip, XFS_IRECLAIM)) { + read_unlock(&pag->pag_ici_lock); delay(1); XFS_STATS_INC(xs_ig_frecycle); goto again; } + ASSERT(xfs_iflags_test(ip, XFS_IRECLAIMABLE)); - inode_vp = XFS_ITOV_NULL(ip); - if (inode_vp == NULL) { - /* - * If IRECLAIM is set this inode is - * on its way out of the system, - * we need to pause and try again. - */ - if (xfs_iflags_test(ip, XFS_IRECLAIM)) { - read_unlock(&ih->ih_lock); - delay(1); - XFS_STATS_INC(xs_ig_frecycle); - - goto again; - } - ASSERT(xfs_iflags_test(ip, XFS_IRECLAIMABLE)); - - /* - * If lookup is racing with unlink, then we - * should return an error immediately so we - * don't remove it from the reclaim list and - * potentially leak the inode. - */ - if ((ip->i_d.di_mode == 0) && - !(flags & XFS_IGET_CREATE)) { - read_unlock(&ih->ih_lock); - return ENOENT; - } - - /* - * There may be transactions sitting in the - * incore log buffers or being flushed to disk - * at this time. We can't clear the - * XFS_IRECLAIMABLE flag until these - * transactions have hit the disk, otherwise we - * will void the guarantee the flag provides - * xfs_iunpin() - */ - if (xfs_ipincount(ip)) { - read_unlock(&ih->ih_lock); - xfs_log_force(mp, 0, - XFS_LOG_FORCE|XFS_LOG_SYNC); - XFS_STATS_INC(xs_ig_frecycle); - goto again; - } - - vn_trace_exit(vp, "xfs_iget.alloc", - (inst_t *)__return_address); + /* + * If lookup is racing with unlink, then we + * should return an error immediately so we + * don't remove it from the reclaim list and + * potentially leak the inode. + */ + if ((ip->i_d.di_mode == 0) && + !(flags & XFS_IGET_CREATE)) { + read_unlock(&pag->pag_ici_lock); + xfs_put_perag(mp, pag); + return ENOENT; + } + + /* + * There may be transactions sitting in the + * incore log buffers or being flushed to disk + * at this time. We can't clear the + * XFS_IRECLAIMABLE flag until these + * transactions have hit the disk, otherwise we + * will void the guarantee the flag provides + * xfs_iunpin() + */ + if (xfs_ipincount(ip)) { + read_unlock(&pag->pag_ici_lock); + xfs_log_force(mp, 0, + XFS_LOG_FORCE|XFS_LOG_SYNC); + XFS_STATS_INC(xs_ig_frecycle); + goto again; + } - XFS_STATS_INC(xs_ig_found); + vn_trace_exit(ip, "xfs_iget.alloc", + (inst_t *)__return_address); - xfs_iflags_clear(ip, XFS_IRECLAIMABLE); - version = ih->ih_version; - read_unlock(&ih->ih_lock); - xfs_ihash_promote(ih, ip, version); + XFS_STATS_INC(xs_ig_found); - XFS_MOUNT_ILOCK(mp); - list_del_init(&ip->i_reclaim); - XFS_MOUNT_IUNLOCK(mp); + xfs_iflags_clear(ip, XFS_IRECLAIMABLE); + read_unlock(&pag->pag_ici_lock); - goto finish_inode; + XFS_MOUNT_ILOCK(mp); + list_del_init(&ip->i_reclaim); + XFS_MOUNT_IUNLOCK(mp); - } else if (vp != inode_vp) { - struct inode *inode = vn_to_inode(inode_vp); + goto finish_inode; - /* The inode is being torn down, pause and - * try again. - */ - if (inode->i_state & (I_FREEING | I_CLEAR)) { - read_unlock(&ih->ih_lock); - delay(1); - XFS_STATS_INC(xs_ig_frecycle); + } else if (vp != inode_vp) { + struct inode *inode = vn_to_inode(inode_vp); - goto again; - } -/* Chances are the other vnode (the one in the inode) is being torn - * down right now, and we landed on top of it. Question is, what do - * we do? Unhook the old inode and hook up the new one? - */ - cmn_err(CE_PANIC, - "xfs_iget_core: ambiguous vns: vp/0x%p, invp/0x%p", - inode_vp, vp); + /* The inode is being torn down, pause and + * try again. + */ + if (inode->i_state & (I_FREEING | I_CLEAR)) { + read_unlock(&pag->pag_ici_lock); + delay(1); + XFS_STATS_INC(xs_ig_frecycle); + + goto again; } +/* Chances are the other vnode (the one in the inode) is being torn +* down right now, and we landed on top of it. Question is, what do +* we do? Unhook the old inode and hook up the new one? +*/ + cmn_err(CE_PANIC, + "xfs_iget_core: ambiguous vns: vp/0x%p, invp/0x%p", + inode_vp, vp); + } - /* - * Inode cache hit: if ip is not at the front of - * its hash chain, move it there now. - * Do this with the lock held for update, but - * do statistics after releasing the lock. - */ - version = ih->ih_version; - read_unlock(&ih->ih_lock); - xfs_ihash_promote(ih, ip, version); - XFS_STATS_INC(xs_ig_found); + /* + * Inode cache hit + */ + read_unlock(&pag->pag_ici_lock); + XFS_STATS_INC(xs_ig_found); finish_inode: - if (ip->i_d.di_mode == 0) { - if (!(flags & XFS_IGET_CREATE)) - return ENOENT; - xfs_iocore_inode_reinit(ip); + if (ip->i_d.di_mode == 0) { + if (!(flags & XFS_IGET_CREATE)) { + xfs_put_perag(mp, pag); + return ENOENT; } + xfs_iocore_inode_reinit(ip); + } - if (lock_flags != 0) - xfs_ilock(ip, lock_flags); + if (lock_flags != 0) + xfs_ilock(ip, lock_flags); - xfs_iflags_clear(ip, XFS_ISTALE); - vn_trace_exit(vp, "xfs_iget.found", - (inst_t *)__return_address); - goto return_ip; - } + xfs_iflags_clear(ip, XFS_ISTALE); + vn_trace_exit(ip, "xfs_iget.found", + (inst_t *)__return_address); + goto return_ip; } /* - * Inode cache miss: save the hash chain version stamp and unlock - * the chain, so we don't deadlock in vn_alloc. + * Inode cache miss */ + read_unlock(&pag->pag_ici_lock); XFS_STATS_INC(xs_ig_missed); - version = ih->ih_version; - - read_unlock(&ih->ih_lock); - /* * Read the disk inode attributes into a new inode structure and get * a new vnode for it. This should also initialize i_ino and i_mount. */ error = xfs_iread(mp, tp, ino, &ip, bno, (flags & XFS_IGET_BULKSTAT) ? XFS_IMAP_BULKSTAT : 0); - if (error) + if (error) { + xfs_put_perag(mp, pag); return error; + } - vn_trace_exit(vp, "xfs_iget.alloc", (inst_t *)__return_address); + vn_trace_exit(ip, "xfs_iget.alloc", (inst_t *)__return_address); xfs_inode_lock_init(ip, vp); xfs_iocore_inode_init(ip); - if (lock_flags) xfs_ilock(ip, lock_flags); if ((ip->i_d.di_mode == 0) && !(flags & XFS_IGET_CREATE)) { xfs_idestroy(ip); + xfs_put_perag(mp, pag); return ENOENT; } /* - * Put ip on its hash chain, unless someone else hashed a duplicate - * after we released the hash lock. + * This is a bit messy - we preallocate everything we _might_ + * need before we pick up the ici lock. That way we don't have to + * juggle locks and go all the way back to the start. */ - write_lock(&ih->ih_lock); + new_icl = kmem_zone_alloc(xfs_icluster_zone, KM_SLEEP); + if (radix_tree_preload(GFP_KERNEL)) { + delay(1); + goto again; + } + mask = ~(((XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog)) - 1); + first_index = agino & mask; + write_lock(&pag->pag_ici_lock); - if (ih->ih_version != version) { - for (iq = ih->ih_next; iq != NULL; iq = iq->i_next) { - if (iq->i_ino == ino) { - write_unlock(&ih->ih_lock); - xfs_idestroy(ip); + /* + * Find the cluster if it exists + */ + icl = NULL; + if (radix_tree_gang_lookup(&pag->pag_ici_root, (void**)&iq, + first_index, 1)) { + if ((iq->i_ino & mask) == first_index) + icl = iq->i_cluster; + } - XFS_STATS_INC(xs_ig_dup); - goto again; - } - } + /* + * insert the new inode + */ + error = radix_tree_insert(&pag->pag_ici_root, agino, ip); + if (unlikely(error)) { + BUG_ON(error != -EEXIST); + write_unlock(&pag->pag_ici_lock); + radix_tree_preload_end(); + xfs_idestroy(ip); + XFS_STATS_INC(xs_ig_dup); + goto again; } /* * These values _must_ be set before releasing ihlock! */ - ip->i_hash = ih; - if ((iq = ih->ih_next)) { - iq->i_prevp = &ip->i_next; - } - ip->i_next = iq; - ip->i_prevp = &ih->ih_next; - ih->ih_next = ip; ip->i_udquot = ip->i_gdquot = NULL; - ih->ih_version++; xfs_iflags_set(ip, XFS_INEW); - write_unlock(&ih->ih_lock); - /* - * put ip on its cluster's hash chain - */ - ASSERT(ip->i_chash == NULL && ip->i_cprev == NULL && - ip->i_cnext == NULL); - - chlnew = NULL; - ch = XFS_CHASH(mp, ip->i_blkno); - chlredo: - s = mutex_spinlock(&ch->ch_lock); - for (chl = ch->ch_list; chl != NULL; chl = chl->chl_next) { - if (chl->chl_blkno == ip->i_blkno) { - - /* insert this inode into the doubly-linked list - * where chl points */ - if ((iq = chl->chl_ip)) { - ip->i_cprev = iq->i_cprev; - iq->i_cprev->i_cnext = ip; - iq->i_cprev = ip; - ip->i_cnext = iq; - } else { - ip->i_cnext = ip; - ip->i_cprev = ip; - } - chl->chl_ip = ip; - ip->i_chash = chl; - break; - } - } + ASSERT(ip->i_cluster == NULL); - /* no hash list found for this block; add a new hash list */ - if (chl == NULL) { - if (chlnew == NULL) { - mutex_spinunlock(&ch->ch_lock, s); - ASSERT(xfs_chashlist_zone != NULL); - chlnew = (xfs_chashlist_t *) - kmem_zone_alloc(xfs_chashlist_zone, - KM_SLEEP); - ASSERT(chlnew != NULL); - goto chlredo; - } else { - ip->i_cnext = ip; - ip->i_cprev = ip; - ip->i_chash = chlnew; - chlnew->chl_ip = ip; - chlnew->chl_blkno = ip->i_blkno; - if (ch->ch_list) - ch->ch_list->chl_prev = chlnew; - chlnew->chl_next = ch->ch_list; - chlnew->chl_prev = NULL; - ch->ch_list = chlnew; - chlnew = NULL; - } + if (!icl) { + spin_lock_init(&new_icl->icl_lock); + INIT_HLIST_HEAD(&new_icl->icl_inodes); + icl = new_icl; + new_icl = NULL; } else { - if (chlnew != NULL) { - kmem_zone_free(xfs_chashlist_zone, chlnew); - } + ASSERT(!hlist_empty(&icl->icl_inodes)); } + spin_lock(&icl->icl_lock); + hlist_add_head(&ip->i_cnode, &icl->icl_inodes); + ip->i_cluster = icl; + spin_unlock(&icl->icl_lock); - mutex_spinunlock(&ch->ch_lock, s); - + write_unlock(&pag->pag_ici_lock); + radix_tree_preload_end(); + if (new_icl) + kmem_zone_free(xfs_icluster_zone, new_icl); /* * Link ip to its mount and thread it on the mount's inode list. @@ -478,6 +327,7 @@ finish_inode: mp->m_inodes = ip; XFS_MOUNT_IUNLOCK(mp); + xfs_put_perag(mp, pag); return_ip: ASSERT(ip->i_df.if_ext_max == @@ -486,14 +336,14 @@ finish_inode: ASSERT(((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != 0) == ((ip->i_iocore.io_flags & XFS_IOCORE_RT) != 0)); + xfs_iflags_set(ip, XFS_IMODIFIED); *ipp = ip; /* * If we have a real type for an on-disk inode, we can set ops(&unlock) * now. If it's a new inode being created, xfs_ialloc will handle it. */ - bhv_vfs_init_vnode(XFS_MTOVFS(mp), vp, XFS_ITOBHV(ip), 1); - + xfs_initialize_vnode(mp, vp, ip); return 0; } @@ -519,7 +369,8 @@ xfs_iget( XFS_STATS_INC(xs_ig_attempts); retry: - if ((inode = iget_locked(XFS_MTOVFS(mp)->vfs_super, ino))) { + inode = iget_locked(mp->m_super, ino); + if (inode) { xfs_inode_t *ip; vp = vn_from_inode(inode); @@ -570,8 +421,8 @@ xfs_inode_lock_init( bhv_vnode_t *vp) { mrlock_init(&ip->i_lock, MRLOCK_ALLOW_EQUAL_PRI|MRLOCK_BARRIER, - "xfsino", (long)vp->v_number); - mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", vp->v_number); + "xfsino", ip->i_ino); + mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", ip->i_ino); init_waitqueue_head(&ip->i_ipin_wait); atomic_set(&ip->i_pincount, 0); initnsema(&ip->i_flock, 1, "xfsfino"); @@ -587,32 +438,19 @@ xfs_inode_incore(xfs_mount_t *mp, xfs_ino_t ino, xfs_trans_t *tp) { - xfs_ihash_t *ih; xfs_inode_t *ip; - ulong version; - - ih = XFS_IHASH(mp, ino); - read_lock(&ih->ih_lock); - for (ip = ih->ih_next; ip != NULL; ip = ip->i_next) { - if (ip->i_ino == ino) { - /* - * If we find it and tp matches, return it. - * Also move it to the front of the hash list - * if we find it and it is not already there. - * Otherwise break from the loop and return - * NULL. - */ - if (ip->i_transp == tp) { - version = ih->ih_version; - read_unlock(&ih->ih_lock); - xfs_ihash_promote(ih, ip, version); - return (ip); - } - break; - } - } - read_unlock(&ih->ih_lock); - return (NULL); + xfs_perag_t *pag; + + pag = xfs_get_perag(mp, ino); + read_lock(&pag->pag_ici_lock); + ip = radix_tree_lookup(&pag->pag_ici_root, XFS_INO_TO_AGINO(mp, ino)); + read_unlock(&pag->pag_ici_lock); + xfs_put_perag(mp, pag); + + /* the returned inode must match the transaction */ + if (ip && (ip->i_transp != tp)) + return NULL; + return ip; } /* @@ -629,7 +467,7 @@ xfs_iput(xfs_inode_t *ip, { bhv_vnode_t *vp = XFS_ITOV(ip); - vn_trace_entry(vp, "xfs_iput", (inst_t *)__return_address); + vn_trace_entry(ip, "xfs_iput", (inst_t *)__return_address); xfs_iunlock(ip, lock_flags); VN_RELE(vp); } @@ -644,7 +482,7 @@ xfs_iput_new(xfs_inode_t *ip, bhv_vnode_t *vp = XFS_ITOV(ip); struct inode *inode = vn_to_inode(vp); - vn_trace_entry(vp, "xfs_iput_new", (inst_t *)__return_address); + vn_trace_entry(ip, "xfs_iput_new", (inst_t *)__return_address); if ((ip->i_d.di_mode == 0)) { ASSERT(!xfs_iflags_test(ip, XFS_IRECLAIMABLE)); @@ -699,7 +537,8 @@ xfs_ireclaim(xfs_inode_t *ip) */ vp = XFS_ITOV_NULL(ip); if (vp) { - vn_bhv_remove(VN_BHV_HEAD(vp), XFS_ITOBHV(ip)); + vn_to_inode(vp)->i_private = NULL; + ip->i_vnode = NULL; } /* @@ -718,58 +557,26 @@ void xfs_iextract( xfs_inode_t *ip) { - xfs_ihash_t *ih; + xfs_mount_t *mp = ip->i_mount; + xfs_perag_t *pag = xfs_get_perag(mp, ip->i_ino); xfs_inode_t *iq; - xfs_mount_t *mp; - xfs_chash_t *ch; - xfs_chashlist_t *chl, *chm; - SPLDECL(s); - - ih = ip->i_hash; - write_lock(&ih->ih_lock); - if ((iq = ip->i_next)) { - iq->i_prevp = ip->i_prevp; - } - *ip->i_prevp = iq; - ih->ih_version++; - write_unlock(&ih->ih_lock); + + write_lock(&pag->pag_ici_lock); + radix_tree_delete(&pag->pag_ici_root, XFS_INO_TO_AGINO(mp, ip->i_ino)); + write_unlock(&pag->pag_ici_lock); + xfs_put_perag(mp, pag); /* - * Remove from cluster hash list - * 1) delete the chashlist if this is the last inode on the chashlist - * 2) unchain from list of inodes - * 3) point chashlist->chl_ip to 'chl_next' if to this inode. + * Remove from cluster list */ mp = ip->i_mount; - ch = XFS_CHASH(mp, ip->i_blkno); - s = mutex_spinlock(&ch->ch_lock); - - if (ip->i_cnext == ip) { - /* Last inode on chashlist */ - ASSERT(ip->i_cnext == ip && ip->i_cprev == ip); - ASSERT(ip->i_chash != NULL); - chm=NULL; - chl = ip->i_chash; - if (chl->chl_prev) - chl->chl_prev->chl_next = chl->chl_next; - else - ch->ch_list = chl->chl_next; - if (chl->chl_next) - chl->chl_next->chl_prev = chl->chl_prev; - kmem_zone_free(xfs_chashlist_zone, chl); - } else { - /* delete one inode from a non-empty list */ - iq = ip->i_cnext; - iq->i_cprev = ip->i_cprev; - ip->i_cprev->i_cnext = iq; - if (ip->i_chash->chl_ip == ip) { - ip->i_chash->chl_ip = iq; - } - ip->i_chash = __return_address; - ip->i_cprev = __return_address; - ip->i_cnext = __return_address; - } - mutex_spinunlock(&ch->ch_lock, s); + spin_lock(&ip->i_cluster->icl_lock); + hlist_del(&ip->i_cnode); + spin_unlock(&ip->i_cluster->icl_lock); + + /* was last inode in cluster? */ + if (hlist_empty(&ip->i_cluster->icl_inodes)) + kmem_zone_free(xfs_icluster_zone, ip->i_cluster); /* * Remove from mount's inode list. diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index cdc4c28926d0..abf509a88915 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -49,12 +49,11 @@ #include "xfs_quota.h" #include "xfs_acl.h" #include "xfs_filestream.h" - -#include <linux/log2.h> +#include "xfs_vnodeops.h" kmem_zone_t *xfs_ifork_zone; kmem_zone_t *xfs_inode_zone; -kmem_zone_t *xfs_chashlist_zone; +kmem_zone_t *xfs_icluster_zone; /* * Used in xfs_itruncate(). This is the maximum number of extents @@ -67,7 +66,6 @@ STATIC int xfs_iformat_local(xfs_inode_t *, xfs_dinode_t *, int, int); STATIC int xfs_iformat_extents(xfs_inode_t *, xfs_dinode_t *, int); STATIC int xfs_iformat_btree(xfs_inode_t *, xfs_dinode_t *, int); - #ifdef DEBUG /* * Make sure that the extents in the given memory buffer @@ -77,28 +75,23 @@ STATIC void xfs_validate_extents( xfs_ifork_t *ifp, int nrecs, - int disk, xfs_exntfmt_t fmt) { - xfs_bmbt_rec_t *ep; xfs_bmbt_irec_t irec; - xfs_bmbt_rec_t rec; + xfs_bmbt_rec_host_t rec; int i; for (i = 0; i < nrecs; i++) { - ep = xfs_iext_get_ext(ifp, i); - rec.l0 = get_unaligned((__uint64_t*)&ep->l0); - rec.l1 = get_unaligned((__uint64_t*)&ep->l1); - if (disk) - xfs_bmbt_disk_get_all(&rec, &irec); - else - xfs_bmbt_get_all(&rec, &irec); + xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i); + rec.l0 = get_unaligned(&ep->l0); + rec.l1 = get_unaligned(&ep->l1); + xfs_bmbt_get_all(&rec, &irec); if (fmt == XFS_EXTFMT_NOSTATE) ASSERT(irec.br_state == XFS_EXT_NORM); } } #else /* DEBUG */ -#define xfs_validate_extents(ifp, nrecs, disk, fmt) +#define xfs_validate_extents(ifp, nrecs, fmt) #endif /* DEBUG */ /* @@ -201,8 +194,8 @@ xfs_inotobp( } dip = (xfs_dinode_t *)xfs_buf_offset(bp, 0); di_ok = - INT_GET(dip->di_core.di_magic, ARCH_CONVERT) == XFS_DINODE_MAGIC && - XFS_DINODE_GOOD_VERSION(INT_GET(dip->di_core.di_version, ARCH_CONVERT)); + be16_to_cpu(dip->di_core.di_magic) == XFS_DINODE_MAGIC && + XFS_DINODE_GOOD_VERSION(dip->di_core.di_version); if (unlikely(XFS_TEST_ERROR(!di_ok, mp, XFS_ERRTAG_ITOBP_INOTOBP, XFS_RANDOM_ITOBP_INOTOBP))) { XFS_CORRUPTION_ERROR("xfs_inotobp", XFS_ERRLEVEL_LOW, mp, dip); @@ -346,8 +339,8 @@ xfs_itobp( dip = (xfs_dinode_t *)xfs_buf_offset(bp, (i << mp->m_sb.sb_inodelog)); - di_ok = INT_GET(dip->di_core.di_magic, ARCH_CONVERT) == XFS_DINODE_MAGIC && - XFS_DINODE_GOOD_VERSION(INT_GET(dip->di_core.di_version, ARCH_CONVERT)); + di_ok = be16_to_cpu(dip->di_core.di_magic) == XFS_DINODE_MAGIC && + XFS_DINODE_GOOD_VERSION(dip->di_core.di_version); if (unlikely(XFS_TEST_ERROR(!di_ok, mp, XFS_ERRTAG_ITOBP_INOTOBP, XFS_RANDOM_ITOBP_INOTOBP))) { @@ -361,7 +354,7 @@ xfs_itobp( "daddr %lld #%d (magic=%x)", XFS_BUFTARG_NAME(mp->m_ddev_targp), (unsigned long long)imap.im_blkno, i, - INT_GET(dip->di_core.di_magic, ARCH_CONVERT)); + be16_to_cpu(dip->di_core.di_magic)); #endif XFS_CORRUPTION_ERROR("xfs_itobp", XFS_ERRLEVEL_HIGH, mp, dip); @@ -407,27 +400,26 @@ xfs_iformat( XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); error = 0; - if (unlikely( - INT_GET(dip->di_core.di_nextents, ARCH_CONVERT) + - INT_GET(dip->di_core.di_anextents, ARCH_CONVERT) > - INT_GET(dip->di_core.di_nblocks, ARCH_CONVERT))) { + if (unlikely(be32_to_cpu(dip->di_core.di_nextents) + + be16_to_cpu(dip->di_core.di_anextents) > + be64_to_cpu(dip->di_core.di_nblocks))) { xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount, "corrupt dinode %Lu, extent total = %d, nblocks = %Lu.", (unsigned long long)ip->i_ino, - (int)(INT_GET(dip->di_core.di_nextents, ARCH_CONVERT) - + INT_GET(dip->di_core.di_anextents, ARCH_CONVERT)), + (int)(be32_to_cpu(dip->di_core.di_nextents) + + be16_to_cpu(dip->di_core.di_anextents)), (unsigned long long) - INT_GET(dip->di_core.di_nblocks, ARCH_CONVERT)); + be64_to_cpu(dip->di_core.di_nblocks)); XFS_CORRUPTION_ERROR("xfs_iformat(1)", XFS_ERRLEVEL_LOW, ip->i_mount, dip); return XFS_ERROR(EFSCORRUPTED); } - if (unlikely(INT_GET(dip->di_core.di_forkoff, ARCH_CONVERT) > ip->i_mount->m_sb.sb_inodesize)) { + if (unlikely(dip->di_core.di_forkoff > ip->i_mount->m_sb.sb_inodesize)) { xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount, "corrupt dinode %Lu, forkoff = 0x%x.", (unsigned long long)ip->i_ino, - (int)(INT_GET(dip->di_core.di_forkoff, ARCH_CONVERT))); + dip->di_core.di_forkoff); XFS_CORRUPTION_ERROR("xfs_iformat(2)", XFS_ERRLEVEL_LOW, ip->i_mount, dip); return XFS_ERROR(EFSCORRUPTED); @@ -438,25 +430,25 @@ xfs_iformat( case S_IFCHR: case S_IFBLK: case S_IFSOCK: - if (unlikely(INT_GET(dip->di_core.di_format, ARCH_CONVERT) != XFS_DINODE_FMT_DEV)) { + if (unlikely(dip->di_core.di_format != XFS_DINODE_FMT_DEV)) { XFS_CORRUPTION_ERROR("xfs_iformat(3)", XFS_ERRLEVEL_LOW, ip->i_mount, dip); return XFS_ERROR(EFSCORRUPTED); } ip->i_d.di_size = 0; ip->i_size = 0; - ip->i_df.if_u2.if_rdev = INT_GET(dip->di_u.di_dev, ARCH_CONVERT); + ip->i_df.if_u2.if_rdev = be32_to_cpu(dip->di_u.di_dev); break; case S_IFREG: case S_IFLNK: case S_IFDIR: - switch (INT_GET(dip->di_core.di_format, ARCH_CONVERT)) { + switch (dip->di_core.di_format) { case XFS_DINODE_FMT_LOCAL: /* * no local regular files yet */ - if (unlikely((INT_GET(dip->di_core.di_mode, ARCH_CONVERT) & S_IFMT) == S_IFREG)) { + if (unlikely((be16_to_cpu(dip->di_core.di_mode) & S_IFMT) == S_IFREG)) { xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount, "corrupt inode %Lu " "(local format for regular file).", @@ -467,7 +459,7 @@ xfs_iformat( return XFS_ERROR(EFSCORRUPTED); } - di_size = INT_GET(dip->di_core.di_size, ARCH_CONVERT); + di_size = be64_to_cpu(dip->di_core.di_size); if (unlikely(di_size > XFS_DFORK_DSIZE(dip, ip->i_mount))) { xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount, "corrupt inode %Lu " @@ -509,7 +501,7 @@ xfs_iformat( ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP); ip->i_afp->if_ext_max = XFS_IFORK_ASIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); - switch (INT_GET(dip->di_core.di_aformat, ARCH_CONVERT)) { + switch (dip->di_core.di_aformat) { case XFS_DINODE_FMT_LOCAL: atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip); size = be16_to_cpu(atp->hdr.totsize); @@ -602,7 +594,7 @@ xfs_iformat_extents( xfs_dinode_t *dip, int whichfork) { - xfs_bmbt_rec_t *ep, *dp; + xfs_bmbt_rec_t *dp; xfs_ifork_t *ifp; int nex; int size; @@ -637,13 +629,11 @@ xfs_iformat_extents( ifp->if_bytes = size; if (size) { dp = (xfs_bmbt_rec_t *) XFS_DFORK_PTR(dip, whichfork); - xfs_validate_extents(ifp, nex, 1, XFS_EXTFMT_INODE(ip)); + xfs_validate_extents(ifp, nex, XFS_EXTFMT_INODE(ip)); for (i = 0; i < nex; i++, dp++) { - ep = xfs_iext_get_ext(ifp, i); - ep->l0 = INT_GET(get_unaligned((__uint64_t*)&dp->l0), - ARCH_CONVERT); - ep->l1 = INT_GET(get_unaligned((__uint64_t*)&dp->l1), - ARCH_CONVERT); + xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i); + ep->l0 = be64_to_cpu(get_unaligned(&dp->l0)); + ep->l1 = be64_to_cpu(get_unaligned(&dp->l1)); } XFS_BMAP_TRACE_EXLIST(ip, nex, whichfork); if (whichfork != XFS_DATA_FORK || @@ -719,70 +709,74 @@ xfs_iformat_btree( return 0; } -/* - * xfs_xlate_dinode_core - translate an xfs_inode_core_t between ondisk - * and native format - * - * buf = on-disk representation - * dip = native representation - * dir = direction - +ve -> disk to native - * -ve -> native to disk - */ void -xfs_xlate_dinode_core( - xfs_caddr_t buf, - xfs_dinode_core_t *dip, - int dir) +xfs_dinode_from_disk( + xfs_icdinode_t *to, + xfs_dinode_core_t *from) { - xfs_dinode_core_t *buf_core = (xfs_dinode_core_t *)buf; - xfs_dinode_core_t *mem_core = (xfs_dinode_core_t *)dip; - xfs_arch_t arch = ARCH_CONVERT; - - ASSERT(dir); - - INT_XLATE(buf_core->di_magic, mem_core->di_magic, dir, arch); - INT_XLATE(buf_core->di_mode, mem_core->di_mode, dir, arch); - INT_XLATE(buf_core->di_version, mem_core->di_version, dir, arch); - INT_XLATE(buf_core->di_format, mem_core->di_format, dir, arch); - INT_XLATE(buf_core->di_onlink, mem_core->di_onlink, dir, arch); - INT_XLATE(buf_core->di_uid, mem_core->di_uid, dir, arch); - INT_XLATE(buf_core->di_gid, mem_core->di_gid, dir, arch); - INT_XLATE(buf_core->di_nlink, mem_core->di_nlink, dir, arch); - INT_XLATE(buf_core->di_projid, mem_core->di_projid, dir, arch); - - if (dir > 0) { - memcpy(mem_core->di_pad, buf_core->di_pad, - sizeof(buf_core->di_pad)); - } else { - memcpy(buf_core->di_pad, mem_core->di_pad, - sizeof(buf_core->di_pad)); - } - - INT_XLATE(buf_core->di_flushiter, mem_core->di_flushiter, dir, arch); - - INT_XLATE(buf_core->di_atime.t_sec, mem_core->di_atime.t_sec, - dir, arch); - INT_XLATE(buf_core->di_atime.t_nsec, mem_core->di_atime.t_nsec, - dir, arch); - INT_XLATE(buf_core->di_mtime.t_sec, mem_core->di_mtime.t_sec, - dir, arch); - INT_XLATE(buf_core->di_mtime.t_nsec, mem_core->di_mtime.t_nsec, - dir, arch); - INT_XLATE(buf_core->di_ctime.t_sec, mem_core->di_ctime.t_sec, - dir, arch); - INT_XLATE(buf_core->di_ctime.t_nsec, mem_core->di_ctime.t_nsec, - dir, arch); - INT_XLATE(buf_core->di_size, mem_core->di_size, dir, arch); - INT_XLATE(buf_core->di_nblocks, mem_core->di_nblocks, dir, arch); - INT_XLATE(buf_core->di_extsize, mem_core->di_extsize, dir, arch); - INT_XLATE(buf_core->di_nextents, mem_core->di_nextents, dir, arch); - INT_XLATE(buf_core->di_anextents, mem_core->di_anextents, dir, arch); - INT_XLATE(buf_core->di_forkoff, mem_core->di_forkoff, dir, arch); - INT_XLATE(buf_core->di_aformat, mem_core->di_aformat, dir, arch); - INT_XLATE(buf_core->di_dmevmask, mem_core->di_dmevmask, dir, arch); - INT_XLATE(buf_core->di_dmstate, mem_core->di_dmstate, dir, arch); - INT_XLATE(buf_core->di_flags, mem_core->di_flags, dir, arch); - INT_XLATE(buf_core->di_gen, mem_core->di_gen, dir, arch); + to->di_magic = be16_to_cpu(from->di_magic); + to->di_mode = be16_to_cpu(from->di_mode); + to->di_version = from ->di_version; + to->di_format = from->di_format; + to->di_onlink = be16_to_cpu(from->di_onlink); + to->di_uid = be32_to_cpu(from->di_uid); + to->di_gid = be32_to_cpu(from->di_gid); + to->di_nlink = be32_to_cpu(from->di_nlink); + to->di_projid = be16_to_cpu(from->di_projid); + memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad)); + to->di_flushiter = be16_to_cpu(from->di_flushiter); + to->di_atime.t_sec = be32_to_cpu(from->di_atime.t_sec); + to->di_atime.t_nsec = be32_to_cpu(from->di_atime.t_nsec); + to->di_mtime.t_sec = be32_to_cpu(from->di_mtime.t_sec); + to->di_mtime.t_nsec = be32_to_cpu(from->di_mtime.t_nsec); + to->di_ctime.t_sec = be32_to_cpu(from->di_ctime.t_sec); + to->di_ctime.t_nsec = be32_to_cpu(from->di_ctime.t_nsec); + to->di_size = be64_to_cpu(from->di_size); + to->di_nblocks = be64_to_cpu(from->di_nblocks); + to->di_extsize = be32_to_cpu(from->di_extsize); + to->di_nextents = be32_to_cpu(from->di_nextents); + to->di_anextents = be16_to_cpu(from->di_anextents); + to->di_forkoff = from->di_forkoff; + to->di_aformat = from->di_aformat; + to->di_dmevmask = be32_to_cpu(from->di_dmevmask); + to->di_dmstate = be16_to_cpu(from->di_dmstate); + to->di_flags = be16_to_cpu(from->di_flags); + to->di_gen = be32_to_cpu(from->di_gen); +} + +void +xfs_dinode_to_disk( + xfs_dinode_core_t *to, + xfs_icdinode_t *from) +{ + to->di_magic = cpu_to_be16(from->di_magic); + to->di_mode = cpu_to_be16(from->di_mode); + to->di_version = from ->di_version; + to->di_format = from->di_format; + to->di_onlink = cpu_to_be16(from->di_onlink); + to->di_uid = cpu_to_be32(from->di_uid); + to->di_gid = cpu_to_be32(from->di_gid); + to->di_nlink = cpu_to_be32(from->di_nlink); + to->di_projid = cpu_to_be16(from->di_projid); + memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad)); + to->di_flushiter = cpu_to_be16(from->di_flushiter); + to->di_atime.t_sec = cpu_to_be32(from->di_atime.t_sec); + to->di_atime.t_nsec = cpu_to_be32(from->di_atime.t_nsec); + to->di_mtime.t_sec = cpu_to_be32(from->di_mtime.t_sec); + to->di_mtime.t_nsec = cpu_to_be32(from->di_mtime.t_nsec); + to->di_ctime.t_sec = cpu_to_be32(from->di_ctime.t_sec); + to->di_ctime.t_nsec = cpu_to_be32(from->di_ctime.t_nsec); + to->di_size = cpu_to_be64(from->di_size); + to->di_nblocks = cpu_to_be64(from->di_nblocks); + to->di_extsize = cpu_to_be32(from->di_extsize); + to->di_nextents = cpu_to_be32(from->di_nextents); + to->di_anextents = cpu_to_be16(from->di_anextents); + to->di_forkoff = from->di_forkoff; + to->di_aformat = from->di_aformat; + to->di_dmevmask = cpu_to_be32(from->di_dmevmask); + to->di_dmstate = cpu_to_be16(from->di_dmstate); + to->di_flags = cpu_to_be16(from->di_flags); + to->di_gen = cpu_to_be32(from->di_gen); } STATIC uint @@ -829,7 +823,7 @@ uint xfs_ip2xflags( xfs_inode_t *ip) { - xfs_dinode_core_t *dic = &ip->i_d; + xfs_icdinode_t *dic = &ip->i_d; return _xfs_dic2xflags(dic->di_flags) | (XFS_CFORK_Q(dic) ? XFS_XFLAG_HASATTR : 0); @@ -839,7 +833,7 @@ uint xfs_dic2xflags( xfs_dinode_core_t *dic) { - return _xfs_dic2xflags(INT_GET(dic->di_flags, ARCH_CONVERT)) | + return _xfs_dic2xflags(be16_to_cpu(dic->di_flags)) | (XFS_CFORK_Q_DISK(dic) ? XFS_XFLAG_HASATTR : 0); } @@ -870,6 +864,7 @@ xfs_iread( ip = kmem_zone_zalloc(xfs_inode_zone, KM_SLEEP); ip->i_ino = ino; ip->i_mount = mp; + atomic_set(&ip->i_iocount, 0); spin_lock_init(&ip->i_flags_lock); /* @@ -889,6 +884,9 @@ xfs_iread( * Initialize inode's trace buffers. * Do this before xfs_iformat in case it adds entries. */ +#ifdef XFS_VNODE_TRACE + ip->i_trace = ktrace_alloc(VNODE_TRACE_SIZE, KM_SLEEP); +#endif #ifdef XFS_BMAP_TRACE ip->i_xtrace = ktrace_alloc(XFS_BMAP_KTRACE_SIZE, KM_SLEEP); #endif @@ -909,14 +907,14 @@ xfs_iread( * If we got something that isn't an inode it means someone * (nfs or dmi) has a stale handle. */ - if (INT_GET(dip->di_core.di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC) { + if (be16_to_cpu(dip->di_core.di_magic) != XFS_DINODE_MAGIC) { kmem_zone_free(xfs_inode_zone, ip); xfs_trans_brelse(tp, bp); #ifdef DEBUG xfs_fs_cmn_err(CE_ALERT, mp, "xfs_iread: " "dip->di_core.di_magic (0x%x) != " "XFS_DINODE_MAGIC (0x%x)", - INT_GET(dip->di_core.di_magic, ARCH_CONVERT), + be16_to_cpu(dip->di_core.di_magic), XFS_DINODE_MAGIC); #endif /* DEBUG */ return XFS_ERROR(EINVAL); @@ -930,8 +928,7 @@ xfs_iread( * Otherwise, just get the truly permanent information. */ if (dip->di_core.di_mode) { - xfs_xlate_dinode_core((xfs_caddr_t)&dip->di_core, - &(ip->i_d), 1); + xfs_dinode_from_disk(&ip->i_d, &dip->di_core); error = xfs_iformat(ip, dip); if (error) { kmem_zone_free(xfs_inode_zone, ip); @@ -944,10 +941,10 @@ xfs_iread( return error; } } else { - ip->i_d.di_magic = INT_GET(dip->di_core.di_magic, ARCH_CONVERT); - ip->i_d.di_version = INT_GET(dip->di_core.di_version, ARCH_CONVERT); - ip->i_d.di_gen = INT_GET(dip->di_core.di_gen, ARCH_CONVERT); - ip->i_d.di_flushiter = INT_GET(dip->di_core.di_flushiter, ARCH_CONVERT); + ip->i_d.di_magic = be16_to_cpu(dip->di_core.di_magic); + ip->i_d.di_version = dip->di_core.di_version; + ip->i_d.di_gen = be32_to_cpu(dip->di_core.di_gen); + ip->i_d.di_flushiter = be16_to_cpu(dip->di_core.di_flushiter); /* * Make sure to pull in the mode here as well in * case the inode is released without being used. @@ -1048,7 +1045,7 @@ xfs_iread_extents( ifp->if_flags &= ~XFS_IFEXTENTS; return error; } - xfs_validate_extents(ifp, nextents, 0, XFS_EXTFMT_INODE(ip)); + xfs_validate_extents(ifp, nextents, XFS_EXTFMT_INODE(ip)); return 0; } @@ -1161,7 +1158,7 @@ xfs_ialloc( if ((prid != 0) && (ip->i_d.di_version == XFS_DINODE_VERSION_1)) xfs_bump_ino_vers2(tp, ip); - if (pip && XFS_INHERIT_GID(pip, vp->v_vfsp)) { + if (pip && XFS_INHERIT_GID(pip)) { ip->i_d.di_gid = pip->i_d.di_gid; if ((pip->i_d.di_mode & S_ISGID) && (mode & S_IFMT) == S_IFDIR) { ip->i_d.di_mode |= S_ISGID; @@ -1275,7 +1272,7 @@ xfs_ialloc( xfs_trans_log_inode(tp, ip, flags); /* now that we have an i_mode we can setup inode ops and unlock */ - bhv_vfs_init_vnode(XFS_MTOVFS(tp->t_mountp), vp, XFS_ITOBHV(ip), 1); + xfs_initialize_vnode(tp->t_mountp, vp, ip); *ipp = ip; return 0; @@ -1462,7 +1459,7 @@ xfs_itruncate_start( mp = ip->i_mount; vp = XFS_ITOV(ip); - vn_iowait(vp); /* wait for the completion of any pending DIOs */ + vn_iowait(ip); /* wait for the completion of any pending DIOs */ /* * Call toss_pages or flushinval_pages to get rid of pages @@ -1497,9 +1494,11 @@ xfs_itruncate_start( last_byte); if (last_byte > toss_start) { if (flags & XFS_ITRUNC_DEFINITE) { - bhv_vop_toss_pages(vp, toss_start, -1, FI_REMAPF_LOCKED); + xfs_tosspages(ip, toss_start, + -1, FI_REMAPF_LOCKED); } else { - error = bhv_vop_flushinval_pages(vp, toss_start, -1, FI_REMAPF_LOCKED); + error = xfs_flushinval_pages(ip, toss_start, + -1, FI_REMAPF_LOCKED); } } @@ -1932,9 +1931,9 @@ xfs_iunlink( */ error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, agdaddr, XFS_FSS_TO_BB(mp, 1), 0, &agibp); - if (error) { + if (error) return error; - } + /* * Validate the magic number of the agi block. */ @@ -1958,6 +1957,24 @@ xfs_iunlink( ASSERT(agi->agi_unlinked[bucket_index]); ASSERT(be32_to_cpu(agi->agi_unlinked[bucket_index]) != agino); + error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0, 0); + if (error) + return error; + + /* + * Clear the on-disk di_nlink. This is to prevent xfs_bulkstat + * from picking up this inode when it is reclaimed (its incore state + * initialzed but not flushed to disk yet). The in-core di_nlink is + * already cleared in xfs_droplink() and a corresponding transaction + * logged. The hack here just synchronizes the in-core to on-disk + * di_nlink value in advance before the actual inode sync to disk. + * This is OK because the inode is already unlinked and would never + * change its di_nlink again for this inode generation. + * This is a temporary hack that would require a proper fix + * in the future. + */ + dip->di_core.di_nlink = 0; + if (be32_to_cpu(agi->agi_unlinked[bucket_index]) != NULLAGINO) { /* * There is already another inode in the bucket we need @@ -1965,12 +1982,7 @@ xfs_iunlink( * Here we put the head pointer into our next pointer, * and then we fall through to point the head at us. */ - error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0, 0); - if (error) { - return error; - } - ASSERT(INT_GET(dip->di_next_unlinked, ARCH_CONVERT) == NULLAGINO); - ASSERT(dip->di_next_unlinked); + ASSERT(be32_to_cpu(dip->di_next_unlinked) == NULLAGINO); /* both on-disk, don't endian flip twice */ dip->di_next_unlinked = agi->agi_unlinked[bucket_index]; offset = ip->i_boffset + @@ -2081,10 +2093,10 @@ xfs_iunlink_remove( error, mp->m_fsname); return error; } - next_agino = INT_GET(dip->di_next_unlinked, ARCH_CONVERT); + next_agino = be32_to_cpu(dip->di_next_unlinked); ASSERT(next_agino != 0); if (next_agino != NULLAGINO) { - INT_SET(dip->di_next_unlinked, ARCH_CONVERT, NULLAGINO); + dip->di_next_unlinked = cpu_to_be32(NULLAGINO); offset = ip->i_boffset + offsetof(xfs_dinode_t, di_next_unlinked); xfs_trans_inode_buf(tp, ibp); @@ -2128,7 +2140,7 @@ xfs_iunlink_remove( error, mp->m_fsname); return error; } - next_agino = INT_GET(last_dip->di_next_unlinked, ARCH_CONVERT); + next_agino = be32_to_cpu(last_dip->di_next_unlinked); ASSERT(next_agino != NULLAGINO); ASSERT(next_agino != 0); } @@ -2143,11 +2155,11 @@ xfs_iunlink_remove( error, mp->m_fsname); return error; } - next_agino = INT_GET(dip->di_next_unlinked, ARCH_CONVERT); + next_agino = be32_to_cpu(dip->di_next_unlinked); ASSERT(next_agino != 0); ASSERT(next_agino != agino); if (next_agino != NULLAGINO) { - INT_SET(dip->di_next_unlinked, ARCH_CONVERT, NULLAGINO); + dip->di_next_unlinked = cpu_to_be32(NULLAGINO); offset = ip->i_boffset + offsetof(xfs_dinode_t, di_next_unlinked); xfs_trans_inode_buf(tp, ibp); @@ -2160,7 +2172,7 @@ xfs_iunlink_remove( /* * Point the previous inode on the list to the next inode. */ - INT_SET(last_dip->di_next_unlinked, ARCH_CONVERT, next_agino); + last_dip->di_next_unlinked = cpu_to_be32(next_agino); ASSERT(next_agino != 0); offset = last_offset + offsetof(xfs_dinode_t, di_next_unlinked); xfs_trans_inode_buf(tp, last_ibp); @@ -2191,10 +2203,10 @@ xfs_ifree_cluster( int i, j, found, pre_flushed; xfs_daddr_t blkno; xfs_buf_t *bp; - xfs_ihash_t *ih; xfs_inode_t *ip, **ip_found; xfs_inode_log_item_t *iip; xfs_log_item_t *lip; + xfs_perag_t *pag = xfs_get_perag(mp, inum); SPLDECL(s); if (mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp)) { @@ -2229,23 +2241,20 @@ xfs_ifree_cluster( */ found = 0; for (i = 0; i < ninodes; i++) { - ih = XFS_IHASH(mp, inum + i); - read_lock(&ih->ih_lock); - for (ip = ih->ih_next; ip != NULL; ip = ip->i_next) { - if (ip->i_ino == inum + i) - break; - } + read_lock(&pag->pag_ici_lock); + ip = radix_tree_lookup(&pag->pag_ici_root, + XFS_INO_TO_AGINO(mp, (inum + i))); /* Inode not in memory or we found it already, * nothing to do */ if (!ip || xfs_iflags_test(ip, XFS_ISTALE)) { - read_unlock(&ih->ih_lock); + read_unlock(&pag->pag_ici_lock); continue; } if (xfs_inode_clean(ip)) { - read_unlock(&ih->ih_lock); + read_unlock(&pag->pag_ici_lock); continue; } @@ -2268,7 +2277,7 @@ xfs_ifree_cluster( ip_found[found++] = ip; } } - read_unlock(&ih->ih_lock); + read_unlock(&pag->pag_ici_lock); continue; } @@ -2286,8 +2295,7 @@ xfs_ifree_cluster( xfs_iunlock(ip, XFS_ILOCK_EXCL); } } - - read_unlock(&ih->ih_lock); + read_unlock(&pag->pag_ici_lock); } bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, blkno, @@ -2342,6 +2350,7 @@ xfs_ifree_cluster( } kmem_free(ip_found, ninodes * sizeof(xfs_inode_t *)); + xfs_put_perag(mp, pag); } /* @@ -2737,6 +2746,10 @@ xfs_idestroy( mrfree(&ip->i_lock); mrfree(&ip->i_iolock); freesema(&ip->i_flock); + +#ifdef XFS_VNODE_TRACE + ktrace_free(ip->i_trace); +#endif #ifdef XFS_BMAP_TRACE ktrace_free(ip->i_xtrace); #endif @@ -2887,12 +2900,10 @@ xfs_iunpin_wait( int xfs_iextents_copy( xfs_inode_t *ip, - xfs_bmbt_rec_t *buffer, + xfs_bmbt_rec_t *dp, int whichfork) { int copied; - xfs_bmbt_rec_t *dest_ep; - xfs_bmbt_rec_t *ep; int i; xfs_ifork_t *ifp; int nrecs; @@ -2912,10 +2923,9 @@ xfs_iextents_copy( * the delayed ones. There must be at least one * non-delayed extent. */ - dest_ep = buffer; copied = 0; for (i = 0; i < nrecs; i++) { - ep = xfs_iext_get_ext(ifp, i); + xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i); start_block = xfs_bmbt_get_startblock(ep); if (ISNULLSTARTBLOCK(start_block)) { /* @@ -2925,15 +2935,13 @@ xfs_iextents_copy( } /* Translate to on disk format */ - put_unaligned(INT_GET(ep->l0, ARCH_CONVERT), - (__uint64_t*)&dest_ep->l0); - put_unaligned(INT_GET(ep->l1, ARCH_CONVERT), - (__uint64_t*)&dest_ep->l1); - dest_ep++; + put_unaligned(cpu_to_be64(ep->l0), &dp->l0); + put_unaligned(cpu_to_be64(ep->l1), &dp->l1); + dp++; copied++; } ASSERT(copied != 0); - xfs_validate_extents(ifp, copied, 1, XFS_EXTFMT_INODE(ip)); + xfs_validate_extents(ifp, copied, XFS_EXTFMT_INODE(ip)); return (copied * (uint)sizeof(xfs_bmbt_rec_t)); } @@ -3024,7 +3032,7 @@ xfs_iflush_fork( case XFS_DINODE_FMT_DEV: if (iip->ili_format.ilf_fields & XFS_ILOG_DEV) { ASSERT(whichfork == XFS_DATA_FORK); - INT_SET(dip->di_u.di_dev, ARCH_CONVERT, ip->i_df.if_u2.if_rdev); + dip->di_u.di_dev = cpu_to_be32(ip->i_df.if_u2.if_rdev); } break; @@ -3064,12 +3072,11 @@ xfs_iflush( xfs_mount_t *mp; int error; /* REFERENCED */ - xfs_chash_t *ch; xfs_inode_t *iq; int clcount; /* count of inodes clustered */ int bufwasdelwri; + struct hlist_node *entry; enum { INT_DELWRI = (1 << 0), INT_ASYNC = (1 << 1) }; - SPLDECL(s); XFS_STATS_INC(xs_iflush_count); @@ -3183,14 +3190,14 @@ xfs_iflush( * inode clustering: * see if other inodes can be gathered into this write */ - - ip->i_chash->chl_buf = bp; - - ch = XFS_CHASH(mp, ip->i_blkno); - s = mutex_spinlock(&ch->ch_lock); + spin_lock(&ip->i_cluster->icl_lock); + ip->i_cluster->icl_buf = bp; clcount = 0; - for (iq = ip->i_cnext; iq != ip; iq = iq->i_cnext) { + hlist_for_each_entry(iq, entry, &ip->i_cluster->icl_inodes, i_cnode) { + if (iq == ip) + continue; + /* * Do an un-protected check to see if the inode is dirty and * is a candidate for flushing. These checks will be repeated @@ -3241,7 +3248,7 @@ xfs_iflush( xfs_iunlock(iq, XFS_ILOCK_SHARED); } } - mutex_spinunlock(&ch->ch_lock, s); + spin_unlock(&ip->i_cluster->icl_lock); if (clcount) { XFS_STATS_INC(xs_icluster_flushcnt); @@ -3278,7 +3285,7 @@ cluster_corrupt_out: /* Corruption detected in the clustering loop. Invalidate the * inode buffer and shut down the filesystem. */ - mutex_spinunlock(&ch->ch_lock, s); + spin_unlock(&ip->i_cluster->icl_lock); /* * Clean up the buffer. If it was B_DELWRI, just release it -- @@ -3373,11 +3380,11 @@ xfs_iflush_int( */ xfs_synchronize_atime(ip); - if (XFS_TEST_ERROR(INT_GET(dip->di_core.di_magic,ARCH_CONVERT) != XFS_DINODE_MAGIC, + if (XFS_TEST_ERROR(be16_to_cpu(dip->di_core.di_magic) != XFS_DINODE_MAGIC, mp, XFS_ERRTAG_IFLUSH_1, XFS_RANDOM_IFLUSH_1)) { xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp, "xfs_iflush: Bad inode %Lu magic number 0x%x, ptr 0x%p", - ip->i_ino, (int) INT_GET(dip->di_core.di_magic, ARCH_CONVERT), dip); + ip->i_ino, be16_to_cpu(dip->di_core.di_magic), dip); goto corrupt_out; } if (XFS_TEST_ERROR(ip->i_d.di_magic != XFS_DINODE_MAGIC, @@ -3440,7 +3447,7 @@ xfs_iflush_int( * because if the inode is dirty at all the core must * be. */ - xfs_xlate_dinode_core((xfs_caddr_t)&(dip->di_core), &(ip->i_d), -1); + xfs_dinode_to_disk(&dip->di_core, &ip->i_d); /* Wrap, we never let the log put out DI_MAX_FLUSH */ if (ip->i_d.di_flushiter == DI_MAX_FLUSH) @@ -3460,7 +3467,7 @@ xfs_iflush_int( * Convert it back. */ ASSERT(ip->i_d.di_nlink <= XFS_MAXLINK_1); - INT_SET(dip->di_core.di_onlink, ARCH_CONVERT, ip->i_d.di_nlink); + dip->di_core.di_onlink = cpu_to_be16(ip->i_d.di_nlink); } else { /* * The superblock version has already been bumped, @@ -3468,7 +3475,7 @@ xfs_iflush_int( * format permanent. */ ip->i_d.di_version = XFS_DINODE_VERSION_2; - INT_SET(dip->di_core.di_version, ARCH_CONVERT, XFS_DINODE_VERSION_2); + dip->di_core.di_version = XFS_DINODE_VERSION_2; ip->i_d.di_onlink = 0; dip->di_core.di_onlink = 0; memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad)); @@ -3711,7 +3718,7 @@ xfs_ilock_trace(xfs_inode_t *ip, int lock, unsigned int lockflags, inst_t *ra) /* * Return a pointer to the extent record at file index idx. */ -xfs_bmbt_rec_t * +xfs_bmbt_rec_host_t * xfs_iext_get_ext( xfs_ifork_t *ifp, /* inode fork pointer */ xfs_extnum_t idx) /* index of target extent */ @@ -3744,15 +3751,12 @@ xfs_iext_insert( xfs_extnum_t count, /* number of inserted items */ xfs_bmbt_irec_t *new) /* items to insert */ { - xfs_bmbt_rec_t *ep; /* extent record pointer */ xfs_extnum_t i; /* extent record index */ ASSERT(ifp->if_flags & XFS_IFEXTENTS); xfs_iext_add(ifp, idx, count); - for (i = idx; i < idx + count; i++, new++) { - ep = xfs_iext_get_ext(ifp, i); - xfs_bmbt_set_all(ep, new); - } + for (i = idx; i < idx + count; i++, new++) + xfs_bmbt_set_all(xfs_iext_get_ext(ifp, i), new); } /* @@ -4203,7 +4207,7 @@ xfs_iext_realloc_direct( rnew_size = xfs_iroundup(new_size); } if (rnew_size != ifp->if_real_bytes) { - ifp->if_u1.if_extents = (xfs_bmbt_rec_t *) + ifp->if_u1.if_extents = kmem_realloc(ifp->if_u1.if_extents, rnew_size, ifp->if_real_bytes, @@ -4266,8 +4270,7 @@ xfs_iext_inline_to_direct( xfs_ifork_t *ifp, /* inode fork pointer */ int new_size) /* number of extents in file */ { - ifp->if_u1.if_extents = (xfs_bmbt_rec_t *) - kmem_alloc(new_size, KM_SLEEP); + ifp->if_u1.if_extents = kmem_alloc(new_size, KM_SLEEP); memset(ifp->if_u1.if_extents, 0, new_size); if (ifp->if_bytes) { memcpy(ifp->if_u1.if_extents, ifp->if_u2.if_inline_ext, @@ -4310,7 +4313,7 @@ void xfs_iext_indirect_to_direct( xfs_ifork_t *ifp) /* inode fork pointer */ { - xfs_bmbt_rec_t *ep; /* extent record pointer */ + xfs_bmbt_rec_host_t *ep; /* extent record pointer */ xfs_extnum_t nextents; /* number of extents in file */ int size; /* size of file extents */ @@ -4362,15 +4365,15 @@ xfs_iext_destroy( /* * Return a pointer to the extent record for file system block bno. */ -xfs_bmbt_rec_t * /* pointer to found extent record */ +xfs_bmbt_rec_host_t * /* pointer to found extent record */ xfs_iext_bno_to_ext( xfs_ifork_t *ifp, /* inode fork pointer */ xfs_fileoff_t bno, /* block number to search for */ xfs_extnum_t *idxp) /* index of target extent */ { - xfs_bmbt_rec_t *base; /* pointer to first extent */ + xfs_bmbt_rec_host_t *base; /* pointer to first extent */ xfs_filblks_t blockcount = 0; /* number of blocks in extent */ - xfs_bmbt_rec_t *ep = NULL; /* pointer to target extent */ + xfs_bmbt_rec_host_t *ep = NULL; /* pointer to target extent */ xfs_ext_irec_t *erp = NULL; /* indirection array pointer */ int high; /* upper boundary in search */ xfs_extnum_t idx = 0; /* index of target extent */ @@ -4545,8 +4548,7 @@ xfs_iext_irec_init( kmem_alloc(sizeof(xfs_ext_irec_t), KM_SLEEP); if (nextents == 0) { - ifp->if_u1.if_extents = (xfs_bmbt_rec_t *) - kmem_alloc(XFS_IEXT_BUFSZ, KM_SLEEP); + ifp->if_u1.if_extents = kmem_alloc(XFS_IEXT_BUFSZ, KM_SLEEP); } else if (!ifp->if_real_bytes) { xfs_iext_inline_to_direct(ifp, XFS_IEXT_BUFSZ); } else if (ifp->if_real_bytes < XFS_IEXT_BUFSZ) { @@ -4594,8 +4596,7 @@ xfs_iext_irec_new( /* Initialize new extent record */ erp = ifp->if_u1.if_ext_irec; - erp[erp_idx].er_extbuf = (xfs_bmbt_rec_t *) - kmem_alloc(XFS_IEXT_BUFSZ, KM_SLEEP); + erp[erp_idx].er_extbuf = kmem_alloc(XFS_IEXT_BUFSZ, KM_SLEEP); ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ; memset(erp[erp_idx].er_extbuf, 0, XFS_IEXT_BUFSZ); erp[erp_idx].er_extcount = 0; @@ -4727,7 +4728,7 @@ void xfs_iext_irec_compact_full( xfs_ifork_t *ifp) /* inode fork pointer */ { - xfs_bmbt_rec_t *ep, *ep_next; /* extent record pointers */ + xfs_bmbt_rec_host_t *ep, *ep_next; /* extent record pointers */ xfs_ext_irec_t *erp, *erp_next; /* extent irec pointers */ int erp_idx = 0; /* extent irec index */ int ext_avail; /* empty entries in ex list */ diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 012dfd4a958c..e5aff929cc65 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -18,6 +18,10 @@ #ifndef __XFS_INODE_H__ #define __XFS_INODE_H__ +struct xfs_dinode; +struct xfs_dinode_core; + + /* * Fork identifiers. */ @@ -44,7 +48,7 @@ * it is possible that a third level of indirection may be required. */ typedef struct xfs_ext_irec { - xfs_bmbt_rec_t *er_extbuf; /* block of extent records */ + xfs_bmbt_rec_host_t *er_extbuf; /* block of extent records */ xfs_extnum_t er_extoff; /* extent offset in file */ xfs_extnum_t er_extcount; /* number of extents in page/block */ } xfs_ext_irec_t; @@ -65,12 +69,12 @@ typedef struct xfs_ifork { unsigned char if_ext_max; /* max # of extent records */ xfs_extnum_t if_lastex; /* last if_extents used */ union { - xfs_bmbt_rec_t *if_extents; /* linear map file exts */ + xfs_bmbt_rec_host_t *if_extents;/* linear map file exts */ xfs_ext_irec_t *if_ext_irec; /* irec map file exts */ char *if_data; /* inline file data */ } if_u1; union { - xfs_bmbt_rec_t if_inline_ext[XFS_INLINE_EXTS]; + xfs_bmbt_rec_host_t if_inline_ext[XFS_INLINE_EXTS]; /* very small file extents */ char if_inline_data[XFS_INLINE_DATA]; /* very small file data */ @@ -102,7 +106,6 @@ typedef struct xfs_ifork { #ifdef __KERNEL__ struct bhv_desc; -struct bhv_vnode; struct cred; struct ktrace; struct xfs_buf; @@ -168,41 +171,18 @@ typedef struct xfs_iocore { extern void xfs_iocore_inode_init(struct xfs_inode *); extern void xfs_iocore_inode_reinit(struct xfs_inode *); - -/* - * This is the type used in the xfs inode hash table. - * An array of these is allocated for each mounted - * file system to hash the inodes for that file system. - */ -typedef struct xfs_ihash { - struct xfs_inode *ih_next; - rwlock_t ih_lock; - uint ih_version; -} xfs_ihash_t; - -#define XFS_IHASH(mp,ino) ((mp)->m_ihash + (((uint)(ino)) % (mp)->m_ihsize)) - /* - * This is the xfs inode cluster hash. This hash is used by xfs_iflush to - * find inodes that share a cluster and can be flushed to disk at the same - * time. + * This is the xfs inode cluster structure. This structure is used by + * xfs_iflush to find inodes that share a cluster and can be flushed to disk at + * the same time. */ -typedef struct xfs_chashlist { - struct xfs_chashlist *chl_next; - struct xfs_chashlist *chl_prev; - struct xfs_inode *chl_ip; - xfs_daddr_t chl_blkno; /* starting block number of +typedef struct xfs_icluster { + struct hlist_head icl_inodes; /* list of inodes on cluster */ + xfs_daddr_t icl_blkno; /* starting block number of * the cluster */ - struct xfs_buf *chl_buf; /* the inode buffer */ -} xfs_chashlist_t; - -typedef struct xfs_chash { - xfs_chashlist_t *ch_list; - lock_t ch_lock; -} xfs_chash_t; - -#define XFS_CHASH(mp,blk) ((mp)->m_chash + (((uint)blk) % (mp)->m_chsize)) - + struct xfs_buf *icl_buf; /* the inode buffer */ + lock_t icl_lock; /* inode list lock */ +} xfs_icluster_t; /* * This is the xfs in-core inode structure. @@ -227,25 +207,56 @@ typedef struct xfs_chash { * chain off the mount structure by xfs_sync calls. */ +typedef struct xfs_ictimestamp { + __int32_t t_sec; /* timestamp seconds */ + __int32_t t_nsec; /* timestamp nanoseconds */ +} xfs_ictimestamp_t; + +/* + * NOTE: This structure must be kept identical to struct xfs_dinode_core + * in xfs_dinode.h except for the endianess annotations. + */ +typedef struct xfs_icdinode { + __uint16_t di_magic; /* inode magic # = XFS_DINODE_MAGIC */ + __uint16_t di_mode; /* mode and type of file */ + __int8_t di_version; /* inode version */ + __int8_t di_format; /* format of di_c data */ + __uint16_t di_onlink; /* old number of links to file */ + __uint32_t di_uid; /* owner's user id */ + __uint32_t di_gid; /* owner's group id */ + __uint32_t di_nlink; /* number of links to file */ + __uint16_t di_projid; /* owner's project id */ + __uint8_t di_pad[8]; /* unused, zeroed space */ + __uint16_t di_flushiter; /* incremented on flush */ + xfs_ictimestamp_t di_atime; /* time last accessed */ + xfs_ictimestamp_t di_mtime; /* time last modified */ + xfs_ictimestamp_t di_ctime; /* time created/inode modified */ + xfs_fsize_t di_size; /* number of bytes in file */ + xfs_drfsbno_t di_nblocks; /* # of direct & btree blocks used */ + xfs_extlen_t di_extsize; /* basic/minimum extent size for file */ + xfs_extnum_t di_nextents; /* number of extents in data fork */ + xfs_aextnum_t di_anextents; /* number of extents in attribute fork*/ + __uint8_t di_forkoff; /* attr fork offs, <<3 for 64b align */ + __int8_t di_aformat; /* format of attr fork's data */ + __uint32_t di_dmevmask; /* DMIG event mask */ + __uint16_t di_dmstate; /* DMIG state info */ + __uint16_t di_flags; /* random flags, XFS_DIFLAG_... */ + __uint32_t di_gen; /* generation number */ +} xfs_icdinode_t; + typedef struct { - struct xfs_ihash *ip_hash; /* pointer to hash header */ - struct xfs_inode *ip_next; /* inode hash link forw */ struct xfs_inode *ip_mnext; /* next inode in mount list */ struct xfs_inode *ip_mprev; /* ptr to prev inode */ - struct xfs_inode **ip_prevp; /* ptr to prev i_next */ struct xfs_mount *ip_mount; /* fs mount struct ptr */ } xfs_iptr_t; typedef struct xfs_inode { /* Inode linking and identification information. */ - struct xfs_ihash *i_hash; /* pointer to hash header */ - struct xfs_inode *i_next; /* inode hash link forw */ struct xfs_inode *i_mnext; /* next inode in mount list */ struct xfs_inode *i_mprev; /* ptr to prev inode */ - struct xfs_inode **i_prevp; /* ptr to prev i_next */ struct xfs_mount *i_mount; /* fs mount struct ptr */ struct list_head i_reclaim; /* reclaim list */ - struct bhv_desc i_bhv_desc; /* inode behavior descriptor*/ + bhv_vnode_t *i_vnode; /* vnode backpointer */ struct xfs_dquot *i_udquot; /* user dquot */ struct xfs_dquot *i_gdquot; /* group dquot */ @@ -282,13 +293,16 @@ typedef struct xfs_inode { unsigned int i_gen; /* generation count */ unsigned int i_delayed_blks; /* count of delay alloc blks */ - xfs_dinode_core_t i_d; /* most of ondisk inode */ - xfs_chashlist_t *i_chash; /* cluster hash list header */ - struct xfs_inode *i_cnext; /* cluster hash link forward */ - struct xfs_inode *i_cprev; /* cluster hash link backward */ + xfs_icdinode_t i_d; /* most of ondisk inode */ + xfs_icluster_t *i_cluster; /* cluster list header */ + struct hlist_node i_cnode; /* cluster link node */ xfs_fsize_t i_size; /* in-memory size */ + atomic_t i_iocount; /* outstanding I/O count */ /* Trace buffers per inode. */ +#ifdef XFS_VNODE_TRACE + struct ktrace *i_trace; /* general inode trace */ +#endif #ifdef XFS_BMAP_TRACE struct ktrace *i_xtrace; /* inode extent list trace */ #endif @@ -349,6 +363,19 @@ xfs_iflags_test(xfs_inode_t *ip, unsigned short flags) spin_unlock(&ip->i_flags_lock); return ret; } + +static inline int +xfs_iflags_test_and_clear(xfs_inode_t *ip, unsigned short flags) +{ + int ret; + + spin_lock(&ip->i_flags_lock); + ret = ip->i_flags & flags; + if (ret) + ip->i_flags &= ~flags; + spin_unlock(&ip->i_flags_lock); + return ret; +} #endif /* __KERNEL__ */ @@ -380,6 +407,9 @@ xfs_iflags_test(xfs_inode_t *ip, unsigned short flags) #define XFS_IRECLAIMABLE 0x0020 /* inode can be reclaimed */ #define XFS_INEW 0x0040 #define XFS_IFILESTREAM 0x0080 /* inode is in a filestream directory */ +#define XFS_IMODIFIED 0x0100 /* XFS inode state possibly differs */ + /* to the Linux inode state. */ +#define XFS_ITRUNCATED 0x0200 /* truncated down so flush-on-close */ /* * Flags for inode locking. @@ -454,20 +484,17 @@ xfs_iflags_test(xfs_inode_t *ip, unsigned short flags) #define XFS_ITRUNC_DEFINITE 0x1 #define XFS_ITRUNC_MAYBE 0x2 -#define XFS_ITOV(ip) BHV_TO_VNODE(XFS_ITOBHV(ip)) -#define XFS_ITOV_NULL(ip) BHV_TO_VNODE_NULL(XFS_ITOBHV(ip)) -#define XFS_ITOBHV(ip) ((struct bhv_desc *)(&((ip)->i_bhv_desc))) -#define XFS_BHVTOI(bhvp) ((xfs_inode_t *)((char *)(bhvp) - \ - (char *)&(((xfs_inode_t *)0)->i_bhv_desc))) -#define BHV_IS_XFS(bdp) (BHV_OPS(bdp) == &xfs_vnodeops) +#define XFS_ITOV(ip) ((ip)->i_vnode) +#define XFS_ITOV_NULL(ip) ((ip)->i_vnode) /* * For multiple groups support: if S_ISGID bit is set in the parent * directory, group of new file is set to that of the parent, and * new subdirectory gets S_ISGID bit from parent. */ -#define XFS_INHERIT_GID(pip, vfsp) \ - (((vfsp)->vfs_flag & VFS_GRPID) || ((pip)->i_d.di_mode & S_ISGID)) +#define XFS_INHERIT_GID(pip) \ + (((pip)->i_mount->m_flags & XFS_MOUNT_GRPID) || \ + ((pip)->i_d.di_mode & S_ISGID)) /* * Flags for xfs_iget() @@ -480,11 +507,9 @@ xfs_iflags_test(xfs_inode_t *ip, unsigned short flags) */ void xfs_ihash_init(struct xfs_mount *); void xfs_ihash_free(struct xfs_mount *); -void xfs_chash_init(struct xfs_mount *); -void xfs_chash_free(struct xfs_mount *); xfs_inode_t *xfs_inode_incore(struct xfs_mount *, xfs_ino_t, struct xfs_trans *); -void xfs_inode_lock_init(xfs_inode_t *, struct bhv_vnode *); +void xfs_inode_lock_init(xfs_inode_t *, bhv_vnode_t *); int xfs_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, uint, uint, xfs_inode_t **, xfs_daddr_t); void xfs_iput(xfs_inode_t *, uint); @@ -506,7 +531,7 @@ int xfs_finish_reclaim_all(struct xfs_mount *, int); * xfs_inode.c prototypes. */ int xfs_itobp(struct xfs_mount *, struct xfs_trans *, - xfs_inode_t *, xfs_dinode_t **, struct xfs_buf **, + xfs_inode_t *, struct xfs_dinode **, struct xfs_buf **, xfs_daddr_t, uint); int xfs_iread(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, xfs_inode_t **, xfs_daddr_t, uint); @@ -514,8 +539,11 @@ int xfs_iread_extents(struct xfs_trans *, xfs_inode_t *, int); int xfs_ialloc(struct xfs_trans *, xfs_inode_t *, mode_t, xfs_nlink_t, xfs_dev_t, struct cred *, xfs_prid_t, int, struct xfs_buf **, boolean_t *, xfs_inode_t **); -void xfs_xlate_dinode_core(xfs_caddr_t, struct xfs_dinode_core *, - int); +void xfs_dinode_from_disk(struct xfs_icdinode *, + struct xfs_dinode_core *); +void xfs_dinode_to_disk(struct xfs_dinode_core *, + struct xfs_icdinode *); + uint xfs_ip2xflags(struct xfs_inode *); uint xfs_dic2xflags(struct xfs_dinode_core *); int xfs_ifree(struct xfs_trans *, xfs_inode_t *, @@ -545,11 +573,9 @@ void xfs_ichgtime(xfs_inode_t *, int); xfs_fsize_t xfs_file_last_byte(xfs_inode_t *); void xfs_lock_inodes(xfs_inode_t **, int, int, uint); -xfs_inode_t *xfs_vtoi(struct bhv_vnode *vp); - void xfs_synchronize_atime(xfs_inode_t *); -xfs_bmbt_rec_t *xfs_iext_get_ext(xfs_ifork_t *, xfs_extnum_t); +xfs_bmbt_rec_host_t *xfs_iext_get_ext(xfs_ifork_t *, xfs_extnum_t); void xfs_iext_insert(xfs_ifork_t *, xfs_extnum_t, xfs_extnum_t, xfs_bmbt_irec_t *); void xfs_iext_add(xfs_ifork_t *, xfs_extnum_t, int); @@ -564,7 +590,7 @@ void xfs_iext_indirect_to_direct(xfs_ifork_t *); void xfs_iext_direct_to_inline(xfs_ifork_t *, xfs_extnum_t); void xfs_iext_inline_to_direct(xfs_ifork_t *, int); void xfs_iext_destroy(xfs_ifork_t *); -xfs_bmbt_rec_t *xfs_iext_bno_to_ext(xfs_ifork_t *, xfs_fileoff_t, int *); +xfs_bmbt_rec_host_t *xfs_iext_bno_to_ext(xfs_ifork_t *, xfs_fileoff_t, int *); xfs_ext_irec_t *xfs_iext_bno_to_irec(xfs_ifork_t *, xfs_fileoff_t, int *); xfs_ext_irec_t *xfs_iext_idx_to_irec(xfs_ifork_t *, xfs_extnum_t *, int *, int); void xfs_iext_irec_init(xfs_ifork_t *); @@ -589,7 +615,7 @@ void xfs_inobp_check(struct xfs_mount *, struct xfs_buf *); #define xfs_inobp_check(mp, bp) #endif /* DEBUG */ -extern struct kmem_zone *xfs_chashlist_zone; +extern struct kmem_zone *xfs_icluster_zone; extern struct kmem_zone *xfs_ifork_zone; extern struct kmem_zone *xfs_inode_zone; extern struct kmem_zone *xfs_ili_zone; diff --git a/fs/xfs/xfs_iocore.c b/fs/xfs/xfs_iocore.c index 81548ec72ba6..b27b5d5be841 100644 --- a/fs/xfs/xfs_iocore.c +++ b/fs/xfs/xfs_iocore.c @@ -57,11 +57,11 @@ xfs_size_fn( STATIC int xfs_ioinit( - struct bhv_vfs *vfsp, + struct xfs_mount *mp, struct xfs_mount_args *mntargs, int flags) { - return xfs_mountfs(vfsp, XFS_VFSTOM(vfsp), flags); + return xfs_mountfs(mp, flags); } xfs_ioops_t xfs_iocore_xfs = { diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index bf57b75acb90..72786e356d56 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -135,14 +135,10 @@ xfs_imap_to_bmap( int flags) { xfs_mount_t *mp; - xfs_fsize_t nisize; int pbm; xfs_fsblock_t start_block; mp = io->io_mount; - nisize = XFS_SIZE(mp, io); - if (io->io_new_size > nisize) - nisize = io->io_new_size; for (pbm = 0; imaps && pbm < iomaps; imaps--, iomapp++, imap++, pbm++) { iomapp->iomap_offset = XFS_FSB_TO_B(mp, imap->br_startoff); @@ -169,10 +165,6 @@ xfs_imap_to_bmap( iomapp->iomap_flags |= IOMAP_UNWRITTEN; } - if ((iomapp->iomap_offset + iomapp->iomap_bsize) >= nisize) { - iomapp->iomap_flags |= IOMAP_EOF; - } - offset += iomapp->iomap_bsize - iomapp->iomap_delta; } return pbm; /* Return the number filled */ diff --git a/fs/xfs/xfs_iomap.h b/fs/xfs/xfs_iomap.h index df441ee936b2..f5c09887fe93 100644 --- a/fs/xfs/xfs_iomap.h +++ b/fs/xfs/xfs_iomap.h @@ -23,7 +23,6 @@ typedef enum { /* iomap_flags values */ IOMAP_READ = 0, /* mapping for a read */ - IOMAP_EOF = 0x01, /* mapping contains EOF */ IOMAP_HOLE = 0x02, /* mapping covers a hole */ IOMAP_DELAY = 0x04, /* mapping covers delalloc region */ IOMAP_REALTIME = 0x10, /* mapping on the realtime device */ diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index 4c2454bcc714..9972992fd3c3 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c @@ -57,7 +57,7 @@ xfs_bulkstat_one_iget( xfs_bstat_t *buf, /* return buffer */ int *stat) /* BULKSTAT_RV_... */ { - xfs_dinode_core_t *dic; /* dinode core info pointer */ + xfs_icdinode_t *dic; /* dinode core info pointer */ xfs_inode_t *ip; /* incore inode pointer */ bhv_vnode_t *vp; int error; @@ -151,37 +151,37 @@ xfs_bulkstat_one_dinode( * the new format. We don't change the version number so that we * can distinguish this from a real new format inode. */ - if (INT_GET(dic->di_version, ARCH_CONVERT) == XFS_DINODE_VERSION_1) { - buf->bs_nlink = INT_GET(dic->di_onlink, ARCH_CONVERT); + if (dic->di_version == XFS_DINODE_VERSION_1) { + buf->bs_nlink = be16_to_cpu(dic->di_onlink); buf->bs_projid = 0; } else { - buf->bs_nlink = INT_GET(dic->di_nlink, ARCH_CONVERT); - buf->bs_projid = INT_GET(dic->di_projid, ARCH_CONVERT); + buf->bs_nlink = be32_to_cpu(dic->di_nlink); + buf->bs_projid = be16_to_cpu(dic->di_projid); } buf->bs_ino = ino; - buf->bs_mode = INT_GET(dic->di_mode, ARCH_CONVERT); - buf->bs_uid = INT_GET(dic->di_uid, ARCH_CONVERT); - buf->bs_gid = INT_GET(dic->di_gid, ARCH_CONVERT); - buf->bs_size = INT_GET(dic->di_size, ARCH_CONVERT); - buf->bs_atime.tv_sec = INT_GET(dic->di_atime.t_sec, ARCH_CONVERT); - buf->bs_atime.tv_nsec = INT_GET(dic->di_atime.t_nsec, ARCH_CONVERT); - buf->bs_mtime.tv_sec = INT_GET(dic->di_mtime.t_sec, ARCH_CONVERT); - buf->bs_mtime.tv_nsec = INT_GET(dic->di_mtime.t_nsec, ARCH_CONVERT); - buf->bs_ctime.tv_sec = INT_GET(dic->di_ctime.t_sec, ARCH_CONVERT); - buf->bs_ctime.tv_nsec = INT_GET(dic->di_ctime.t_nsec, ARCH_CONVERT); + buf->bs_mode = be16_to_cpu(dic->di_mode); + buf->bs_uid = be32_to_cpu(dic->di_uid); + buf->bs_gid = be32_to_cpu(dic->di_gid); + buf->bs_size = be64_to_cpu(dic->di_size); + buf->bs_atime.tv_sec = be32_to_cpu(dic->di_atime.t_sec); + buf->bs_atime.tv_nsec = be32_to_cpu(dic->di_atime.t_nsec); + buf->bs_mtime.tv_sec = be32_to_cpu(dic->di_mtime.t_sec); + buf->bs_mtime.tv_nsec = be32_to_cpu(dic->di_mtime.t_nsec); + buf->bs_ctime.tv_sec = be32_to_cpu(dic->di_ctime.t_sec); + buf->bs_ctime.tv_nsec = be32_to_cpu(dic->di_ctime.t_nsec); buf->bs_xflags = xfs_dic2xflags(dic); - buf->bs_extsize = INT_GET(dic->di_extsize, ARCH_CONVERT) << mp->m_sb.sb_blocklog; - buf->bs_extents = INT_GET(dic->di_nextents, ARCH_CONVERT); - buf->bs_gen = INT_GET(dic->di_gen, ARCH_CONVERT); + buf->bs_extsize = be32_to_cpu(dic->di_extsize) << mp->m_sb.sb_blocklog; + buf->bs_extents = be32_to_cpu(dic->di_nextents); + buf->bs_gen = be32_to_cpu(dic->di_gen); memset(buf->bs_pad, 0, sizeof(buf->bs_pad)); - buf->bs_dmevmask = INT_GET(dic->di_dmevmask, ARCH_CONVERT); - buf->bs_dmstate = INT_GET(dic->di_dmstate, ARCH_CONVERT); - buf->bs_aextents = INT_GET(dic->di_anextents, ARCH_CONVERT); + buf->bs_dmevmask = be32_to_cpu(dic->di_dmevmask); + buf->bs_dmstate = be16_to_cpu(dic->di_dmstate); + buf->bs_aextents = be16_to_cpu(dic->di_anextents); - switch (INT_GET(dic->di_format, ARCH_CONVERT)) { + switch (dic->di_format) { case XFS_DINODE_FMT_DEV: - buf->bs_rdev = INT_GET(dip->di_u.di_dev, ARCH_CONVERT); + buf->bs_rdev = be32_to_cpu(dip->di_u.di_dev); buf->bs_blksize = BLKDEV_IOSIZE; buf->bs_blocks = 0; break; @@ -195,7 +195,7 @@ xfs_bulkstat_one_dinode( case XFS_DINODE_FMT_BTREE: buf->bs_rdev = 0; buf->bs_blksize = mp->m_sb.sb_blocksize; - buf->bs_blocks = INT_GET(dic->di_nblocks, ARCH_CONVERT); + buf->bs_blocks = be64_to_cpu(dic->di_nblocks); break; } @@ -290,16 +290,23 @@ xfs_bulkstat_use_dinode( return 1; dip = (xfs_dinode_t *) xfs_buf_offset(bp, clustidx << mp->m_sb.sb_inodelog); - if (INT_GET(dip->di_core.di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC || - !XFS_DINODE_GOOD_VERSION( - INT_GET(dip->di_core.di_version, ARCH_CONVERT))) + /* + * Check the buffer containing the on-disk inode for di_nlink == 0. + * This is to prevent xfs_bulkstat from picking up just reclaimed + * inodes that have their in-core state initialized but not flushed + * to disk yet. This is a temporary hack that would require a proper + * fix in the future. + */ + if (be16_to_cpu(dip->di_core.di_magic) != XFS_DINODE_MAGIC || + !XFS_DINODE_GOOD_VERSION(dip->di_core.di_version) || + !dip->di_core.di_nlink) return 0; if (flags & BULKSTAT_FG_QUICK) { *dipp = dip; return 1; } /* BULKSTAT_FG_INLINE: if attr fork is local, or not there, use it */ - aformat = INT_GET(dip->di_core.di_aformat, ARCH_CONVERT); + aformat = dip->di_core.di_aformat; if ((XFS_CFORK_Q(&dip->di_core) == 0) || (aformat == XFS_DINODE_FMT_LOCAL) || (aformat == XFS_DINODE_FMT_EXTENTS && !dip->di_core.di_anextents)) { @@ -612,21 +619,25 @@ xfs_bulkstat( } } } + ino = XFS_AGINO_TO_INO(mp, agno, agino); + bno = XFS_AGB_TO_DADDR(mp, agno, agbno); /* * Skip if this inode is free. */ - if (XFS_INOBT_MASK(chunkidx) & irbp->ir_free) + if (XFS_INOBT_MASK(chunkidx) & irbp->ir_free) { + lastino = ino; continue; + } /* * Count used inodes as free so we can tell * when the chunk is used up. */ irbp->ir_freecount++; - ino = XFS_AGINO_TO_INO(mp, agno, agino); - bno = XFS_AGB_TO_DADDR(mp, agno, agbno); if (!xfs_bulkstat_use_dinode(mp, flags, bp, - clustidx, &dip)) + clustidx, &dip)) { + lastino = ino; continue; + } /* * If we need to do an iget, cannot hold bp. * Drop it, until starting the next cluster. @@ -687,8 +698,7 @@ xfs_bulkstat( if (end_of_ag) { agno++; agino = 0; - } else - agino = XFS_INO_TO_AGINO(mp, lastino); + } } else break; } diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 9bfb69e1e885..77c12715a7d0 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -252,6 +252,29 @@ xlog_grant_add_space(struct log *log, int bytes) xlog_grant_add_space_reserve(log, bytes); } +static void +xlog_tic_reset_res(xlog_ticket_t *tic) +{ + tic->t_res_num = 0; + tic->t_res_arr_sum = 0; + tic->t_res_num_ophdrs = 0; +} + +static void +xlog_tic_add_region(xlog_ticket_t *tic, uint len, uint type) +{ + if (tic->t_res_num == XLOG_TIC_LEN_MAX) { + /* add to overflow and start again */ + tic->t_res_o_flow += tic->t_res_arr_sum; + tic->t_res_num = 0; + tic->t_res_arr_sum = 0; + } + + tic->t_res_arr[tic->t_res_num].r_len = len; + tic->t_res_arr[tic->t_res_num].r_type = type; + tic->t_res_arr_sum += len; + tic->t_res_num++; +} /* * NOTES: @@ -486,7 +509,7 @@ xfs_log_mount(xfs_mount_t *mp, cmn_err(CE_NOTE, "!Mounting filesystem \"%s\" in no-recovery mode. Filesystem will be inconsistent.", mp->m_fsname); - ASSERT(XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY); + ASSERT(mp->m_flags & XFS_MOUNT_RDONLY); } mp->m_log = xlog_alloc_log(mp, log_target, blk_offset, num_bblks); @@ -496,16 +519,15 @@ xfs_log_mount(xfs_mount_t *mp, * just worked. */ if (!(mp->m_flags & XFS_MOUNT_NORECOVERY)) { - bhv_vfs_t *vfsp = XFS_MTOVFS(mp); - int error, readonly = (vfsp->vfs_flag & VFS_RDONLY); + int error, readonly = (mp->m_flags & XFS_MOUNT_RDONLY); if (readonly) - vfsp->vfs_flag &= ~VFS_RDONLY; + mp->m_flags &= ~XFS_MOUNT_RDONLY; error = xlog_recover(mp->m_log); if (readonly) - vfsp->vfs_flag |= VFS_RDONLY; + mp->m_flags |= XFS_MOUNT_RDONLY; if (error) { cmn_err(CE_WARN, "XFS: log mount/recovery failed: error %d", error); xlog_dealloc_log(mp->m_log); @@ -537,7 +559,7 @@ xfs_log_mount_finish(xfs_mount_t *mp, int mfsi_flags) error = xlog_recover_finish(mp->m_log, mfsi_flags); else { error = 0; - ASSERT(XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY); + ASSERT(mp->m_flags & XFS_MOUNT_RDONLY); } return error; @@ -597,7 +619,7 @@ xfs_log_unmount_write(xfs_mount_t *mp) * Don't write out unmount record on read-only mounts. * Or, if we are doing a forced umount (typically because of IO errors). */ - if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY) + if (mp->m_flags & XFS_MOUNT_RDONLY) return 0; xfs_log_force(mp, 0, XFS_LOG_FORCE|XFS_LOG_SYNC); @@ -949,6 +971,19 @@ xlog_iodone(xfs_buf_t *bp) l = iclog->ic_log; /* + * If the ordered flag has been removed by a lower + * layer, it means the underlyin device no longer supports + * barrier I/O. Warn loudly and turn off barriers. + */ + if ((l->l_mp->m_flags & XFS_MOUNT_BARRIER) && !XFS_BUF_ORDERED(bp)) { + l->l_mp->m_flags &= ~XFS_MOUNT_BARRIER; + xfs_fs_cmn_err(CE_WARN, l->l_mp, + "xlog_iodone: Barriers are no longer supported" + " by device. Disabling barriers\n"); + xfs_buftrace("XLOG_IODONE BARRIERS OFF", bp); + } + + /* * Race to shutdown the filesystem if we see an error. */ if (XFS_TEST_ERROR((XFS_BUF_GETERROR(bp)), l->l_mp, @@ -1012,10 +1047,7 @@ xlog_bdstrat_cb(struct xfs_buf *bp) /* * Return size of each in-core log record buffer. * - * Low memory machines only get 2 16KB buffers. We don't want to waste - * memory here. However, all other machines get at least 2 32KB buffers. - * The number is hard coded because we don't care about the minimum - * memory size, just 32MB systems. + * All machines get 8 x 32KB buffers by default, unless tuned otherwise. * * If the filesystem blocksize is too large, we may need to choose a * larger size since the directory code currently logs entire blocks. @@ -1028,17 +1060,10 @@ xlog_get_iclog_buffer_size(xfs_mount_t *mp, int size; int xhdrs; - if (mp->m_logbufs <= 0) { - if (xfs_physmem <= btoc(128*1024*1024)) { - log->l_iclog_bufs = XLOG_MIN_ICLOGS; - } else if (xfs_physmem <= btoc(400*1024*1024)) { - log->l_iclog_bufs = XLOG_MED_ICLOGS; - } else { /* 256K with 32K bufs */ - log->l_iclog_bufs = XLOG_MAX_ICLOGS; - } - } else { + if (mp->m_logbufs <= 0) + log->l_iclog_bufs = XLOG_MAX_ICLOGS; + else log->l_iclog_bufs = mp->m_logbufs; - } /* * Buffer size passed in from mount system call. @@ -1069,18 +1094,9 @@ xlog_get_iclog_buffer_size(xfs_mount_t *mp, goto done; } - /* - * Special case machines that have less than 32MB of memory. - * All machines with more memory use 32KB buffers. - */ - if (xfs_physmem <= btoc(32*1024*1024)) { - /* Don't change; min configuration */ - log->l_iclog_size = XLOG_RECORD_BSIZE; /* 16k */ - log->l_iclog_size_log = XLOG_RECORD_BSHIFT; - } else { - log->l_iclog_size = XLOG_BIG_RECORD_BSIZE; /* 32k */ - log->l_iclog_size_log = XLOG_BIG_RECORD_BSHIFT; - } + /* All machines use 32KB buffers by default. */ + log->l_iclog_size = XLOG_BIG_RECORD_BSIZE; + log->l_iclog_size_log = XLOG_BIG_RECORD_BSHIFT; /* the default log size is 16k or 32k which is one header sector */ log->l_iclog_hsize = BBSIZE; @@ -1771,14 +1787,14 @@ xlog_write(xfs_mount_t * mp, len = 0; if (ticket->t_flags & XLOG_TIC_INITED) { /* acct for start rec of xact */ len += sizeof(xlog_op_header_t); - XLOG_TIC_ADD_OPHDR(ticket); + ticket->t_res_num_ophdrs++; } for (index = 0; index < nentries; index++) { len += sizeof(xlog_op_header_t); /* each region gets >= 1 */ - XLOG_TIC_ADD_OPHDR(ticket); + ticket->t_res_num_ophdrs++; len += reg[index].i_len; - XLOG_TIC_ADD_REGION(ticket, reg[index].i_len, reg[index].i_type); + xlog_tic_add_region(ticket, reg[index].i_len, reg[index].i_type); } contwr = *start_lsn = 0; @@ -1887,7 +1903,7 @@ xlog_write(xfs_mount_t * mp, len += sizeof(xlog_op_header_t); /* from splitting of region */ /* account for new log op header */ ticket->t_curr_res -= sizeof(xlog_op_header_t); - XLOG_TIC_ADD_OPHDR(ticket); + ticket->t_res_num_ophdrs++; } xlog_verify_dest_ptr(log, ptr); @@ -2385,7 +2401,7 @@ restart: */ if (log_offset == 0) { ticket->t_curr_res -= log->l_iclog_hsize; - XLOG_TIC_ADD_REGION(ticket, + xlog_tic_add_region(ticket, log->l_iclog_hsize, XLOG_REG_TYPE_LRHEADER); INT_SET(head->h_cycle, ARCH_CONVERT, log->l_curr_cycle); @@ -2573,7 +2589,7 @@ xlog_regrant_write_log_space(xlog_t *log, #endif tic->t_curr_res = tic->t_unit_res; - XLOG_TIC_RESET_RES(tic); + xlog_tic_reset_res(tic); if (tic->t_cnt > 0) return 0; @@ -2714,7 +2730,7 @@ xlog_regrant_reserve_log_space(xlog_t *log, s = GRANT_LOCK(log); xlog_grant_sub_space(log, ticket->t_curr_res); ticket->t_curr_res = ticket->t_unit_res; - XLOG_TIC_RESET_RES(ticket); + xlog_tic_reset_res(ticket); xlog_trace_loggrant(log, ticket, "xlog_regrant_reserve_log_space: sub current res"); xlog_verify_grant_head(log, 1); @@ -2731,7 +2747,7 @@ xlog_regrant_reserve_log_space(xlog_t *log, xlog_verify_grant_head(log, 0); GRANT_UNLOCK(log, s); ticket->t_curr_res = ticket->t_unit_res; - XLOG_TIC_RESET_RES(ticket); + xlog_tic_reset_res(ticket); } /* xlog_regrant_reserve_log_space */ @@ -3354,7 +3370,7 @@ xlog_ticket_get(xlog_t *log, tic->t_flags |= XLOG_TIC_PERM_RESERV; sv_init(&(tic->t_sema), SV_DEFAULT, "logtick"); - XLOG_TIC_RESET_RES(tic); + xlog_tic_reset_res(tic); return tic; } /* xlog_ticket_get */ diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h index 9bd3cdf11a87..752f964b3699 100644 --- a/fs/xfs/xfs_log_priv.h +++ b/fs/xfs/xfs_log_priv.h @@ -30,17 +30,16 @@ struct xfs_mount; */ #define XLOG_MIN_ICLOGS 2 -#define XLOG_MED_ICLOGS 4 #define XLOG_MAX_ICLOGS 8 #define XLOG_HEADER_MAGIC_NUM 0xFEEDbabe /* Invalid cycle number */ #define XLOG_VERSION_1 1 #define XLOG_VERSION_2 2 /* Large IClogs, Log sunit */ #define XLOG_VERSION_OKBITS (XLOG_VERSION_1 | XLOG_VERSION_2) -#define XLOG_RECORD_BSIZE (16*1024) /* eventually 32k */ +#define XLOG_MIN_RECORD_BSIZE (16*1024) /* eventually 32k */ #define XLOG_BIG_RECORD_BSIZE (32*1024) /* 32k buffers */ #define XLOG_MAX_RECORD_BSIZE (256*1024) #define XLOG_HEADER_CYCLE_SIZE (32*1024) /* cycle data in header */ -#define XLOG_RECORD_BSHIFT 14 /* 16384 == 1 << 14 */ +#define XLOG_MIN_RECORD_BSHIFT 14 /* 16384 == 1 << 14 */ #define XLOG_BIG_RECORD_BSHIFT 15 /* 32k == 1 << 15 */ #define XLOG_MAX_RECORD_BSHIFT 18 /* 256k == 1 << 18 */ #define XLOG_BTOLSUNIT(log, b) (((b)+(log)->l_mp->m_sb.sb_logsunit-1) / \ @@ -250,22 +249,6 @@ typedef __uint32_t xlog_tid_t; /* Ticket reservation region accounting */ #define XLOG_TIC_LEN_MAX 15 -#define XLOG_TIC_RESET_RES(t) ((t)->t_res_num = \ - (t)->t_res_arr_sum = (t)->t_res_num_ophdrs = 0) -#define XLOG_TIC_ADD_OPHDR(t) ((t)->t_res_num_ophdrs++) -#define XLOG_TIC_ADD_REGION(t, len, type) \ - do { \ - if ((t)->t_res_num == XLOG_TIC_LEN_MAX) { \ - /* add to overflow and start again */ \ - (t)->t_res_o_flow += (t)->t_res_arr_sum; \ - (t)->t_res_num = 0; \ - (t)->t_res_arr_sum = 0; \ - } \ - (t)->t_res_arr[(t)->t_res_num].r_len = (len); \ - (t)->t_res_arr[(t)->t_res_num].r_type = (type); \ - (t)->t_res_arr_sum += (len); \ - (t)->t_res_num++; \ - } while (0) /* * Reservation region diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 8ae6e8e5f3db..851eca8a7150 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -2245,7 +2245,7 @@ xlog_recover_do_inode_trans( int error; int attr_index; uint fields; - xfs_dinode_core_t *dicp; + xfs_icdinode_t *dicp; int need_free = 0; if (pass == XLOG_RECOVER_PASS1) { @@ -2309,7 +2309,7 @@ xlog_recover_do_inode_trans( * Make sure the place we're flushing out to really looks * like an inode! */ - if (unlikely(INT_GET(dip->di_core.di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC)) { + if (unlikely(be16_to_cpu(dip->di_core.di_magic) != XFS_DINODE_MAGIC)) { xfs_buf_relse(bp); xfs_fs_cmn_err(CE_ALERT, mp, "xfs_inode_recover: Bad inode magic number, dino ptr = 0x%p, dino bp = 0x%p, ino = %Ld", @@ -2319,7 +2319,7 @@ xlog_recover_do_inode_trans( error = EFSCORRUPTED; goto error; } - dicp = (xfs_dinode_core_t*)(item->ri_buf[1].i_addr); + dicp = (xfs_icdinode_t *)(item->ri_buf[1].i_addr); if (unlikely(dicp->di_magic != XFS_DINODE_MAGIC)) { xfs_buf_relse(bp); xfs_fs_cmn_err(CE_ALERT, mp, @@ -2332,15 +2332,13 @@ xlog_recover_do_inode_trans( } /* Skip replay when the on disk inode is newer than the log one */ - if (dicp->di_flushiter < - INT_GET(dip->di_core.di_flushiter, ARCH_CONVERT)) { + if (dicp->di_flushiter < be16_to_cpu(dip->di_core.di_flushiter)) { /* * Deal with the wrap case, DI_MAX_FLUSH is less * than smaller numbers */ - if ((INT_GET(dip->di_core.di_flushiter, ARCH_CONVERT) - == DI_MAX_FLUSH) && - (dicp->di_flushiter < (DI_MAX_FLUSH>>1))) { + if (be16_to_cpu(dip->di_core.di_flushiter) == DI_MAX_FLUSH && + dicp->di_flushiter < (DI_MAX_FLUSH >> 1)) { /* do nothing */ } else { xfs_buf_relse(bp); @@ -2411,8 +2409,8 @@ xlog_recover_do_inode_trans( } /* The core is in in-core format */ - xfs_xlate_dinode_core((xfs_caddr_t)&dip->di_core, - (xfs_dinode_core_t*)item->ri_buf[1].i_addr, -1); + xfs_dinode_to_disk(&dip->di_core, + (xfs_icdinode_t *)item->ri_buf[1].i_addr); /* the rest is in on-disk format */ if (item->ri_buf[1].i_len > sizeof(xfs_dinode_core_t)) { @@ -2424,8 +2422,7 @@ xlog_recover_do_inode_trans( fields = in_f->ilf_fields; switch (fields & (XFS_ILOG_DEV | XFS_ILOG_UUID)) { case XFS_ILOG_DEV: - INT_SET(dip->di_u.di_dev, ARCH_CONVERT, in_f->ilf_u.ilfu_rdev); - + dip->di_u.di_dev = cpu_to_be32(in_f->ilf_u.ilfu_rdev); break; case XFS_ILOG_UUID: dip->di_u.di_muuid = in_f->ilf_u.ilfu_uuid; @@ -3234,8 +3231,8 @@ xlog_recover_process_iunlinks( ASSERT(ip->i_d.di_nlink == 0); /* setup for the next pass */ - agino = INT_GET(dip->di_next_unlinked, - ARCH_CONVERT); + agino = be32_to_cpu( + dip->di_next_unlinked); xfs_buf_relse(ibp); /* * Prevent any DMAPI event from @@ -3837,7 +3834,10 @@ xlog_do_recover( */ bp = xfs_getsb(log->l_mp, 0); XFS_BUF_UNDONE(bp); + ASSERT(!(XFS_BUF_ISWRITE(bp))); + ASSERT(!(XFS_BUF_ISDELAYWRITE(bp))); XFS_BUF_READ(bp); + XFS_BUF_UNASYNC(bp); xfsbdstrat(log->l_mp, bp); if ((error = xfs_iowait(bp))) { xfs_ioerror_alert("xlog_do_recover", @@ -3849,7 +3849,7 @@ xlog_do_recover( /* Convert superblock from on-disk format */ sbp = &log->l_mp->m_sb; - xfs_xlatesb(XFS_BUF_TO_SBP(bp), sbp, 1, XFS_SB_ALL_BITS); + xfs_sb_from_disk(sbp, XFS_BUF_TO_SBP(bp)); ASSERT(sbp->sb_magicnum == XFS_SB_MAGIC); ASSERT(XFS_SB_GOOD_VERSION(sbp)); xfs_buf_relse(bp); @@ -4027,7 +4027,7 @@ xlog_recover_check_summary( sbbp = xfs_getsb(mp, 0); #ifdef XFS_LOUD_RECOVERY sbp = &mp->m_sb; - xfs_xlatesb(XFS_BUF_TO_SBP(sbbp), sbp, 1, XFS_SB_ALL_BITS); + xfs_sb_from_disk(sbp, XFS_BUF_TO_SBP(sbbp)); cmn_err(CE_NOTE, "xlog_recover_check_summary: sb_icount %Lu itotal %Lu", sbp->sb_icount, itotal); diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index a66b39805176..ebdb76da527c 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -139,7 +139,7 @@ xfs_mount_init(void) AIL_LOCKINIT(&mp->m_ail_lock, "xfs_ail"); spinlock_init(&mp->m_sb_lock, "xfs_sb"); mutex_init(&mp->m_ilock); - initnsema(&mp->m_growlock, 1, "xfs_grow"); + mutex_init(&mp->m_growlock); /* * Initialize the AIL. */ @@ -157,14 +157,8 @@ xfs_mount_init(void) */ void xfs_mount_free( - xfs_mount_t *mp, - int remove_bhv) + xfs_mount_t *mp) { - if (mp->m_ihash) - xfs_ihash_free(mp); - if (mp->m_chash) - xfs_chash_free(mp); - if (mp->m_perag) { int agno; @@ -180,7 +174,7 @@ xfs_mount_free( AIL_LOCK_DESTROY(&mp->m_ail_lock); spinlock_destroy(&mp->m_sb_lock); mutex_destroy(&mp->m_ilock); - freesema(&mp->m_growlock); + mutex_destroy(&mp->m_growlock); if (mp->m_quotainfo) XFS_QM_DONE(mp); @@ -191,15 +185,7 @@ xfs_mount_free( if (mp->m_logname != NULL) kmem_free(mp->m_logname, strlen(mp->m_logname) + 1); - if (remove_bhv) { - struct bhv_vfs *vfsp = XFS_MTOVFS(mp); - - bhv_remove_all_vfsops(vfsp, 0); - VFS_REMOVEBHV(vfsp, &mp->m_bhv); - } - xfs_icsb_destroy_counters(mp); - kmem_free(mp, sizeof(xfs_mount_t)); } /* @@ -342,9 +328,19 @@ xfs_mount_validate_sb( return 0; } +STATIC void +xfs_initialize_perag_icache( + xfs_perag_t *pag) +{ + if (!pag->pag_ici_init) { + rwlock_init(&pag->pag_ici_lock); + INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC); + pag->pag_ici_init = 1; + } +} + xfs_agnumber_t xfs_initialize_perag( - bhv_vfs_t *vfs, xfs_mount_t *mp, xfs_agnumber_t agcount) { @@ -362,7 +358,7 @@ xfs_initialize_perag( /* Clear the mount flag if no inode can overflow 32 bits * on this filesystem, or if specifically requested.. */ - if ((vfs->vfs_flag & VFS_32BITINODES) && ino > max_inum) { + if ((mp->m_flags & XFS_MOUNT_SMALL_INUMS) && ino > max_inum) { mp->m_flags |= XFS_MOUNT_32BITINODES; } else { mp->m_flags &= ~XFS_MOUNT_32BITINODES; @@ -396,48 +392,92 @@ xfs_initialize_perag( pag->pagi_inodeok = 1; if (index < max_metadata) pag->pagf_metadata = 1; + xfs_initialize_perag_icache(pag); } } else { /* Setup default behavior for smaller filesystems */ for (index = 0; index < agcount; index++) { pag = &mp->m_perag[index]; pag->pagi_inodeok = 1; + xfs_initialize_perag_icache(pag); } } return index; } +void +xfs_sb_from_disk( + xfs_sb_t *to, + xfs_dsb_t *from) +{ + to->sb_magicnum = be32_to_cpu(from->sb_magicnum); + to->sb_blocksize = be32_to_cpu(from->sb_blocksize); + to->sb_dblocks = be64_to_cpu(from->sb_dblocks); + to->sb_rblocks = be64_to_cpu(from->sb_rblocks); + to->sb_rextents = be64_to_cpu(from->sb_rextents); + memcpy(&to->sb_uuid, &from->sb_uuid, sizeof(to->sb_uuid)); + to->sb_logstart = be64_to_cpu(from->sb_logstart); + to->sb_rootino = be64_to_cpu(from->sb_rootino); + to->sb_rbmino = be64_to_cpu(from->sb_rbmino); + to->sb_rsumino = be64_to_cpu(from->sb_rsumino); + to->sb_rextsize = be32_to_cpu(from->sb_rextsize); + to->sb_agblocks = be32_to_cpu(from->sb_agblocks); + to->sb_agcount = be32_to_cpu(from->sb_agcount); + to->sb_rbmblocks = be32_to_cpu(from->sb_rbmblocks); + to->sb_logblocks = be32_to_cpu(from->sb_logblocks); + to->sb_versionnum = be16_to_cpu(from->sb_versionnum); + to->sb_sectsize = be16_to_cpu(from->sb_sectsize); + to->sb_inodesize = be16_to_cpu(from->sb_inodesize); + to->sb_inopblock = be16_to_cpu(from->sb_inopblock); + memcpy(&to->sb_fname, &from->sb_fname, sizeof(to->sb_fname)); + to->sb_blocklog = from->sb_blocklog; + to->sb_sectlog = from->sb_sectlog; + to->sb_inodelog = from->sb_inodelog; + to->sb_inopblog = from->sb_inopblog; + to->sb_agblklog = from->sb_agblklog; + to->sb_rextslog = from->sb_rextslog; + to->sb_inprogress = from->sb_inprogress; + to->sb_imax_pct = from->sb_imax_pct; + to->sb_icount = be64_to_cpu(from->sb_icount); + to->sb_ifree = be64_to_cpu(from->sb_ifree); + to->sb_fdblocks = be64_to_cpu(from->sb_fdblocks); + to->sb_frextents = be64_to_cpu(from->sb_frextents); + to->sb_uquotino = be64_to_cpu(from->sb_uquotino); + to->sb_gquotino = be64_to_cpu(from->sb_gquotino); + to->sb_qflags = be16_to_cpu(from->sb_qflags); + to->sb_flags = from->sb_flags; + to->sb_shared_vn = from->sb_shared_vn; + to->sb_inoalignmt = be32_to_cpu(from->sb_inoalignmt); + to->sb_unit = be32_to_cpu(from->sb_unit); + to->sb_width = be32_to_cpu(from->sb_width); + to->sb_dirblklog = from->sb_dirblklog; + to->sb_logsectlog = from->sb_logsectlog; + to->sb_logsectsize = be16_to_cpu(from->sb_logsectsize); + to->sb_logsunit = be32_to_cpu(from->sb_logsunit); + to->sb_features2 = be32_to_cpu(from->sb_features2); +} + /* - * xfs_xlatesb + * Copy in core superblock to ondisk one. * - * data - on disk version of sb - * sb - a superblock - * dir - conversion direction: <0 - convert sb to buf - * >0 - convert buf to sb - * fields - which fields to copy (bitmask) + * The fields argument is mask of superblock fields to copy. */ void -xfs_xlatesb( - void *data, - xfs_sb_t *sb, - int dir, +xfs_sb_to_disk( + xfs_dsb_t *to, + xfs_sb_t *from, __int64_t fields) { - xfs_caddr_t buf_ptr; - xfs_caddr_t mem_ptr; + xfs_caddr_t to_ptr = (xfs_caddr_t)to; + xfs_caddr_t from_ptr = (xfs_caddr_t)from; xfs_sb_field_t f; int first; int size; - ASSERT(dir); ASSERT(fields); - if (!fields) return; - buf_ptr = (xfs_caddr_t)data; - mem_ptr = (xfs_caddr_t)sb; - while (fields) { f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields); first = xfs_sb_info[f].offset; @@ -446,26 +486,20 @@ xfs_xlatesb( ASSERT(xfs_sb_info[f].type == 0 || xfs_sb_info[f].type == 1); if (size == 1 || xfs_sb_info[f].type == 1) { - if (dir > 0) { - memcpy(mem_ptr + first, buf_ptr + first, size); - } else { - memcpy(buf_ptr + first, mem_ptr + first, size); - } + memcpy(to_ptr + first, from_ptr + first, size); } else { switch (size) { case 2: - INT_XLATE(*(__uint16_t*)(buf_ptr+first), - *(__uint16_t*)(mem_ptr+first), - dir, ARCH_CONVERT); + *(__be16 *)(to_ptr + first) = + cpu_to_be16(*(__u16 *)(from_ptr + first)); break; case 4: - INT_XLATE(*(__uint32_t*)(buf_ptr+first), - *(__uint32_t*)(mem_ptr+first), - dir, ARCH_CONVERT); + *(__be32 *)(to_ptr + first) = + cpu_to_be32(*(__u32 *)(from_ptr + first)); break; case 8: - INT_XLATE(*(__uint64_t*)(buf_ptr+first), - *(__uint64_t*)(mem_ptr+first), dir, ARCH_CONVERT); + *(__be64 *)(to_ptr + first) = + cpu_to_be64(*(__u64 *)(from_ptr + first)); break; default: ASSERT(0); @@ -487,7 +521,6 @@ xfs_readsb(xfs_mount_t *mp, int flags) unsigned int sector_size; unsigned int extra_flags; xfs_buf_t *bp; - xfs_sb_t *sbp; int error; ASSERT(mp->m_sb_bp == NULL); @@ -515,8 +548,7 @@ xfs_readsb(xfs_mount_t *mp, int flags) * Initialize the mount structure from the superblock. * But first do some basic consistency checking. */ - sbp = XFS_BUF_TO_SBP(bp); - xfs_xlatesb(XFS_BUF_PTR(bp), &(mp->m_sb), 1, XFS_SB_ALL_BITS); + xfs_sb_from_disk(&mp->m_sb, XFS_BUF_TO_SBP(bp)); error = xfs_mount_validate_sb(mp, &(mp->m_sb), flags); if (error) { @@ -715,7 +747,6 @@ xfs_initialize_perag_data(xfs_mount_t *mp, xfs_agnumber_t agcount) */ int xfs_mountfs( - bhv_vfs_t *vfsp, xfs_mount_t *mp, int mfsi_flags) { @@ -842,14 +873,11 @@ xfs_mountfs( */ if ((mfsi_flags & XFS_MFSI_SECOND) == 0 && (mp->m_flags & XFS_MOUNT_NOUUID) == 0) { - __uint64_t ret64; if (xfs_uuid_mount(mp)) { error = XFS_ERROR(EINVAL); goto error1; } uuid_mounted=1; - ret64 = uuid_hash64(&sbp->sb_uuid); - memcpy(&vfsp->vfs_fsid, &ret64, sizeof(ret64)); } /* @@ -871,16 +899,6 @@ xfs_mountfs( writeio_log = mp->m_writeio_log; } - /* - * Set the number of readahead buffers to use based on - * physical memory size. - */ - if (xfs_physmem <= 4096) /* <= 16MB */ - mp->m_nreadaheads = XFS_RW_NREADAHEAD_16MB; - else if (xfs_physmem <= 8192) /* <= 32MB */ - mp->m_nreadaheads = XFS_RW_NREADAHEAD_32MB; - else - mp->m_nreadaheads = XFS_RW_NREADAHEAD_K32; if (sbp->sb_blocklog > readio_log) { mp->m_readio_log = sbp->sb_blocklog; } else { @@ -895,15 +913,12 @@ xfs_mountfs( mp->m_writeio_blocks = 1 << (mp->m_writeio_log - sbp->sb_blocklog); /* - * Set the inode cluster size based on the physical memory - * size. This may still be overridden by the file system + * Set the inode cluster size. + * This may still be overridden by the file system * block size if it is larger than the chosen cluster size. */ - if (xfs_physmem <= btoc(32 * 1024 * 1024)) { /* <= 32 MB */ - mp->m_inode_cluster_size = XFS_INODE_SMALL_CLUSTER_SIZE; - } else { - mp->m_inode_cluster_size = XFS_INODE_BIG_CLUSTER_SIZE; - } + mp->m_inode_cluster_size = XFS_INODE_BIG_CLUSTER_SIZE; + /* * Set whether we're using inode alignment. */ @@ -987,16 +1002,6 @@ xfs_mountfs( */ uuid_getnodeuniq(&sbp->sb_uuid, mp->m_fixedfsid); - /* - * The vfs structure needs to have a file system independent - * way of checking for the invariant file system ID. Since it - * can't look at mount structures it has a pointer to the data - * in the mount structure. - * - * File systems that don't support user level file handles (i.e. - * all of them except for XFS) will leave vfs_altfsid as NULL. - */ - vfsp->vfs_altfsid = (xfs_fsid_t *)mp->m_fixedfsid; mp->m_dmevmask = 0; /* not persistent; set after each mount */ xfs_dir_mount(mp); @@ -1012,20 +1017,13 @@ xfs_mountfs( xfs_trans_init(mp); /* - * Allocate and initialize the inode hash table for this - * file system. - */ - xfs_ihash_init(mp); - xfs_chash_init(mp); - - /* * Allocate and initialize the per-ag data. */ init_rwsem(&mp->m_peraglock); mp->m_perag = kmem_zalloc(sbp->sb_agcount * sizeof(xfs_perag_t), KM_SLEEP); - mp->m_maxagi = xfs_initialize_perag(vfsp, mp, sbp->sb_agcount); + mp->m_maxagi = xfs_initialize_perag(mp, sbp->sb_agcount); /* * log's mount-time initialization. Perform 1st part recovery if needed @@ -1116,7 +1114,7 @@ xfs_mountfs( * If fs is not mounted readonly, then update the superblock * unit and width changes. */ - if (update_flags && !(vfsp->vfs_flag & VFS_RDONLY)) + if (update_flags && !(mp->m_flags & XFS_MOUNT_RDONLY)) xfs_mount_log_sbunit(mp, update_flags); /* @@ -1169,8 +1167,6 @@ xfs_mountfs( error3: xfs_log_unmount_dealloc(mp); error2: - xfs_ihash_free(mp); - xfs_chash_free(mp); for (agno = 0; agno < sbp->sb_agcount; agno++) if (mp->m_perag[agno].pagb_list) kmem_free(mp->m_perag[agno].pagb_list, @@ -1194,10 +1190,6 @@ xfs_mountfs( int xfs_unmountfs(xfs_mount_t *mp, struct cred *cr) { - struct bhv_vfs *vfsp = XFS_MTOVFS(mp); -#if defined(DEBUG) || defined(INDUCE_IO_ERROR) - int64_t fsid; -#endif __uint64_t resblks; /* @@ -1261,21 +1253,17 @@ xfs_unmountfs(xfs_mount_t *mp, struct cred *cr) xfs_uuid_unmount(mp); #if defined(DEBUG) || defined(INDUCE_IO_ERROR) - /* - * clear all error tags on this filesystem - */ - memcpy(&fsid, &vfsp->vfs_fsid, sizeof(int64_t)); - xfs_errortag_clearall_umount(fsid, mp->m_fsname, 0); + xfs_errortag_clearall(mp, 0); #endif - XFS_IODONE(vfsp); - xfs_mount_free(mp, 1); + XFS_IODONE(mp); + xfs_mount_free(mp); return 0; } void xfs_unmountfs_close(xfs_mount_t *mp, struct cred *cr) { - if (mp->m_logdev_targp != mp->m_ddev_targp) + if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp) xfs_free_buftarg(mp->m_logdev_targp, 1); if (mp->m_rtdev_targp) xfs_free_buftarg(mp->m_rtdev_targp, 1); @@ -1295,10 +1283,8 @@ xfs_unmountfs_wait(xfs_mount_t *mp) int xfs_fs_writable(xfs_mount_t *mp) { - bhv_vfs_t *vfsp = XFS_MTOVFS(mp); - - return !(vfs_test_for_freeze(vfsp) || XFS_FORCED_SHUTDOWN(mp) || - (vfsp->vfs_flag & VFS_RDONLY)); + return !(xfs_test_for_freeze(mp) || XFS_FORCED_SHUTDOWN(mp) || + (mp->m_flags & XFS_MOUNT_RDONLY)); } /* @@ -1348,34 +1334,44 @@ xfs_log_sbcount( return 0; } +STATIC void +xfs_mark_shared_ro( + xfs_mount_t *mp, + xfs_buf_t *bp) +{ + xfs_dsb_t *sb = XFS_BUF_TO_SBP(bp); + __uint16_t version; + + if (!(sb->sb_flags & XFS_SBF_READONLY)) + sb->sb_flags |= XFS_SBF_READONLY; + + version = be16_to_cpu(sb->sb_versionnum); + if ((version & XFS_SB_VERSION_NUMBITS) != XFS_SB_VERSION_4 || + !(version & XFS_SB_VERSION_SHAREDBIT)) + version |= XFS_SB_VERSION_SHAREDBIT; + sb->sb_versionnum = cpu_to_be16(version); +} + int xfs_unmountfs_writesb(xfs_mount_t *mp) { xfs_buf_t *sbp; - xfs_sb_t *sb; int error = 0; /* * skip superblock write if fs is read-only, or * if we are doing a forced umount. */ - if (!(XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY || + if (!((mp->m_flags & XFS_MOUNT_RDONLY) || XFS_FORCED_SHUTDOWN(mp))) { sbp = xfs_getsb(mp, 0); - sb = XFS_BUF_TO_SBP(sbp); /* * mark shared-readonly if desired */ - if (mp->m_mk_sharedro) { - if (!(sb->sb_flags & XFS_SBF_READONLY)) - sb->sb_flags |= XFS_SBF_READONLY; - if (!XFS_SB_VERSION_HASSHARED(sb)) - XFS_SB_VERSION_ADDSHARED(sb); - xfs_fs_cmn_err(CE_NOTE, mp, - "Unmounting, marking shared read-only"); - } + if (mp->m_mk_sharedro) + xfs_mark_shared_ro(mp, sbp); XFS_BUF_UNDONE(sbp); XFS_BUF_UNREAD(sbp); @@ -1410,7 +1406,6 @@ xfs_mod_sb(xfs_trans_t *tp, __int64_t fields) int first; int last; xfs_mount_t *mp; - xfs_sb_t *sbp; xfs_sb_field_t f; ASSERT(fields); @@ -1418,13 +1413,12 @@ xfs_mod_sb(xfs_trans_t *tp, __int64_t fields) return; mp = tp->t_mountp; bp = xfs_trans_getsb(tp, mp, 0); - sbp = XFS_BUF_TO_SBP(bp); first = sizeof(xfs_sb_t); last = 0; /* translate/copy */ - xfs_xlatesb(XFS_BUF_PTR(bp), &(mp->m_sb), -1, fields); + xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb, fields); /* find modified range */ diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 76ad74758696..c618f7cb5f0e 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -54,13 +54,8 @@ typedef struct xfs_trans_reservations { #else struct cred; struct log; -struct bhv_vfs; -struct bhv_vnode; struct xfs_mount_args; -struct xfs_ihash; -struct xfs_chash; struct xfs_inode; -struct xfs_perag; struct xfs_iocore; struct xfs_bmbt_irec; struct xfs_bmap_free; @@ -68,9 +63,6 @@ struct xfs_extdelta; struct xfs_swapext; struct xfs_mru_cache; -extern struct bhv_vfsops xfs_vfsops; -extern struct bhv_vnodeops xfs_vnodeops; - #define AIL_LOCK_T lock_t #define AIL_LOCKINIT(x,y) spinlock_init(x,y) #define AIL_LOCK_DESTROY(x) spinlock_destroy(x) @@ -82,15 +74,17 @@ extern struct bhv_vnodeops xfs_vnodeops; * Prototypes and functions for the Data Migration subsystem. */ -typedef int (*xfs_send_data_t)(int, struct bhv_vnode *, +typedef int (*xfs_send_data_t)(int, bhv_vnode_t *, xfs_off_t, size_t, int, bhv_vrwlock_t *); typedef int (*xfs_send_mmap_t)(struct vm_area_struct *, uint); -typedef int (*xfs_send_destroy_t)(struct bhv_vnode *, dm_right_t); -typedef int (*xfs_send_namesp_t)(dm_eventtype_t, struct bhv_vfs *, - struct bhv_vnode *, - dm_right_t, struct bhv_vnode *, dm_right_t, +typedef int (*xfs_send_destroy_t)(bhv_vnode_t *, dm_right_t); +typedef int (*xfs_send_namesp_t)(dm_eventtype_t, struct xfs_mount *, + bhv_vnode_t *, + dm_right_t, bhv_vnode_t *, dm_right_t, char *, char *, mode_t, int, int); -typedef void (*xfs_send_unmount_t)(struct bhv_vfs *, struct bhv_vnode *, +typedef int (*xfs_send_mount_t)(struct xfs_mount *, dm_right_t, + char *, char *); +typedef void (*xfs_send_unmount_t)(struct xfs_mount *, bhv_vnode_t *, dm_right_t, mode_t, int, int); typedef struct xfs_dmops { @@ -98,21 +92,24 @@ typedef struct xfs_dmops { xfs_send_mmap_t xfs_send_mmap; xfs_send_destroy_t xfs_send_destroy; xfs_send_namesp_t xfs_send_namesp; + xfs_send_mount_t xfs_send_mount; xfs_send_unmount_t xfs_send_unmount; } xfs_dmops_t; #define XFS_SEND_DATA(mp, ev,vp,off,len,fl,lock) \ - (*(mp)->m_dm_ops.xfs_send_data)(ev,vp,off,len,fl,lock) + (*(mp)->m_dm_ops->xfs_send_data)(ev,vp,off,len,fl,lock) #define XFS_SEND_MMAP(mp, vma,fl) \ - (*(mp)->m_dm_ops.xfs_send_mmap)(vma,fl) + (*(mp)->m_dm_ops->xfs_send_mmap)(vma,fl) #define XFS_SEND_DESTROY(mp, vp,right) \ - (*(mp)->m_dm_ops.xfs_send_destroy)(vp,right) + (*(mp)->m_dm_ops->xfs_send_destroy)(vp,right) #define XFS_SEND_NAMESP(mp, ev,b1,r1,b2,r2,n1,n2,mode,rval,fl) \ - (*(mp)->m_dm_ops.xfs_send_namesp)(ev,NULL,b1,r1,b2,r2,n1,n2,mode,rval,fl) -#define XFS_SEND_PREUNMOUNT(mp, vfs,b1,r1,b2,r2,n1,n2,mode,rval,fl) \ - (*(mp)->m_dm_ops.xfs_send_namesp)(DM_EVENT_PREUNMOUNT,vfs,b1,r1,b2,r2,n1,n2,mode,rval,fl) -#define XFS_SEND_UNMOUNT(mp, vfsp,vp,right,mode,rval,fl) \ - (*(mp)->m_dm_ops.xfs_send_unmount)(vfsp,vp,right,mode,rval,fl) + (*(mp)->m_dm_ops->xfs_send_namesp)(ev,NULL,b1,r1,b2,r2,n1,n2,mode,rval,fl) +#define XFS_SEND_PREUNMOUNT(mp,b1,r1,b2,r2,n1,n2,mode,rval,fl) \ + (*(mp)->m_dm_ops->xfs_send_namesp)(DM_EVENT_PREUNMOUNT,mp,b1,r1,b2,r2,n1,n2,mode,rval,fl) +#define XFS_SEND_MOUNT(mp,right,path,name) \ + (*(mp)->m_dm_ops->xfs_send_mount)(mp,right,path,name) +#define XFS_SEND_UNMOUNT(mp, vp,right,mode,rval,fl) \ + (*(mp)->m_dm_ops->xfs_send_unmount)(mp,vp,right,mode,rval,fl) /* @@ -142,6 +139,9 @@ typedef struct xfs_dquot * (*xfs_dqvopchown_t)( struct xfs_dquot **, struct xfs_dquot *); typedef int (*xfs_dqvopchownresv_t)(struct xfs_trans *, struct xfs_inode *, struct xfs_dquot *, struct xfs_dquot *, uint); +typedef void (*xfs_dqstatvfs_t)(struct xfs_inode *, bhv_statvfs_t *); +typedef int (*xfs_dqsync_t)(struct xfs_mount *, int flags); +typedef int (*xfs_quotactl_t)(struct xfs_mount *, int, int, xfs_caddr_t); typedef struct xfs_qmops { xfs_qminit_t xfs_qminit; @@ -157,42 +157,51 @@ typedef struct xfs_qmops { xfs_dqvoprename_t xfs_dqvoprename; xfs_dqvopchown_t xfs_dqvopchown; xfs_dqvopchownresv_t xfs_dqvopchownresv; + xfs_dqstatvfs_t xfs_dqstatvfs; + xfs_dqsync_t xfs_dqsync; + xfs_quotactl_t xfs_quotactl; struct xfs_dqtrxops *xfs_dqtrxops; } xfs_qmops_t; #define XFS_QM_INIT(mp, mnt, fl) \ - (*(mp)->m_qm_ops.xfs_qminit)(mp, mnt, fl) + (*(mp)->m_qm_ops->xfs_qminit)(mp, mnt, fl) #define XFS_QM_MOUNT(mp, mnt, fl, mfsi_flags) \ - (*(mp)->m_qm_ops.xfs_qmmount)(mp, mnt, fl, mfsi_flags) + (*(mp)->m_qm_ops->xfs_qmmount)(mp, mnt, fl, mfsi_flags) #define XFS_QM_UNMOUNT(mp) \ - (*(mp)->m_qm_ops.xfs_qmunmount)(mp) + (*(mp)->m_qm_ops->xfs_qmunmount)(mp) #define XFS_QM_DONE(mp) \ - (*(mp)->m_qm_ops.xfs_qmdone)(mp) + (*(mp)->m_qm_ops->xfs_qmdone)(mp) #define XFS_QM_DQRELE(mp, dq) \ - (*(mp)->m_qm_ops.xfs_dqrele)(dq) + (*(mp)->m_qm_ops->xfs_dqrele)(dq) #define XFS_QM_DQATTACH(mp, ip, fl) \ - (*(mp)->m_qm_ops.xfs_dqattach)(ip, fl) + (*(mp)->m_qm_ops->xfs_dqattach)(ip, fl) #define XFS_QM_DQDETACH(mp, ip) \ - (*(mp)->m_qm_ops.xfs_dqdetach)(ip) + (*(mp)->m_qm_ops->xfs_dqdetach)(ip) #define XFS_QM_DQPURGEALL(mp, fl) \ - (*(mp)->m_qm_ops.xfs_dqpurgeall)(mp, fl) + (*(mp)->m_qm_ops->xfs_dqpurgeall)(mp, fl) #define XFS_QM_DQVOPALLOC(mp, ip, uid, gid, prid, fl, dq1, dq2) \ - (*(mp)->m_qm_ops.xfs_dqvopalloc)(mp, ip, uid, gid, prid, fl, dq1, dq2) + (*(mp)->m_qm_ops->xfs_dqvopalloc)(mp, ip, uid, gid, prid, fl, dq1, dq2) #define XFS_QM_DQVOPCREATE(mp, tp, ip, dq1, dq2) \ - (*(mp)->m_qm_ops.xfs_dqvopcreate)(tp, ip, dq1, dq2) + (*(mp)->m_qm_ops->xfs_dqvopcreate)(tp, ip, dq1, dq2) #define XFS_QM_DQVOPRENAME(mp, ip) \ - (*(mp)->m_qm_ops.xfs_dqvoprename)(ip) + (*(mp)->m_qm_ops->xfs_dqvoprename)(ip) #define XFS_QM_DQVOPCHOWN(mp, tp, ip, dqp, dq) \ - (*(mp)->m_qm_ops.xfs_dqvopchown)(tp, ip, dqp, dq) + (*(mp)->m_qm_ops->xfs_dqvopchown)(tp, ip, dqp, dq) #define XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, dq1, dq2, fl) \ - (*(mp)->m_qm_ops.xfs_dqvopchownresv)(tp, ip, dq1, dq2, fl) + (*(mp)->m_qm_ops->xfs_dqvopchownresv)(tp, ip, dq1, dq2, fl) +#define XFS_QM_DQSTATVFS(ip, statp) \ + (*(ip)->i_mount->m_qm_ops->xfs_dqstatvfs)(ip, statp) +#define XFS_QM_DQSYNC(mp, flags) \ + (*(mp)->m_qm_ops->xfs_dqsync)(mp, flags) +#define XFS_QM_QUOTACTL(mp, cmd, id, addr) \ + (*(mp)->m_qm_ops->xfs_quotactl)(mp, cmd, id, addr) /* * Prototypes and functions for I/O core modularization. */ -typedef int (*xfs_ioinit_t)(struct bhv_vfs *, +typedef int (*xfs_ioinit_t)(struct xfs_mount *, struct xfs_mount_args *, int); typedef int (*xfs_bmapi_t)(struct xfs_trans *, void *, xfs_fileoff_t, xfs_filblks_t, int, @@ -222,7 +231,7 @@ typedef void (*xfs_lock_demote_t)(void *, uint); typedef int (*xfs_lock_nowait_t)(void *, uint); typedef void (*xfs_unlk_t)(void *, unsigned int); typedef xfs_fsize_t (*xfs_size_t)(void *); -typedef xfs_fsize_t (*xfs_iodone_t)(struct bhv_vfs *); +typedef xfs_fsize_t (*xfs_iodone_t)(struct xfs_mount *); typedef int (*xfs_swap_extents_t)(void *, void *, struct xfs_swapext*); @@ -245,8 +254,8 @@ typedef struct xfs_ioops { xfs_swap_extents_t xfs_swap_extents_func; } xfs_ioops_t; -#define XFS_IOINIT(vfsp, args, flags) \ - (*(mp)->m_io_ops.xfs_ioinit)(vfsp, args, flags) +#define XFS_IOINIT(mp, args, flags) \ + (*(mp)->m_io_ops.xfs_ioinit)(mp, args, flags) #define XFS_BMAPI(mp, trans,io,bno,len,f,first,tot,mval,nmap,flist,delta) \ (*(mp)->m_io_ops.xfs_bmapi_func) \ (trans,(io)->io_obj,bno,len,f,first,tot,mval,nmap,flist,delta) @@ -280,8 +289,8 @@ typedef struct xfs_ioops { (*(mp)->m_io_ops.xfs_ilock_demote)((io)->io_obj, mode) #define XFS_SIZE(mp, io) \ (*(mp)->m_io_ops.xfs_size_func)((io)->io_obj) -#define XFS_IODONE(vfsp) \ - (*(mp)->m_io_ops.xfs_iodone)(vfsp) +#define XFS_IODONE(mp) \ + (*(mp)->m_io_ops.xfs_iodone)(mp) #define XFS_SWAP_EXTENTS(mp, io, tio, sxp) \ (*(mp)->m_io_ops.xfs_swap_extents_func) \ ((io)->io_obj, (tio)->io_obj, sxp) @@ -318,7 +327,7 @@ extern void xfs_icsb_sync_counters_flags(struct xfs_mount *, int); #endif typedef struct xfs_mount { - bhv_desc_t m_bhv; /* vfs xfs behavior */ + struct super_block *m_super; xfs_tid_t m_tid; /* next unused tid for fs */ AIL_LOCK_T m_ail_lock; /* fs AIL mutex */ xfs_ail_entry_t m_ail; /* fs active log item list */ @@ -335,8 +344,6 @@ typedef struct xfs_mount { xfs_agnumber_t m_agirotor; /* last ag dir inode alloced */ lock_t m_agirotor_lock;/* .. and lock protecting it */ xfs_agnumber_t m_maxagi; /* highest inode alloc group */ - size_t m_ihsize; /* size of next field */ - struct xfs_ihash *m_ihash; /* fs private inode hash table*/ struct xfs_inode *m_inodes; /* active inode list */ struct list_head m_del_inodes; /* inodes to reclaim */ mutex_t m_ilock; /* inode list mutex */ @@ -362,7 +369,6 @@ typedef struct xfs_mount { __uint8_t m_blkbb_log; /* blocklog - BBSHIFT */ __uint8_t m_agno_log; /* log #ag's */ __uint8_t m_agino_log; /* #bits for agino in inum */ - __uint8_t m_nreadaheads; /* #readahead buffers */ __uint16_t m_inode_cluster_size;/* min inode buf size */ uint m_blockmask; /* sb_blocksize-1 */ uint m_blockwsize; /* sb_blocksize in words */ @@ -378,7 +384,7 @@ typedef struct xfs_mount { uint m_in_maxlevels; /* XFS_IN_MAXLEVELS */ struct xfs_perag *m_perag; /* per-ag accounting info */ struct rw_semaphore m_peraglock; /* lock for m_perag (pointer) */ - sema_t m_growlock; /* growfs mutex */ + struct mutex m_growlock; /* growfs mutex */ int m_fixedfsid[2]; /* unchanged for life of FS */ uint m_dmevmask; /* DMI events for this FS */ __uint64_t m_flags; /* global mount flags */ @@ -415,8 +421,8 @@ typedef struct xfs_mount { uint m_chsize; /* size of next field */ struct xfs_chash *m_chash; /* fs private inode per-cluster * hash table */ - struct xfs_dmops m_dm_ops; /* vector of DMI ops */ - struct xfs_qmops m_qm_ops; /* vector of XQM ops */ + struct xfs_dmops *m_dm_ops; /* vector of DMI ops */ + struct xfs_qmops *m_qm_ops; /* vector of XQM ops */ struct xfs_ioops m_io_ops; /* vector of I/O ops */ atomic_t m_active_trans; /* number trans frozen */ #ifdef HAVE_PERCPU_SB @@ -426,6 +432,12 @@ typedef struct xfs_mount { struct mutex m_icsb_mutex; /* balancer sync lock */ #endif struct xfs_mru_cache *m_filestream; /* per-mount filestream data */ + struct task_struct *m_sync_task; /* generalised sync thread */ + bhv_vfs_sync_work_t m_sync_work; /* work item for VFS_SYNC */ + struct list_head m_sync_list; /* sync thread work item list */ + spinlock_t m_sync_lock; /* work item list lock */ + int m_sync_seq; /* sync thread generation no. */ + wait_queue_head_t m_wait_single_sync_task; } xfs_mount_t; /* @@ -435,7 +447,7 @@ typedef struct xfs_mount { must be synchronous except for space allocations */ #define XFS_MOUNT_INO64 (1ULL << 1) - /* (1ULL << 2) -- currently unused */ +#define XFS_MOUNT_DMAPI (1ULL << 2) /* dmapi is enabled */ #define XFS_MOUNT_WAS_CLEAN (1ULL << 3) #define XFS_MOUNT_FS_SHUTDOWN (1ULL << 4) /* atomic stop of all filesystem operations, typically for @@ -445,7 +457,7 @@ typedef struct xfs_mount { #define XFS_MOUNT_NOALIGN (1ULL << 7) /* turn off stripe alignment allocations */ #define XFS_MOUNT_ATTR2 (1ULL << 8) /* allow use of attr2 format */ - /* (1ULL << 9) -- currently unused */ +#define XFS_MOUNT_GRPID (1ULL << 9) /* group-ID assigned from directory */ #define XFS_MOUNT_NORECOVERY (1ULL << 10) /* no recovery - dirty fs */ #define XFS_MOUNT_SHARED (1ULL << 11) /* shared mount */ #define XFS_MOUNT_DFLT_IOSIZE (1ULL << 12) /* set default i/o size */ @@ -453,13 +465,13 @@ typedef struct xfs_mount { /* osyncisdsync is now default*/ #define XFS_MOUNT_32BITINODES (1ULL << 14) /* do not create inodes above * 32 bits in size */ - /* (1ULL << 15) -- currently unused */ +#define XFS_MOUNT_SMALL_INUMS (1ULL << 15) /* users wants 32bit inodes */ #define XFS_MOUNT_NOUUID (1ULL << 16) /* ignore uuid during mount */ #define XFS_MOUNT_BARRIER (1ULL << 17) #define XFS_MOUNT_IDELETE (1ULL << 18) /* delete empty inode clusters*/ #define XFS_MOUNT_SWALLOC (1ULL << 19) /* turn on stripe width * allocation */ -#define XFS_MOUNT_IHASHSIZE (1ULL << 20) /* inode hash table size */ +#define XFS_MOUNT_RDONLY (1ULL << 20) /* read-only fs */ #define XFS_MOUNT_DIRSYNC (1ULL << 21) /* synchronous directory ops */ #define XFS_MOUNT_COMPAT_IOSIZE (1ULL << 22) /* don't report large preferred * I/O size in stat() */ @@ -518,8 +530,10 @@ xfs_preferred_iosize(xfs_mount_t *mp) #define XFS_LAST_UNMOUNT_WAS_CLEAN(mp) \ ((mp)->m_flags & XFS_MOUNT_WAS_CLEAN) #define XFS_FORCED_SHUTDOWN(mp) ((mp)->m_flags & XFS_MOUNT_FS_SHUTDOWN) +void xfs_do_force_shutdown(struct xfs_mount *mp, int flags, char *fname, + int lnnum); #define xfs_force_shutdown(m,f) \ - bhv_vfs_force_shutdown((XFS_MTOVFS(m)), f, __FILE__, __LINE__) + xfs_do_force_shutdown(m, f, __FILE__, __LINE__) /* * Flags for xfs_mountfs @@ -533,28 +547,6 @@ xfs_preferred_iosize(xfs_mount_t *mp) /* XFS_MFSI_CONVERT_SUNIT */ #define XFS_MFSI_QUIET 0x40 /* Be silent if mount errors found */ -/* - * Macros for getting from mount to vfs and back. - */ -#define XFS_MTOVFS(mp) xfs_mtovfs(mp) -static inline struct bhv_vfs *xfs_mtovfs(xfs_mount_t *mp) -{ - return bhvtovfs(&mp->m_bhv); -} - -#define XFS_BHVTOM(bdp) xfs_bhvtom(bdp) -static inline xfs_mount_t *xfs_bhvtom(bhv_desc_t *bdp) -{ - return (xfs_mount_t *)BHV_PDATA(bdp); -} - -#define XFS_VFSTOM(vfs) xfs_vfstom(vfs) -static inline xfs_mount_t *xfs_vfstom(bhv_vfs_t *vfs) -{ - return XFS_BHVTOM(bhv_lookup_range(VFS_BHVHEAD(vfs), - VFS_POSITION_XFS, VFS_POSITION_XFS)); -} - #define XFS_DADDR_TO_AGNO(mp,d) xfs_daddr_to_agno(mp,d) static inline xfs_agnumber_t xfs_daddr_to_agno(struct xfs_mount *mp, xfs_daddr_t d) @@ -573,6 +565,21 @@ xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d) } /* + * perag get/put wrappers for eventual ref counting + */ +static inline xfs_perag_t * +xfs_get_perag(struct xfs_mount *mp, xfs_ino_t ino) +{ + return &mp->m_perag[XFS_INO_TO_AGNO(mp, ino)]; +} + +static inline void +xfs_put_perag(struct xfs_mount *mp, xfs_perag_t *pag) +{ + /* nothing to see here, move along */ +} + +/* * Per-cpu superblock locking functions */ #ifdef HAVE_PERCPU_SB @@ -609,8 +616,8 @@ typedef struct xfs_mod_sb { extern xfs_mount_t *xfs_mount_init(void); extern void xfs_mod_sb(xfs_trans_t *, __int64_t); extern int xfs_log_sbcount(xfs_mount_t *, uint); -extern void xfs_mount_free(xfs_mount_t *mp, int remove_bhv); -extern int xfs_mountfs(struct bhv_vfs *, xfs_mount_t *mp, int); +extern void xfs_mount_free(xfs_mount_t *mp); +extern int xfs_mountfs(xfs_mount_t *mp, int); extern void xfs_mountfs_check_barriers(xfs_mount_t *mp); extern int xfs_unmountfs(xfs_mount_t *, struct cred *); @@ -626,16 +633,19 @@ extern struct xfs_buf *xfs_getsb(xfs_mount_t *, int); extern int xfs_readsb(xfs_mount_t *, int); extern void xfs_freesb(xfs_mount_t *); extern int xfs_fs_writable(xfs_mount_t *); -extern void xfs_do_force_shutdown(bhv_desc_t *, int, char *, int); extern int xfs_syncsub(xfs_mount_t *, int, int *); extern int xfs_sync_inodes(xfs_mount_t *, int, int *); -extern xfs_agnumber_t xfs_initialize_perag(struct bhv_vfs *, xfs_mount_t *, - xfs_agnumber_t); -extern void xfs_xlatesb(void *, struct xfs_sb *, int, __int64_t); +extern xfs_agnumber_t xfs_initialize_perag(xfs_mount_t *, xfs_agnumber_t); +extern void xfs_sb_from_disk(struct xfs_sb *, struct xfs_dsb *); +extern void xfs_sb_to_disk(struct xfs_dsb *, struct xfs_sb *, __int64_t); extern int xfs_sb_validate_fsb_count(struct xfs_sb *, __uint64_t); -extern struct xfs_dmops xfs_dmcore_stub; -extern struct xfs_qmops xfs_qmcore_stub; +extern int xfs_dmops_get(struct xfs_mount *, struct xfs_mount_args *); +extern void xfs_dmops_put(struct xfs_mount *); +extern int xfs_qmops_get(struct xfs_mount *, struct xfs_mount_args *); +extern void xfs_qmops_put(struct xfs_mount *); + +extern struct xfs_dmops xfs_dmcore_xfs; extern struct xfs_ioops xfs_iocore_xfs; extern int xfs_init(void); diff --git a/fs/xfs/xfs_qmops.c b/fs/xfs/xfs_qmops.c index 0d594ed7efef..2ec1d8a27352 100644 --- a/fs/xfs/xfs_qmops.c +++ b/fs/xfs/xfs_qmops.c @@ -28,6 +28,8 @@ #include "xfs_mount.h" #include "xfs_quota.h" #include "xfs_error.h" +#include "xfs_clnt.h" + STATIC struct xfs_dquot * xfs_dqvopchown_default( @@ -64,7 +66,7 @@ xfs_mount_reset_sbqflags(xfs_mount_t *mp) * if the fs is readonly, let the incore superblock run * with quotas off but don't flush the update out to disk */ - if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY) + if (mp->m_flags & XFS_MOUNT_RDONLY) return 0; #ifdef QUOTADEBUG xfs_fs_cmn_err(CE_NOTE, mp, "Writing superblock quota changes"); @@ -110,7 +112,7 @@ xfs_noquota_init( return error; } -xfs_qmops_t xfs_qmcore_stub = { +static struct xfs_qmops xfs_qmcore_stub = { .xfs_qminit = (xfs_qminit_t) xfs_noquota_init, .xfs_qmdone = (xfs_qmdone_t) fs_noerr, .xfs_qmmount = (xfs_qmmount_t) fs_noerr, @@ -124,4 +126,30 @@ xfs_qmops_t xfs_qmcore_stub = { .xfs_dqvoprename = (xfs_dqvoprename_t) fs_noerr, .xfs_dqvopchown = xfs_dqvopchown_default, .xfs_dqvopchownresv = (xfs_dqvopchownresv_t) fs_noerr, + .xfs_dqstatvfs = (xfs_dqstatvfs_t) fs_noval, + .xfs_dqsync = (xfs_dqsync_t) fs_noerr, + .xfs_quotactl = (xfs_quotactl_t) fs_nosys, }; + +int +xfs_qmops_get(struct xfs_mount *mp, struct xfs_mount_args *args) +{ + if (args->flags & (XFSMNT_UQUOTA | XFSMNT_PQUOTA | XFSMNT_GQUOTA)) { +#ifdef CONFIG_XFS_QUOTA + mp->m_qm_ops = &xfs_qmcore_xfs; +#else + cmn_err(CE_WARN, + "XFS: qouta support not available in this kernel."); + return EINVAL; +#endif + } else { + mp->m_qm_ops = &xfs_qmcore_stub; + } + + return 0; +} + +void +xfs_qmops_put(struct xfs_mount *mp) +{ +} diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h index 6f14df976f73..12c4ec775af8 100644 --- a/fs/xfs/xfs_quota.h +++ b/fs/xfs/xfs_quota.h @@ -330,12 +330,12 @@ typedef struct xfs_dqtrxops { } xfs_dqtrxops_t; #define XFS_DQTRXOP(mp, tp, op, args...) \ - ((mp)->m_qm_ops.xfs_dqtrxops ? \ - ((mp)->m_qm_ops.xfs_dqtrxops->op)(tp, ## args) : 0) + ((mp)->m_qm_ops->xfs_dqtrxops ? \ + ((mp)->m_qm_ops->xfs_dqtrxops->op)(tp, ## args) : 0) #define XFS_DQTRXOP_VOID(mp, tp, op, args...) \ - ((mp)->m_qm_ops.xfs_dqtrxops ? \ - ((mp)->m_qm_ops.xfs_dqtrxops->op)(tp, ## args) : (void)0) + ((mp)->m_qm_ops->xfs_dqtrxops ? \ + ((mp)->m_qm_ops->xfs_dqtrxops->op)(tp, ## args) : (void)0) #define XFS_TRANS_DUP_DQINFO(mp, otp, ntp) \ XFS_DQTRXOP_VOID(mp, otp, qo_dup_dqinfo, ntp) @@ -364,7 +364,7 @@ typedef struct xfs_dqtrxops { extern int xfs_qm_dqcheck(xfs_disk_dquot_t *, xfs_dqid_t, uint, uint, char *); extern int xfs_mount_reset_sbqflags(struct xfs_mount *); -extern struct bhv_module_vfsops xfs_qmops; +extern struct xfs_qmops xfs_qmcore_xfs; #endif /* __KERNEL__ */ diff --git a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c index 7679d7a7022d..44ea0ba36476 100644 --- a/fs/xfs/xfs_rename.c +++ b/fs/xfs/xfs_rename.c @@ -22,6 +22,7 @@ #include "xfs_inum.h" #include "xfs_trans.h" #include "xfs_sb.h" +#include "xfs_ag.h" #include "xfs_dir2.h" #include "xfs_dmapi.h" #include "xfs_mount.h" @@ -128,8 +129,7 @@ xfs_lock_for_rename( lock_mode = xfs_ilock_map_shared(dp2); } - error = xfs_dir_lookup_int(XFS_ITOBHV(dp2), lock_mode, - vname2, &inum2, &ip2); + error = xfs_dir_lookup_int(dp2, lock_mode, vname2, &inum2, &ip2); if (error == ENOENT) { /* target does not need to exist. */ inum2 = 0; } else if (error) { @@ -221,15 +221,15 @@ xfs_lock_for_rename( */ int xfs_rename( - bhv_desc_t *src_dir_bdp, + xfs_inode_t *src_dp, bhv_vname_t *src_vname, bhv_vnode_t *target_dir_vp, - bhv_vname_t *target_vname, - cred_t *credp) + bhv_vname_t *target_vname) { + bhv_vnode_t *src_dir_vp = XFS_ITOV(src_dp); xfs_trans_t *tp; - xfs_inode_t *src_dp, *target_dp, *src_ip, *target_ip; - xfs_mount_t *mp; + xfs_inode_t *target_dp, *src_ip, *target_ip; + xfs_mount_t *mp = src_dp->i_mount; int new_parent; /* moving to a new dir */ int src_is_directory; /* src_name is a directory */ int error; @@ -239,7 +239,6 @@ xfs_rename( int committed; xfs_inode_t *inodes[4]; int target_ip_dropped = 0; /* dropped target_ip link? */ - bhv_vnode_t *src_dir_vp; int spaceres; int target_link_zero = 0; int num_inodes; @@ -248,9 +247,8 @@ xfs_rename( int src_namelen = VNAMELEN(src_vname); int target_namelen = VNAMELEN(target_vname); - src_dir_vp = BHV_TO_VNODE(src_dir_bdp); - vn_trace_entry(src_dir_vp, "xfs_rename", (inst_t *)__return_address); - vn_trace_entry(target_dir_vp, "xfs_rename", (inst_t *)__return_address); + vn_trace_entry(src_dp, "xfs_rename", (inst_t *)__return_address); + vn_trace_entry(xfs_vtoi(target_dir_vp), "xfs_rename", (inst_t *)__return_address); /* * Find the XFS behavior descriptor for the target directory @@ -261,12 +259,8 @@ xfs_rename( return XFS_ERROR(EXDEV); } - src_dp = XFS_BHVTOI(src_dir_bdp); - mp = src_dp->i_mount; - - if (DM_EVENT_ENABLED(src_dir_vp->v_vfsp, src_dp, DM_EVENT_RENAME) || - DM_EVENT_ENABLED(target_dir_vp->v_vfsp, - target_dp, DM_EVENT_RENAME)) { + if (DM_EVENT_ENABLED(src_dp, DM_EVENT_RENAME) || + DM_EVENT_ENABLED(target_dp, DM_EVENT_RENAME)) { error = XFS_SEND_NAMESP(mp, DM_EVENT_RENAME, src_dir_vp, DM_RIGHT_NULL, target_dir_vp, DM_RIGHT_NULL, @@ -592,20 +586,16 @@ xfs_rename( /* * Let interposed file systems know about removed links. */ - if (target_ip_dropped) { - bhv_vop_link_removed(XFS_ITOV(target_ip), target_dir_vp, - target_link_zero); + if (target_ip_dropped) IRELE(target_ip); - } IRELE(src_ip); /* Fall through to std_return with error = 0 or errno from * xfs_trans_commit */ std_return: - if (DM_EVENT_ENABLED(src_dir_vp->v_vfsp, src_dp, DM_EVENT_POSTRENAME) || - DM_EVENT_ENABLED(target_dir_vp->v_vfsp, - target_dp, DM_EVENT_POSTRENAME)) { + if (DM_EVENT_ENABLED(src_dp, DM_EVENT_POSTRENAME) || + DM_EVENT_ENABLED(target_dp, DM_EVENT_POSTRENAME)) { (void) XFS_SEND_NAMESP (mp, DM_EVENT_POSTRENAME, src_dir_vp, DM_RIGHT_NULL, target_dir_vp, DM_RIGHT_NULL, diff --git a/fs/xfs/xfs_rw.c b/fs/xfs/xfs_rw.c index 905d1c008be7..cd3ece6cc918 100644 --- a/fs/xfs/xfs_rw.c +++ b/fs/xfs/xfs_rw.c @@ -178,18 +178,15 @@ xfs_write_sync_logforce( * the shop, make sure that absolutely nothing persistent happens to * this filesystem after this point. */ - void xfs_do_force_shutdown( - bhv_desc_t *bdp, + xfs_mount_t *mp, int flags, char *fname, int lnnum) { int logerror; - xfs_mount_t *mp; - mp = XFS_BHVTOM(bdp); logerror = flags & SHUTDOWN_LOG_IO_ERROR; if (!(flags & SHUTDOWN_FORCE_UMOUNT)) { diff --git a/fs/xfs/xfs_rw.h b/fs/xfs/xfs_rw.h index fcf28dbded7c..49875e1d129f 100644 --- a/fs/xfs/xfs_rw.h +++ b/fs/xfs/xfs_rw.h @@ -23,32 +23,6 @@ struct xfs_inode; struct xfs_mount; /* - * Maximum count of bmaps used by read and write paths. - */ -#define XFS_MAX_RW_NBMAPS 4 - -/* - * Counts of readahead buffers to use based on physical memory size. - * None of these should be more than XFS_MAX_RW_NBMAPS. - */ -#define XFS_RW_NREADAHEAD_16MB 2 -#define XFS_RW_NREADAHEAD_32MB 3 -#define XFS_RW_NREADAHEAD_K32 4 -#define XFS_RW_NREADAHEAD_K64 4 - -/* - * Maximum size of a buffer that we\'ll map. Making this - * too big will degrade performance due to the number of - * pages which need to be gathered. Making it too small - * will prevent us from doing large I/O\'s to hardware that - * needs it. - * - * This is currently set to 512 KB. - */ -#define XFS_MAX_BMAP_LEN_BB 1024 -#define XFS_MAX_BMAP_LEN_BYTES 524288 - -/* * Convert the given file system block to a disk block. * We have to treat it differently based on whether the * file is a real time file or not, because the bmap code @@ -116,14 +90,6 @@ extern void xfs_ioerror_alert(char *func, struct xfs_mount *mp, /* * Prototypes for functions in xfs_vnodeops.c. */ -extern int xfs_rwlock(bhv_desc_t *bdp, bhv_vrwlock_t write_lock); -extern void xfs_rwunlock(bhv_desc_t *bdp, bhv_vrwlock_t write_lock); -extern int xfs_setattr(bhv_desc_t *, bhv_vattr_t *vap, int flags, - cred_t *credp); -extern int xfs_change_file_space(bhv_desc_t *bdp, int cmd, xfs_flock64_t *bf, - xfs_off_t offset, cred_t *credp, int flags); -extern int xfs_set_dmattrs(bhv_desc_t *bdp, u_int evmask, u_int16_t state, - cred_t *credp); extern int xfs_free_eofblocks(struct xfs_mount *mp, struct xfs_inode *ip, int flags); diff --git a/fs/xfs/xfs_sb.h b/fs/xfs/xfs_sb.h index ef42537a607a..94660b1a6ccc 100644 --- a/fs/xfs/xfs_sb.h +++ b/fs/xfs/xfs_sb.h @@ -87,8 +87,10 @@ struct xfs_mount; (XFS_SB_VERSION2_OKREALFBITS | \ XFS_SB_VERSION2_OKSASHFBITS ) -typedef struct xfs_sb -{ +/* + * Superblock - in core version. Must match the ondisk version below. + */ +typedef struct xfs_sb { __uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */ __uint32_t sb_blocksize; /* logical block size, bytes */ xfs_drfsbno_t sb_dblocks; /* number of data blocks */ @@ -146,6 +148,66 @@ typedef struct xfs_sb } xfs_sb_t; /* + * Superblock - on disk version. Must match the in core version below. + */ +typedef struct xfs_dsb { + __be32 sb_magicnum; /* magic number == XFS_SB_MAGIC */ + __be32 sb_blocksize; /* logical block size, bytes */ + __be64 sb_dblocks; /* number of data blocks */ + __be64 sb_rblocks; /* number of realtime blocks */ + __be64 sb_rextents; /* number of realtime extents */ + uuid_t sb_uuid; /* file system unique id */ + __be64 sb_logstart; /* starting block of log if internal */ + __be64 sb_rootino; /* root inode number */ + __be64 sb_rbmino; /* bitmap inode for realtime extents */ + __be64 sb_rsumino; /* summary inode for rt bitmap */ + __be32 sb_rextsize; /* realtime extent size, blocks */ + __be32 sb_agblocks; /* size of an allocation group */ + __be32 sb_agcount; /* number of allocation groups */ + __be32 sb_rbmblocks; /* number of rt bitmap blocks */ + __be32 sb_logblocks; /* number of log blocks */ + __be16 sb_versionnum; /* header version == XFS_SB_VERSION */ + __be16 sb_sectsize; /* volume sector size, bytes */ + __be16 sb_inodesize; /* inode size, bytes */ + __be16 sb_inopblock; /* inodes per block */ + char sb_fname[12]; /* file system name */ + __u8 sb_blocklog; /* log2 of sb_blocksize */ + __u8 sb_sectlog; /* log2 of sb_sectsize */ + __u8 sb_inodelog; /* log2 of sb_inodesize */ + __u8 sb_inopblog; /* log2 of sb_inopblock */ + __u8 sb_agblklog; /* log2 of sb_agblocks (rounded up) */ + __u8 sb_rextslog; /* log2 of sb_rextents */ + __u8 sb_inprogress; /* mkfs is in progress, don't mount */ + __u8 sb_imax_pct; /* max % of fs for inode space */ + /* statistics */ + /* + * These fields must remain contiguous. If you really + * want to change their layout, make sure you fix the + * code in xfs_trans_apply_sb_deltas(). + */ + __be64 sb_icount; /* allocated inodes */ + __be64 sb_ifree; /* free inodes */ + __be64 sb_fdblocks; /* free data blocks */ + __be64 sb_frextents; /* free realtime extents */ + /* + * End contiguous fields. + */ + __be64 sb_uquotino; /* user quota inode */ + __be64 sb_gquotino; /* group quota inode */ + __be16 sb_qflags; /* quota flags */ + __u8 sb_flags; /* misc. flags */ + __u8 sb_shared_vn; /* shared version number */ + __be32 sb_inoalignmt; /* inode chunk alignment, fsblocks */ + __be32 sb_unit; /* stripe or raid unit */ + __be32 sb_width; /* stripe or raid width */ + __u8 sb_dirblklog; /* log2 of dir block size (fsbs) */ + __u8 sb_logsectlog; /* log2 of the log sector size */ + __be16 sb_logsectsize; /* sector size for the log, bytes */ + __be32 sb_logsunit; /* stripe unit size for the log */ + __be32 sb_features2; /* additional feature bits */ +} xfs_dsb_t; + +/* * Sequence number values for the fields. */ typedef enum { @@ -446,7 +508,7 @@ static inline void xfs_sb_version_addattr2(xfs_sb_t *sbp) #define XFS_SB_DADDR ((xfs_daddr_t)0) /* daddr in filesystem/ag */ #define XFS_SB_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_SB_DADDR) -#define XFS_BUF_TO_SBP(bp) ((xfs_sb_t *)XFS_BUF_PTR(bp)) +#define XFS_BUF_TO_SBP(bp) ((xfs_dsb_t *)XFS_BUF_PTR(bp)) #define XFS_HDR_BLOCK(mp,d) ((xfs_agblock_t)XFS_BB_TO_FSBT(mp,d)) #define XFS_DADDR_TO_FSB(mp,d) XFS_AGB_TO_FSB(mp, \ diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index 356d6627f581..8878322ee793 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c @@ -234,7 +234,7 @@ xfs_trans_alloc( xfs_mount_t *mp, uint type) { - vfs_wait_for_freeze(XFS_MTOVFS(mp), SB_FREEZE_TRANS); + xfs_wait_for_freeze(mp, SB_FREEZE_TRANS); return _xfs_trans_alloc(mp, type); } @@ -548,7 +548,7 @@ STATIC void xfs_trans_apply_sb_deltas( xfs_trans_t *tp) { - xfs_sb_t *sbp; + xfs_dsb_t *sbp; xfs_buf_t *bp; int whole = 0; @@ -566,57 +566,51 @@ xfs_trans_apply_sb_deltas( * Only update the superblock counters if we are logging them */ if (!xfs_sb_version_haslazysbcount(&(tp->t_mountp->m_sb))) { - if (tp->t_icount_delta != 0) { - INT_MOD(sbp->sb_icount, ARCH_CONVERT, tp->t_icount_delta); - } - if (tp->t_ifree_delta != 0) { - INT_MOD(sbp->sb_ifree, ARCH_CONVERT, tp->t_ifree_delta); - } - - if (tp->t_fdblocks_delta != 0) { - INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_fdblocks_delta); - } - if (tp->t_res_fdblocks_delta != 0) { - INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_res_fdblocks_delta); - } + if (tp->t_icount_delta) + be64_add(&sbp->sb_icount, tp->t_icount_delta); + if (tp->t_ifree_delta) + be64_add(&sbp->sb_ifree, tp->t_ifree_delta); + if (tp->t_fdblocks_delta) + be64_add(&sbp->sb_fdblocks, tp->t_fdblocks_delta); + if (tp->t_res_fdblocks_delta) + be64_add(&sbp->sb_fdblocks, tp->t_res_fdblocks_delta); } - if (tp->t_frextents_delta != 0) { - INT_MOD(sbp->sb_frextents, ARCH_CONVERT, tp->t_frextents_delta); - } - if (tp->t_res_frextents_delta != 0) { - INT_MOD(sbp->sb_frextents, ARCH_CONVERT, tp->t_res_frextents_delta); - } - if (tp->t_dblocks_delta != 0) { - INT_MOD(sbp->sb_dblocks, ARCH_CONVERT, tp->t_dblocks_delta); + if (tp->t_frextents_delta) + be64_add(&sbp->sb_frextents, tp->t_frextents_delta); + if (tp->t_res_frextents_delta) + be64_add(&sbp->sb_frextents, tp->t_res_frextents_delta); + + if (tp->t_dblocks_delta) { + be64_add(&sbp->sb_dblocks, tp->t_dblocks_delta); whole = 1; } - if (tp->t_agcount_delta != 0) { - INT_MOD(sbp->sb_agcount, ARCH_CONVERT, tp->t_agcount_delta); + if (tp->t_agcount_delta) { + be32_add(&sbp->sb_agcount, tp->t_agcount_delta); whole = 1; } - if (tp->t_imaxpct_delta != 0) { - INT_MOD(sbp->sb_imax_pct, ARCH_CONVERT, tp->t_imaxpct_delta); + if (tp->t_imaxpct_delta) { + sbp->sb_imax_pct += tp->t_imaxpct_delta; whole = 1; } - if (tp->t_rextsize_delta != 0) { - INT_MOD(sbp->sb_rextsize, ARCH_CONVERT, tp->t_rextsize_delta); + if (tp->t_rextsize_delta) { + be32_add(&sbp->sb_rextsize, tp->t_rextsize_delta); whole = 1; } - if (tp->t_rbmblocks_delta != 0) { - INT_MOD(sbp->sb_rbmblocks, ARCH_CONVERT, tp->t_rbmblocks_delta); + if (tp->t_rbmblocks_delta) { + be32_add(&sbp->sb_rbmblocks, tp->t_rbmblocks_delta); whole = 1; } - if (tp->t_rblocks_delta != 0) { - INT_MOD(sbp->sb_rblocks, ARCH_CONVERT, tp->t_rblocks_delta); + if (tp->t_rblocks_delta) { + be64_add(&sbp->sb_rblocks, tp->t_rblocks_delta); whole = 1; } - if (tp->t_rextents_delta != 0) { - INT_MOD(sbp->sb_rextents, ARCH_CONVERT, tp->t_rextents_delta); + if (tp->t_rextents_delta) { + be64_add(&sbp->sb_rextents, tp->t_rextents_delta); whole = 1; } - if (tp->t_rextslog_delta != 0) { - INT_MOD(sbp->sb_rextslog, ARCH_CONVERT, tp->t_rextslog_delta); + if (tp->t_rextslog_delta) { + sbp->sb_rextslog += tp->t_rextslog_delta; whole = 1; } @@ -624,17 +618,17 @@ xfs_trans_apply_sb_deltas( /* * Log the whole thing, the fields are noncontiguous. */ - xfs_trans_log_buf(tp, bp, 0, sizeof(xfs_sb_t) - 1); + xfs_trans_log_buf(tp, bp, 0, sizeof(xfs_dsb_t) - 1); else /* * Since all the modifiable fields are contiguous, we * can get away with this. */ - xfs_trans_log_buf(tp, bp, offsetof(xfs_sb_t, sb_icount), - offsetof(xfs_sb_t, sb_frextents) + + xfs_trans_log_buf(tp, bp, offsetof(xfs_dsb_t, sb_icount), + offsetof(xfs_dsb_t, sb_frextents) + sizeof(sbp->sb_frextents) - 1); - XFS_MTOVFS(tp->t_mountp)->vfs_super->s_dirt = 1; + tp->t_mountp->m_super->s_dirt = 1; } /* diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index ceb4f6e99960..5b2ff59f19cf 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/fs/xfs/xfs_trans_ail.c @@ -22,6 +22,7 @@ #include "xfs_inum.h" #include "xfs_trans.h" #include "xfs_sb.h" +#include "xfs_ag.h" #include "xfs_dmapi.h" #include "xfs_mount.h" #include "xfs_trans_priv.h" diff --git a/fs/xfs/xfs_trans_extfree.c b/fs/xfs/xfs_trans_extfree.c index b290270dd4a6..27cce2a9c7e9 100644 --- a/fs/xfs/xfs_trans_extfree.c +++ b/fs/xfs/xfs_trans_extfree.c @@ -22,6 +22,7 @@ #include "xfs_inum.h" #include "xfs_trans.h" #include "xfs_sb.h" +#include "xfs_ag.h" #include "xfs_dmapi.h" #include "xfs_mount.h" #include "xfs_trans_priv.h" diff --git a/fs/xfs/xfs_types.h b/fs/xfs/xfs_types.h index 104f64a98790..5c89be475464 100644 --- a/fs/xfs/xfs_types.h +++ b/fs/xfs/xfs_types.h @@ -151,18 +151,6 @@ typedef __uint8_t xfs_arch_t; /* architecture of an xfs fs */ */ #define MAXNAMELEN 256 -typedef struct xfs_dirent { /* data from readdir() */ - xfs_ino_t d_ino; /* inode number of entry */ - xfs_off_t d_off; /* offset of disk directory entry */ - unsigned short d_reclen; /* length of this record */ - char d_name[1]; /* name of file */ -} xfs_dirent_t; - -#define DIRENTBASESIZE (((xfs_dirent_t *)0)->d_name - (char *)0) -#define DIRENTSIZE(namelen) \ - ((DIRENTBASESIZE + (namelen) + \ - sizeof(xfs_off_t)) & ~(sizeof(xfs_off_t) - 1)) - typedef enum { XFS_LOOKUP_EQi, XFS_LOOKUP_LEi, XFS_LOOKUP_GEi } xfs_lookup_t; diff --git a/fs/xfs/xfs_utils.c b/fs/xfs/xfs_utils.c index 20ffec308e1e..673b405eaa31 100644 --- a/fs/xfs/xfs_utils.c +++ b/fs/xfs/xfs_utils.c @@ -65,20 +65,15 @@ xfs_get_dir_entry( int xfs_dir_lookup_int( - bhv_desc_t *dir_bdp, + xfs_inode_t *dp, uint lock_mode, bhv_vname_t *dentry, xfs_ino_t *inum, xfs_inode_t **ipp) { - bhv_vnode_t *dir_vp; - xfs_inode_t *dp; int error; - dir_vp = BHV_TO_VNODE(dir_bdp); - vn_trace_entry(dir_vp, __FUNCTION__, (inst_t *)__return_address); - - dp = XFS_BHVTOI(dir_bdp); + vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); error = xfs_dir_lookup(NULL, dp, VNAME(dentry), VNAMELEN(dentry), inum); if (!error) { diff --git a/fs/xfs/xfs_utils.h b/fs/xfs/xfs_utils.h index fe953e98afa7..a00b26d8840e 100644 --- a/fs/xfs/xfs_utils.h +++ b/fs/xfs/xfs_utils.h @@ -20,13 +20,11 @@ #define IRELE(ip) VN_RELE(XFS_ITOV(ip)) #define IHOLD(ip) VN_HOLD(XFS_ITOV(ip)) -#define ITRACE(ip) vn_trace_ref(XFS_ITOV(ip), __FILE__, __LINE__, \ +#define ITRACE(ip) vn_trace_ref(ip, __FILE__, __LINE__, \ (inst_t *)__return_address) -extern int xfs_rename (bhv_desc_t *, bhv_vname_t *, bhv_vnode_t *, - bhv_vname_t *, cred_t *); extern int xfs_get_dir_entry (bhv_vname_t *, xfs_inode_t **); -extern int xfs_dir_lookup_int (bhv_desc_t *, uint, bhv_vname_t *, xfs_ino_t *, +extern int xfs_dir_lookup_int (xfs_inode_t *, uint, bhv_vname_t *, xfs_ino_t *, xfs_inode_t **); extern int xfs_truncate_file (xfs_mount_t *, xfs_inode_t *); extern int xfs_dir_ialloc (xfs_trans_t **, xfs_inode_t *, mode_t, xfs_nlink_t, diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c index 11f5ea29a038..a1544597bcd3 100644 --- a/fs/xfs/xfs_vfsops.c +++ b/fs/xfs/xfs_vfsops.c @@ -54,8 +54,9 @@ #include "xfs_mru_cache.h" #include "xfs_filestream.h" #include "xfs_fsops.h" +#include "xfs_vnodeops.h" +#include "xfs_vfsops.h" -STATIC int xfs_sync(bhv_desc_t *, int, cred_t *); int xfs_init(void) @@ -117,8 +118,8 @@ xfs_init(void) xfs_ili_zone = kmem_zone_init_flags(sizeof(xfs_inode_log_item_t), "xfs_ili", KM_ZONE_SPREAD, NULL); - xfs_chashlist_zone = - kmem_zone_init_flags(sizeof(xfs_chashlist_t), "xfs_chashlist", + xfs_icluster_zone = + kmem_zone_init_flags(sizeof(xfs_icluster_t), "xfs_icluster", KM_ZONE_SPREAD, NULL); /* @@ -163,7 +164,7 @@ xfs_cleanup(void) extern kmem_zone_t *xfs_efd_zone; extern kmem_zone_t *xfs_efi_zone; extern kmem_zone_t *xfs_buf_item_zone; - extern kmem_zone_t *xfs_chashlist_zone; + extern kmem_zone_t *xfs_icluster_zone; xfs_cleanup_procfs(); xfs_sysctl_unregister(); @@ -199,7 +200,7 @@ xfs_cleanup(void) kmem_zone_destroy(xfs_efi_zone); kmem_zone_destroy(xfs_ifork_zone); kmem_zone_destroy(xfs_ili_zone); - kmem_zone_destroy(xfs_chashlist_zone); + kmem_zone_destroy(xfs_icluster_zone); } /* @@ -210,7 +211,6 @@ xfs_cleanup(void) */ STATIC int xfs_start_flags( - struct bhv_vfs *vfs, struct xfs_mount_args *ap, struct xfs_mount *mp) { @@ -238,17 +238,14 @@ xfs_start_flags( mp->m_logbufs = ap->logbufs; if (ap->logbufsize != -1 && ap->logbufsize != 0 && - ap->logbufsize != 16 * 1024 && - ap->logbufsize != 32 * 1024 && - ap->logbufsize != 64 * 1024 && - ap->logbufsize != 128 * 1024 && - ap->logbufsize != 256 * 1024) { + (ap->logbufsize < XLOG_MIN_RECORD_BSIZE || + ap->logbufsize > XLOG_MAX_RECORD_BSIZE || + !is_power_of_2(ap->logbufsize))) { cmn_err(CE_WARN, "XFS: invalid logbufsize: %d [not 16k,32k,64k,128k or 256k]", ap->logbufsize); return XFS_ERROR(EINVAL); } - mp->m_ihsize = ap->ihashsize; mp->m_logbsize = ap->logbufsize; mp->m_fsname_len = strlen(ap->fsname) + 1; mp->m_fsname = kmem_alloc(mp->m_fsname_len, KM_SLEEP); @@ -295,8 +292,6 @@ xfs_start_flags( mp->m_readio_log = mp->m_writeio_log = ap->iosizelog; } - if (ap->flags & XFSMNT_IHASHSIZE) - mp->m_flags |= XFS_MOUNT_IHASHSIZE; if (ap->flags & XFSMNT_IDELETE) mp->m_flags |= XFS_MOUNT_IDELETE; if (ap->flags & XFSMNT_DIRSYNC) @@ -311,7 +306,7 @@ xfs_start_flags( * no recovery flag requires a read-only mount */ if (ap->flags & XFSMNT_NORECOVERY) { - if (!(vfs->vfs_flag & VFS_RDONLY)) { + if (!(mp->m_flags & XFS_MOUNT_RDONLY)) { cmn_err(CE_WARN, "XFS: tried to mount a FS read-write without recovery!"); return XFS_ERROR(EINVAL); @@ -329,6 +324,8 @@ xfs_start_flags( if (ap->flags2 & XFSMNT2_FILESTREAMS) mp->m_flags |= XFS_MOUNT_FILESTREAMS; + if (ap->flags & XFSMNT_DMAPI) + mp->m_flags |= XFS_MOUNT_DMAPI; return 0; } @@ -338,11 +335,10 @@ xfs_start_flags( */ STATIC int xfs_finish_flags( - struct bhv_vfs *vfs, struct xfs_mount_args *ap, struct xfs_mount *mp) { - int ronly = (vfs->vfs_flag & VFS_RDONLY); + int ronly = (mp->m_flags & XFS_MOUNT_RDONLY); /* Fail a mount where the logbuf is smaller then the log stripe */ if (XFS_SB_VERSION_HASLOGV2(&mp->m_sb)) { @@ -403,6 +399,22 @@ xfs_finish_flags( return XFS_ERROR(EINVAL); } + if (ap->flags & XFSMNT_UQUOTA) { + mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE); + if (ap->flags & XFSMNT_UQUOTAENF) + mp->m_qflags |= XFS_UQUOTA_ENFD; + } + + if (ap->flags & XFSMNT_GQUOTA) { + mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE); + if (ap->flags & XFSMNT_GQUOTAENF) + mp->m_qflags |= XFS_OQUOTA_ENFD; + } else if (ap->flags & XFSMNT_PQUOTA) { + mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE); + if (ap->flags & XFSMNT_PQUOTAENF) + mp->m_qflags |= XFS_OQUOTA_ENFD; + } + return 0; } @@ -418,30 +430,26 @@ xfs_finish_flags( * they are present. The data subvolume has already been opened by * get_sb_bdev() and is stored in vfsp->vfs_super->s_bdev. */ -STATIC int +int xfs_mount( - struct bhv_desc *bhvp, + struct xfs_mount *mp, struct xfs_mount_args *args, cred_t *credp) { - struct bhv_vfs *vfsp = bhvtovfs(bhvp); - struct bhv_desc *p; - struct xfs_mount *mp = XFS_BHVTOM(bhvp); struct block_device *ddev, *logdev, *rtdev; int flags = 0, error; - ddev = vfsp->vfs_super->s_bdev; + ddev = mp->m_super->s_bdev; logdev = rtdev = NULL; - /* - * Setup xfs_mount function vectors from available behaviors - */ - p = vfs_bhv_lookup(vfsp, VFS_POSITION_DM); - mp->m_dm_ops = p ? *(xfs_dmops_t *) vfs_bhv_custom(p) : xfs_dmcore_stub; - p = vfs_bhv_lookup(vfsp, VFS_POSITION_QM); - mp->m_qm_ops = p ? *(xfs_qmops_t *) vfs_bhv_custom(p) : xfs_qmcore_stub; - p = vfs_bhv_lookup(vfsp, VFS_POSITION_IO); - mp->m_io_ops = p ? *(xfs_ioops_t *) vfs_bhv_custom(p) : xfs_iocore_xfs; + error = xfs_dmops_get(mp, args); + if (error) + return error; + error = xfs_qmops_get(mp, args); + if (error) + return error; + + mp->m_io_ops = xfs_iocore_xfs; if (args->flags & XFSMNT_QUIET) flags |= XFS_MFSI_QUIET; @@ -482,24 +490,30 @@ xfs_mount( } if (rtdev) { mp->m_rtdev_targp = xfs_alloc_buftarg(rtdev, 1); - if (!mp->m_rtdev_targp) + if (!mp->m_rtdev_targp) { + xfs_blkdev_put(logdev); + xfs_blkdev_put(rtdev); goto error0; + } } mp->m_logdev_targp = (logdev && logdev != ddev) ? xfs_alloc_buftarg(logdev, 1) : mp->m_ddev_targp; - if (!mp->m_logdev_targp) + if (!mp->m_logdev_targp) { + xfs_blkdev_put(logdev); + xfs_blkdev_put(rtdev); goto error0; + } /* * Setup flags based on mount(2) options and then the superblock */ - error = xfs_start_flags(vfsp, args, mp); + error = xfs_start_flags(args, mp); if (error) goto error1; error = xfs_readsb(mp, flags); if (error) goto error1; - error = xfs_finish_flags(vfsp, args, mp); + error = xfs_finish_flags(args, mp); if (error) goto error2; @@ -530,10 +544,12 @@ xfs_mount( if ((error = xfs_filestream_mount(mp))) goto error2; - error = XFS_IOINIT(vfsp, args, flags); + error = XFS_IOINIT(mp, args, flags); if (error) goto error2; + XFS_SEND_MOUNT(mp, DM_RIGHT_NULL, args->mtpt, args->fsname); + return 0; error2: @@ -547,17 +563,17 @@ error1: xfs_binval(mp->m_rtdev_targp); error0: xfs_unmountfs_close(mp, credp); + xfs_qmops_put(mp); + xfs_dmops_put(mp); return error; } -STATIC int +int xfs_unmount( - bhv_desc_t *bdp, + xfs_mount_t *mp, int flags, cred_t *credp) { - bhv_vfs_t *vfsp = bhvtovfs(bdp); - xfs_mount_t *mp = XFS_BHVTOM(bdp); xfs_inode_t *rip; bhv_vnode_t *rvp; int unmount_event_wanted = 0; @@ -568,8 +584,9 @@ xfs_unmount( rip = mp->m_rootip; rvp = XFS_ITOV(rip); - if (vfsp->vfs_flag & VFS_DMI) { - error = XFS_SEND_PREUNMOUNT(mp, vfsp, +#ifdef HAVE_DMAPI + if (mp->m_flags & XFS_MOUNT_DMAPI) { + error = XFS_SEND_PREUNMOUNT(mp, rvp, DM_RIGHT_NULL, rvp, DM_RIGHT_NULL, NULL, NULL, 0, 0, (mp->m_dmevmask & (1<<DM_EVENT_PREUNMOUNT))? @@ -580,7 +597,7 @@ xfs_unmount( unmount_event_flags = (mp->m_dmevmask & (1<<DM_EVENT_UNMOUNT))? 0 : DM_FLAGS_UNWANTED; } - +#endif /* * First blow any referenced inode from this file system * out of the reference cache, and delete the timer. @@ -612,8 +629,7 @@ xfs_unmount( * referenced vnodes as well. */ if (XFS_FORCED_SHUTDOWN(mp)) { - error = xfs_sync(&mp->m_bhv, - (SYNC_WAIT | SYNC_CLOSE), credp); + error = xfs_sync(mp, SYNC_WAIT | SYNC_CLOSE); ASSERT(error != EFSCORRUPTED); } xfs_unmountfs_needed = 1; @@ -627,7 +643,7 @@ out: /* Note: mp structure must still exist for * XFS_SEND_UNMOUNT() call. */ - XFS_SEND_UNMOUNT(mp, vfsp, error == 0 ? rvp : NULL, + XFS_SEND_UNMOUNT(mp, error == 0 ? rvp : NULL, DM_RIGHT_NULL, 0, error, unmount_event_flags); } if (xfs_unmountfs_needed) { @@ -636,6 +652,9 @@ out: * and free the super block buffer & mount structures. */ xfs_unmountfs(mp, credp); + xfs_qmops_put(mp); + xfs_dmops_put(mp); + kmem_free(mp, sizeof(xfs_mount_t)); } return XFS_ERROR(error); @@ -694,29 +713,26 @@ xfs_attr_quiesce( xfs_unmountfs_writesb(mp); } -STATIC int +int xfs_mntupdate( - bhv_desc_t *bdp, + struct xfs_mount *mp, int *flags, struct xfs_mount_args *args) { - bhv_vfs_t *vfsp = bhvtovfs(bdp); - xfs_mount_t *mp = XFS_BHVTOM(bdp); - if (!(*flags & MS_RDONLY)) { /* rw/ro -> rw */ - if (vfsp->vfs_flag & VFS_RDONLY) - vfsp->vfs_flag &= ~VFS_RDONLY; + if (mp->m_flags & XFS_MOUNT_RDONLY) + mp->m_flags &= ~XFS_MOUNT_RDONLY; if (args->flags & XFSMNT_BARRIER) { mp->m_flags |= XFS_MOUNT_BARRIER; xfs_mountfs_check_barriers(mp); } else { mp->m_flags &= ~XFS_MOUNT_BARRIER; } - } else if (!(vfsp->vfs_flag & VFS_RDONLY)) { /* rw -> ro */ + } else if (!(mp->m_flags & XFS_MOUNT_RDONLY)) { /* rw -> ro */ xfs_filestream_flush(mp); - bhv_vfs_sync(vfsp, SYNC_DATA_QUIESCE, NULL); + xfs_sync(mp, SYNC_DATA_QUIESCE); xfs_attr_quiesce(mp); - vfsp->vfs_flag |= VFS_RDONLY; + mp->m_flags |= XFS_MOUNT_RDONLY; } return 0; } @@ -811,14 +827,14 @@ fscorrupt_out2: * vpp -- address of the caller's vnode pointer which should be * set to the desired fs root vnode */ -STATIC int +int xfs_root( - bhv_desc_t *bdp, + xfs_mount_t *mp, bhv_vnode_t **vpp) { bhv_vnode_t *vp; - vp = XFS_ITOV((XFS_BHVTOM(bdp))->m_rootip); + vp = XFS_ITOV(mp->m_rootip); VN_HOLD(vp); *vpp = vp; return 0; @@ -831,19 +847,17 @@ xfs_root( * the superblock lock in the mount structure to ensure a consistent * snapshot of the counters returned. */ -STATIC int +int xfs_statvfs( - bhv_desc_t *bdp, + xfs_mount_t *mp, bhv_statvfs_t *statp, bhv_vnode_t *vp) { __uint64_t fakeinos; xfs_extlen_t lsize; - xfs_mount_t *mp; xfs_sb_t *sbp; unsigned long s; - mp = XFS_BHVTOM(bdp); sbp = &(mp->m_sb); statp->f_type = XFS_SB_MAGIC; @@ -874,6 +888,8 @@ xfs_statvfs( xfs_statvfs_fsid(statp, mp); statp->f_namelen = MAXNAMELEN - 1; + if (vp) + XFS_QM_DQSTATVFS(xfs_vtoi(vp), statp); return 0; } @@ -920,14 +936,30 @@ xfs_statvfs( * filesystem. * */ -/*ARGSUSED*/ -STATIC int +int xfs_sync( - bhv_desc_t *bdp, - int flags, - cred_t *credp) + xfs_mount_t *mp, + int flags) { - xfs_mount_t *mp = XFS_BHVTOM(bdp); + int error; + + /* + * Get the Quota Manager to flush the dquots. + * + * If XFS quota support is not enabled or this filesystem + * instance does not use quotas XFS_QM_DQSYNC will always + * return zero. + */ + error = XFS_QM_DQSYNC(mp, flags); + if (error) { + /* + * If we got an IO error, we will be shutting down. + * So, there's nothing more for us to do here. + */ + ASSERT(error != EIO || XFS_FORCED_SHUTDOWN(mp)); + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(error); + } if (flags & SYNC_IOWAIT) xfs_filestream_flush(mp); @@ -1015,7 +1047,7 @@ xfs_sync_inodes( if (bypassed) *bypassed = 0; - if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY) + if (mp->m_flags & XFS_MOUNT_RDONLY) return 0; error = 0; last_error = 0; @@ -1189,12 +1221,13 @@ xfs_sync_inodes( if (flags & SYNC_CLOSE) { /* Shutdown case. Flush and invalidate. */ if (XFS_FORCED_SHUTDOWN(mp)) - bhv_vop_toss_pages(vp, 0, -1, FI_REMAPF); + xfs_tosspages(ip, 0, -1, + FI_REMAPF); else - error = bhv_vop_flushinval_pages(vp, 0, - -1, FI_REMAPF); + error = xfs_flushinval_pages(ip, + 0, -1, FI_REMAPF); } else if ((flags & SYNC_DELWRI) && VN_DIRTY(vp)) { - error = bhv_vop_flush_pages(vp, (xfs_off_t)0, + error = xfs_flush_pages(ip, 0, -1, fflag, FI_NONE); } @@ -1204,7 +1237,7 @@ xfs_sync_inodes( * place after this point */ if (flags & SYNC_IOWAIT) - vn_iowait(vp); + vn_iowait(ip); xfs_ilock(ip, XFS_ILOCK_SHARED); } @@ -1598,14 +1631,12 @@ xfs_syncsub( /* * xfs_vget - called by DMAPI and NFSD to get vnode from file handle */ -STATIC int +int xfs_vget( - bhv_desc_t *bdp, + xfs_mount_t *mp, bhv_vnode_t **vpp, - fid_t *fidp) + xfs_fid_t *xfid) { - xfs_mount_t *mp = XFS_BHVTOM(bdp); - xfs_fid_t *xfid = (struct xfs_fid *)fidp; xfs_inode_t *ip; int error; xfs_ino_t ino; @@ -1615,11 +1646,11 @@ xfs_vget( * Invalid. Since handles can be created in user space and passed in * via gethandle(), this is not cause for a panic. */ - if (xfid->xfs_fid_len != sizeof(*xfid) - sizeof(xfid->xfs_fid_len)) + if (xfid->fid_len != sizeof(*xfid) - sizeof(xfid->fid_len)) return XFS_ERROR(EINVAL); - ino = xfid->xfs_fid_ino; - igen = xfid->xfs_fid_gen; + ino = xfid->fid_ino; + igen = xfid->fid_gen; /* * NFS can sometimes send requests for ino 0. Fail them gracefully. @@ -1668,7 +1699,6 @@ xfs_vget( #define MNTOPT_BSDGROUPS "bsdgroups" /* group-ID from parent directory */ #define MNTOPT_SYSVGROUPS "sysvgroups" /* group-ID from current process */ #define MNTOPT_ALLOCSIZE "allocsize" /* preferred allocation size */ -#define MNTOPT_IHASHSIZE "ihashsize" /* size of inode hash table */ #define MNTOPT_NORECOVERY "norecovery" /* don't run XFS recovery */ #define MNTOPT_BARRIER "barrier" /* use writer barriers for log write and * unwritten extent conversion */ @@ -1683,6 +1713,21 @@ xfs_vget( #define MNTOPT_ATTR2 "attr2" /* do use attr2 attribute format */ #define MNTOPT_NOATTR2 "noattr2" /* do not use attr2 attribute format */ #define MNTOPT_FILESTREAM "filestreams" /* use filestreams allocator */ +#define MNTOPT_QUOTA "quota" /* disk quotas (user) */ +#define MNTOPT_NOQUOTA "noquota" /* no quotas */ +#define MNTOPT_USRQUOTA "usrquota" /* user quota enabled */ +#define MNTOPT_GRPQUOTA "grpquota" /* group quota enabled */ +#define MNTOPT_PRJQUOTA "prjquota" /* project quota enabled */ +#define MNTOPT_UQUOTA "uquota" /* user quota (IRIX variant) */ +#define MNTOPT_GQUOTA "gquota" /* group quota (IRIX variant) */ +#define MNTOPT_PQUOTA "pquota" /* project quota (IRIX variant) */ +#define MNTOPT_UQUOTANOENF "uqnoenforce"/* user quota limit enforcement */ +#define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */ +#define MNTOPT_PQUOTANOENF "pqnoenforce"/* project quota limit enforcement */ +#define MNTOPT_QUOTANOENF "qnoenforce" /* same as uqnoenforce */ +#define MNTOPT_DMAPI "dmapi" /* DMI enabled (DMAPI / XDSM) */ +#define MNTOPT_XDSM "xdsm" /* DMI enabled (DMAPI / XDSM) */ +#define MNTOPT_DMI "dmi" /* DMI enabled (DMAPI / XDSM) */ STATIC unsigned long suffix_strtoul(char *s, char **endp, unsigned int base) @@ -1707,19 +1752,18 @@ suffix_strtoul(char *s, char **endp, unsigned int base) return simple_strtoul((const char *)s, endp, base) << shift_left_factor; } -STATIC int +int xfs_parseargs( - struct bhv_desc *bhv, + struct xfs_mount *mp, char *options, struct xfs_mount_args *args, int update) { - bhv_vfs_t *vfsp = bhvtovfs(bhv); char *this_char, *value, *eov; int dsunit, dswidth, vol_dsunit, vol_dswidth; int iosize; + int ikeep = 0; - args->flags |= XFSMNT_IDELETE; args->flags |= XFSMNT_BARRIER; args->flags2 |= XFSMNT2_COMPAT_IOSIZE; @@ -1794,21 +1838,12 @@ xfs_parseargs( iosize = suffix_strtoul(value, &eov, 10); args->flags |= XFSMNT_IOSIZE; args->iosizelog = ffs(iosize) - 1; - } else if (!strcmp(this_char, MNTOPT_IHASHSIZE)) { - if (!value || !*value) { - cmn_err(CE_WARN, - "XFS: %s option requires an argument", - this_char); - return EINVAL; - } - args->flags |= XFSMNT_IHASHSIZE; - args->ihashsize = simple_strtoul(value, &eov, 10); } else if (!strcmp(this_char, MNTOPT_GRPID) || !strcmp(this_char, MNTOPT_BSDGROUPS)) { - vfsp->vfs_flag |= VFS_GRPID; + mp->m_flags |= XFS_MOUNT_GRPID; } else if (!strcmp(this_char, MNTOPT_NOGRPID) || !strcmp(this_char, MNTOPT_SYSVGROUPS)) { - vfsp->vfs_flag &= ~VFS_GRPID; + mp->m_flags &= ~XFS_MOUNT_GRPID; } else if (!strcmp(this_char, MNTOPT_WSYNC)) { args->flags |= XFSMNT_WSYNC; } else if (!strcmp(this_char, MNTOPT_OSYNCISOSYNC)) { @@ -1858,6 +1893,7 @@ xfs_parseargs( } else if (!strcmp(this_char, MNTOPT_NOBARRIER)) { args->flags &= ~XFSMNT_BARRIER; } else if (!strcmp(this_char, MNTOPT_IKEEP)) { + ikeep = 1; args->flags &= ~XFSMNT_IDELETE; } else if (!strcmp(this_char, MNTOPT_NOIKEEP)) { args->flags |= XFSMNT_IDELETE; @@ -1871,6 +1907,38 @@ xfs_parseargs( args->flags &= ~XFSMNT_ATTR2; } else if (!strcmp(this_char, MNTOPT_FILESTREAM)) { args->flags2 |= XFSMNT2_FILESTREAMS; + } else if (!strcmp(this_char, MNTOPT_NOQUOTA)) { + args->flags &= ~(XFSMNT_UQUOTAENF|XFSMNT_UQUOTA); + args->flags &= ~(XFSMNT_GQUOTAENF|XFSMNT_GQUOTA); + } else if (!strcmp(this_char, MNTOPT_QUOTA) || + !strcmp(this_char, MNTOPT_UQUOTA) || + !strcmp(this_char, MNTOPT_USRQUOTA)) { + args->flags |= XFSMNT_UQUOTA | XFSMNT_UQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_QUOTANOENF) || + !strcmp(this_char, MNTOPT_UQUOTANOENF)) { + args->flags |= XFSMNT_UQUOTA; + args->flags &= ~XFSMNT_UQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_PQUOTA) || + !strcmp(this_char, MNTOPT_PRJQUOTA)) { + args->flags |= XFSMNT_PQUOTA | XFSMNT_PQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_PQUOTANOENF)) { + args->flags |= XFSMNT_PQUOTA; + args->flags &= ~XFSMNT_PQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_GQUOTA) || + !strcmp(this_char, MNTOPT_GRPQUOTA)) { + args->flags |= XFSMNT_GQUOTA | XFSMNT_GQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) { + args->flags |= XFSMNT_GQUOTA; + args->flags &= ~XFSMNT_GQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_DMAPI)) { + args->flags |= XFSMNT_DMAPI; + } else if (!strcmp(this_char, MNTOPT_XDSM)) { + args->flags |= XFSMNT_DMAPI; + } else if (!strcmp(this_char, MNTOPT_DMI)) { + args->flags |= XFSMNT_DMAPI; + } else if (!strcmp(this_char, "ihashsize")) { + cmn_err(CE_WARN, + "XFS: ihashsize no longer used, option is deprecated."); } else if (!strcmp(this_char, "osyncisdsync")) { /* no-op, this is now the default */ cmn_err(CE_WARN, @@ -1886,7 +1954,7 @@ xfs_parseargs( } if (args->flags & XFSMNT_NORECOVERY) { - if ((vfsp->vfs_flag & VFS_RDONLY) == 0) { + if ((mp->m_flags & XFS_MOUNT_RDONLY) == 0) { cmn_err(CE_WARN, "XFS: no-recovery mounts must be read-only."); return EINVAL; @@ -1899,6 +1967,18 @@ xfs_parseargs( return EINVAL; } + if ((args->flags & XFSMNT_GQUOTA) && (args->flags & XFSMNT_PQUOTA)) { + cmn_err(CE_WARN, + "XFS: cannot mount with both project and group quota"); + return EINVAL; + } + + if ((args->flags & XFSMNT_DMAPI) && *args->mtpt == '\0') { + printk("XFS: %s option needs the mount point option as well\n", + MNTOPT_DMAPI); + return EINVAL; + } + if ((dsunit && !dswidth) || (!dsunit && dswidth)) { cmn_err(CE_WARN, "XFS: sunit and swidth must be specified together"); @@ -1912,6 +1992,18 @@ xfs_parseargs( return EINVAL; } + /* + * Applications using DMI filesystems often expect the + * inode generation number to be monotonically increasing. + * If we delete inode chunks we break this assumption, so + * keep unused inode chunks on disk for DMI filesystems + * until we come up with a better solution. + * Note that if "ikeep" or "noikeep" mount options are + * supplied, then they are honored. + */ + if (!(args->flags & XFSMNT_DMAPI) && !ikeep) + args->flags |= XFSMNT_IDELETE; + if ((args->flags & XFSMNT_NOALIGN) != XFSMNT_NOALIGN) { if (dsunit) { args->sunit = dsunit; @@ -1927,15 +2019,15 @@ xfs_parseargs( done: if (args->flags & XFSMNT_32BITINODES) - vfsp->vfs_flag |= VFS_32BITINODES; + mp->m_flags |= XFS_MOUNT_SMALL_INUMS; if (args->flags2) args->flags |= XFSMNT_FLAGS2; return 0; } -STATIC int +int xfs_showargs( - struct bhv_desc *bhv, + struct xfs_mount *mp, struct seq_file *m) { static struct proc_xfs_info { @@ -1953,17 +2045,12 @@ xfs_showargs( { 0, NULL } }; struct proc_xfs_info *xfs_infop; - struct xfs_mount *mp = XFS_BHVTOM(bhv); - struct bhv_vfs *vfsp = XFS_MTOVFS(mp); for (xfs_infop = xfs_info; xfs_infop->flag; xfs_infop++) { if (mp->m_flags & xfs_infop->flag) seq_puts(m, xfs_infop->str); } - if (mp->m_flags & XFS_MOUNT_IHASHSIZE) - seq_printf(m, "," MNTOPT_IHASHSIZE "=%d", (int)mp->m_ihsize); - if (mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) seq_printf(m, "," MNTOPT_ALLOCSIZE "=%dk", (int)(1 << mp->m_writeio_log) >> 10); @@ -1990,11 +2077,37 @@ xfs_showargs( if (!(mp->m_flags & XFS_MOUNT_COMPAT_IOSIZE)) seq_printf(m, "," MNTOPT_LARGEIO); - if (!(vfsp->vfs_flag & VFS_32BITINODES)) + if (!(mp->m_flags & XFS_MOUNT_SMALL_INUMS)) seq_printf(m, "," MNTOPT_64BITINODE); - if (vfsp->vfs_flag & VFS_GRPID) + if (mp->m_flags & XFS_MOUNT_GRPID) seq_printf(m, "," MNTOPT_GRPID); + if (mp->m_qflags & XFS_UQUOTA_ACCT) { + if (mp->m_qflags & XFS_UQUOTA_ENFD) + seq_puts(m, "," MNTOPT_USRQUOTA); + else + seq_puts(m, "," MNTOPT_UQUOTANOENF); + } + + if (mp->m_qflags & XFS_PQUOTA_ACCT) { + if (mp->m_qflags & XFS_OQUOTA_ENFD) + seq_puts(m, "," MNTOPT_PRJQUOTA); + else + seq_puts(m, "," MNTOPT_PQUOTANOENF); + } + + if (mp->m_qflags & XFS_GQUOTA_ACCT) { + if (mp->m_qflags & XFS_OQUOTA_ENFD) + seq_puts(m, "," MNTOPT_GRPQUOTA); + else + seq_puts(m, "," MNTOPT_GQUOTANOENF); + } + + if (!(mp->m_qflags & XFS_ALL_QUOTA_ACCT)) + seq_puts(m, "," MNTOPT_NOQUOTA); + + if (mp->m_flags & XFS_MOUNT_DMAPI) + seq_puts(m, "," MNTOPT_DMAPI); return 0; } @@ -2003,31 +2116,10 @@ xfs_showargs( * need to take care of themetadata. Once that's done write a dummy * record to dirty the log in case of a crash while frozen. */ -STATIC void +void xfs_freeze( - bhv_desc_t *bdp) + xfs_mount_t *mp) { - xfs_mount_t *mp = XFS_BHVTOM(bdp); - xfs_attr_quiesce(mp); xfs_fs_log_dummy(mp); } - - -bhv_vfsops_t xfs_vfsops = { - BHV_IDENTITY_INIT(VFS_BHV_XFS,VFS_POSITION_XFS), - .vfs_parseargs = xfs_parseargs, - .vfs_showargs = xfs_showargs, - .vfs_mount = xfs_mount, - .vfs_unmount = xfs_unmount, - .vfs_mntupdate = xfs_mntupdate, - .vfs_root = xfs_root, - .vfs_statvfs = xfs_statvfs, - .vfs_sync = xfs_sync, - .vfs_vget = xfs_vget, - .vfs_dmapiops = (vfs_dmapiops_t)fs_nosys, - .vfs_quotactl = (vfs_quotactl_t)fs_nosys, - .vfs_init_vnode = xfs_initialize_vnode, - .vfs_force_shutdown = xfs_do_force_shutdown, - .vfs_freeze = xfs_freeze, -}; diff --git a/fs/xfs/xfs_vfsops.h b/fs/xfs/xfs_vfsops.h new file mode 100644 index 000000000000..a592fe02a339 --- /dev/null +++ b/fs/xfs/xfs_vfsops.h @@ -0,0 +1,28 @@ +#ifndef _XFS_VFSOPS_H +#define _XFS_VFSOPS_H 1 + +struct cred; +struct xfs_fid; +struct inode; +struct kstatfs; +struct xfs_mount; +struct xfs_mount_args; + +int xfs_mount(struct xfs_mount *mp, struct xfs_mount_args *args, + struct cred *credp); +int xfs_unmount(struct xfs_mount *mp, int flags, struct cred *credp); +int xfs_mntupdate(struct xfs_mount *mp, int *flags, + struct xfs_mount_args *args); +int xfs_root(struct xfs_mount *mp, bhv_vnode_t **vpp); +int xfs_statvfs(struct xfs_mount *mp, struct kstatfs *statp, + bhv_vnode_t *vp); +int xfs_sync(struct xfs_mount *mp, int flags); +int xfs_vget(struct xfs_mount *mp, bhv_vnode_t **vpp, struct xfs_fid *xfid); +int xfs_parseargs(struct xfs_mount *mp, char *options, + struct xfs_mount_args *args, int update); +int xfs_showargs(struct xfs_mount *mp, struct seq_file *m); +void xfs_freeze(struct xfs_mount *mp); +void xfs_do_force_shutdown(struct xfs_mount *mp, int flags, char *fname, + int lnnum); + +#endif /* _XFS_VFSOPS_H */ diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 603459229904..efd5aff9eaf6 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -52,15 +52,13 @@ #include "xfs_trans_space.h" #include "xfs_log_priv.h" #include "xfs_filestream.h" +#include "xfs_vnodeops.h" -STATIC int +int xfs_open( - bhv_desc_t *bdp, - cred_t *credp) + xfs_inode_t *ip) { int mode; - bhv_vnode_t *vp = BHV_TO_VNODE(bdp); - xfs_inode_t *ip = XFS_BHVTOI(bdp); if (XFS_FORCED_SHUTDOWN(ip->i_mount)) return XFS_ERROR(EIO); @@ -69,7 +67,7 @@ xfs_open( * If it's a directory with any blocks, read-ahead block 0 * as we're almost certain to have the next operation be a read there. */ - if (VN_ISDIR(vp) && ip->i_d.di_nextents > 0) { + if (S_ISDIR(ip->i_d.di_mode) && ip->i_d.di_nextents > 0) { mode = xfs_ilock_map_shared(ip); if (ip->i_d.di_nextents > 0) (void)xfs_da_reada_buf(NULL, ip, 0, XFS_DATA_FORK); @@ -81,22 +79,16 @@ xfs_open( /* * xfs_getattr */ -STATIC int +int xfs_getattr( - bhv_desc_t *bdp, + xfs_inode_t *ip, bhv_vattr_t *vap, - int flags, - cred_t *credp) + int flags) { - xfs_inode_t *ip; - xfs_mount_t *mp; - bhv_vnode_t *vp; - - vp = BHV_TO_VNODE(bdp); - vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); + bhv_vnode_t *vp = XFS_ITOV(ip); + xfs_mount_t *mp = ip->i_mount; - ip = XFS_BHVTOI(bdp); - mp = ip->i_mount; + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); @@ -215,14 +207,14 @@ xfs_getattr( */ int xfs_setattr( - bhv_desc_t *bdp, + xfs_inode_t *ip, bhv_vattr_t *vap, int flags, cred_t *credp) { - xfs_inode_t *ip; + bhv_vnode_t *vp = XFS_ITOV(ip); + xfs_mount_t *mp = ip->i_mount; xfs_trans_t *tp; - xfs_mount_t *mp; int mask; int code; uint lock_flags; @@ -230,17 +222,15 @@ xfs_setattr( uid_t uid=0, iuid=0; gid_t gid=0, igid=0; int timeflags = 0; - bhv_vnode_t *vp; xfs_prid_t projid=0, iprojid=0; int mandlock_before, mandlock_after; struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2; int file_owner; int need_iolock = 1; - vp = BHV_TO_VNODE(bdp); - vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); - if (vp->v_vfsp->vfs_flag & VFS_RDONLY) + if (mp->m_flags & XFS_MOUNT_RDONLY) return XFS_ERROR(EROFS); /* @@ -251,9 +241,6 @@ xfs_setattr( return XFS_ERROR(EINVAL); } - ip = XFS_BHVTOI(bdp); - mp = ip->i_mount; - if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); @@ -337,7 +324,7 @@ xfs_setattr( } } } else { - if (DM_EVENT_ENABLED (vp->v_vfsp, ip, DM_EVENT_TRUNCATE) && + if (DM_EVENT_ENABLED(ip, DM_EVENT_TRUNCATE) && !(flags & ATTR_DMI)) { int dmflags = AT_DELAY_FLAG(flags) | DM_SEM_FLAG_WR; code = XFS_SEND_DATA(mp, DM_EVENT_TRUNCATE, vp, @@ -605,13 +592,13 @@ xfs_setattr( if (!code && (ip->i_size != ip->i_d.di_size) && (vap->va_size > ip->i_d.di_size)) { - code = bhv_vop_flush_pages(XFS_ITOV(ip), + code = xfs_flush_pages(ip, ip->i_d.di_size, vap->va_size, XFS_B_ASYNC, FI_NONE); } /* wait for all I/O to complete */ - vn_iowait(vp); + vn_iowait(ip); if (!code) code = xfs_itruncate_data(ip, vap->va_size); @@ -673,7 +660,7 @@ xfs_setattr( * vnode and flush it when the file is closed, and * do not wait the usual (long) time for writeout. */ - VTRUNCATE(vp); + xfs_iflags_set(ip, XFS_ITRUNCATED); } /* * Have to do this even if the file's size doesn't change. @@ -877,10 +864,6 @@ xfs_setattr( * racing calls to vop_vnode_change. */ mandlock_after = MANDLOCK(vp, ip->i_d.di_mode); - if (mandlock_before != mandlock_after) { - bhv_vop_vnode_change(vp, VCHANGE_FLAGS_ENF_LOCKING, - mandlock_after); - } xfs_iunlock(ip, lock_flags); @@ -896,7 +879,7 @@ xfs_setattr( return code; } - if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_ATTRIBUTE) && + if (DM_EVENT_ENABLED(ip, DM_EVENT_ATTRIBUTE) && !(flags & ATTR_DMI)) { (void) XFS_SEND_NAMESP(mp, DM_EVENT_ATTRIBUTE, vp, DM_RIGHT_NULL, NULL, DM_RIGHT_NULL, NULL, NULL, @@ -924,19 +907,16 @@ xfs_setattr( * xfs_access * Null conversion from vnode mode bits to inode mode bits, as in efs. */ -STATIC int +int xfs_access( - bhv_desc_t *bdp, + xfs_inode_t *ip, int mode, cred_t *credp) { - xfs_inode_t *ip; int error; - vn_trace_entry(BHV_TO_VNODE(bdp), __FUNCTION__, - (inst_t *)__return_address); + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); - ip = XFS_BHVTOI(bdp); xfs_ilock(ip, XFS_ILOCK_SHARED); error = xfs_iaccess(ip, mode, credp); xfs_iunlock(ip, XFS_ILOCK_SHARED); @@ -951,105 +931,88 @@ xfs_access( */ #define SYMLINK_MAPS 2 -/* - * xfs_readlink - * - */ STATIC int -xfs_readlink( - bhv_desc_t *bdp, - uio_t *uiop, - int ioflags, - cred_t *credp) +xfs_readlink_bmap( + xfs_inode_t *ip, + char *link) { - xfs_inode_t *ip; - int count; - xfs_off_t offset; - int pathlen; - bhv_vnode_t *vp; - int error = 0; - xfs_mount_t *mp; - int nmaps; + xfs_mount_t *mp = ip->i_mount; + int pathlen = ip->i_d.di_size; + int nmaps = SYMLINK_MAPS; xfs_bmbt_irec_t mval[SYMLINK_MAPS]; xfs_daddr_t d; int byte_cnt; int n; xfs_buf_t *bp; + int error = 0; - vp = BHV_TO_VNODE(bdp); - vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); - - ip = XFS_BHVTOI(bdp); - mp = ip->i_mount; + error = xfs_bmapi(NULL, ip, 0, XFS_B_TO_FSB(mp, pathlen), 0, NULL, 0, + mval, &nmaps, NULL, NULL); + if (error) + goto out; - if (XFS_FORCED_SHUTDOWN(mp)) - return XFS_ERROR(EIO); + for (n = 0; n < nmaps; n++) { + d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); + byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); - xfs_ilock(ip, XFS_ILOCK_SHARED); + bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0); + error = XFS_BUF_GETERROR(bp); + if (error) { + xfs_ioerror_alert("xfs_readlink", + ip->i_mount, bp, XFS_BUF_ADDR(bp)); + xfs_buf_relse(bp); + goto out; + } + if (pathlen < byte_cnt) + byte_cnt = pathlen; + pathlen -= byte_cnt; - ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFLNK); + memcpy(link, XFS_BUF_PTR(bp), byte_cnt); + xfs_buf_relse(bp); + } - offset = uiop->uio_offset; - count = uiop->uio_resid; + link[ip->i_d.di_size] = '\0'; + error = 0; - if (offset < 0) { - error = XFS_ERROR(EINVAL); - goto error_return; - } - if (count <= 0) { - error = 0; - goto error_return; - } + out: + return error; +} - /* - * See if the symlink is stored inline. - */ - pathlen = (int)ip->i_d.di_size; +int +xfs_readlink( + xfs_inode_t *ip, + char *link) +{ + xfs_mount_t *mp = ip->i_mount; + int pathlen; + int error = 0; - if (ip->i_df.if_flags & XFS_IFINLINE) { - error = xfs_uio_read(ip->i_df.if_u1.if_data, pathlen, uiop); - } - else { - /* - * Symlink not inline. Call bmap to get it in. - */ - nmaps = SYMLINK_MAPS; + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); - error = xfs_bmapi(NULL, ip, 0, XFS_B_TO_FSB(mp, pathlen), - 0, NULL, 0, mval, &nmaps, NULL, NULL); + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); - if (error) { - goto error_return; - } + xfs_ilock(ip, XFS_ILOCK_SHARED); - for (n = 0; n < nmaps; n++) { - d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); - byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); - bp = xfs_buf_read(mp->m_ddev_targp, d, - BTOBB(byte_cnt), 0); - error = XFS_BUF_GETERROR(bp); - if (error) { - xfs_ioerror_alert("xfs_readlink", - ip->i_mount, bp, XFS_BUF_ADDR(bp)); - xfs_buf_relse(bp); - goto error_return; - } - if (pathlen < byte_cnt) - byte_cnt = pathlen; - pathlen -= byte_cnt; + ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFLNK); + ASSERT(ip->i_d.di_size <= MAXPATHLEN); - error = xfs_uio_read(XFS_BUF_PTR(bp), byte_cnt, uiop); - xfs_buf_relse (bp); - } + pathlen = ip->i_d.di_size; + if (!pathlen) + goto out; + if (ip->i_df.if_flags & XFS_IFINLINE) { + memcpy(link, ip->i_df.if_u1.if_data, pathlen); + link[pathlen] = '\0'; + } else { + error = xfs_readlink_bmap(ip, link); } -error_return: + out: xfs_iunlock(ip, XFS_ILOCK_SHARED); return error; } - /* * xfs_fsync * @@ -1059,23 +1022,18 @@ error_return: * be held while flushing the data, so acquire after we're done * with that. */ -STATIC int +int xfs_fsync( - bhv_desc_t *bdp, + xfs_inode_t *ip, int flag, - cred_t *credp, xfs_off_t start, xfs_off_t stop) { - xfs_inode_t *ip; xfs_trans_t *tp; int error; int log_flushed = 0, changed = 1; - vn_trace_entry(BHV_TO_VNODE(bdp), - __FUNCTION__, (inst_t *)__return_address); - - ip = XFS_BHVTOI(bdp); + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); ASSERT(start >= 0 && stop >= -1); @@ -1545,27 +1503,24 @@ xfs_inactive_attrs( return 0; } -STATIC int +int xfs_release( - bhv_desc_t *bdp) + xfs_inode_t *ip) { - xfs_inode_t *ip; - bhv_vnode_t *vp; - xfs_mount_t *mp; + bhv_vnode_t *vp = XFS_ITOV(ip); + xfs_mount_t *mp = ip->i_mount; int error; - vp = BHV_TO_VNODE(bdp); - ip = XFS_BHVTOI(bdp); - mp = ip->i_mount; - if (!VN_ISREG(vp) || (ip->i_d.di_mode == 0)) return 0; /* If this is a read-only mount, don't do this (would generate I/O) */ - if (vp->v_vfsp->vfs_flag & VFS_RDONLY) + if (mp->m_flags & XFS_MOUNT_RDONLY) return 0; if (!XFS_FORCED_SHUTDOWN(mp)) { + int truncated; + /* * If we are using filestreams, and we have an unlinked * file that we are processing the last close on, then nothing @@ -1586,8 +1541,9 @@ xfs_release( * significantly reducing the time window where we'd otherwise * be exposed to that problem. */ - if (VUNTRUNCATE(vp) && VN_DIRTY(vp) && ip->i_delayed_blks > 0) - bhv_vop_flush_pages(vp, 0, -1, XFS_B_ASYNC, FI_NONE); + truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED); + if (truncated && VN_DIRTY(vp) && ip->i_delayed_blks > 0) + xfs_flush_pages(ip, 0, -1, XFS_B_ASYNC, FI_NONE); } #ifdef HAVE_REFCACHE @@ -1623,13 +1579,11 @@ xfs_release( * now be truncated. Also, we clear all of the read-ahead state * kept for the inode here since the file is now closed. */ -STATIC int +int xfs_inactive( - bhv_desc_t *bdp, - cred_t *credp) + xfs_inode_t *ip) { - xfs_inode_t *ip; - bhv_vnode_t *vp; + bhv_vnode_t *vp = XFS_ITOV(ip); xfs_bmap_free_t free_list; xfs_fsblock_t first_block; int committed; @@ -1638,10 +1592,7 @@ xfs_inactive( int error; int truncate; - vp = BHV_TO_VNODE(bdp); - vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); - - ip = XFS_BHVTOI(bdp); + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); /* * If the inode is already free, then there can be nothing @@ -1666,15 +1617,14 @@ xfs_inactive( mp = ip->i_mount; - if (ip->i_d.di_nlink == 0 && - DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_DESTROY)) { + if (ip->i_d.di_nlink == 0 && DM_EVENT_ENABLED(ip, DM_EVENT_DESTROY)) { (void) XFS_SEND_DESTROY(mp, vp, DM_RIGHT_NULL); } error = 0; /* If this is a read-only mount, don't do this (would generate I/O) */ - if (vp->v_vfsp->vfs_flag & VFS_RDONLY) + if (mp->m_flags & XFS_MOUNT_RDONLY) goto out; if (ip->i_d.di_nlink != 0) { @@ -1844,34 +1794,24 @@ xfs_inactive( } -/* - * xfs_lookup - */ -STATIC int +int xfs_lookup( - bhv_desc_t *dir_bdp, + xfs_inode_t *dp, bhv_vname_t *dentry, - bhv_vnode_t **vpp, - int flags, - bhv_vnode_t *rdir, - cred_t *credp) + bhv_vnode_t **vpp) { - xfs_inode_t *dp, *ip; + xfs_inode_t *ip; xfs_ino_t e_inum; int error; uint lock_mode; - bhv_vnode_t *dir_vp; - dir_vp = BHV_TO_VNODE(dir_bdp); - vn_trace_entry(dir_vp, __FUNCTION__, (inst_t *)__return_address); - - dp = XFS_BHVTOI(dir_bdp); + vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); if (XFS_FORCED_SHUTDOWN(dp->i_mount)) return XFS_ERROR(EIO); lock_mode = xfs_ilock_map_shared(dp); - error = xfs_dir_lookup_int(dir_bdp, lock_mode, dentry, &e_inum, &ip); + error = xfs_dir_lookup_int(dp, lock_mode, dentry, &e_inum, &ip); if (!error) { *vpp = XFS_ITOV(ip); ITRACE(ip); @@ -1880,53 +1820,43 @@ xfs_lookup( return error; } - -/* - * xfs_create (create a new file). - */ -STATIC int +int xfs_create( - bhv_desc_t *dir_bdp, + xfs_inode_t *dp, bhv_vname_t *dentry, - bhv_vattr_t *vap, + mode_t mode, + xfs_dev_t rdev, bhv_vnode_t **vpp, cred_t *credp) { char *name = VNAME(dentry); - bhv_vnode_t *dir_vp; - xfs_inode_t *dp, *ip; + xfs_mount_t *mp = dp->i_mount; + bhv_vnode_t *dir_vp = XFS_ITOV(dp); + xfs_inode_t *ip; bhv_vnode_t *vp = NULL; xfs_trans_t *tp; - xfs_mount_t *mp; - xfs_dev_t rdev; int error; xfs_bmap_free_t free_list; xfs_fsblock_t first_block; - boolean_t dp_joined_to_trans; + boolean_t unlock_dp_on_error = B_FALSE; int dm_event_sent = 0; uint cancel_flags; int committed; xfs_prid_t prid; struct xfs_dquot *udqp, *gdqp; uint resblks; - int dm_di_mode; int namelen; ASSERT(!*vpp); - dir_vp = BHV_TO_VNODE(dir_bdp); - vn_trace_entry(dir_vp, __FUNCTION__, (inst_t *)__return_address); + vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); - dp = XFS_BHVTOI(dir_bdp); - mp = dp->i_mount; - - dm_di_mode = vap->va_mode; namelen = VNAMELEN(dentry); - if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_CREATE)) { + if (DM_EVENT_ENABLED(dp, DM_EVENT_CREATE)) { error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE, dir_vp, DM_RIGHT_NULL, NULL, DM_RIGHT_NULL, name, NULL, - dm_di_mode, 0, 0); + mode, 0, 0); if (error) return error; @@ -1941,8 +1871,6 @@ xfs_create( udqp = gdqp = NULL; if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) prid = dp->i_d.di_projid; - else if (vap->va_mask & XFS_AT_PROJID) - prid = (xfs_prid_t)vap->va_projid; else prid = (xfs_prid_t)dfltprid; @@ -1956,7 +1884,6 @@ xfs_create( goto std_return; ip = NULL; - dp_joined_to_trans = B_FALSE; tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE); cancel_flags = XFS_TRANS_RELEASE_LOG_RES; @@ -1976,11 +1903,11 @@ xfs_create( } if (error) { cancel_flags = 0; - dp = NULL; goto error_return; } xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); + unlock_dp_on_error = B_TRUE; XFS_BMAP_INIT(&free_list, &first_block); @@ -1995,8 +1922,7 @@ xfs_create( if (resblks == 0 && (error = xfs_dir_canenter(tp, dp, name, namelen))) goto error_return; - rdev = (vap->va_mask & XFS_AT_RDEV) ? vap->va_rdev : 0; - error = xfs_dir_ialloc(&tp, dp, vap->va_mode, 1, + error = xfs_dir_ialloc(&tp, dp, mode, 1, rdev, credp, prid, resblks > 0, &ip, &committed); if (error) { @@ -2014,15 +1940,15 @@ xfs_create( ASSERT(ismrlocked (&ip->i_lock, MR_UPDATE)); /* - * Now we join the directory inode to the transaction. - * We do not do it earlier because xfs_dir_ialloc - * might commit the previous transaction (and release - * all the locks). + * Now we join the directory inode to the transaction. We do not do it + * earlier because xfs_dir_ialloc might commit the previous transaction + * (and release all the locks). An error from here on will result in + * the transaction cancel unlocking dp so don't do it explicitly in the + * error path. */ - VN_HOLD(dir_vp); xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); - dp_joined_to_trans = B_TRUE; + unlock_dp_on_error = B_FALSE; error = xfs_dir_createname(tp, dp, name, namelen, ip->i_ino, &first_block, &free_list, resblks ? @@ -2076,25 +2002,18 @@ xfs_create( XFS_QM_DQRELE(mp, udqp); XFS_QM_DQRELE(mp, gdqp); - /* - * Propagate the fact that the vnode changed after the - * xfs_inode locks have been released. - */ - bhv_vop_vnode_change(vp, VCHANGE_FLAGS_TRUNCATED, 3); - *vpp = vp; /* Fallthrough to std_return with error = 0 */ std_return: - if ( (*vpp || (error != 0 && dm_event_sent != 0)) && - DM_EVENT_ENABLED(dir_vp->v_vfsp, XFS_BHVTOI(dir_bdp), - DM_EVENT_POSTCREATE)) { + if ((*vpp || (error != 0 && dm_event_sent != 0)) && + DM_EVENT_ENABLED(dp, DM_EVENT_POSTCREATE)) { (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTCREATE, dir_vp, DM_RIGHT_NULL, *vpp ? vp:NULL, DM_RIGHT_NULL, name, NULL, - dm_di_mode, error, 0); + mode, error, 0); } return error; @@ -2106,11 +2025,12 @@ std_return: if (tp != NULL) xfs_trans_cancel(tp, cancel_flags); - if (!dp_joined_to_trans && (dp != NULL)) - xfs_iunlock(dp, XFS_ILOCK_EXCL); XFS_QM_DQRELE(mp, udqp); XFS_QM_DQRELE(mp, gdqp); + if (unlock_dp_on_error) + xfs_iunlock(dp, XFS_ILOCK_EXCL); + goto std_return; abort_rele: @@ -2381,22 +2301,16 @@ int remove_which_error_return = 0; #define REMOVE_DEBUG_TRACE(x) #endif /* ! DEBUG */ - -/* - * xfs_remove - * - */ -STATIC int +int xfs_remove( - bhv_desc_t *dir_bdp, - bhv_vname_t *dentry, - cred_t *credp) + xfs_inode_t *dp, + bhv_vname_t *dentry) { - bhv_vnode_t *dir_vp; + bhv_vnode_t *dir_vp = XFS_ITOV(dp); char *name = VNAME(dentry); - xfs_inode_t *dp, *ip; + xfs_mount_t *mp = dp->i_mount; + xfs_inode_t *ip; xfs_trans_t *tp = NULL; - xfs_mount_t *mp; int error = 0; xfs_bmap_free_t free_list; xfs_fsblock_t first_block; @@ -2407,11 +2321,7 @@ xfs_remove( uint resblks; int namelen; - dir_vp = BHV_TO_VNODE(dir_bdp); - vn_trace_entry(dir_vp, __FUNCTION__, (inst_t *)__return_address); - - dp = XFS_BHVTOI(dir_bdp); - mp = dp->i_mount; + vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); @@ -2423,7 +2333,7 @@ xfs_remove( IRELE(ip); } - if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_REMOVE)) { + if (DM_EVENT_ENABLED(dp, DM_EVENT_REMOVE)) { error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE, dir_vp, DM_RIGHT_NULL, NULL, DM_RIGHT_NULL, name, NULL, dm_di_mode, 0, 0); @@ -2454,7 +2364,7 @@ xfs_remove( dm_di_mode = ip->i_d.di_mode; - vn_trace_entry(XFS_ITOV(ip), __FUNCTION__, (inst_t *)__return_address); + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); ITRACE(ip); @@ -2588,19 +2498,13 @@ xfs_remove( if (link_zero && xfs_inode_is_filestream(ip)) xfs_filestream_deassociate(ip); - vn_trace_exit(XFS_ITOV(ip), __FUNCTION__, (inst_t *)__return_address); - - /* - * Let interposed file systems know about removed links. - */ - bhv_vop_link_removed(XFS_ITOV(ip), dir_vp, link_zero); + vn_trace_exit(ip, __FUNCTION__, (inst_t *)__return_address); IRELE(ip); /* Fall through to std_return with error = 0 */ std_return: - if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, - DM_EVENT_POSTREMOVE)) { + if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTREMOVE)) { (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTREMOVE, dir_vp, DM_RIGHT_NULL, NULL, DM_RIGHT_NULL, @@ -2638,46 +2542,36 @@ xfs_remove( goto std_return; } - -/* - * xfs_link - * - */ -STATIC int +int xfs_link( - bhv_desc_t *target_dir_bdp, + xfs_inode_t *tdp, bhv_vnode_t *src_vp, - bhv_vname_t *dentry, - cred_t *credp) + bhv_vname_t *dentry) { - xfs_inode_t *tdp, *sip; + bhv_vnode_t *target_dir_vp = XFS_ITOV(tdp); + xfs_mount_t *mp = tdp->i_mount; + xfs_inode_t *sip = xfs_vtoi(src_vp); xfs_trans_t *tp; - xfs_mount_t *mp; xfs_inode_t *ips[2]; int error; xfs_bmap_free_t free_list; xfs_fsblock_t first_block; int cancel_flags; int committed; - bhv_vnode_t *target_dir_vp; int resblks; char *target_name = VNAME(dentry); int target_namelen; - target_dir_vp = BHV_TO_VNODE(target_dir_bdp); - vn_trace_entry(target_dir_vp, __FUNCTION__, (inst_t *)__return_address); - vn_trace_entry(src_vp, __FUNCTION__, (inst_t *)__return_address); + vn_trace_entry(tdp, __FUNCTION__, (inst_t *)__return_address); + vn_trace_entry(xfs_vtoi(src_vp), __FUNCTION__, (inst_t *)__return_address); target_namelen = VNAMELEN(dentry); ASSERT(!VN_ISDIR(src_vp)); - sip = xfs_vtoi(src_vp); - tdp = XFS_BHVTOI(target_dir_bdp); - mp = tdp->i_mount; if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); - if (DM_EVENT_ENABLED(src_vp->v_vfsp, tdp, DM_EVENT_LINK)) { + if (DM_EVENT_ENABLED(tdp, DM_EVENT_LINK)) { error = XFS_SEND_NAMESP(mp, DM_EVENT_LINK, target_dir_vp, DM_RIGHT_NULL, src_vp, DM_RIGHT_NULL, @@ -2788,8 +2682,7 @@ xfs_link( /* Fall through to std_return with error = 0. */ std_return: - if (DM_EVENT_ENABLED(src_vp->v_vfsp, sip, - DM_EVENT_POSTLINK)) { + if (DM_EVENT_ENABLED(sip, DM_EVENT_POSTLINK)) { (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTLINK, target_dir_vp, DM_RIGHT_NULL, src_vp, DM_RIGHT_NULL, @@ -2807,57 +2700,43 @@ std_return: } -/* - * xfs_mkdir - * - */ -STATIC int +int xfs_mkdir( - bhv_desc_t *dir_bdp, + xfs_inode_t *dp, bhv_vname_t *dentry, - bhv_vattr_t *vap, + mode_t mode, bhv_vnode_t **vpp, cred_t *credp) { + bhv_vnode_t *dir_vp = XFS_ITOV(dp); char *dir_name = VNAME(dentry); - xfs_inode_t *dp; + int dir_namelen = VNAMELEN(dentry); + xfs_mount_t *mp = dp->i_mount; xfs_inode_t *cdp; /* inode of created dir */ bhv_vnode_t *cvp; /* vnode of created dir */ xfs_trans_t *tp; - xfs_mount_t *mp; int cancel_flags; int error; int committed; xfs_bmap_free_t free_list; xfs_fsblock_t first_block; - bhv_vnode_t *dir_vp; - boolean_t dp_joined_to_trans; + boolean_t unlock_dp_on_error = B_FALSE; boolean_t created = B_FALSE; int dm_event_sent = 0; xfs_prid_t prid; struct xfs_dquot *udqp, *gdqp; uint resblks; - int dm_di_mode; - int dir_namelen; - - dir_vp = BHV_TO_VNODE(dir_bdp); - dp = XFS_BHVTOI(dir_bdp); - mp = dp->i_mount; if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); - dir_namelen = VNAMELEN(dentry); - tp = NULL; - dp_joined_to_trans = B_FALSE; - dm_di_mode = vap->va_mode; - if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_CREATE)) { + if (DM_EVENT_ENABLED(dp, DM_EVENT_CREATE)) { error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE, dir_vp, DM_RIGHT_NULL, NULL, DM_RIGHT_NULL, dir_name, NULL, - dm_di_mode, 0, 0); + mode, 0, 0); if (error) return error; dm_event_sent = 1; @@ -2865,14 +2744,12 @@ xfs_mkdir( /* Return through std_return after this point. */ - vn_trace_entry(dir_vp, __FUNCTION__, (inst_t *)__return_address); + vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); mp = dp->i_mount; udqp = gdqp = NULL; if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) prid = dp->i_d.di_projid; - else if (vap->va_mask & XFS_AT_PROJID) - prid = (xfs_prid_t)vap->va_projid; else prid = (xfs_prid_t)dfltprid; @@ -2898,11 +2775,11 @@ xfs_mkdir( } if (error) { cancel_flags = 0; - dp = NULL; goto error_return; } xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); + unlock_dp_on_error = B_TRUE; /* * Check for directory link count overflow. @@ -2925,7 +2802,7 @@ xfs_mkdir( /* * create the directory inode. */ - error = xfs_dir_ialloc(&tp, dp, vap->va_mode, 2, + error = xfs_dir_ialloc(&tp, dp, mode, 2, 0, credp, prid, resblks > 0, &cdp, NULL); if (error) { @@ -2939,11 +2816,13 @@ xfs_mkdir( * Now we add the directory inode to the transaction. * We waited until now since xfs_dir_ialloc might start * a new transaction. Had we joined the transaction - * earlier, the locks might have gotten released. + * earlier, the locks might have gotten released. An error + * from here on will result in the transaction cancel + * unlocking dp so don't do it explicitly in the error path. */ VN_HOLD(dir_vp); xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); - dp_joined_to_trans = B_TRUE; + unlock_dp_on_error = B_FALSE; XFS_BMAP_INIT(&free_list, &first_block); @@ -3010,15 +2889,14 @@ xfs_mkdir( * xfs_trans_commit. */ std_return: - if ( (created || (error != 0 && dm_event_sent != 0)) && - DM_EVENT_ENABLED(dir_vp->v_vfsp, XFS_BHVTOI(dir_bdp), - DM_EVENT_POSTCREATE)) { + if ((created || (error != 0 && dm_event_sent != 0)) && + DM_EVENT_ENABLED(dp, DM_EVENT_POSTCREATE)) { (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTCREATE, dir_vp, DM_RIGHT_NULL, created ? XFS_ITOV(cdp):NULL, DM_RIGHT_NULL, dir_name, NULL, - dm_di_mode, error, 0); + mode, error, 0); } return error; @@ -3032,56 +2910,43 @@ std_return: XFS_QM_DQRELE(mp, udqp); XFS_QM_DQRELE(mp, gdqp); - if (!dp_joined_to_trans && (dp != NULL)) { + if (unlock_dp_on_error) xfs_iunlock(dp, XFS_ILOCK_EXCL); - } goto std_return; } - -/* - * xfs_rmdir - * - */ -STATIC int +int xfs_rmdir( - bhv_desc_t *dir_bdp, - bhv_vname_t *dentry, - cred_t *credp) + xfs_inode_t *dp, + bhv_vname_t *dentry) { + bhv_vnode_t *dir_vp = XFS_ITOV(dp); char *name = VNAME(dentry); - xfs_inode_t *dp; - xfs_inode_t *cdp; /* child directory */ + int namelen = VNAMELEN(dentry); + xfs_mount_t *mp = dp->i_mount; + xfs_inode_t *cdp; /* child directory */ xfs_trans_t *tp; - xfs_mount_t *mp; int error; xfs_bmap_free_t free_list; xfs_fsblock_t first_block; int cancel_flags; int committed; - bhv_vnode_t *dir_vp; int dm_di_mode = S_IFDIR; int last_cdp_link; - int namelen; uint resblks; - dir_vp = BHV_TO_VNODE(dir_bdp); - dp = XFS_BHVTOI(dir_bdp); - mp = dp->i_mount; - - vn_trace_entry(dir_vp, __FUNCTION__, (inst_t *)__return_address); + vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); - if (XFS_FORCED_SHUTDOWN(XFS_BHVTOI(dir_bdp)->i_mount)) + if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); - namelen = VNAMELEN(dentry); if (!xfs_get_dir_entry(dentry, &cdp)) { dm_di_mode = cdp->i_d.di_mode; IRELE(cdp); } - if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_REMOVE)) { + if (DM_EVENT_ENABLED(dp, DM_EVENT_REMOVE)) { error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE, dir_vp, DM_RIGHT_NULL, NULL, DM_RIGHT_NULL, @@ -3260,17 +3125,12 @@ xfs_rmdir( } - /* - * Let interposed file systems know about removed links. - */ - bhv_vop_link_removed(XFS_ITOV(cdp), dir_vp, last_cdp_link); - IRELE(cdp); /* Fall through to std_return with error = 0 or the errno * from xfs_trans_commit. */ std_return: - if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_POSTREMOVE)) { + if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTREMOVE)) { (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTREMOVE, dir_vp, DM_RIGHT_NULL, NULL, DM_RIGHT_NULL, @@ -3289,56 +3149,24 @@ xfs_rmdir( goto std_return; } - -/* - * Read dp's entries starting at uiop->uio_offset and translate them into - * bufsize bytes worth of struct dirents starting at bufbase. - */ -STATIC int -xfs_readdir( - bhv_desc_t *dir_bdp, - uio_t *uiop, - cred_t *credp, - int *eofp) -{ - xfs_inode_t *dp; - xfs_trans_t *tp = NULL; - int error = 0; - uint lock_mode; - - vn_trace_entry(BHV_TO_VNODE(dir_bdp), __FUNCTION__, - (inst_t *)__return_address); - dp = XFS_BHVTOI(dir_bdp); - - if (XFS_FORCED_SHUTDOWN(dp->i_mount)) - return XFS_ERROR(EIO); - - lock_mode = xfs_ilock_map_shared(dp); - error = xfs_dir_getdents(tp, dp, uiop, eofp); - xfs_iunlock_map_shared(dp, lock_mode); - return error; -} - - -STATIC int +int xfs_symlink( - bhv_desc_t *dir_bdp, + xfs_inode_t *dp, bhv_vname_t *dentry, - bhv_vattr_t *vap, char *target_path, + mode_t mode, bhv_vnode_t **vpp, cred_t *credp) { + bhv_vnode_t *dir_vp = XFS_ITOV(dp); + xfs_mount_t *mp = dp->i_mount; xfs_trans_t *tp; - xfs_mount_t *mp; - xfs_inode_t *dp; xfs_inode_t *ip; int error; int pathlen; xfs_bmap_free_t free_list; xfs_fsblock_t first_block; - boolean_t dp_joined_to_trans; - bhv_vnode_t *dir_vp; + boolean_t unlock_dp_on_error = B_FALSE; uint cancel_flags; int committed; xfs_fileoff_t first_fsb; @@ -3357,16 +3185,12 @@ xfs_symlink( int link_namelen; *vpp = NULL; - dir_vp = BHV_TO_VNODE(dir_bdp); - dp = XFS_BHVTOI(dir_bdp); - dp_joined_to_trans = B_FALSE; error = 0; ip = NULL; tp = NULL; - vn_trace_entry(dir_vp, __FUNCTION__, (inst_t *)__return_address); + vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); - mp = dp->i_mount; if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); @@ -3405,7 +3229,7 @@ xfs_symlink( } } - if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_SYMLINK)) { + if (DM_EVENT_ENABLED(dp, DM_EVENT_SYMLINK)) { error = XFS_SEND_NAMESP(mp, DM_EVENT_SYMLINK, dir_vp, DM_RIGHT_NULL, NULL, DM_RIGHT_NULL, link_name, target_path, 0, 0, 0); @@ -3418,8 +3242,6 @@ xfs_symlink( udqp = gdqp = NULL; if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) prid = dp->i_d.di_projid; - else if (vap->va_mask & XFS_AT_PROJID) - prid = (xfs_prid_t)vap->va_projid; else prid = (xfs_prid_t)dfltprid; @@ -3452,11 +3274,11 @@ xfs_symlink( } if (error) { cancel_flags = 0; - dp = NULL; goto error_return; } xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); + unlock_dp_on_error = B_TRUE; /* * Check whether the directory allows new symlinks or not. @@ -3488,7 +3310,7 @@ xfs_symlink( /* * Allocate an inode for the symlink. */ - error = xfs_dir_ialloc(&tp, dp, S_IFLNK | (vap->va_mode&~S_IFMT), + error = xfs_dir_ialloc(&tp, dp, S_IFLNK | (mode & ~S_IFMT), 1, 0, credp, prid, resblks > 0, &ip, NULL); if (error) { if (error == ENOSPC) @@ -3497,9 +3319,14 @@ xfs_symlink( } ITRACE(ip); + /* + * An error after we've joined dp to the transaction will result in the + * transaction cancel unlocking dp so don't do it explicitly in the + * error path. + */ VN_HOLD(dir_vp); xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); - dp_joined_to_trans = B_TRUE; + unlock_dp_on_error = B_FALSE; /* * Also attach the dquot(s) to it, if applicable. @@ -3605,8 +3432,7 @@ xfs_symlink( /* Fall through to std_return with error = 0 or errno from * xfs_trans_commit */ std_return: - if (DM_EVENT_ENABLED(dir_vp->v_vfsp, XFS_BHVTOI(dir_bdp), - DM_EVENT_POSTSYMLINK)) { + if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTSYMLINK)) { (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTSYMLINK, dir_vp, DM_RIGHT_NULL, error ? NULL : XFS_ITOV(ip), @@ -3633,35 +3459,21 @@ std_return: XFS_QM_DQRELE(mp, udqp); XFS_QM_DQRELE(mp, gdqp); - if (!dp_joined_to_trans && (dp != NULL)) { + if (unlock_dp_on_error) xfs_iunlock(dp, XFS_ILOCK_EXCL); - } goto std_return; } -/* - * xfs_fid2 - * - * A fid routine that takes a pointer to a previously allocated - * fid structure (like xfs_fast_fid) but uses a 64 bit inode number. - */ -STATIC int +int xfs_fid2( - bhv_desc_t *bdp, - fid_t *fidp) + xfs_inode_t *ip, + xfs_fid_t *xfid) { - xfs_inode_t *ip; - xfs_fid2_t *xfid; - - vn_trace_entry(BHV_TO_VNODE(bdp), __FUNCTION__, - (inst_t *)__return_address); - ASSERT(sizeof(fid_t) >= sizeof(xfs_fid2_t)); + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); - xfid = (xfs_fid2_t *)fidp; - ip = XFS_BHVTOI(bdp); - xfid->fid_len = sizeof(xfs_fid2_t) - sizeof(xfid->fid_len); + xfid->fid_len = sizeof(xfs_fid_t) - sizeof(xfid->fid_len); xfid->fid_pad = 0; /* * use memcpy because the inode is a long long and there's no @@ -3674,21 +3486,13 @@ xfs_fid2( } -/* - * xfs_rwlock - */ int xfs_rwlock( - bhv_desc_t *bdp, + xfs_inode_t *ip, bhv_vrwlock_t locktype) { - xfs_inode_t *ip; - bhv_vnode_t *vp; - - vp = BHV_TO_VNODE(bdp); - if (VN_ISDIR(vp)) + if (S_ISDIR(ip->i_d.di_mode)) return 1; - ip = XFS_BHVTOI(bdp); if (locktype == VRWLOCK_WRITE) { xfs_ilock(ip, XFS_IOLOCK_EXCL); } else if (locktype == VRWLOCK_TRY_READ) { @@ -3705,21 +3509,13 @@ xfs_rwlock( } -/* - * xfs_rwunlock - */ void xfs_rwunlock( - bhv_desc_t *bdp, + xfs_inode_t *ip, bhv_vrwlock_t locktype) { - xfs_inode_t *ip; - bhv_vnode_t *vp; - - vp = BHV_TO_VNODE(bdp); - if (VN_ISDIR(vp)) - return; - ip = XFS_BHVTOI(bdp); + if (S_ISDIR(ip->i_d.di_mode)) + return; if (locktype == VRWLOCK_WRITE) { /* * In the write case, we may have added a new entry to @@ -3737,20 +3533,16 @@ xfs_rwunlock( return; } -STATIC int + +int xfs_inode_flush( - bhv_desc_t *bdp, + xfs_inode_t *ip, int flags) { - xfs_inode_t *ip; - xfs_mount_t *mp; - xfs_inode_log_item_t *iip; + xfs_mount_t *mp = ip->i_mount; + xfs_inode_log_item_t *iip = ip->i_itemp; int error = 0; - ip = XFS_BHVTOI(bdp); - mp = ip->i_mount; - iip = ip->i_itemp; - if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); @@ -3819,24 +3611,20 @@ xfs_inode_flush( return error; } + int -xfs_set_dmattrs ( - bhv_desc_t *bdp, +xfs_set_dmattrs( + xfs_inode_t *ip, u_int evmask, - u_int16_t state, - cred_t *credp) + u_int16_t state) { - xfs_inode_t *ip; + xfs_mount_t *mp = ip->i_mount; xfs_trans_t *tp; - xfs_mount_t *mp; int error; if (!capable(CAP_SYS_ADMIN)) return XFS_ERROR(EPERM); - ip = XFS_BHVTOI(bdp); - mp = ip->i_mount; - if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); @@ -3859,17 +3647,13 @@ xfs_set_dmattrs ( return error; } -STATIC int +int xfs_reclaim( - bhv_desc_t *bdp) + xfs_inode_t *ip) { - xfs_inode_t *ip; - bhv_vnode_t *vp; - - vp = BHV_TO_VNODE(bdp); - ip = XFS_BHVTOI(bdp); + bhv_vnode_t *vp = XFS_ITOV(ip); - vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); ASSERT(!VN_MAPPED(vp)); @@ -3879,7 +3663,7 @@ xfs_reclaim( return 0; } - vn_iowait(vp); + vn_iowait(ip); ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || ip->i_delayed_blks == 0); @@ -3911,7 +3695,8 @@ xfs_reclaim( XFS_MOUNT_ILOCK(mp); spin_lock(&ip->i_flags_lock); __xfs_iflags_set(ip, XFS_IRECLAIMABLE); - vn_bhv_remove(VN_BHV_HEAD(vp), XFS_ITOBHV(ip)); + vn_to_inode(vp)->i_private = NULL; + ip->i_vnode = NULL; spin_unlock(&ip->i_flags_lock); list_add_tail(&ip->i_reclaim, &mp->m_del_inodes); XFS_MOUNT_IUNLOCK(mp); @@ -3925,7 +3710,7 @@ xfs_finish_reclaim( int locked, int sync_mode) { - xfs_ihash_t *ih = ip->i_hash; + xfs_perag_t *pag = xfs_get_perag(ip->i_mount, ip->i_ino); bhv_vnode_t *vp = XFS_ITOV_NULL(ip); int error; @@ -3937,12 +3722,12 @@ xfs_finish_reclaim( * Once we have the XFS_IRECLAIM flag set it will not touch * us. */ - write_lock(&ih->ih_lock); + write_lock(&pag->pag_ici_lock); spin_lock(&ip->i_flags_lock); if (__xfs_iflags_test(ip, XFS_IRECLAIM) || (!__xfs_iflags_test(ip, XFS_IRECLAIMABLE) && vp == NULL)) { spin_unlock(&ip->i_flags_lock); - write_unlock(&ih->ih_lock); + write_unlock(&pag->pag_ici_lock); if (locked) { xfs_ifunlock(ip); xfs_iunlock(ip, XFS_ILOCK_EXCL); @@ -3951,7 +3736,8 @@ xfs_finish_reclaim( } __xfs_iflags_set(ip, XFS_IRECLAIM); spin_unlock(&ip->i_flags_lock); - write_unlock(&ih->ih_lock); + write_unlock(&pag->pag_ici_lock); + xfs_put_perag(ip->i_mount, pag); /* * If the inode is still dirty, then flush it out. If the inode @@ -4085,7 +3871,7 @@ xfs_alloc_file_space( int committed; int error; - vn_trace_entry(XFS_ITOV(ip), __FUNCTION__, (inst_t *)__return_address); + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); @@ -4109,7 +3895,7 @@ xfs_alloc_file_space( /* Generate a DMAPI event if needed. */ if (alloc_type != 0 && offset < ip->i_size && (attr_flags&ATTR_DMI) == 0 && - DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_WRITE)) { + DM_EVENT_ENABLED(ip, DM_EVENT_WRITE)) { xfs_off_t end_dmi_offset; end_dmi_offset = offset+len; @@ -4223,9 +4009,8 @@ retry: allocatesize_fsb -= allocated_fsb; } dmapi_enospc_check: - if (error == ENOSPC && (attr_flags&ATTR_DMI) == 0 && - DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_NOSPACE)) { - + if (error == ENOSPC && (attr_flags & ATTR_DMI) == 0 && + DM_EVENT_ENABLED(ip, DM_EVENT_NOSPACE)) { error = XFS_SEND_NAMESP(mp, DM_EVENT_NOSPACE, XFS_ITOV(ip), DM_RIGHT_NULL, XFS_ITOV(ip), DM_RIGHT_NULL, @@ -4356,7 +4141,7 @@ xfs_free_file_space( vp = XFS_ITOV(ip); mp = ip->i_mount; - vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); if ((error = XFS_QM_DQATTACH(mp, ip, 0))) return error; @@ -4369,9 +4154,8 @@ xfs_free_file_space( end_dmi_offset = offset + len; endoffset_fsb = XFS_B_TO_FSBT(mp, end_dmi_offset); - if (offset < ip->i_size && - (attr_flags & ATTR_DMI) == 0 && - DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_WRITE)) { + if (offset < ip->i_size && (attr_flags & ATTR_DMI) == 0 && + DM_EVENT_ENABLED(ip, DM_EVENT_WRITE)) { if (end_dmi_offset > ip->i_size) end_dmi_offset = ip->i_size; error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, vp, @@ -4385,7 +4169,7 @@ xfs_free_file_space( need_iolock = 0; if (need_iolock) { xfs_ilock(ip, XFS_IOLOCK_EXCL); - vn_iowait(vp); /* wait for the completion of any pending DIOs */ + vn_iowait(ip); /* wait for the completion of any pending DIOs */ } rounding = max_t(uint, 1 << mp->m_sb.sb_blocklog, NBPP); @@ -4394,7 +4178,8 @@ xfs_free_file_space( if (VN_CACHED(vp) != 0) { xfs_inval_cached_trace(&ip->i_iocore, ioffset, -1, ctooff(offtoct(ioffset)), -1); - error = bhv_vop_flushinval_pages(vp, ctooff(offtoct(ioffset)), + error = xfs_flushinval_pages(ip, + ctooff(offtoct(ioffset)), -1, FI_REMAPF_LOCKED); if (error) goto out_unlock_iolock; @@ -4545,35 +4330,29 @@ xfs_free_file_space( */ int xfs_change_file_space( - bhv_desc_t *bdp, + xfs_inode_t *ip, int cmd, xfs_flock64_t *bf, xfs_off_t offset, cred_t *credp, int attr_flags) { + xfs_mount_t *mp = ip->i_mount; int clrprealloc; int error; xfs_fsize_t fsize; - xfs_inode_t *ip; - xfs_mount_t *mp; int setprealloc; xfs_off_t startoffset; xfs_off_t llen; xfs_trans_t *tp; bhv_vattr_t va; - bhv_vnode_t *vp; - vp = BHV_TO_VNODE(bdp); - vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); - - ip = XFS_BHVTOI(bdp); - mp = ip->i_mount; + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); /* * must be a regular file and have write permission */ - if (!VN_ISREG(vp)) + if (!S_ISREG(ip->i_d.di_mode)) return XFS_ERROR(EINVAL); xfs_ilock(ip, XFS_ILOCK_SHARED); @@ -4655,7 +4434,7 @@ xfs_change_file_space( va.va_mask = XFS_AT_SIZE; va.va_size = startoffset; - error = xfs_setattr(bdp, &va, attr_flags, credp); + error = xfs_setattr(ip, &va, attr_flags, credp); if (error) return error; @@ -4714,46 +4493,3 @@ xfs_change_file_space( return error; } - -bhv_vnodeops_t xfs_vnodeops = { - BHV_IDENTITY_INIT(VN_BHV_XFS,VNODE_POSITION_XFS), - .vop_open = xfs_open, - .vop_read = xfs_read, -#ifdef HAVE_SPLICE - .vop_splice_read = xfs_splice_read, - .vop_splice_write = xfs_splice_write, -#endif - .vop_write = xfs_write, - .vop_ioctl = xfs_ioctl, - .vop_getattr = xfs_getattr, - .vop_setattr = xfs_setattr, - .vop_access = xfs_access, - .vop_lookup = xfs_lookup, - .vop_create = xfs_create, - .vop_remove = xfs_remove, - .vop_link = xfs_link, - .vop_rename = xfs_rename, - .vop_mkdir = xfs_mkdir, - .vop_rmdir = xfs_rmdir, - .vop_readdir = xfs_readdir, - .vop_symlink = xfs_symlink, - .vop_readlink = xfs_readlink, - .vop_fsync = xfs_fsync, - .vop_inactive = xfs_inactive, - .vop_fid2 = xfs_fid2, - .vop_rwlock = xfs_rwlock, - .vop_rwunlock = xfs_rwunlock, - .vop_bmap = xfs_bmap, - .vop_reclaim = xfs_reclaim, - .vop_attr_get = xfs_attr_get, - .vop_attr_set = xfs_attr_set, - .vop_attr_remove = xfs_attr_remove, - .vop_attr_list = xfs_attr_list, - .vop_link_removed = (vop_link_removed_t)fs_noval, - .vop_vnode_change = (vop_vnode_change_t)fs_noval, - .vop_tosspages = fs_tosspages, - .vop_flushinval_pages = fs_flushinval_pages, - .vop_flush_pages = fs_flush_pages, - .vop_release = xfs_release, - .vop_iflush = xfs_inode_flush, -}; diff --git a/fs/xfs/xfs_vnodeops.h b/fs/xfs/xfs_vnodeops.h new file mode 100644 index 000000000000..b7e461c40cfb --- /dev/null +++ b/fs/xfs/xfs_vnodeops.h @@ -0,0 +1,86 @@ +#ifndef _XFS_VNODEOPS_H +#define _XFS_VNODEOPS_H 1 + +struct attrlist_cursor_kern; +struct bhv_vattr; +struct cred; +struct file; +struct inode; +struct iovec; +struct kiocb; +struct pipe_inode_info; +struct uio; +struct xfs_inode; +struct xfs_iomap; + + +int xfs_open(struct xfs_inode *ip); +int xfs_getattr(struct xfs_inode *ip, struct bhv_vattr *vap, int flags); +int xfs_setattr(struct xfs_inode *ip, struct bhv_vattr *vap, int flags, + struct cred *credp); +int xfs_access(struct xfs_inode *ip, int mode, struct cred *credp); +int xfs_readlink(struct xfs_inode *ip, char *link); +int xfs_fsync(struct xfs_inode *ip, int flag, xfs_off_t start, + xfs_off_t stop); +int xfs_release(struct xfs_inode *ip); +int xfs_inactive(struct xfs_inode *ip); +int xfs_lookup(struct xfs_inode *dp, bhv_vname_t *dentry, + bhv_vnode_t **vpp); +int xfs_create(struct xfs_inode *dp, bhv_vname_t *dentry, mode_t mode, + xfs_dev_t rdev, bhv_vnode_t **vpp, struct cred *credp); +int xfs_remove(struct xfs_inode *dp, bhv_vname_t *dentry); +int xfs_link(struct xfs_inode *tdp, bhv_vnode_t *src_vp, + bhv_vname_t *dentry); +int xfs_mkdir(struct xfs_inode *dp, bhv_vname_t *dentry, + mode_t mode, bhv_vnode_t **vpp, struct cred *credp); +int xfs_rmdir(struct xfs_inode *dp, bhv_vname_t *dentry); +int xfs_readdir(struct xfs_inode *dp, void *dirent, size_t bufsize, + xfs_off_t *offset, filldir_t filldir); +int xfs_symlink(struct xfs_inode *dp, bhv_vname_t *dentry, + char *target_path, mode_t mode, bhv_vnode_t **vpp, + struct cred *credp); +int xfs_fid2(struct xfs_inode *ip, struct xfs_fid *xfid); +int xfs_rwlock(struct xfs_inode *ip, bhv_vrwlock_t locktype); +void xfs_rwunlock(struct xfs_inode *ip, bhv_vrwlock_t locktype); +int xfs_inode_flush(struct xfs_inode *ip, int flags); +int xfs_set_dmattrs(struct xfs_inode *ip, u_int evmask, u_int16_t state); +int xfs_reclaim(struct xfs_inode *ip); +int xfs_change_file_space(struct xfs_inode *ip, int cmd, + xfs_flock64_t *bf, xfs_off_t offset, + struct cred *credp, int attr_flags); +int xfs_rename(struct xfs_inode *src_dp, bhv_vname_t *src_vname, + bhv_vnode_t *target_dir_vp, bhv_vname_t *target_vname); +int xfs_attr_get(struct xfs_inode *ip, const char *name, char *value, + int *valuelenp, int flags, cred_t *cred); +int xfs_attr_set(struct xfs_inode *dp, const char *name, char *value, + int valuelen, int flags); +int xfs_attr_remove(struct xfs_inode *dp, const char *name, int flags); +int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize, + int flags, struct attrlist_cursor_kern *cursor); +int xfs_ioctl(struct xfs_inode *ip, struct file *filp, + int ioflags, unsigned int cmd, void __user *arg); +ssize_t xfs_read(struct xfs_inode *ip, struct kiocb *iocb, + const struct iovec *iovp, unsigned int segs, + loff_t *offset, int ioflags); +ssize_t xfs_sendfile(struct xfs_inode *ip, struct file *filp, + loff_t *offset, int ioflags, size_t count, + read_actor_t actor, void *target); +ssize_t xfs_splice_read(struct xfs_inode *ip, struct file *infilp, + loff_t *ppos, struct pipe_inode_info *pipe, size_t count, + int flags, int ioflags); +ssize_t xfs_splice_write(struct xfs_inode *ip, + struct pipe_inode_info *pipe, struct file *outfilp, + loff_t *ppos, size_t count, int flags, int ioflags); +ssize_t xfs_write(struct xfs_inode *xip, struct kiocb *iocb, + const struct iovec *iovp, unsigned int nsegs, + loff_t *offset, int ioflags); +int xfs_bmap(struct xfs_inode *ip, xfs_off_t offset, ssize_t count, + int flags, struct xfs_iomap *iomapp, int *niomaps); +void xfs_tosspages(struct xfs_inode *inode, xfs_off_t first, + xfs_off_t last, int fiopt); +int xfs_flushinval_pages(struct xfs_inode *ip, xfs_off_t first, + xfs_off_t last, int fiopt); +int xfs_flush_pages(struct xfs_inode *ip, xfs_off_t first, + xfs_off_t last, uint64_t flags, int fiopt); + +#endif /* _XFS_VNODEOPS_H */ |