diff options
Diffstat (limited to 'fs')
267 files changed, 1920 insertions, 7706 deletions
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h index 410ffd6ceb5f..dc95a252523d 100644 --- a/fs/9p/v9fs_vfs.h +++ b/fs/9p/v9fs_vfs.h @@ -54,9 +54,9 @@ extern struct kmem_cache *v9fs_inode_cache; struct inode *v9fs_alloc_inode(struct super_block *sb); void v9fs_destroy_inode(struct inode *inode); -struct inode *v9fs_get_inode(struct super_block *sb, int mode, dev_t); +struct inode *v9fs_get_inode(struct super_block *sb, umode_t mode, dev_t); int v9fs_init_inode(struct v9fs_session_info *v9ses, - struct inode *inode, int mode, dev_t); + struct inode *inode, umode_t mode, dev_t); void v9fs_evict_inode(struct inode *inode); ino_t v9fs_qid2ino(struct p9_qid *qid); void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *); diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 879ed8851737..e0f20de6aa2b 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -59,15 +59,13 @@ static const struct inode_operations v9fs_symlink_inode_operations; * */ -static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode) +static u32 unixmode2p9mode(struct v9fs_session_info *v9ses, umode_t mode) { int res; res = mode & 0777; if (S_ISDIR(mode)) res |= P9_DMDIR; if (v9fs_proto_dotu(v9ses)) { - if (S_ISLNK(mode)) - res |= P9_DMSYMLINK; if (v9ses->nodev == 0) { if (S_ISSOCK(mode)) res |= P9_DMSOCKET; @@ -85,10 +83,7 @@ static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode) res |= P9_DMSETGID; if ((mode & S_ISVTX) == S_ISVTX) res |= P9_DMSETVTX; - if ((mode & P9_DMLINK)) - res |= P9_DMLINK; } - return res; } @@ -99,11 +94,11 @@ static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode) * @rdev: major number, minor number in case of device files. * */ -static int p9mode2unixmode(struct v9fs_session_info *v9ses, - struct p9_wstat *stat, dev_t *rdev) +static umode_t p9mode2unixmode(struct v9fs_session_info *v9ses, + struct p9_wstat *stat, dev_t *rdev) { int res; - int mode = stat->mode; + u32 mode = stat->mode; res = mode & S_IALLUGO; *rdev = 0; @@ -251,7 +246,6 @@ struct inode *v9fs_alloc_inode(struct super_block *sb) static void v9fs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(v9fs_inode_cache, V9FS_I(inode)); } @@ -261,7 +255,7 @@ void v9fs_destroy_inode(struct inode *inode) } int v9fs_init_inode(struct v9fs_session_info *v9ses, - struct inode *inode, int mode, dev_t rdev) + struct inode *inode, umode_t mode, dev_t rdev) { int err = 0; @@ -335,7 +329,7 @@ int v9fs_init_inode(struct v9fs_session_info *v9ses, break; default: - P9_DPRINTK(P9_DEBUG_ERROR, "BAD mode 0x%x S_IFMT 0x%x\n", + P9_DPRINTK(P9_DEBUG_ERROR, "BAD mode 0x%hx S_IFMT 0x%x\n", mode, mode & S_IFMT); err = -EINVAL; goto error; @@ -352,13 +346,13 @@ error: * */ -struct inode *v9fs_get_inode(struct super_block *sb, int mode, dev_t rdev) +struct inode *v9fs_get_inode(struct super_block *sb, umode_t mode, dev_t rdev) { int err; struct inode *inode; struct v9fs_session_info *v9ses = sb->s_fs_info; - P9_DPRINTK(P9_DEBUG_VFS, "super block: %p mode: %o\n", sb, mode); + P9_DPRINTK(P9_DEBUG_VFS, "super block: %p mode: %ho\n", sb, mode); inode = new_inode(sb); if (!inode) { @@ -492,7 +486,8 @@ static struct inode *v9fs_qid_iget(struct super_block *sb, int new) { dev_t rdev; - int retval, umode; + int retval; + umode_t umode; unsigned long i_ino; struct inode *inode; struct v9fs_session_info *v9ses = sb->s_fs_info; @@ -703,7 +698,7 @@ error: */ static int -v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, +v9fs_vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { int err; @@ -786,7 +781,7 @@ error: * */ -static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { int err; u32 perm; @@ -1131,7 +1126,7 @@ void v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode, struct super_block *sb) { - mode_t mode; + umode_t mode; char ext[32]; char tag_name[14]; unsigned int i_nlink; @@ -1304,9 +1299,8 @@ v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p) */ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, - int mode, const char *extension) + u32 perm, const char *extension) { - u32 perm; struct p9_fid *fid; struct v9fs_session_info *v9ses; @@ -1316,7 +1310,6 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, return -EPERM; } - perm = unixmode2p9mode(v9ses, mode); fid = v9fs_create(v9ses, dir, dentry, (char *) extension, perm, P9_OREAD); if (IS_ERR(fid)) @@ -1343,7 +1336,7 @@ v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) P9_DPRINTK(P9_DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, symname); - return v9fs_vfs_mkspecial(dir, dentry, S_IFLNK, symname); + return v9fs_vfs_mkspecial(dir, dentry, P9_DMSYMLINK, symname); } /** @@ -1398,13 +1391,15 @@ clunk_fid: */ static int -v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) +v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { + struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); int retval; char *name; + u32 perm; P9_DPRINTK(P9_DEBUG_VFS, - " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, + " %lu,%s mode: %hx MAJOR: %u MINOR: %u\n", dir->i_ino, dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); if (!new_valid_dev(rdev)) @@ -1427,7 +1422,8 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) return -EINVAL; } - retval = v9fs_vfs_mkspecial(dir, dentry, mode, name); + perm = unixmode2p9mode(v9ses, mode); + retval = v9fs_vfs_mkspecial(dir, dentry, perm, name); __putname(name); return retval; diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index 0b5745e21946..8ef152ac6a16 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -48,7 +48,7 @@ #include "acl.h" static int -v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode, +v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode, dev_t rdev); /** @@ -253,7 +253,7 @@ int v9fs_open_to_dotl_flags(int flags) */ static int -v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, +v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode, struct nameidata *nd) { int err = 0; @@ -284,7 +284,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, name = (char *) dentry->d_name.name; P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_create_dotl: name:%s flags:0x%x " - "mode:0x%x\n", name, flags, omode); + "mode:0x%hx\n", name, flags, omode); dfid = v9fs_fid_lookup(dentry->d_parent); if (IS_ERR(dfid)) { @@ -395,7 +395,7 @@ err_clunk_old_fid: */ static int v9fs_vfs_mkdir_dotl(struct inode *dir, - struct dentry *dentry, int omode) + struct dentry *dentry, umode_t omode) { int err; struct v9fs_session_info *v9ses; @@ -594,7 +594,7 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) void v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode) { - mode_t mode; + umode_t mode; struct v9fs_inode *v9inode = V9FS_I(inode); if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) { @@ -799,7 +799,7 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir, * */ static int -v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode, +v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode, dev_t rdev) { int err; @@ -814,7 +814,7 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode, struct posix_acl *dacl = NULL, *pacl = NULL; P9_DPRINTK(P9_DEBUG_VFS, - " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, + " %lu,%s mode: %hx MAJOR: %u MINOR: %u\n", dir->i_ino, dentry->d_name.name, omode, MAJOR(rdev), MINOR(rdev)); if (!new_valid_dev(rdev)) diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index c70251d47ed1..f68ff65a32a5 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -117,7 +117,7 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags, struct inode *inode = NULL; struct dentry *root = NULL; struct v9fs_session_info *v9ses = NULL; - int mode = S_IRWXUGO | S_ISVTX; + umode_t mode = S_IRWXUGO | S_ISVTX; struct p9_fid *fid; int retval = 0; diff --git a/fs/Kconfig b/fs/Kconfig index 5f4c45d4aa10..30145d886bc2 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -266,14 +266,6 @@ source "fs/9p/Kconfig" endif # NETWORK_FILESYSTEMS -if BLOCK -menu "Partition Types" - -source "fs/partitions/Kconfig" - -endmenu -endif - source "fs/nls/Kconfig" source "fs/dlm/Kconfig" diff --git a/fs/Makefile b/fs/Makefile index d2c3353d5477..93804d4d66e1 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -19,6 +19,8 @@ else obj-y += no-block.o endif +obj-$(CONFIG_PROC_FS) += proc_namespace.o + obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o obj-y += notify/ obj-$(CONFIG_EPOLL) += eventpoll.o @@ -52,7 +54,6 @@ obj-$(CONFIG_FHANDLE) += fhandle.o obj-y += quota/ obj-$(CONFIG_PROC_FS) += proc/ -obj-y += partitions/ obj-$(CONFIG_SYSFS) += sysfs/ obj-$(CONFIG_CONFIGFS_FS) += configfs/ obj-y += devpts/ diff --git a/fs/adfs/super.c b/fs/adfs/super.c index c8bf36a1996a..8e3b36ace305 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -126,9 +126,9 @@ static void adfs_put_super(struct super_block *sb) sb->s_fs_info = NULL; } -static int adfs_show_options(struct seq_file *seq, struct vfsmount *mnt) +static int adfs_show_options(struct seq_file *seq, struct dentry *root) { - struct adfs_sb_info *asb = ADFS_SB(mnt->mnt_sb); + struct adfs_sb_info *asb = ADFS_SB(root->d_sb); if (asb->s_uid != 0) seq_printf(seq, ",uid=%u", asb->s_uid); diff --git a/fs/affs/affs.h b/fs/affs/affs.h index c2b9c79eb64e..45a0ce45d7b4 100644 --- a/fs/affs/affs.h +++ b/fs/affs/affs.h @@ -136,7 +136,7 @@ extern int affs_remove_header(struct dentry *dentry); extern u32 affs_checksum_block(struct super_block *sb, struct buffer_head *bh); extern void affs_fix_checksum(struct super_block *sb, struct buffer_head *bh); extern void secs_to_datestamp(time_t secs, struct affs_date *ds); -extern mode_t prot_to_mode(u32 prot); +extern umode_t prot_to_mode(u32 prot); extern void mode_to_prot(struct inode *inode); extern void affs_error(struct super_block *sb, const char *function, const char *fmt, ...); extern void affs_warning(struct super_block *sb, const char *function, const char *fmt, ...); @@ -156,8 +156,8 @@ extern void affs_free_bitmap(struct super_block *sb); extern int affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len); extern struct dentry *affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *); extern int affs_unlink(struct inode *dir, struct dentry *dentry); -extern int affs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *); -extern int affs_mkdir(struct inode *dir, struct dentry *dentry, int mode); +extern int affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *); +extern int affs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode); extern int affs_rmdir(struct inode *dir, struct dentry *dentry); extern int affs_link(struct dentry *olddentry, struct inode *dir, struct dentry *dentry); diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c index de37ec842340..52a6407682e6 100644 --- a/fs/affs/amigaffs.c +++ b/fs/affs/amigaffs.c @@ -390,10 +390,10 @@ secs_to_datestamp(time_t secs, struct affs_date *ds) ds->ticks = cpu_to_be32(secs * 50); } -mode_t +umode_t prot_to_mode(u32 prot) { - int mode = 0; + umode_t mode = 0; if (!(prot & FIBF_NOWRITE)) mode |= S_IWUSR; @@ -421,7 +421,7 @@ void mode_to_prot(struct inode *inode) { u32 prot = AFFS_I(inode)->i_protect; - mode_t mode = inode->i_mode; + umode_t mode = inode->i_mode; if (!(mode & S_IXUSR)) prot |= FIBF_NOEXECUTE; diff --git a/fs/affs/namei.c b/fs/affs/namei.c index 780a11dc6318..47806940aac0 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -255,13 +255,13 @@ affs_unlink(struct inode *dir, struct dentry *dentry) } int -affs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) +affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { struct super_block *sb = dir->i_sb; struct inode *inode; int error; - pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,(int)dentry->d_name.len, + pr_debug("AFFS: create(%lu,\"%.*s\",0%ho)\n",dir->i_ino,(int)dentry->d_name.len, dentry->d_name.name,mode); inode = affs_new_inode(dir); @@ -285,12 +285,12 @@ affs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata } int -affs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +affs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct inode *inode; int error; - pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino, + pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%ho)\n",dir->i_ino, (int)dentry->d_name.len,dentry->d_name.name,mode); inode = affs_new_inode(dir); diff --git a/fs/affs/super.c b/fs/affs/super.c index b31507d0f9b9..8ba73fed7964 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -98,7 +98,6 @@ static struct inode *affs_alloc_inode(struct super_block *sb) static void affs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(affs_inode_cachep, AFFS_I(inode)); } diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 1b0b19550015..e22dc4b4a503 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -28,9 +28,9 @@ static int afs_d_delete(const struct dentry *dentry); static void afs_d_release(struct dentry *dentry); static int afs_lookup_filldir(void *_cookie, const char *name, int nlen, loff_t fpos, u64 ino, unsigned dtype); -static int afs_create(struct inode *dir, struct dentry *dentry, int mode, +static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd); -static int afs_mkdir(struct inode *dir, struct dentry *dentry, int mode); +static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode); static int afs_rmdir(struct inode *dir, struct dentry *dentry); static int afs_unlink(struct inode *dir, struct dentry *dentry); static int afs_link(struct dentry *from, struct inode *dir, @@ -764,7 +764,7 @@ static void afs_d_release(struct dentry *dentry) /* * create a directory on an AFS filesystem */ -static int afs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct afs_file_status status; struct afs_callback cb; @@ -777,7 +777,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, int mode) dvnode = AFS_FS_I(dir); - _enter("{%x:%u},{%s},%o", + _enter("{%x:%u},{%s},%ho", dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode); ret = -ENAMETOOLONG; @@ -948,7 +948,7 @@ error: /* * create a regular file on an AFS filesystem */ -static int afs_create(struct inode *dir, struct dentry *dentry, int mode, +static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { struct afs_file_status status; @@ -962,7 +962,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, int mode, dvnode = AFS_FS_I(dir); - _enter("{%x:%u},{%s},%o,", + _enter("{%x:%u},{%s},%ho,", dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode); ret = -ENAMETOOLONG; diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index aa59184151d0..8f4ce2658b7d 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c @@ -242,7 +242,7 @@ struct vfsmount *afs_d_automount(struct path *path) { struct vfsmount *newmnt; - _enter("{%s,%s}", path->mnt->mnt_devname, path->dentry->d_name.name); + _enter("{%s}", path->dentry->d_name.name); newmnt = afs_mntpt_do_automount(path->dentry); if (IS_ERR(newmnt)) @@ -252,7 +252,7 @@ struct vfsmount *afs_d_automount(struct path *path) mnt_set_expiry(newmnt, &afs_vfsmounts); queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer, afs_mntpt_expiry_timeout * HZ); - _leave(" = %p {%s}", newmnt, newmnt->mnt_devname); + _leave(" = %p", newmnt); return newmnt; } diff --git a/fs/afs/super.c b/fs/afs/super.c index 356dcf0929e8..983ec59fc80d 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -495,7 +495,6 @@ static void afs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); struct afs_vnode *vnode = AFS_FS_I(inode); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(afs_inode_cachep, vnode); } diff --git a/fs/attr.c b/fs/attr.c index 7ee7ba488313..95053ad8abcc 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -166,7 +166,7 @@ EXPORT_SYMBOL(setattr_copy); int notify_change(struct dentry * dentry, struct iattr * attr) { struct inode *inode = dentry->d_inode; - mode_t mode = inode->i_mode; + umode_t mode = inode->i_mode; int error; struct timespec now; unsigned int ia_valid = attr->ia_valid; @@ -177,7 +177,7 @@ int notify_change(struct dentry * dentry, struct iattr * attr) } if ((ia_valid & ATTR_MODE)) { - mode_t amode = attr->ia_mode; + umode_t amode = attr->ia_mode; /* Flag setting protected by i_mutex */ if (is_sxid(amode)) inode->i_flags &= ~S_NOSEC; diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index 326dc08d3e3f..5869d4e974a9 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h @@ -155,7 +155,7 @@ static inline int autofs4_ispending(struct dentry *dentry) return 0; } -struct inode *autofs4_get_inode(struct super_block *, mode_t); +struct inode *autofs4_get_inode(struct super_block *, umode_t); void autofs4_free_ino(struct autofs_info *); /* Expiration */ diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c index 509fe1eb66ae..76741d8d7786 100644 --- a/fs/autofs4/dev-ioctl.c +++ b/fs/autofs4/dev-ioctl.c @@ -194,7 +194,7 @@ static int find_autofs_mount(const char *pathname, return err; err = -ENOENT; while (path.dentry == path.mnt->mnt_root) { - if (path.mnt->mnt_sb->s_magic == AUTOFS_SUPER_MAGIC) { + if (path.dentry->d_sb->s_magic == AUTOFS_SUPER_MAGIC) { if (test(&path, data)) { path_get(&path); if (!err) /* already found some */ @@ -212,7 +212,7 @@ static int find_autofs_mount(const char *pathname, static int test_by_dev(struct path *path, void *p) { - return path->mnt->mnt_sb->s_dev == *(dev_t *)p; + return path->dentry->d_sb->s_dev == *(dev_t *)p; } static int test_by_type(struct path *path, void *p) @@ -538,11 +538,11 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp, err = find_autofs_mount(name, &path, test_by_type, &type); if (err) goto out; - devid = new_encode_dev(path.mnt->mnt_sb->s_dev); + devid = new_encode_dev(path.dentry->d_sb->s_dev); err = 0; if (path.mnt->mnt_root == path.dentry) { err = 1; - magic = path.mnt->mnt_sb->s_magic; + magic = path.dentry->d_sb->s_magic; } } else { dev_t dev = sbi->sb->s_dev; @@ -556,7 +556,7 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp, err = have_submounts(path.dentry); if (follow_down_one(&path)) - magic = path.mnt->mnt_sb->s_magic; + magic = path.dentry->d_sb->s_magic; } param->ismountpoint.out.devid = devid; diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index 8179f1ab8175..2ba44c79d548 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c @@ -70,10 +70,10 @@ out_kill_sb: kill_litter_super(sb); } -static int autofs4_show_options(struct seq_file *m, struct vfsmount *mnt) +static int autofs4_show_options(struct seq_file *m, struct dentry *root) { - struct autofs_sb_info *sbi = autofs4_sbi(mnt->mnt_sb); - struct inode *root_inode = mnt->mnt_sb->s_root->d_inode; + struct autofs_sb_info *sbi = autofs4_sbi(root->d_sb); + struct inode *root_inode = root->d_sb->s_root->d_inode; if (!sbi) return 0; @@ -326,7 +326,7 @@ fail_unlock: return -EINVAL; } -struct inode *autofs4_get_inode(struct super_block *sb, mode_t mode) +struct inode *autofs4_get_inode(struct super_block *sb, umode_t mode) { struct inode *inode = new_inode(sb); diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index f55ae23b137e..75e5f1c8e028 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -26,7 +26,7 @@ static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *); static int autofs4_dir_unlink(struct inode *,struct dentry *); static int autofs4_dir_rmdir(struct inode *,struct dentry *); -static int autofs4_dir_mkdir(struct inode *,struct dentry *,int); +static int autofs4_dir_mkdir(struct inode *,struct dentry *,umode_t); static long autofs4_root_ioctl(struct file *,unsigned int,unsigned long); #ifdef CONFIG_COMPAT static long autofs4_root_compat_ioctl(struct file *,unsigned int,unsigned long); @@ -699,7 +699,7 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) return 0; } -static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); struct autofs_info *ino = autofs4_dentry_ino(dentry); diff --git a/fs/bad_inode.c b/fs/bad_inode.c index 9205cf25f1c6..22e9a78872ff 100644 --- a/fs/bad_inode.c +++ b/fs/bad_inode.c @@ -173,7 +173,7 @@ static const struct file_operations bad_file_ops = }; static int bad_inode_create (struct inode *dir, struct dentry *dentry, - int mode, struct nameidata *nd) + umode_t mode, struct nameidata *nd) { return -EIO; } @@ -202,7 +202,7 @@ static int bad_inode_symlink (struct inode *dir, struct dentry *dentry, } static int bad_inode_mkdir(struct inode *dir, struct dentry *dentry, - int mode) + umode_t mode) { return -EIO; } @@ -213,7 +213,7 @@ static int bad_inode_rmdir (struct inode *dir, struct dentry *dentry) } static int bad_inode_mknod (struct inode *dir, struct dentry *dentry, - int mode, dev_t rdev) + umode_t mode, dev_t rdev) { return -EIO; } diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 8342ca67abcd..6e6d536767fe 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -286,7 +286,6 @@ befs_alloc_inode(struct super_block *sb) static void befs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(befs_inode_cachep, BEFS_I(inode)); } diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c index 9cc074019479..d12c7966db27 100644 --- a/fs/bfs/dir.c +++ b/fs/bfs/dir.c @@ -84,7 +84,7 @@ const struct file_operations bfs_dir_operations = { extern void dump_imap(const char *, struct super_block *); -static int bfs_create(struct inode *dir, struct dentry *dentry, int mode, +static int bfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { int err; diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index 697af5bf70b3..b0391bc402b1 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -251,7 +251,6 @@ static struct inode *bfs_alloc_inode(struct super_block *sb) static void bfs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(bfs_inode_cachep, BFS_I(inode)); } diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 1e9edbdeda7e..a9198dfd5f85 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -560,7 +560,7 @@ static ssize_t bm_entry_write(struct file *file, const char __user *buffer, break; case 2: set_bit(Enabled, &e->flags); break; - case 3: root = dget(file->f_path.mnt->mnt_sb->s_root); + case 3: root = dget(file->f_path.dentry->d_sb->s_root); mutex_lock(&root->d_inode->i_mutex); kill_node(e); @@ -587,7 +587,7 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer, Node *e; struct inode *inode; struct dentry *root, *dentry; - struct super_block *sb = file->f_path.mnt->mnt_sb; + struct super_block *sb = file->f_path.dentry->d_sb; int err = 0; e = create_entry(buffer, count); @@ -666,7 +666,7 @@ static ssize_t bm_status_write(struct file * file, const char __user * buffer, switch (res) { case 1: enabled = 0; break; case 2: enabled = 1; break; - case 3: root = dget(file->f_path.mnt->mnt_sb->s_root); + case 3: root = dget(file->f_path.dentry->d_sb->s_root); mutex_lock(&root->d_inode->i_mutex); while (!list_empty(&entries)) diff --git a/fs/block_dev.c b/fs/block_dev.c index b07f1da1de4e..69a5b6fbee2b 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -17,6 +17,7 @@ #include <linux/module.h> #include <linux/blkpg.h> #include <linux/buffer_head.h> +#include <linux/swap.h> #include <linux/pagevec.h> #include <linux/writeback.h> #include <linux/mpage.h> @@ -25,6 +26,7 @@ #include <linux/namei.h> #include <linux/log2.h> #include <linux/kmemleak.h> +#include <linux/cleancache.h> #include <asm/uaccess.h> #include "internal.h" @@ -82,13 +84,35 @@ static sector_t max_block(struct block_device *bdev) } /* Kill _all_ buffers and pagecache , dirty or not.. */ -static void kill_bdev(struct block_device *bdev) +void kill_bdev(struct block_device *bdev) { - if (bdev->bd_inode->i_mapping->nrpages == 0) + struct address_space *mapping = bdev->bd_inode->i_mapping; + + if (mapping->nrpages == 0) return; + invalidate_bh_lrus(); - truncate_inode_pages(bdev->bd_inode->i_mapping, 0); + truncate_inode_pages(mapping, 0); } +EXPORT_SYMBOL(kill_bdev); + +/* Invalidate clean unused buffers and pagecache. */ +void invalidate_bdev(struct block_device *bdev) +{ + struct address_space *mapping = bdev->bd_inode->i_mapping; + + if (mapping->nrpages == 0) + return; + + invalidate_bh_lrus(); + lru_add_drain_all(); /* make sure all lru add caches are flushed */ + invalidate_mapping_pages(mapping, 0, -1); + /* 99% of the time, we don't need to flush the cleancache on the bdev. + * But, for the strange corners, lets be cautious + */ + cleancache_flush_inode(mapping); +} +EXPORT_SYMBOL(invalidate_bdev); int set_blocksize(struct block_device *bdev, int size) { @@ -425,7 +449,6 @@ static void bdev_i_callback(struct rcu_head *head) struct inode *inode = container_of(head, struct inode, i_rcu); struct bdev_inode *bdi = BDEV_I(inode); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(bdev_cachep, bdi); } @@ -493,7 +516,7 @@ static struct file_system_type bd_type = { .kill_sb = kill_anon_super, }; -struct super_block *blockdev_superblock __read_mostly; +static struct super_block *blockdev_superblock __read_mostly; void __init bdev_cache_init(void) { @@ -639,6 +662,11 @@ static struct block_device *bd_acquire(struct inode *inode) return bdev; } +static inline int sb_is_blkdev_sb(struct super_block *sb) +{ + return sb == blockdev_superblock; +} + /* Call when you free inode */ void bd_forget(struct inode *inode) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index fd1a06df5bc6..2f426a51e60d 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4412,8 +4412,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct inode *dir, const char *name, int name_len, - u64 ref_objectid, u64 objectid, int mode, - u64 *index) + u64 ref_objectid, u64 objectid, + umode_t mode, u64 *index) { struct inode *inode; struct btrfs_inode_item *inode_item; @@ -4596,7 +4596,7 @@ static int btrfs_add_nondir(struct btrfs_trans_handle *trans, } static int btrfs_mknod(struct inode *dir, struct dentry *dentry, - int mode, dev_t rdev) + umode_t mode, dev_t rdev) { struct btrfs_trans_handle *trans; struct btrfs_root *root = BTRFS_I(dir)->root; @@ -4665,7 +4665,7 @@ out_unlock: } static int btrfs_create(struct inode *dir, struct dentry *dentry, - int mode, struct nameidata *nd) + umode_t mode, struct nameidata *nd) { struct btrfs_trans_handle *trans; struct btrfs_root *root = BTRFS_I(dir)->root; @@ -4792,7 +4792,7 @@ fail: return err; } -static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct inode *inode = NULL; struct btrfs_trans_handle *trans; @@ -6761,7 +6761,6 @@ struct inode *btrfs_alloc_inode(struct super_block *sb) static void btrfs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode)); } diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index c04f02c7d5bb..5441ff1480fd 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -201,7 +201,7 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) } } - ret = mnt_want_write(file->f_path.mnt); + ret = mnt_want_write_file(file); if (ret) goto out_unlock; @@ -259,7 +259,7 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) btrfs_end_transaction(trans, root); - mnt_drop_write(file->f_path.mnt); + mnt_drop_write_file(file); ret = 0; out_unlock: @@ -1855,7 +1855,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, goto out; } - err = mnt_want_write(file->f_path.mnt); + err = mnt_want_write_file(file); if (err) goto out; @@ -1971,7 +1971,7 @@ out_dput: dput(dentry); out_unlock_dir: mutex_unlock(&dir->i_mutex); - mnt_drop_write(file->f_path.mnt); + mnt_drop_write_file(file); out: kfree(vol_args); return err; @@ -1987,7 +1987,7 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp) if (btrfs_root_readonly(root)) return -EROFS; - ret = mnt_want_write(file->f_path.mnt); + ret = mnt_want_write_file(file); if (ret) return ret; @@ -2040,7 +2040,7 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp) ret = -EINVAL; } out: - mnt_drop_write(file->f_path.mnt); + mnt_drop_write_file(file); return ret; } @@ -2195,7 +2195,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, if (btrfs_root_readonly(root)) return -EROFS; - ret = mnt_want_write(file->f_path.mnt); + ret = mnt_want_write_file(file); if (ret) return ret; @@ -2510,7 +2510,7 @@ out_unlock: out_fput: fput(src_file); out_drop_write: - mnt_drop_write(file->f_path.mnt); + mnt_drop_write_file(file); return ret; } @@ -2549,7 +2549,7 @@ static long btrfs_ioctl_trans_start(struct file *file) if (btrfs_root_readonly(root)) goto out; - ret = mnt_want_write(file->f_path.mnt); + ret = mnt_want_write_file(file); if (ret) goto out; @@ -2565,7 +2565,7 @@ static long btrfs_ioctl_trans_start(struct file *file) out_drop: atomic_dec(&root->fs_info->open_ioctl_trans); - mnt_drop_write(file->f_path.mnt); + mnt_drop_write_file(file); out: return ret; } @@ -2800,7 +2800,7 @@ long btrfs_ioctl_trans_end(struct file *file) atomic_dec(&root->fs_info->open_ioctl_trans); - mnt_drop_write(file->f_path.mnt); + mnt_drop_write_file(file); return 0; } diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 200f63bc6675..ae488aa1966a 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -40,7 +40,6 @@ #include <linux/magic.h> #include <linux/slab.h> #include <linux/cleancache.h> -#include <linux/mnt_namespace.h> #include <linux/ratelimit.h> #include "compat.h" #include "delayed-inode.h" @@ -662,9 +661,9 @@ int btrfs_sync_fs(struct super_block *sb, int wait) return ret; } -static int btrfs_show_options(struct seq_file *seq, struct vfsmount *vfs) +static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry) { - struct btrfs_root *root = btrfs_sb(vfs->mnt_sb); + struct btrfs_root *root = btrfs_sb(dentry->d_sb); struct btrfs_fs_info *info = root->fs_info; char *compress_type; diff --git a/fs/buffer.c b/fs/buffer.c index 19d8eb7fdc81..1a30db77af32 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -41,7 +41,6 @@ #include <linux/bitops.h> #include <linux/mpage.h> #include <linux/bit_spinlock.h> -#include <linux/cleancache.h> static int fsync_buffers_list(spinlock_t *lock, struct list_head *list); @@ -231,55 +230,6 @@ out: return ret; } -/* If invalidate_buffers() will trash dirty buffers, it means some kind - of fs corruption is going on. Trashing dirty data always imply losing - information that was supposed to be just stored on the physical layer - by the user. - - Thus invalidate_buffers in general usage is not allwowed to trash - dirty buffers. For example ioctl(FLSBLKBUF) expects dirty data to - be preserved. These buffers are simply skipped. - - We also skip buffers which are still in use. For example this can - happen if a userspace program is reading the block device. - - NOTE: In the case where the user removed a removable-media-disk even if - there's still dirty data not synced on disk (due a bug in the device driver - or due an error of the user), by not destroying the dirty buffers we could - generate corruption also on the next media inserted, thus a parameter is - necessary to handle this case in the most safe way possible (trying - to not corrupt also the new disk inserted with the data belonging to - the old now corrupted disk). Also for the ramdisk the natural thing - to do in order to release the ramdisk memory is to destroy dirty buffers. - - These are two special cases. Normal usage imply the device driver - to issue a sync on the device (without waiting I/O completion) and - then an invalidate_buffers call that doesn't trash dirty buffers. - - For handling cache coherency with the blkdev pagecache the 'update' case - is been introduced. It is needed to re-read from disk any pinned - buffer. NOTE: re-reading from disk is destructive so we can do it only - when we assume nobody is changing the buffercache under our I/O and when - we think the disk contains more recent information than the buffercache. - The update == 1 pass marks the buffers we need to update, the update == 2 - pass does the actual I/O. */ -void invalidate_bdev(struct block_device *bdev) -{ - struct address_space *mapping = bdev->bd_inode->i_mapping; - - if (mapping->nrpages == 0) - return; - - invalidate_bh_lrus(); - lru_add_drain_all(); /* make sure all lru add caches are flushed */ - invalidate_mapping_pages(mapping, 0, -1); - /* 99% of the time, we don't need to flush the cleancache on the bdev. - * But, for the strange corners, lets be cautious - */ - cleancache_flush_inode(mapping); -} -EXPORT_SYMBOL(invalidate_bdev); - /* * Kick the writeback threads then try to free up some ZONE_NORMAL memory. */ diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c index 1064805e653b..67bef6d01484 100644 --- a/fs/cachefiles/interface.c +++ b/fs/cachefiles/interface.c @@ -11,7 +11,6 @@ #include <linux/slab.h> #include <linux/mount.h> -#include <linux/buffer_head.h> #include "internal.h" #define list_to_page(head) (list_entry((head)->prev, struct page, lru)) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 8b53193e4f7c..b60fc8bfb3e9 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -928,7 +928,7 @@ static int send_cap_msg(struct ceph_mds_session *session, u64 size, u64 max_size, struct timespec *mtime, struct timespec *atime, u64 time_warp_seq, - uid_t uid, gid_t gid, mode_t mode, + uid_t uid, gid_t gid, umode_t mode, u64 xattr_version, struct ceph_buffer *xattrs_buf, u64 follows) @@ -1078,7 +1078,7 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap, u64 size, max_size; struct timespec mtime, atime; int wake = 0; - mode_t mode; + umode_t mode; uid_t uid; gid_t gid; struct ceph_mds_session *session; diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 98954003a8d3..74fd74719dc2 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -666,7 +666,7 @@ int ceph_handle_notrace_create(struct inode *dir, struct dentry *dentry) } static int ceph_mknod(struct inode *dir, struct dentry *dentry, - int mode, dev_t rdev) + umode_t mode, dev_t rdev) { struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb); struct ceph_mds_client *mdsc = fsc->mdsc; @@ -676,7 +676,7 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry, if (ceph_snap(dir) != CEPH_NOSNAP) return -EROFS; - dout("mknod in dir %p dentry %p mode 0%o rdev %d\n", + dout("mknod in dir %p dentry %p mode 0%ho rdev %d\n", dir, dentry, mode, rdev); req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_MKNOD, USE_AUTH_MDS); if (IS_ERR(req)) { @@ -699,7 +699,7 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry, return err; } -static int ceph_create(struct inode *dir, struct dentry *dentry, int mode, +static int ceph_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { dout("create in dir %p dentry %p name '%.*s'\n", @@ -753,7 +753,7 @@ static int ceph_symlink(struct inode *dir, struct dentry *dentry, return err; } -static int ceph_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int ceph_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb); struct ceph_mds_client *mdsc = fsc->mdsc; @@ -767,7 +767,7 @@ static int ceph_mkdir(struct inode *dir, struct dentry *dentry, int mode) dout("mksnap dir %p snap '%.*s' dn %p\n", dir, dentry->d_name.len, dentry->d_name.name, dentry); } else if (ceph_snap(dir) == CEPH_NOSNAP) { - dout("mkdir dir %p dn %p mode 0%o\n", dir, dentry, mode); + dout("mkdir dir %p dn %p mode 0%ho\n", dir, dentry, mode); op = CEPH_MDS_OP_MKDIR; } else { goto out; @@ -870,7 +870,7 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry) } else if (ceph_snap(dir) == CEPH_NOSNAP) { dout("unlink/rmdir dir %p dn %p inode %p\n", dir, dentry, inode); - op = ((dentry->d_inode->i_mode & S_IFMT) == S_IFDIR) ? + op = S_ISDIR(dentry->d_inode->i_mode) ? CEPH_MDS_OP_RMDIR : CEPH_MDS_OP_UNLINK; } else goto out; diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 87fb132fb330..25283e7a37f8 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -384,7 +384,6 @@ static void ceph_i_callback(struct rcu_head *head) struct inode *inode = container_of(head, struct inode, i_rcu); struct ceph_inode_info *ci = ceph_inode(inode); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(ceph_inode_cachep, ci); } diff --git a/fs/ceph/super.c b/fs/ceph/super.c index b48f15f101a0..11bd0fc4853f 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -341,11 +341,11 @@ out: /** * ceph_show_options - Show mount options in /proc/mounts * @m: seq_file to write to - * @mnt: mount descriptor + * @root: root of that (sub)tree */ -static int ceph_show_options(struct seq_file *m, struct vfsmount *mnt) +static int ceph_show_options(struct seq_file *m, struct dentry *root) { - struct ceph_fs_client *fsc = ceph_sb_to_client(mnt->mnt_sb); + struct ceph_fs_client *fsc = ceph_sb_to_client(root->d_sb); struct ceph_mount_options *fsopt = fsc->mount_options; struct ceph_options *opt = fsc->client->options; diff --git a/fs/ceph/super.h b/fs/ceph/super.h index edcbf3774a56..cb3652b37271 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -136,7 +136,7 @@ struct ceph_cap_snap { int issued, dirty; struct ceph_snap_context *context; - mode_t mode; + umode_t mode; uid_t uid; gid_t gid; diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 500d65859279..c865bfdfe819 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -59,8 +59,8 @@ struct cifs_sb_info { gid_t mnt_gid; uid_t mnt_backupuid; gid_t mnt_backupgid; - mode_t mnt_file_mode; - mode_t mnt_dir_mode; + umode_t mnt_file_mode; + umode_t mnt_dir_mode; unsigned int mnt_cifs_flags; char *mountdata; /* options received at mount time or via DFS refs */ struct backing_dev_info bdi; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 8f1fe324162b..b1fd382d1952 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -343,9 +343,9 @@ cifs_show_security(struct seq_file *s, struct TCP_Server_Info *server) * ones are. */ static int -cifs_show_options(struct seq_file *s, struct vfsmount *m) +cifs_show_options(struct seq_file *s, struct dentry *root) { - struct cifs_sb_info *cifs_sb = CIFS_SB(m->mnt_sb); + struct cifs_sb_info *cifs_sb = CIFS_SB(root->d_sb); struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); struct sockaddr *srcaddr; srcaddr = (struct sockaddr *)&tcon->ses->server->srcaddr; @@ -393,7 +393,7 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) cifs_show_address(s, tcon->ses->server); if (!tcon->unix_ext) - seq_printf(s, ",file_mode=0%o,dir_mode=0%o", + seq_printf(s, ",file_mode=0%ho,dir_mode=0%ho", cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode); if (tcon->seal) @@ -430,7 +430,7 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) seq_printf(s, ",cifsacl"); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) seq_printf(s, ",dynperm"); - if (m->mnt_sb->s_flags & MS_POSIXACL) + if (root->d_sb->s_flags & MS_POSIXACL) seq_printf(s, ",acl"); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) seq_printf(s, ",mfsymlinks"); @@ -488,7 +488,7 @@ static void cifs_umount_begin(struct super_block *sb) } #ifdef CONFIG_CIFS_STATS2 -static int cifs_show_stats(struct seq_file *s, struct vfsmount *mnt) +static int cifs_show_stats(struct seq_file *s, struct dentry *root) { /* BB FIXME */ return 0; diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 30ff56005d8f..fe5ecf1b422a 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -44,14 +44,14 @@ extern const struct address_space_operations cifs_addr_ops_smallbuf; /* Functions related to inodes */ extern const struct inode_operations cifs_dir_inode_ops; extern struct inode *cifs_root_iget(struct super_block *); -extern int cifs_create(struct inode *, struct dentry *, int, +extern int cifs_create(struct inode *, struct dentry *, umode_t, struct nameidata *); extern struct dentry *cifs_lookup(struct inode *, struct dentry *, struct nameidata *); extern int cifs_unlink(struct inode *dir, struct dentry *dentry); extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *); -extern int cifs_mknod(struct inode *, struct dentry *, int, dev_t); -extern int cifs_mkdir(struct inode *, struct dentry *, int); +extern int cifs_mknod(struct inode *, struct dentry *, umode_t, dev_t); +extern int cifs_mkdir(struct inode *, struct dentry *, umode_t); extern int cifs_rmdir(struct inode *, struct dentry *); extern int cifs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 8238aa13e01c..ba53c1c6c6cc 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -169,8 +169,8 @@ struct smb_vol { gid_t linux_gid; uid_t backupuid; gid_t backupgid; - mode_t file_mode; - mode_t dir_mode; + umode_t file_mode; + umode_t dir_mode; unsigned secFlg; bool retry:1; bool intr:1; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index f3670cf72587..4666780f315d 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2819,7 +2819,7 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, cifs_sb->mnt_backupgid = pvolume_info->backupgid; cifs_sb->mnt_file_mode = pvolume_info->file_mode; cifs_sb->mnt_dir_mode = pvolume_info->dir_mode; - cFYI(1, "file mode: 0x%x dir mode: 0x%x", + cFYI(1, "file mode: 0x%hx dir mode: 0x%hx", cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode); cifs_sb->actimeo = pvolume_info->actimeo; diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index d7eeb9d3ed6f..df8fecb5b993 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -136,7 +136,7 @@ cifs_bp_rename_retry: /* Inode operations in similar order to how they appear in Linux file fs.h */ int -cifs_create(struct inode *inode, struct dentry *direntry, int mode, +cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, struct nameidata *nd) { int rc = -ENOENT; @@ -355,7 +355,7 @@ cifs_create_out: return rc; } -int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, +int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, dev_t device_number) { int rc = -EPERM; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index e851d5b8931e..a5f54b7d9822 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1264,7 +1264,7 @@ unlink_out: return rc; } -int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) +int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode) { int rc = 0, tmprc; int xid; @@ -1275,7 +1275,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) struct inode *newinode = NULL; struct cifs_fattr fattr; - cFYI(1, "In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode); + cFYI(1, "In cifs_mkdir, mode = 0x%hx inode = 0x%p", mode, inode); cifs_sb = CIFS_SB(inode->i_sb); tlink = cifs_sb_tlink(cifs_sb); diff --git a/fs/coda/dir.c b/fs/coda/dir.c index 28e7e135cfab..83d2fd8ec24b 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -30,14 +30,14 @@ #include "coda_int.h" /* dir inode-ops */ -static int coda_create(struct inode *dir, struct dentry *new, int mode, struct nameidata *nd); +static int coda_create(struct inode *dir, struct dentry *new, umode_t mode, struct nameidata *nd); static struct dentry *coda_lookup(struct inode *dir, struct dentry *target, struct nameidata *nd); static int coda_link(struct dentry *old_dentry, struct inode *dir_inode, struct dentry *entry); static int coda_unlink(struct inode *dir_inode, struct dentry *entry); static int coda_symlink(struct inode *dir_inode, struct dentry *entry, const char *symname); -static int coda_mkdir(struct inode *dir_inode, struct dentry *entry, int mode); +static int coda_mkdir(struct inode *dir_inode, struct dentry *entry, umode_t mode); static int coda_rmdir(struct inode *dir_inode, struct dentry *entry); static int coda_rename(struct inode *old_inode, struct dentry *old_dentry, struct inode *new_inode, struct dentry *new_dentry); @@ -191,7 +191,7 @@ static inline void coda_dir_drop_nlink(struct inode *dir) } /* creation routines: create, mknod, mkdir, link, symlink */ -static int coda_create(struct inode *dir, struct dentry *de, int mode, struct nameidata *nd) +static int coda_create(struct inode *dir, struct dentry *de, umode_t mode, struct nameidata *nd) { int error; const char *name=de->d_name.name; @@ -223,7 +223,7 @@ err_out: return error; } -static int coda_mkdir(struct inode *dir, struct dentry *de, int mode) +static int coda_mkdir(struct inode *dir, struct dentry *de, umode_t mode) { struct inode *inode; struct coda_vattr attrs; diff --git a/fs/coda/inode.c b/fs/coda/inode.c index 871b27715465..1c08a8cd673a 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -58,7 +58,6 @@ static struct inode *coda_alloc_inode(struct super_block *sb) static void coda_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(coda_inode_cachep, ITOC(inode)); } diff --git a/fs/compat.c b/fs/compat.c index c98787536bb8..fa9d721ecfee 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -342,16 +342,9 @@ asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct c */ asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *u) { - struct super_block *sb; struct compat_ustat tmp; struct kstatfs sbuf; - int err; - - sb = user_get_super(new_decode_dev(dev)); - if (!sb) - return -EINVAL; - err = statfs_by_dentry(sb->s_root, &sbuf); - drop_super(sb); + int err = vfs_ustat(new_decode_dev(dev), &sbuf); if (err) return err; @@ -1288,7 +1281,7 @@ compat_sys_vmsplice(int fd, const struct compat_iovec __user *iov32, * O_LARGEFILE flag. */ asmlinkage long -compat_sys_open(const char __user *filename, int flags, int mode) +compat_sys_open(const char __user *filename, int flags, umode_t mode) { return do_sys_open(AT_FDCWD, filename, flags, mode); } @@ -1298,7 +1291,7 @@ compat_sys_open(const char __user *filename, int flags, int mode) * O_LARGEFILE flag. */ asmlinkage long -compat_sys_openat(unsigned int dfd, const char __user *filename, int flags, int mode) +compat_sys_openat(unsigned int dfd, const char __user *filename, int flags, umode_t mode) { return do_sys_open(dfd, filename, flags, mode); } diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h index 82bda8fdfc1c..ede857d20a04 100644 --- a/fs/configfs/configfs_internal.h +++ b/fs/configfs/configfs_internal.h @@ -63,8 +63,8 @@ extern struct kmem_cache *configfs_dir_cachep; 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 struct inode * configfs_new_inode(umode_t mode, struct configfs_dirent *); +extern int configfs_create(struct dentry *, umode_t mode, int (*init)(struct inode *)); extern int configfs_inode_init(void); extern void configfs_inode_exit(void); diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 9a37a9b6de3a..5ddd7ebd9dcd 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -311,8 +311,8 @@ static int configfs_create_dir(struct config_item * item, struct dentry *dentry) if (item->ci_parent) parent = item->ci_parent->ci_dentry; - else if (configfs_mount && configfs_mount->mnt_sb) - parent = configfs_mount->mnt_sb->s_root; + else if (configfs_mount) + parent = configfs_mount->mnt_root; else return -EFAULT; @@ -1170,7 +1170,7 @@ void configfs_undepend_item(struct configfs_subsystem *subsys, } EXPORT_SYMBOL(configfs_undepend_item); -static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int configfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { int ret = 0; int module_got = 0; diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c index 9d8715c45f25..3ee36d418863 100644 --- a/fs/configfs/inode.c +++ b/fs/configfs/inode.c @@ -116,7 +116,7 @@ int configfs_setattr(struct dentry * dentry, struct iattr * iattr) return error; } -static inline void set_default_inode_attr(struct inode * inode, mode_t mode) +static inline void set_default_inode_attr(struct inode * inode, umode_t mode) { inode->i_mode = mode; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; @@ -132,7 +132,7 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) inode->i_ctime = iattr->ia_ctime; } -struct inode * configfs_new_inode(mode_t mode, struct configfs_dirent * sd) +struct inode *configfs_new_inode(umode_t mode, struct configfs_dirent * sd) { struct inode * inode = new_inode(configfs_sb); if (inode) { @@ -185,7 +185,7 @@ static void configfs_set_inode_lock_class(struct configfs_dirent *sd, #endif /* CONFIG_LOCKDEP */ -int configfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *)) +int configfs_create(struct dentry * dentry, umode_t mode, int (*init)(struct inode *)) { int error = 0; struct inode * inode = NULL; diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 739fb59bcdc2..a2ee8f9f5a38 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -20,7 +20,6 @@ #include <linux/cramfs_fs.h> #include <linux/slab.h> #include <linux/cramfs_fs_sb.h> -#include <linux/buffer_head.h> #include <linux/vfs.h> #include <linux/mutex.h> @@ -378,7 +377,7 @@ static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir) unsigned long nextoffset; char *name; ino_t ino; - mode_t mode; + umode_t mode; int namelen, error; mutex_lock(&read_mutex); diff --git a/fs/dcache.c b/fs/dcache.c index 89509b5a090e..9791b1e7eee4 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -38,6 +38,7 @@ #include <linux/prefetch.h> #include <linux/ratelimit.h> #include "internal.h" +#include "mount.h" /* * Usage: @@ -2451,6 +2452,7 @@ static int prepend_path(const struct path *path, { struct dentry *dentry = path->dentry; struct vfsmount *vfsmnt = path->mnt; + struct mount *mnt = real_mount(vfsmnt); bool slash = false; int error = 0; @@ -2460,11 +2462,11 @@ static int prepend_path(const struct path *path, if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { /* Global root? */ - if (vfsmnt->mnt_parent == vfsmnt) { + if (!mnt_has_parent(mnt)) goto global_root; - } - dentry = vfsmnt->mnt_mountpoint; - vfsmnt = vfsmnt->mnt_parent; + dentry = mnt->mnt_mountpoint; + mnt = mnt->mnt_parent; + vfsmnt = &mnt->mnt; continue; } parent = dentry->d_parent; @@ -2501,7 +2503,7 @@ global_root: if (!slash) error = prepend(buffer, buflen, "/", 1); if (!error) - error = vfsmnt->mnt_ns ? 1 : 2; + error = real_mount(vfsmnt)->mnt_ns ? 1 : 2; goto out; } @@ -2853,31 +2855,6 @@ int is_subdir(struct dentry *new_dentry, struct dentry *old_dentry) return result; } -int path_is_under(struct path *path1, struct path *path2) -{ - struct vfsmount *mnt = path1->mnt; - struct dentry *dentry = path1->dentry; - int res; - - br_read_lock(vfsmount_lock); - if (mnt != path2->mnt) { - for (;;) { - if (mnt->mnt_parent == mnt) { - br_read_unlock(vfsmount_lock); - return 0; - } - if (mnt->mnt_parent == path2->mnt) - break; - mnt = mnt->mnt_parent; - } - dentry = mnt->mnt_mountpoint; - } - res = is_subdir(dentry, path2->dentry); - br_read_unlock(vfsmount_lock); - return res; -} -EXPORT_SYMBOL(path_is_under); - void d_genocide(struct dentry *root) { struct dentry *this_parent; diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index ea62afa4fd57..f65d4455c5e5 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -97,7 +97,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%llu\n"); * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling * code. */ -struct dentry *debugfs_create_u8(const char *name, mode_t mode, +struct dentry *debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent, u8 *value) { /* if there are no write bits set, make read only */ @@ -149,7 +149,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, "%llu\n"); * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling * code. */ -struct dentry *debugfs_create_u16(const char *name, mode_t mode, +struct dentry *debugfs_create_u16(const char *name, umode_t mode, struct dentry *parent, u16 *value) { /* if there are no write bits set, make read only */ @@ -201,7 +201,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u32_wo, NULL, debugfs_u32_set, "%llu\n"); * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling * code. */ -struct dentry *debugfs_create_u32(const char *name, mode_t mode, +struct dentry *debugfs_create_u32(const char *name, umode_t mode, struct dentry *parent, u32 *value) { /* if there are no write bits set, make read only */ @@ -254,7 +254,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n"); * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling * code. */ -struct dentry *debugfs_create_u64(const char *name, mode_t mode, +struct dentry *debugfs_create_u64(const char *name, umode_t mode, struct dentry *parent, u64 *value) { /* if there are no write bits set, make read only */ @@ -300,7 +300,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_x64, debugfs_u64_get, debugfs_u64_set, "0x%016llx\n * @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 *debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent, u8 *value) { /* if there are no write bits set, make read only */ @@ -324,7 +324,7 @@ EXPORT_SYMBOL_GPL(debugfs_create_x8); * @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 *debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent, u16 *value) { /* if there are no write bits set, make read only */ @@ -348,7 +348,7 @@ EXPORT_SYMBOL_GPL(debugfs_create_x16); * @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 *debugfs_create_x32(const char *name, umode_t mode, struct dentry *parent, u32 *value) { /* if there are no write bits set, make read only */ @@ -372,7 +372,7 @@ EXPORT_SYMBOL_GPL(debugfs_create_x32); * @value: a pointer to the variable that the file should read to and write * from. */ -struct dentry *debugfs_create_x64(const char *name, mode_t mode, +struct dentry *debugfs_create_x64(const char *name, umode_t mode, struct dentry *parent, u64 *value) { return debugfs_create_file(name, mode, parent, value, &fops_x64); @@ -403,7 +403,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_size_t, debugfs_size_t_get, debugfs_size_t_set, * @value: a pointer to the variable that the file should read to and write * from. */ -struct dentry *debugfs_create_size_t(const char *name, mode_t mode, +struct dentry *debugfs_create_size_t(const char *name, umode_t mode, struct dentry *parent, size_t *value) { return debugfs_create_file(name, mode, parent, value, &fops_size_t); @@ -475,7 +475,7 @@ static const struct file_operations fops_bool = { * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling * code. */ -struct dentry *debugfs_create_bool(const char *name, mode_t mode, +struct dentry *debugfs_create_bool(const char *name, umode_t mode, struct dentry *parent, u32 *value) { return debugfs_create_file(name, mode, parent, value, &fops_bool); @@ -520,7 +520,7 @@ static const struct file_operations fops_blob = { * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling * code. */ -struct dentry *debugfs_create_blob(const char *name, mode_t mode, +struct dentry *debugfs_create_blob(const char *name, umode_t mode, struct dentry *parent, struct debugfs_blob_wrapper *blob) { diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index f3a257d7a985..956d5ddddf6e 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -30,7 +30,7 @@ static struct vfsmount *debugfs_mount; static int debugfs_mount_count; static bool debugfs_registered; -static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t dev, +static struct inode *debugfs_get_inode(struct super_block *sb, umode_t mode, dev_t dev, void *data, const struct file_operations *fops) { @@ -69,7 +69,7 @@ static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t d /* SMP-safe */ static int debugfs_mknod(struct inode *dir, struct dentry *dentry, - int mode, dev_t dev, void *data, + umode_t mode, dev_t dev, void *data, const struct file_operations *fops) { struct inode *inode; @@ -87,7 +87,7 @@ static int debugfs_mknod(struct inode *dir, struct dentry *dentry, return error; } -static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, int mode, +static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode, void *data, const struct file_operations *fops) { int res; @@ -101,14 +101,14 @@ static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, int mode, return res; } -static int debugfs_link(struct inode *dir, struct dentry *dentry, int mode, +static int debugfs_link(struct inode *dir, struct dentry *dentry, umode_t mode, void *data, const struct file_operations *fops) { mode = (mode & S_IALLUGO) | S_IFLNK; return debugfs_mknod(dir, dentry, mode, 0, data, fops); } -static int debugfs_create(struct inode *dir, struct dentry *dentry, int mode, +static int debugfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, void *data, const struct file_operations *fops) { int res; @@ -146,7 +146,7 @@ static struct file_system_type debug_fs_type = { .kill_sb = kill_litter_super, }; -static int debugfs_create_by_name(const char *name, mode_t mode, +static int debugfs_create_by_name(const char *name, umode_t mode, struct dentry *parent, struct dentry **dentry, void *data, @@ -160,7 +160,7 @@ static int debugfs_create_by_name(const char *name, mode_t mode, * have around. */ if (!parent) - parent = debugfs_mount->mnt_sb->s_root; + parent = debugfs_mount->mnt_root; *dentry = NULL; mutex_lock(&parent->d_inode->i_mutex); @@ -214,7 +214,7 @@ static int debugfs_create_by_name(const char *name, mode_t mode, * If debugfs is not enabled in the kernel, the value -%ENODEV will be * returned. */ -struct dentry *debugfs_create_file(const char *name, mode_t mode, +struct dentry *debugfs_create_file(const char *name, umode_t mode, struct dentry *parent, void *data, const struct file_operations *fops) { diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index d5d5297efe97..79673eb71151 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -246,9 +246,9 @@ static int devpts_remount(struct super_block *sb, int *flags, char *data) return err; } -static int devpts_show_options(struct seq_file *seq, struct vfsmount *vfs) +static int devpts_show_options(struct seq_file *seq, struct dentry *root) { - struct pts_fs_info *fsi = DEVPTS_SB(vfs->mnt_sb); + struct pts_fs_info *fsi = DEVPTS_SB(root->d_sb); struct pts_mount_opts *opts = &fsi->mount_opts; if (opts->setuid) diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 32f90a3ae63e..19a8ca4ab1dd 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -144,24 +144,6 @@ static int ecryptfs_interpose(struct dentry *lower_dentry, } /** - * ecryptfs_create_underlying_file - * @lower_dir_inode: inode of the parent in the lower fs of the new file - * @dentry: New file's dentry - * @mode: The mode of the new file - * - * Creates the file in the lower file system. - * - * Returns zero on success; non-zero on error condition - */ -static int -ecryptfs_create_underlying_file(struct inode *lower_dir_inode, - struct dentry *dentry, int mode) -{ - struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); - return vfs_create(lower_dir_inode, lower_dentry, mode, NULL); -} - -/** * ecryptfs_do_create * @directory_inode: inode of the new file's dentry's parent in ecryptfs * @ecryptfs_dentry: New file's dentry in ecryptfs @@ -176,7 +158,7 @@ ecryptfs_create_underlying_file(struct inode *lower_dir_inode, */ static struct inode * ecryptfs_do_create(struct inode *directory_inode, - struct dentry *ecryptfs_dentry, int mode) + struct dentry *ecryptfs_dentry, umode_t mode) { int rc; struct dentry *lower_dentry; @@ -191,8 +173,7 @@ ecryptfs_do_create(struct inode *directory_inode, inode = ERR_CAST(lower_dir_dentry); goto out; } - rc = ecryptfs_create_underlying_file(lower_dir_dentry->d_inode, - ecryptfs_dentry, mode); + rc = vfs_create(lower_dir_dentry->d_inode, lower_dentry, mode, NULL); if (rc) { printk(KERN_ERR "%s: Failure to create dentry in lower fs; " "rc = [%d]\n", __func__, rc); @@ -267,7 +248,7 @@ out: */ static int ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry, - int mode, struct nameidata *nd) + umode_t mode, struct nameidata *nd) { struct inode *ecryptfs_inode; int rc; @@ -559,7 +540,7 @@ out_lock: return rc; } -static int ecryptfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int ecryptfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { int rc; struct dentry *lower_dentry; @@ -607,7 +588,7 @@ static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry) } static int -ecryptfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) +ecryptfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) { int rc; struct dentry *lower_dentry; diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c index dbd52d40df4c..9df7fd6e0c39 100644 --- a/fs/ecryptfs/super.c +++ b/fs/ecryptfs/super.c @@ -69,7 +69,6 @@ static void ecryptfs_i_callback(struct rcu_head *head) struct ecryptfs_inode_info *inode_info; inode_info = ecryptfs_inode_to_private(inode); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(ecryptfs_inode_info_cache, inode_info); } @@ -132,9 +131,9 @@ static void ecryptfs_evict_inode(struct inode *inode) * Prints the mount options for a given superblock. * Returns zero; does not fail. */ -static int ecryptfs_show_options(struct seq_file *m, struct vfsmount *mnt) +static int ecryptfs_show_options(struct seq_file *m, struct dentry *root) { - struct super_block *sb = mnt->mnt_sb; + struct super_block *sb = root->d_sb; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = &ecryptfs_superblock_to_private(sb)->mount_crypt_stat; struct ecryptfs_global_auth_tok *walker; diff --git a/fs/efs/super.c b/fs/efs/super.c index 0f31acb0131c..981106429a9f 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c @@ -68,7 +68,6 @@ static struct inode *efs_alloc_inode(struct super_block *sb) static void efs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(efs_inode_cachep, INODE_INFO(inode)); } diff --git a/fs/exec.c b/fs/exec.c index 36254645b7cc..3f64b9f26e7d 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1225,7 +1225,7 @@ EXPORT_SYMBOL(install_exec_creds); * - the caller must hold ->cred_guard_mutex to protect against * PTRACE_ATTACH */ -int check_unsafe_exec(struct linux_binprm *bprm) +static int check_unsafe_exec(struct linux_binprm *bprm) { struct task_struct *p = current, *t; unsigned n_fs; diff --git a/fs/exofs/dir.c b/fs/exofs/dir.c index d0941c6a1f72..80405836ba6e 100644 --- a/fs/exofs/dir.c +++ b/fs/exofs/dir.c @@ -234,7 +234,7 @@ static unsigned char exofs_type_by_mode[S_IFMT >> S_SHIFT] = { static inline void exofs_set_de_type(struct exofs_dir_entry *de, struct inode *inode) { - mode_t mode = inode->i_mode; + umode_t mode = inode->i_mode; de->file_type = exofs_type_by_mode[(mode & S_IFMT) >> S_SHIFT]; } diff --git a/fs/exofs/exofs.h b/fs/exofs/exofs.h index 51f4b4c40f09..ca9d49665ef6 100644 --- a/fs/exofs/exofs.h +++ b/fs/exofs/exofs.h @@ -154,7 +154,7 @@ int exofs_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata); extern struct inode *exofs_iget(struct super_block *, unsigned long); -struct inode *exofs_new_inode(struct inode *, int); +struct inode *exofs_new_inode(struct inode *, umode_t); extern int exofs_write_inode(struct inode *, struct writeback_control *wbc); extern void exofs_evict_inode(struct inode *); diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c index f6dbf7768ce6..ea5e1f97806a 100644 --- a/fs/exofs/inode.c +++ b/fs/exofs/inode.c @@ -1276,7 +1276,7 @@ static void create_done(struct ore_io_state *ios, void *p) /* * Set up a new inode and create an object for it on the OSD */ -struct inode *exofs_new_inode(struct inode *dir, int mode) +struct inode *exofs_new_inode(struct inode *dir, umode_t mode) { struct super_block *sb = dir->i_sb; struct exofs_sb_info *sbi = sb->s_fs_info; diff --git a/fs/exofs/namei.c b/fs/exofs/namei.c index b54c43775f17..9dbf0c301030 100644 --- a/fs/exofs/namei.c +++ b/fs/exofs/namei.c @@ -59,7 +59,7 @@ static struct dentry *exofs_lookup(struct inode *dir, struct dentry *dentry, return d_splice_alias(inode, dentry); } -static int exofs_create(struct inode *dir, struct dentry *dentry, int mode, +static int exofs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { struct inode *inode = exofs_new_inode(dir, mode); @@ -74,7 +74,7 @@ static int exofs_create(struct inode *dir, struct dentry *dentry, int mode, return err; } -static int exofs_mknod(struct inode *dir, struct dentry *dentry, int mode, +static int exofs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { struct inode *inode; @@ -153,7 +153,7 @@ static int exofs_link(struct dentry *old_dentry, struct inode *dir, return exofs_add_nondir(dentry, inode); } -static int exofs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int exofs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct inode *inode; int err = -EMLINK; diff --git a/fs/exofs/super.c b/fs/exofs/super.c index e6085ec192d6..8addfe314dc7 100644 --- a/fs/exofs/super.c +++ b/fs/exofs/super.c @@ -166,7 +166,6 @@ static struct inode *exofs_alloc_inode(struct super_block *sb) static void exofs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(exofs_inode_cachep, exofs_i(inode)); } diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index 47cda410b548..d37df352d324 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -279,7 +279,7 @@ static unsigned char ext2_type_by_mode[S_IFMT >> S_SHIFT] = { static inline void ext2_set_de_type(ext2_dirent *de, struct inode *inode) { - mode_t mode = inode->i_mode; + umode_t mode = inode->i_mode; if (EXT2_HAS_INCOMPAT_FEATURE(inode->i_sb, EXT2_FEATURE_INCOMPAT_FILETYPE)) de->file_type = ext2_type_by_mode[(mode & S_IFMT)>>S_SHIFT]; else diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index 9a4e5e206d08..75ad433c6691 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h @@ -110,7 +110,7 @@ extern struct ext2_dir_entry_2 * ext2_dotdot (struct inode *, struct page **); extern void ext2_set_link(struct inode *, struct ext2_dir_entry_2 *, struct page *, struct inode *, int); /* ialloc.c */ -extern struct inode * ext2_new_inode (struct inode *, int, const struct qstr *); +extern struct inode * ext2_new_inode (struct inode *, umode_t, const struct qstr *); extern void ext2_free_inode (struct inode *); extern unsigned long ext2_count_free_inodes (struct super_block *); extern void ext2_check_inodes_bitmap (struct super_block *); diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index c4e81dfb74ba..cd7f5f424a75 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c @@ -429,7 +429,7 @@ found: return group; } -struct inode *ext2_new_inode(struct inode *dir, int mode, +struct inode *ext2_new_inode(struct inode *dir, umode_t mode, const struct qstr *qstr) { struct super_block *sb; diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c index f81e250ac5c4..1089f760c847 100644 --- a/fs/ext2/ioctl.c +++ b/fs/ext2/ioctl.c @@ -35,7 +35,7 @@ long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case EXT2_IOC_SETFLAGS: { unsigned int oldflags; - ret = mnt_want_write(filp->f_path.mnt); + ret = mnt_want_write_file(filp); if (ret) return ret; @@ -83,7 +83,7 @@ long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); setflags_out: - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); return ret; } case EXT2_IOC_GETVERSION: @@ -91,7 +91,7 @@ setflags_out: case EXT2_IOC_SETVERSION: if (!inode_owner_or_capable(inode)) return -EPERM; - ret = mnt_want_write(filp->f_path.mnt); + ret = mnt_want_write_file(filp); if (ret) return ret; if (get_user(inode->i_generation, (int __user *) arg)) { @@ -100,7 +100,7 @@ setflags_out: inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); } - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); return ret; case EXT2_IOC_GETRSVSZ: if (test_opt(inode->i_sb, RESERVATION) @@ -121,7 +121,7 @@ setflags_out: if (get_user(rsv_window_size, (int __user *)arg)) return -EFAULT; - ret = mnt_want_write(filp->f_path.mnt); + ret = mnt_want_write_file(filp); if (ret) return ret; @@ -145,7 +145,7 @@ setflags_out: rsv->rsv_goal_size = rsv_window_size; } mutex_unlock(&ei->truncate_mutex); - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); return 0; } default: diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 761fde807fc9..080419814bae 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -94,7 +94,7 @@ struct dentry *ext2_get_parent(struct dentry *child) * If the create succeeds, we fill in the inode information * with d_instantiate(). */ -static int ext2_create (struct inode * dir, struct dentry * dentry, int mode, struct nameidata *nd) +static int ext2_create (struct inode * dir, struct dentry * dentry, umode_t mode, struct nameidata *nd) { struct inode *inode; @@ -119,7 +119,7 @@ static int ext2_create (struct inode * dir, struct dentry * dentry, int mode, st return ext2_add_nondir(dentry, inode); } -static int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, dev_t rdev) +static int ext2_mknod (struct inode * dir, struct dentry *dentry, umode_t mode, dev_t rdev) { struct inode * inode; int err; @@ -214,7 +214,7 @@ static int ext2_link (struct dentry * old_dentry, struct inode * dir, return err; } -static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode) +static int ext2_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode) { struct inode * inode; int err = -EMLINK; diff --git a/fs/ext2/super.c b/fs/ext2/super.c index bd8ac164a3bf..9b403f064ce0 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -173,7 +173,6 @@ static struct inode *ext2_alloc_inode(struct super_block *sb) static void ext2_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(ext2_inode_cachep, EXT2_I(inode)); } @@ -211,9 +210,9 @@ static void destroy_inodecache(void) kmem_cache_destroy(ext2_inode_cachep); } -static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs) +static int ext2_show_options(struct seq_file *seq, struct dentry *root) { - struct super_block *sb = vfs->mnt_sb; + struct super_block *sb = root->d_sb; struct ext2_sb_info *sbi = EXT2_SB(sb); struct ext2_super_block *es = sbi->s_es; unsigned long def_mount_opts; diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c index 5c866e06e7ab..92cc86dfa23d 100644 --- a/fs/ext3/ialloc.c +++ b/fs/ext3/ialloc.c @@ -371,7 +371,7 @@ static int find_group_other(struct super_block *sb, struct inode *parent) * group to find a free inode. */ struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, - const struct qstr *qstr, int mode) + const struct qstr *qstr, umode_t mode) { struct super_block *sb; struct buffer_head *bitmap_bh = NULL; diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c index ba1b54e23cae..8e37c41a071b 100644 --- a/fs/ext3/ioctl.c +++ b/fs/ext3/ioctl.c @@ -44,7 +44,7 @@ long ext3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (get_user(flags, (int __user *) arg)) return -EFAULT; - err = mnt_want_write(filp->f_path.mnt); + err = mnt_want_write_file(filp); if (err) return err; @@ -110,7 +110,7 @@ flags_err: err = ext3_change_inode_journal_flag(inode, jflag); flags_out: mutex_unlock(&inode->i_mutex); - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); return err; } case EXT3_IOC_GETVERSION: @@ -126,7 +126,7 @@ flags_out: if (!inode_owner_or_capable(inode)) return -EPERM; - err = mnt_want_write(filp->f_path.mnt); + err = mnt_want_write_file(filp); if (err) return err; if (get_user(generation, (int __user *) arg)) { @@ -147,7 +147,7 @@ flags_out: } ext3_journal_stop(handle); setversion_out: - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); return err; } case EXT3_IOC_GETRSVSZ: @@ -164,7 +164,7 @@ setversion_out: if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) return -ENOTTY; - err = mnt_want_write(filp->f_path.mnt); + err = mnt_want_write_file(filp); if (err) return err; @@ -195,7 +195,7 @@ setversion_out: } mutex_unlock(&ei->truncate_mutex); setrsvsz_out: - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); return err; } case EXT3_IOC_GROUP_EXTEND: { @@ -206,7 +206,7 @@ setrsvsz_out: if (!capable(CAP_SYS_RESOURCE)) return -EPERM; - err = mnt_want_write(filp->f_path.mnt); + err = mnt_want_write_file(filp); if (err) return err; @@ -221,7 +221,7 @@ setrsvsz_out: if (err == 0) err = err2; group_extend_out: - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); return err; } case EXT3_IOC_GROUP_ADD: { @@ -232,7 +232,7 @@ group_extend_out: if (!capable(CAP_SYS_RESOURCE)) return -EPERM; - err = mnt_want_write(filp->f_path.mnt); + err = mnt_want_write_file(filp); if (err) return err; @@ -249,7 +249,7 @@ group_extend_out: if (err == 0) err = err2; group_add_out: - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); return err; } case FITRIM: { diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 642dc6d66dfd..4f35b2f315d4 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -1698,7 +1698,7 @@ static int ext3_add_nondir(handle_t *handle, * If the create succeeds, we fill in the inode information * with d_instantiate(). */ -static int ext3_create (struct inode * dir, struct dentry * dentry, int mode, +static int ext3_create (struct inode * dir, struct dentry * dentry, umode_t mode, struct nameidata *nd) { handle_t *handle; @@ -1732,7 +1732,7 @@ retry: } static int ext3_mknod (struct inode * dir, struct dentry *dentry, - int mode, dev_t rdev) + umode_t mode, dev_t rdev) { handle_t *handle; struct inode *inode; @@ -1768,7 +1768,7 @@ retry: return err; } -static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode) +static int ext3_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode) { handle_t *handle; struct inode * inode; diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 922d289aeeb3..3a10b884e1be 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -511,7 +511,6 @@ static int ext3_drop_inode(struct inode *inode) static void ext3_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(ext3_inode_cachep, EXT3_I(inode)); } @@ -611,9 +610,9 @@ static char *data_mode_string(unsigned long mode) * - 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) +static int ext3_show_options(struct seq_file *seq, struct dentry *root) { - struct super_block *sb = vfs->mnt_sb; + struct super_block *sb = root->d_sb; struct ext3_sb_info *sbi = EXT3_SB(sb); struct ext3_super_block *es = sbi->s_es; unsigned long def_mount_opts; @@ -2910,7 +2909,7 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id, return -EINVAL; /* Quotafile not on the same filesystem? */ - if (path->mnt->mnt_sb != sb) + if (path->dentry->d_sb != sb) return -EXDEV; /* Journaling quota? */ if (EXT3_SB(sb)->s_qf_names[type]) { diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 5b0e26a1272d..1554b15f91bc 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1819,7 +1819,7 @@ extern int ext4fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo); /* ialloc.c */ -extern struct inode *ext4_new_inode(handle_t *, struct inode *, int, +extern struct inode *ext4_new_inode(handle_t *, struct inode *, umode_t, const struct qstr *qstr, __u32 goal, uid_t *owner); extern void ext4_free_inode(handle_t *, struct inode *); diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 00beb4f9cc4f..4637af036d9c 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -351,7 +351,7 @@ static void get_orlov_stats(struct super_block *sb, ext4_group_t g, */ static int find_group_orlov(struct super_block *sb, struct inode *parent, - ext4_group_t *group, int mode, + ext4_group_t *group, umode_t mode, const struct qstr *qstr) { ext4_group_t parent_group = EXT4_I(parent)->i_block_group; @@ -497,7 +497,7 @@ fallback_retry: } static int find_group_other(struct super_block *sb, struct inode *parent, - ext4_group_t *group, int mode) + ext4_group_t *group, umode_t mode) { ext4_group_t parent_group = EXT4_I(parent)->i_block_group; ext4_group_t i, last, ngroups = ext4_get_groups_count(sb); @@ -602,7 +602,7 @@ static int find_group_other(struct super_block *sb, struct inode *parent, */ static int ext4_claim_inode(struct super_block *sb, struct buffer_head *inode_bitmap_bh, - unsigned long ino, ext4_group_t group, int mode) + unsigned long ino, ext4_group_t group, umode_t mode) { int free = 0, retval = 0, count; struct ext4_sb_info *sbi = EXT4_SB(sb); @@ -690,7 +690,7 @@ err_ret: * For other inodes, search forward from the parent directory's block * group to find a free inode. */ -struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode, +struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, umode_t mode, const struct qstr *qstr, __u32 goal, uid_t *owner) { struct super_block *sb; diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index a56796814d6a..d37b3bb2a3b8 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -45,7 +45,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (get_user(flags, (int __user *) arg)) return -EFAULT; - err = mnt_want_write(filp->f_path.mnt); + err = mnt_want_write_file(filp); if (err) return err; @@ -134,7 +134,7 @@ flags_err: err = ext4_ext_migrate(inode); flags_out: mutex_unlock(&inode->i_mutex); - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); return err; } case EXT4_IOC_GETVERSION: @@ -150,7 +150,7 @@ flags_out: if (!inode_owner_or_capable(inode)) return -EPERM; - err = mnt_want_write(filp->f_path.mnt); + err = mnt_want_write_file(filp); if (err) return err; if (get_user(generation, (int __user *) arg)) { @@ -171,7 +171,7 @@ flags_out: } ext4_journal_stop(handle); setversion_out: - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); return err; } case EXT4_IOC_GROUP_EXTEND: { @@ -192,7 +192,7 @@ setversion_out: return -EOPNOTSUPP; } - err = mnt_want_write(filp->f_path.mnt); + err = mnt_want_write_file(filp); if (err) return err; @@ -204,7 +204,7 @@ setversion_out: } if (err == 0) err = err2; - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); ext4_resize_end(sb); return err; @@ -240,13 +240,13 @@ setversion_out: return -EOPNOTSUPP; } - err = mnt_want_write(filp->f_path.mnt); + err = mnt_want_write_file(filp); if (err) goto mext_out; err = ext4_move_extents(filp, donor_filp, me.orig_start, me.donor_start, me.len, &me.moved_len); - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); if (me.moved_len > 0) file_remove_suid(donor_filp); @@ -277,7 +277,7 @@ mext_out: return -EOPNOTSUPP; } - err = mnt_want_write(filp->f_path.mnt); + err = mnt_want_write_file(filp); if (err) return err; @@ -289,7 +289,7 @@ mext_out: } if (err == 0) err = err2; - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); ext4_resize_end(sb); return err; @@ -301,7 +301,7 @@ mext_out: if (!inode_owner_or_capable(inode)) return -EACCES; - err = mnt_want_write(filp->f_path.mnt); + err = mnt_want_write_file(filp); if (err) return err; /* @@ -313,7 +313,7 @@ mext_out: mutex_lock(&(inode->i_mutex)); err = ext4_ext_migrate(inode); mutex_unlock(&(inode->i_mutex)); - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); return err; } @@ -323,11 +323,11 @@ mext_out: if (!inode_owner_or_capable(inode)) return -EACCES; - err = mnt_want_write(filp->f_path.mnt); + err = mnt_want_write_file(filp); if (err) return err; err = ext4_alloc_da_blocks(inode); - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); return err; } diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index aa4c782c9dd7..86edc45b52a4 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -1736,7 +1736,7 @@ static int ext4_add_nondir(handle_t *handle, * If the create succeeds, we fill in the inode information * with d_instantiate(). */ -static int ext4_create(struct inode *dir, struct dentry *dentry, int mode, +static int ext4_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { handle_t *handle; @@ -1770,7 +1770,7 @@ retry: } static int ext4_mknod(struct inode *dir, struct dentry *dentry, - int mode, dev_t rdev) + umode_t mode, dev_t rdev) { handle_t *handle; struct inode *inode; @@ -1806,7 +1806,7 @@ retry: return err; } -static int ext4_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { handle_t *handle; struct inode *inode; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 3e1329e2f826..6733b3736b3b 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -930,7 +930,6 @@ static int ext4_drop_inode(struct inode *inode) static void ext4_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(ext4_inode_cachep, EXT4_I(inode)); } @@ -1033,11 +1032,11 @@ static inline void ext4_show_quota_options(struct seq_file *seq, * - 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) +static int ext4_show_options(struct seq_file *seq, struct dentry *root) { int def_errors; unsigned long def_mount_opts; - struct super_block *sb = vfs->mnt_sb; + struct super_block *sb = root->d_sb; struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_super_block *es = sbi->s_es; @@ -4782,7 +4781,7 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id, return -EINVAL; /* Quotafile not on the same filesystem? */ - if (path->mnt->mnt_sb != sb) + if (path->dentry->d_sb != sb) return -EXDEV; /* Journaling quota? */ if (EXT4_SB(sb)->s_qf_names[type]) { diff --git a/fs/fat/fat.h b/fs/fat/fat.h index 1510a4d51990..66994f316e18 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h @@ -141,7 +141,7 @@ static inline struct msdos_inode_info *MSDOS_I(struct inode *inode) static inline int fat_mode_can_hold_ro(struct inode *inode) { struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); - mode_t mask; + umode_t mask; if (S_ISDIR(inode->i_mode)) { if (!sbi->options.rodir) @@ -156,8 +156,8 @@ static inline int fat_mode_can_hold_ro(struct inode *inode) } /* Convert attribute bits and a mask to the UNIX mode. */ -static inline mode_t fat_make_mode(struct msdos_sb_info *sbi, - u8 attrs, mode_t mode) +static inline umode_t fat_make_mode(struct msdos_sb_info *sbi, + u8 attrs, umode_t mode) { if (attrs & ATTR_RO && !((attrs & ATTR_DIR) && !sbi->options.rodir)) mode &= ~S_IWUGO; diff --git a/fs/fat/file.c b/fs/fat/file.c index c118acf16e43..a71fe3715ee8 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -44,7 +44,7 @@ static int fat_ioctl_set_attributes(struct file *file, u32 __user *user_attr) goto out; mutex_lock(&inode->i_mutex); - err = mnt_want_write(file->f_path.mnt); + err = mnt_want_write_file(file); if (err) goto out_unlock_inode; @@ -108,7 +108,7 @@ static int fat_ioctl_set_attributes(struct file *file, u32 __user *user_attr) fat_save_attrs(inode, attr); mark_inode_dirty(inode); out_drop_write: - mnt_drop_write(file->f_path.mnt); + mnt_drop_write_file(file); out_unlock_inode: mutex_unlock(&inode->i_mutex); out: @@ -314,7 +314,7 @@ EXPORT_SYMBOL_GPL(fat_getattr); static int fat_sanitize_mode(const struct msdos_sb_info *sbi, struct inode *inode, umode_t *mode_ptr) { - mode_t mask, perm; + umode_t mask, perm; /* * Note, the basic check is already done by a caller of @@ -351,7 +351,7 @@ static int fat_sanitize_mode(const struct msdos_sb_info *sbi, static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode) { - mode_t allow_utime = sbi->options.allow_utime; + umode_t allow_utime = sbi->options.allow_utime; if (current_fsuid() != inode->i_uid) { if (in_group_p(inode->i_gid)) diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 808cac7edcfb..7873797cc76a 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -518,7 +518,6 @@ static struct inode *fat_alloc_inode(struct super_block *sb) static void fat_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(fat_inode_cachep, MSDOS_I(inode)); } @@ -672,7 +671,7 @@ int fat_sync_inode(struct inode *inode) EXPORT_SYMBOL_GPL(fat_sync_inode); -static int fat_show_options(struct seq_file *m, struct vfsmount *mnt); +static int fat_show_options(struct seq_file *m, struct dentry *root); static const struct super_operations fat_sops = { .alloc_inode = fat_alloc_inode, .destroy_inode = fat_destroy_inode, @@ -811,9 +810,9 @@ static const struct export_operations fat_export_ops = { .get_parent = fat_get_parent, }; -static int fat_show_options(struct seq_file *m, struct vfsmount *mnt) +static int fat_show_options(struct seq_file *m, struct dentry *root) { - struct msdos_sb_info *sbi = MSDOS_SB(mnt->mnt_sb); + struct msdos_sb_info *sbi = MSDOS_SB(root->d_sb); struct fat_mount_options *opts = &sbi->options; int isvfat = opts->isvfat; diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index 216b419f30e2..c5938c9084b9 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c @@ -264,7 +264,7 @@ static int msdos_add_entry(struct inode *dir, const unsigned char *name, } /***** Create a file */ -static int msdos_create(struct inode *dir, struct dentry *dentry, int mode, +static int msdos_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { struct super_block *sb = dir->i_sb; @@ -346,7 +346,7 @@ out: } /***** Make a directory */ -static int msdos_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int msdos_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct super_block *sb = dir->i_sb; struct fat_slot_info sinfo; diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index a87a65663c25..3a444b4e2368 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -781,7 +781,7 @@ error: return ERR_PTR(err); } -static int vfat_create(struct inode *dir, struct dentry *dentry, int mode, +static int vfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { struct super_block *sb = dir->i_sb; @@ -870,7 +870,7 @@ out: return err; } -static int vfat_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int vfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct super_block *sb = dir->i_sb; struct inode *inode; diff --git a/fs/fhandle.c b/fs/fhandle.c index 6b088641f5bf..a48e4a139be1 100644 --- a/fs/fhandle.c +++ b/fs/fhandle.c @@ -10,6 +10,7 @@ #include <linux/personality.h> #include <asm/uaccess.h> #include "internal.h" +#include "mount.h" static long do_sys_name_to_handle(struct path *path, struct file_handle __user *ufh, @@ -24,8 +25,8 @@ static long do_sys_name_to_handle(struct path *path, * We need t make sure wether the file system * support decoding of the file handle */ - if (!path->mnt->mnt_sb->s_export_op || - !path->mnt->mnt_sb->s_export_op->fh_to_dentry) + if (!path->dentry->d_sb->s_export_op || + !path->dentry->d_sb->s_export_op->fh_to_dentry) return -EOPNOTSUPP; if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle))) @@ -66,7 +67,8 @@ static long do_sys_name_to_handle(struct path *path, } else retval = 0; /* copy the mount id */ - if (copy_to_user(mnt_id, &path->mnt->mnt_id, sizeof(*mnt_id)) || + if (copy_to_user(mnt_id, &real_mount(path->mnt)->mnt_id, + sizeof(*mnt_id)) || copy_to_user(ufh, handle, sizeof(struct file_handle) + handle_bytes)) retval = -EFAULT; diff --git a/fs/file_table.c b/fs/file_table.c index c322794f7360..20002e39754d 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -474,29 +474,6 @@ void file_sb_list_del(struct file *file) #endif -int fs_may_remount_ro(struct super_block *sb) -{ - struct file *file; - /* Check that no files are currently opened for writing. */ - lg_global_lock(files_lglock); - do_file_list_for_each_entry(sb, file) { - struct inode *inode = file->f_path.dentry->d_inode; - - /* File with pending delete? */ - if (inode->i_nlink == 0) - goto too_bad; - - /* Writeable file? */ - if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE)) - goto too_bad; - } while_file_list_for_each_entry; - lg_global_unlock(files_lglock); - return 1; /* Tis' cool bro. */ -too_bad: - lg_global_unlock(files_lglock); - return 0; -} - /** * mark_files_ro - mark all files read-only * @sb: superblock in question diff --git a/fs/filesystems.c b/fs/filesystems.c index 0845f84f2a5f..96f24286667a 100644 --- a/fs/filesystems.c +++ b/fs/filesystems.c @@ -74,7 +74,6 @@ int register_filesystem(struct file_system_type * fs) BUG_ON(strchr(fs->name, '.')); if (fs->next) return -EBUSY; - INIT_LIST_HEAD(&fs->fs_supers); write_lock(&file_systems_lock); p = find_filesystem(fs->name, strlen(fs->name)); if (*p) diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c index 7b2af5abe2fa..cf9ef918a2a9 100644 --- a/fs/freevxfs/vxfs_inode.c +++ b/fs/freevxfs/vxfs_inode.c @@ -187,10 +187,10 @@ vxfs_stiget(struct super_block *sbp, ino_t ino) * vxfs_transmod returns a Linux mode_t for a given * VxFS inode structure. */ -static __inline__ mode_t +static __inline__ umode_t vxfs_transmod(struct vxfs_inode_info *vip) { - mode_t ret = vip->vii_mode & ~VXFS_TYPE_MASK; + umode_t ret = vip->vii_mode & ~VXFS_TYPE_MASK; if (VXFS_ISFIFO(vip)) ret |= S_IFIFO; @@ -340,7 +340,6 @@ vxfs_iget(struct super_block *sbp, ino_t ino) static void vxfs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(vxfs_inode_cachep, inode->i_private); } diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 517f211a3bd4..80a4574028f1 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -25,7 +25,6 @@ #include <linux/writeback.h> #include <linux/blkdev.h> #include <linux/backing-dev.h> -#include <linux/buffer_head.h> #include <linux/tracepoint.h> #include "internal.h" diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 9f63e493a9b6..5ddd6ea8f839 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -369,8 +369,8 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, * If the filesystem doesn't support this, then fall back to separate * 'mknod' + 'open' requests. */ -static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, - struct nameidata *nd) +static int fuse_create_open(struct inode *dir, struct dentry *entry, + umode_t mode, struct nameidata *nd) { int err; struct inode *inode; @@ -480,7 +480,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, */ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, struct inode *dir, struct dentry *entry, - int mode) + umode_t mode) { struct fuse_entry_out outarg; struct inode *inode; @@ -547,7 +547,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, return err; } -static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, +static int fuse_mknod(struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev) { struct fuse_mknod_in inarg; @@ -573,7 +573,7 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, return create_new_entry(fc, req, dir, entry, mode); } -static int fuse_create(struct inode *dir, struct dentry *entry, int mode, +static int fuse_create(struct inode *dir, struct dentry *entry, umode_t mode, struct nameidata *nd) { if (nd) { @@ -585,7 +585,7 @@ static int fuse_create(struct inode *dir, struct dentry *entry, int mode, return fuse_mknod(dir, entry, mode, 0); } -static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode) +static int fuse_mkdir(struct inode *dir, struct dentry *entry, umode_t mode) { struct fuse_mkdir_in inarg; struct fuse_conn *fc = get_fuse_conn(dir); diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index cf6db0a93219..1964da0257d9 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -80,7 +80,7 @@ struct fuse_inode { /** The sticky bit in inode->i_mode may have been removed, so preserve the original mode */ - mode_t orig_i_mode; + umode_t orig_i_mode; /** Version of last attribute change */ u64 attr_version; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index aa83109b9431..64cf8d07393e 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -107,7 +107,6 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) static void fuse_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(fuse_inode_cachep, inode); } @@ -498,9 +497,10 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev) return 1; } -static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) +static int fuse_show_options(struct seq_file *m, struct dentry *root) { - struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb); + struct super_block *sb = root->d_sb; + struct fuse_conn *fc = get_fuse_conn_super(sb); seq_printf(m, ",user_id=%u", fc->user_id); seq_printf(m, ",group_id=%u", fc->group_id); @@ -510,9 +510,8 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) seq_puts(m, ",allow_other"); if (fc->max_read != ~0) seq_printf(m, ",max_read=%u", fc->max_read); - if (mnt->mnt_sb->s_bdev && - mnt->mnt_sb->s_blocksize != FUSE_DEFAULT_BLKSIZE) - seq_printf(m, ",blksize=%lu", mnt->mnt_sb->s_blocksize); + if (sb->s_bdev && sb->s_blocksize != FUSE_DEFAULT_BLKSIZE) + seq_printf(m, ",blksize=%lu", sb->s_blocksize); return 0; } diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index ce36a56dfeac..b8927d4f3bf2 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -223,7 +223,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) int error; u32 new_flags, flags; - error = mnt_want_write(filp->f_path.mnt); + error = mnt_want_write_file(filp); if (error) return error; @@ -285,7 +285,7 @@ out_trans_end: out: gfs2_glock_dq_uninit(&gh); out_drop_write: - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); return error; } diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index cfd4959b218c..4b0e59e0a249 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -333,7 +333,7 @@ out: */ static int create_ok(struct gfs2_inode *dip, const struct qstr *name, - unsigned int mode) + umode_t mode) { int error; @@ -364,7 +364,7 @@ static int create_ok(struct gfs2_inode *dip, const struct qstr *name, return 0; } -static void munge_mode_uid_gid(struct gfs2_inode *dip, unsigned int *mode, +static void munge_mode_uid_gid(struct gfs2_inode *dip, umode_t *mode, unsigned int *uid, unsigned int *gid) { if (GFS2_SB(&dip->i_inode)->sd_args.ar_suiddir && @@ -447,7 +447,7 @@ static void gfs2_init_dir(struct buffer_head *dibh, */ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, - const struct gfs2_inum_host *inum, unsigned int mode, + const struct gfs2_inum_host *inum, umode_t mode, unsigned int uid, unsigned int gid, const u64 *generation, dev_t dev, const char *symname, unsigned size, struct buffer_head **bhp) @@ -516,7 +516,7 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, } static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, - unsigned int mode, const struct gfs2_inum_host *inum, + umode_t mode, const struct gfs2_inum_host *inum, const u64 *generation, dev_t dev, const char *symname, unsigned int size, struct buffer_head **bhp) { @@ -659,7 +659,7 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip, */ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, - unsigned int mode, dev_t dev, const char *symname, + umode_t mode, dev_t dev, const char *symname, unsigned int size, int excl) { const struct qstr *name = &dentry->d_name; @@ -760,7 +760,7 @@ fail: */ static int gfs2_create(struct inode *dir, struct dentry *dentry, - int mode, struct nameidata *nd) + umode_t mode, struct nameidata *nd) { int excl = 0; if (nd && (nd->flags & LOOKUP_EXCL)) @@ -1129,7 +1129,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry, * Returns: errno */ -static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { return gfs2_create_inode(dir, dentry, S_IFDIR | mode, 0, NULL, 0, 0); } @@ -1143,7 +1143,7 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) * */ -static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, +static int gfs2_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) { return gfs2_create_inode(dir, dentry, mode, dev, NULL, 0, 0); diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 71e420989f77..10c7733a899b 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1284,18 +1284,18 @@ static int is_ancestor(const struct dentry *d1, const struct dentry *d2) /** * gfs2_show_options - Show mount options for /proc/mounts * @s: seq_file structure - * @mnt: vfsmount + * @root: root of this (sub)tree * * Returns: 0 on success or error code */ -static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt) +static int gfs2_show_options(struct seq_file *s, struct dentry *root) { - struct gfs2_sbd *sdp = mnt->mnt_sb->s_fs_info; + struct gfs2_sbd *sdp = root->d_sb->s_fs_info; struct gfs2_args *args = &sdp->sd_args; int val; - if (is_ancestor(mnt->mnt_root, sdp->sd_master_dir)) + if (is_ancestor(root, sdp->sd_master_dir)) seq_printf(s, ",meta"); if (args->ar_lockproto[0]) seq_printf(s, ",lockproto=%s", args->ar_lockproto); @@ -1582,7 +1582,6 @@ static struct inode *gfs2_alloc_inode(struct super_block *sb) static void gfs2_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(gfs2_inode_cachep, inode); } diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index bce4eef91a06..62fc14ea4b73 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c @@ -186,7 +186,7 @@ static int hfs_dir_release(struct inode *inode, struct file *file) * a directory and return a corresponding inode, given the inode for * the directory and the name (and its length) of the new file. */ -static int hfs_create(struct inode *dir, struct dentry *dentry, int mode, +static int hfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { struct inode *inode; @@ -216,7 +216,7 @@ static int hfs_create(struct inode *dir, struct dentry *dentry, int mode, * in a directory, given the inode for the parent directory and the * name (and its length) of the new directory. */ -static int hfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int hfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct inode *inode; int res; diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h index ad97c2d58287..1bf967c6bfdc 100644 --- a/fs/hfs/hfs_fs.h +++ b/fs/hfs/hfs_fs.h @@ -184,7 +184,7 @@ extern int hfs_get_block(struct inode *, sector_t, struct buffer_head *, int); extern const struct address_space_operations hfs_aops; extern const struct address_space_operations hfs_btree_aops; -extern struct inode *hfs_new_inode(struct inode *, struct qstr *, int); +extern struct inode *hfs_new_inode(struct inode *, struct qstr *, umode_t); extern void hfs_inode_write_fork(struct inode *, struct hfs_extent *, __be32 *, __be32 *); extern int hfs_write_inode(struct inode *, struct writeback_control *); extern int hfs_inode_setattr(struct dentry *, struct iattr *); diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index a1a9fdcd2a00..737dbeb64320 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c @@ -169,7 +169,7 @@ const struct address_space_operations hfs_aops = { /* * hfs_new_inode */ -struct inode *hfs_new_inode(struct inode *dir, struct qstr *name, int mode) +struct inode *hfs_new_inode(struct inode *dir, struct qstr *name, umode_t mode) { struct super_block *sb = dir->i_sb; struct inode *inode = new_inode(sb); diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 1b55f704fb22..8137fb3e6780 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -133,9 +133,9 @@ static int hfs_remount(struct super_block *sb, int *flags, char *data) return 0; } -static int hfs_show_options(struct seq_file *seq, struct vfsmount *mnt) +static int hfs_show_options(struct seq_file *seq, struct dentry *root) { - struct hfs_sb_info *sbi = HFS_SB(mnt->mnt_sb); + struct hfs_sb_info *sbi = HFS_SB(root->d_sb); if (sbi->s_creator != cpu_to_be32(0x3f3f3f3f)) seq_printf(seq, ",creator=%.4s", (char *)&sbi->s_creator); @@ -170,7 +170,6 @@ static struct inode *hfs_alloc_inode(struct super_block *sb) static void hfs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(hfs_inode_cachep, HFS_I(inode)); } diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index 4536cd3f15ae..88e155f895c6 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c @@ -424,7 +424,7 @@ out: } static int hfsplus_mknod(struct inode *dir, struct dentry *dentry, - int mode, dev_t rdev) + umode_t mode, dev_t rdev) { struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb); struct inode *inode; @@ -453,13 +453,13 @@ out: return res; } -static int hfsplus_create(struct inode *dir, struct dentry *dentry, int mode, +static int hfsplus_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { return hfsplus_mknod(dir, dentry, mode, 0); } -static int hfsplus_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int hfsplus_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { return hfsplus_mknod(dir, dentry, mode | S_IFDIR, 0); } diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index d7674d051f52..21a5b7fc6db4 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h @@ -402,7 +402,7 @@ void hfsplus_inode_read_fork(struct inode *, struct hfsplus_fork_raw *); void hfsplus_inode_write_fork(struct inode *, struct hfsplus_fork_raw *); int hfsplus_cat_read_inode(struct inode *, struct hfs_find_data *); int hfsplus_cat_write_inode(struct inode *); -struct inode *hfsplus_new_inode(struct super_block *, int); +struct inode *hfsplus_new_inode(struct super_block *, umode_t); void hfsplus_delete_inode(struct inode *); int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, int datasync); @@ -419,7 +419,7 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size); int hfsplus_parse_options(char *, struct hfsplus_sb_info *); int hfsplus_parse_options_remount(char *input, int *force); void hfsplus_fill_defaults(struct hfsplus_sb_info *); -int hfsplus_show_options(struct seq_file *, struct vfsmount *); +int hfsplus_show_options(struct seq_file *, struct dentry *); /* super.c */ struct inode *hfsplus_iget(struct super_block *, unsigned long); diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 40e1413be4cf..6643b242bdd7 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -378,7 +378,7 @@ static const struct file_operations hfsplus_file_operations = { .unlocked_ioctl = hfsplus_ioctl, }; -struct inode *hfsplus_new_inode(struct super_block *sb, int mode) +struct inode *hfsplus_new_inode(struct super_block *sb, umode_t mode) { struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); struct inode *inode = new_inode(sb); diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c index fbaa6690c8e0..f66c7655b3f7 100644 --- a/fs/hfsplus/ioctl.c +++ b/fs/hfsplus/ioctl.c @@ -43,7 +43,7 @@ static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags) unsigned int flags; int err = 0; - err = mnt_want_write(file->f_path.mnt); + err = mnt_want_write_file(file); if (err) goto out; @@ -94,7 +94,7 @@ static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags) out_unlock_inode: mutex_unlock(&inode->i_mutex); out_drop_write: - mnt_drop_write(file->f_path.mnt); + mnt_drop_write_file(file); out: return err; } diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c index bb62a5882147..06fa5618600c 100644 --- a/fs/hfsplus/options.c +++ b/fs/hfsplus/options.c @@ -206,9 +206,9 @@ done: return 1; } -int hfsplus_show_options(struct seq_file *seq, struct vfsmount *mnt) +int hfsplus_show_options(struct seq_file *seq, struct dentry *root) { - struct hfsplus_sb_info *sbi = HFSPLUS_SB(mnt->mnt_sb); + struct hfsplus_sb_info *sbi = HFSPLUS_SB(root->d_sb); if (sbi->creator != HFSPLUS_DEF_CR_TYPE) seq_printf(seq, ",creator=%.4s", (char *)&sbi->creator); diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index d24a9b666a23..edf0a801446b 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -558,7 +558,6 @@ static void hfsplus_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(hfsplus_inode_cachep, HFSPLUS_I(inode)); } diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h index bf15a43016b9..3cbfa93cd782 100644 --- a/fs/hostfs/hostfs.h +++ b/fs/hostfs/hostfs.h @@ -39,7 +39,7 @@ struct hostfs_iattr { unsigned int ia_valid; - mode_t ia_mode; + unsigned short ia_mode; uid_t ia_uid; gid_t ia_gid; loff_t ia_size; diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 2f72da5ae686..e130bd46d671 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -250,7 +250,6 @@ static void hostfs_evict_inode(struct inode *inode) static void hostfs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kfree(HOSTFS_I(inode)); } @@ -259,9 +258,9 @@ static void hostfs_destroy_inode(struct inode *inode) call_rcu(&inode->i_rcu, hostfs_i_callback); } -static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs) +static int hostfs_show_options(struct seq_file *seq, struct dentry *root) { - const char *root_path = vfs->mnt_sb->s_fs_info; + const char *root_path = root->d_sb->s_fs_info; size_t offset = strlen(root_ino) + 1; if (strlen(root_path) > offset) @@ -552,7 +551,7 @@ static int read_name(struct inode *ino, char *name) return 0; } -int hostfs_create(struct inode *dir, struct dentry *dentry, int mode, +int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { struct inode *inode; @@ -677,7 +676,7 @@ int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to) return err; } -int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode) +int hostfs_mkdir(struct inode *ino, struct dentry *dentry, umode_t mode) { char *file; int err; @@ -701,7 +700,7 @@ int hostfs_rmdir(struct inode *ino, struct dentry *dentry) return err; } -int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) +static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) { struct inode *inode; char *name; diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index ea91fcb0ef9b..30dd7b10b507 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c @@ -8,7 +8,7 @@ #include <linux/sched.h> #include "hpfs_fn.h" -static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { const unsigned char *name = dentry->d_name.name; unsigned len = dentry->d_name.len; @@ -115,7 +115,7 @@ bail: return err; } -static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) +static int hpfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { const unsigned char *name = dentry->d_name.name; unsigned len = dentry->d_name.len; @@ -201,7 +201,7 @@ bail: return err; } -static int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) +static int hpfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { const unsigned char *name = dentry->d_name.name; unsigned len = dentry->d_name.len; diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 98580a3b5005..3690467c944e 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -181,7 +181,6 @@ static struct inode *hpfs_alloc_inode(struct super_block *sb) static void hpfs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(hpfs_inode_cachep, hpfs_i(inode)); } diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c index f590b1160c6c..d92f4ce80925 100644 --- a/fs/hppfs/hppfs.c +++ b/fs/hppfs/hppfs.c @@ -622,7 +622,6 @@ void hppfs_evict_inode(struct inode *ino) static void hppfs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kfree(HPPFS_I(inode)); } @@ -726,7 +725,7 @@ static int hppfs_fill_super(struct super_block *sb, void *d, int silent) sb->s_fs_info = proc_mnt; err = -ENOMEM; - root_inode = get_inode(sb, dget(proc_mnt->mnt_sb->s_root)); + root_inode = get_inode(sb, dget(proc_mnt->mnt_root)); if (!root_inode) goto out_mntput; diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 0be5a78598d0..e425ad9d0490 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -447,8 +447,8 @@ static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr) return 0; } -static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid, - gid_t gid, int mode, dev_t dev) +static struct inode *hugetlbfs_get_root(struct super_block *sb, + struct hugetlbfs_config *config) { struct inode *inode; @@ -456,9 +456,31 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid, if (inode) { struct hugetlbfs_inode_info *info; inode->i_ino = get_next_ino(); - inode->i_mode = mode; - inode->i_uid = uid; - inode->i_gid = gid; + inode->i_mode = S_IFDIR | config->mode; + inode->i_uid = config->uid; + inode->i_gid = config->gid; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + info = HUGETLBFS_I(inode); + mpol_shared_policy_init(&info->policy, NULL); + inode->i_op = &hugetlbfs_dir_inode_operations; + inode->i_fop = &simple_dir_operations; + /* directory inodes start off with i_nlink == 2 (for "." entry) */ + inc_nlink(inode); + } + return inode; +} + +static struct inode *hugetlbfs_get_inode(struct super_block *sb, + struct inode *dir, + umode_t mode, dev_t dev) +{ + struct inode *inode; + + inode = new_inode(sb); + if (inode) { + struct hugetlbfs_inode_info *info; + inode->i_ino = get_next_ino(); + inode_init_owner(inode, dir, mode); inode->i_mapping->a_ops = &hugetlbfs_aops; inode->i_mapping->backing_dev_info =&hugetlbfs_backing_dev_info; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; @@ -500,20 +522,12 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid, * File creation. Allocate an inode, and we're done.. */ static int hugetlbfs_mknod(struct inode *dir, - struct dentry *dentry, int mode, dev_t dev) + struct dentry *dentry, umode_t mode, dev_t dev) { struct inode *inode; int error = -ENOSPC; - gid_t gid; - - if (dir->i_mode & S_ISGID) { - gid = dir->i_gid; - if (S_ISDIR(mode)) - mode |= S_ISGID; - } else { - gid = current_fsgid(); - } - inode = hugetlbfs_get_inode(dir->i_sb, current_fsuid(), gid, mode, dev); + + inode = hugetlbfs_get_inode(dir->i_sb, dir, mode, dev); if (inode) { dir->i_ctime = dir->i_mtime = CURRENT_TIME; d_instantiate(dentry, inode); @@ -523,7 +537,7 @@ static int hugetlbfs_mknod(struct inode *dir, return error; } -static int hugetlbfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int hugetlbfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { int retval = hugetlbfs_mknod(dir, dentry, mode | S_IFDIR, 0); if (!retval) @@ -531,7 +545,7 @@ static int hugetlbfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) return retval; } -static int hugetlbfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) +static int hugetlbfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { return hugetlbfs_mknod(dir, dentry, mode | S_IFREG, 0); } @@ -541,15 +555,8 @@ static int hugetlbfs_symlink(struct inode *dir, { struct inode *inode; int error = -ENOSPC; - gid_t gid; - - if (dir->i_mode & S_ISGID) - gid = dir->i_gid; - else - gid = current_fsgid(); - inode = hugetlbfs_get_inode(dir->i_sb, current_fsuid(), - gid, S_IFLNK|S_IRWXUGO, 0); + inode = hugetlbfs_get_inode(dir->i_sb, dir, S_IFLNK|S_IRWXUGO, 0); if (inode) { int l = strlen(symname)+1; error = page_symlink(inode, symname, l); @@ -666,7 +673,6 @@ static struct inode *hugetlbfs_alloc_inode(struct super_block *sb) static void hugetlbfs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(hugetlbfs_inode_cachep, HUGETLBFS_I(inode)); } @@ -858,8 +864,7 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_magic = HUGETLBFS_MAGIC; sb->s_op = &hugetlbfs_ops; sb->s_time_gran = 1; - inode = hugetlbfs_get_inode(sb, config.uid, config.gid, - S_IFDIR | config.mode, 0); + inode = hugetlbfs_get_root(sb, &config); if (!inode) goto out_free; @@ -957,8 +962,7 @@ struct file *hugetlb_file_setup(const char *name, size_t size, path.mnt = mntget(hugetlbfs_vfsmount); error = -ENOSPC; - inode = hugetlbfs_get_inode(root->d_sb, current_fsuid(), - current_fsgid(), S_IFREG | S_IRWXUGO, 0); + inode = hugetlbfs_get_inode(root->d_sb, NULL, S_IFREG | S_IRWXUGO, 0); if (!inode) goto out_dentry; diff --git a/fs/inode.c b/fs/inode.c index ee4e66b998f4..87535753ab04 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -26,6 +26,7 @@ #include <linux/ima.h> #include <linux/cred.h> #include <linux/buffer_head.h> /* for inode_has_buffers */ +#include <linux/ratelimit.h> #include "internal.h" /* @@ -191,6 +192,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode) } inode->i_private = NULL; inode->i_mapping = mapping; + INIT_LIST_HEAD(&inode->i_dentry); /* buggered by rcu freeing */ #ifdef CONFIG_FS_POSIX_ACL inode->i_acl = inode->i_default_acl = ACL_NOT_CACHED; #endif @@ -241,6 +243,11 @@ void __destroy_inode(struct inode *inode) BUG_ON(inode_has_buffers(inode)); security_inode_free(inode); fsnotify_inode_delete(inode); + if (!inode->i_nlink) { + WARN_ON(atomic_long_read(&inode->i_sb->s_remove_count) == 0); + atomic_long_dec(&inode->i_sb->s_remove_count); + } + #ifdef CONFIG_FS_POSIX_ACL if (inode->i_acl && inode->i_acl != ACL_NOT_CACHED) posix_acl_release(inode->i_acl); @@ -254,7 +261,6 @@ EXPORT_SYMBOL(__destroy_inode); static void i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(inode_cachep, inode); } @@ -268,6 +274,85 @@ static void destroy_inode(struct inode *inode) call_rcu(&inode->i_rcu, i_callback); } +/** + * drop_nlink - directly drop an inode's link count + * @inode: inode + * + * This is a low-level filesystem helper to replace any + * direct filesystem manipulation of i_nlink. In cases + * where we are attempting to track writes to the + * filesystem, a decrement to zero means an imminent + * write when the file is truncated and actually unlinked + * on the filesystem. + */ +void drop_nlink(struct inode *inode) +{ + WARN_ON(inode->i_nlink == 0); + inode->__i_nlink--; + if (!inode->i_nlink) + atomic_long_inc(&inode->i_sb->s_remove_count); +} +EXPORT_SYMBOL(drop_nlink); + +/** + * clear_nlink - directly zero an inode's link count + * @inode: inode + * + * This is a low-level filesystem helper to replace any + * direct filesystem manipulation of i_nlink. See + * drop_nlink() for why we care about i_nlink hitting zero. + */ +void clear_nlink(struct inode *inode) +{ + if (inode->i_nlink) { + inode->__i_nlink = 0; + atomic_long_inc(&inode->i_sb->s_remove_count); + } +} +EXPORT_SYMBOL(clear_nlink); + +/** + * set_nlink - directly set an inode's link count + * @inode: inode + * @nlink: new nlink (should be non-zero) + * + * This is a low-level filesystem helper to replace any + * direct filesystem manipulation of i_nlink. + */ +void set_nlink(struct inode *inode, unsigned int nlink) +{ + if (!nlink) { + printk_ratelimited(KERN_INFO + "set_nlink() clearing i_nlink on %s inode %li\n", + inode->i_sb->s_type->name, inode->i_ino); + clear_nlink(inode); + } else { + /* Yes, some filesystems do change nlink from zero to one */ + if (inode->i_nlink == 0) + atomic_long_dec(&inode->i_sb->s_remove_count); + + inode->__i_nlink = nlink; + } +} +EXPORT_SYMBOL(set_nlink); + +/** + * inc_nlink - directly increment an inode's link count + * @inode: inode + * + * This is a low-level filesystem helper to replace any + * direct filesystem manipulation of i_nlink. Currently, + * it is only here for parity with dec_nlink(). + */ +void inc_nlink(struct inode *inode) +{ + if (WARN_ON(inode->i_nlink == 0)) + atomic_long_dec(&inode->i_sb->s_remove_count); + + inode->__i_nlink++; +} +EXPORT_SYMBOL(inc_nlink); + void address_space_init_once(struct address_space *mapping) { memset(mapping, 0, sizeof(*mapping)); @@ -290,7 +375,6 @@ void inode_init_once(struct inode *inode) { memset(inode, 0, sizeof(*inode)); INIT_HLIST_NODE(&inode->i_hash); - INIT_LIST_HEAD(&inode->i_dentry); INIT_LIST_HEAD(&inode->i_devices); INIT_LIST_HEAD(&inode->i_wb_list); INIT_LIST_HEAD(&inode->i_lru); @@ -1508,7 +1592,7 @@ void file_update_time(struct file *file) if (sync_it & S_MTIME) inode->i_mtime = now; mark_inode_dirty_sync(inode); - mnt_drop_write(file->f_path.mnt); + mnt_drop_write_file(file); } EXPORT_SYMBOL(file_update_time); @@ -1647,7 +1731,7 @@ EXPORT_SYMBOL(init_special_inode); * @mode: mode of the new inode */ void inode_init_owner(struct inode *inode, const struct inode *dir, - mode_t mode) + umode_t mode) { inode->i_uid = current_fsuid(); if (dir && dir->i_mode & S_ISGID) { diff --git a/fs/internal.h b/fs/internal.h index fe327c20af83..9962c59ba280 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -15,19 +15,14 @@ struct super_block; struct file_system_type; struct linux_binprm; struct path; +struct mount; /* * block_dev.c */ #ifdef CONFIG_BLOCK -extern struct super_block *blockdev_superblock; extern void __init bdev_cache_init(void); -static inline int sb_is_blkdev_sb(struct super_block *sb) -{ - return sb == blockdev_superblock; -} - extern int __sync_blockdev(struct block_device *bdev, int wait); #else @@ -35,11 +30,6 @@ static inline void bdev_cache_init(void) { } -static inline int sb_is_blkdev_sb(struct super_block *sb) -{ - return 0; -} - static inline int __sync_blockdev(struct block_device *bdev, int wait) { return 0; @@ -52,28 +42,17 @@ static inline int __sync_blockdev(struct block_device *bdev, int wait) extern void __init chrdev_init(void); /* - * exec.c - */ -extern int check_unsafe_exec(struct linux_binprm *); - -/* * namespace.c */ extern int copy_mount_options(const void __user *, unsigned long *); extern int copy_mount_string(const void __user *, char **); -extern unsigned int mnt_get_count(struct vfsmount *mnt); -extern struct vfsmount *__lookup_mnt(struct vfsmount *, struct dentry *, int); extern struct vfsmount *lookup_mnt(struct path *); -extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *, - struct vfsmount *); -extern void release_mounts(struct list_head *); -extern void umount_tree(struct vfsmount *, int, struct list_head *); -extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int); extern int finish_automount(struct vfsmount *, struct path *); extern void mnt_make_longterm(struct vfsmount *); extern void mnt_make_shortterm(struct vfsmount *); +extern int sb_prepare_remount_readonly(struct super_block *); extern void __init mnt_init(void); @@ -98,10 +77,9 @@ extern struct file *get_empty_filp(void); */ extern int do_remount_sb(struct super_block *, int, void *, int); extern bool grab_super_passive(struct super_block *sb); -extern void __put_super(struct super_block *sb); -extern void put_super(struct super_block *sb); extern struct dentry *mount_fs(struct file_system_type *, int, const char *, void *); +extern struct super_block *user_get_super(dev_t); /* * open.c @@ -111,7 +89,7 @@ extern struct file *nameidata_to_filp(struct nameidata *); extern void release_open_intent(struct nameidata *); struct open_flags { int open_flag; - int mode; + umode_t mode; int acc_mode; int intent; }; diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index f950059525fc..7b99f5f460be 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -85,7 +85,6 @@ static struct inode *isofs_alloc_inode(struct super_block *sb) static void isofs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(isofs_inode_cachep, ISOFS_I(inode)); } @@ -170,8 +169,8 @@ struct iso9660_options{ unsigned char map; unsigned char check; unsigned int blocksize; - mode_t fmode; - mode_t dmode; + umode_t fmode; + umode_t dmode; gid_t gid; uid_t uid; char *iocharset; diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h index 7d33de84f52a..0e73f63d9274 100644 --- a/fs/isofs/isofs.h +++ b/fs/isofs/isofs.h @@ -50,14 +50,14 @@ struct isofs_sb_info { unsigned int s_uid_set:1; unsigned int s_gid_set:1; - mode_t s_fmode; - mode_t s_dmode; + umode_t s_fmode; + umode_t s_dmode; gid_t s_gid; uid_t s_uid; struct nls_table *s_nls_iocharset; /* Native language support table */ }; -#define ISOFS_INVALID_MODE ((mode_t) -1) +#define ISOFS_INVALID_MODE ((umode_t) -1) static inline struct isofs_sb_info *ISOFS_SB(struct super_block *sb) { diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index be6169bd8acd..973ac5822bd7 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -22,16 +22,16 @@ static int jffs2_readdir (struct file *, void *, filldir_t); -static int jffs2_create (struct inode *,struct dentry *,int, +static int jffs2_create (struct inode *,struct dentry *,umode_t, struct nameidata *); static struct dentry *jffs2_lookup (struct inode *,struct dentry *, struct nameidata *); static int jffs2_link (struct dentry *,struct inode *,struct dentry *); static int jffs2_unlink (struct inode *,struct dentry *); static int jffs2_symlink (struct inode *,struct dentry *,const char *); -static int jffs2_mkdir (struct inode *,struct dentry *,int); +static int jffs2_mkdir (struct inode *,struct dentry *,umode_t); static int jffs2_rmdir (struct inode *,struct dentry *); -static int jffs2_mknod (struct inode *,struct dentry *,int,dev_t); +static int jffs2_mknod (struct inode *,struct dentry *,umode_t,dev_t); static int jffs2_rename (struct inode *, struct dentry *, struct inode *, struct dentry *); @@ -169,8 +169,8 @@ static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir) /***********************************************************************/ -static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, - struct nameidata *nd) +static int jffs2_create(struct inode *dir_i, struct dentry *dentry, + umode_t mode, struct nameidata *nd) { struct jffs2_raw_inode *ri; struct jffs2_inode_info *f, *dir_f; @@ -450,7 +450,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char } -static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) +static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, umode_t mode) { struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; @@ -618,7 +618,7 @@ static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) return ret; } -static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, dev_t rdev) +static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, umode_t mode, dev_t rdev) { struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index e7e974454115..8be4925296cf 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -45,7 +45,6 @@ static struct inode *jffs2_alloc_inode(struct super_block *sb) static void jffs2_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode)); } @@ -97,9 +96,9 @@ static const char *jffs2_compr_name(unsigned int compr) } } -static int jffs2_show_options(struct seq_file *s, struct vfsmount *mnt) +static int jffs2_show_options(struct seq_file *s, struct dentry *root) { - struct jffs2_sb_info *c = JFFS2_SB_INFO(mnt->mnt_sb); + struct jffs2_sb_info *c = JFFS2_SB_INFO(root->d_sb); struct jffs2_mount_opts *opts = &c->mount_opts; if (opts->override_compr) diff --git a/fs/jfs/ioctl.c b/fs/jfs/ioctl.c index 6f98a1866776..f19d1e04a374 100644 --- a/fs/jfs/ioctl.c +++ b/fs/jfs/ioctl.c @@ -68,7 +68,7 @@ long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) unsigned int oldflags; int err; - err = mnt_want_write(filp->f_path.mnt); + err = mnt_want_write_file(filp); if (err) return err; @@ -120,7 +120,7 @@ long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); setflags_out: - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); return err; } default: diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index a112ad96e474..5f7c160ea64f 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -72,7 +72,7 @@ static inline void free_ea_wmap(struct inode *inode) * RETURN: Errors from subroutines * */ -static int jfs_create(struct inode *dip, struct dentry *dentry, int mode, +static int jfs_create(struct inode *dip, struct dentry *dentry, umode_t mode, struct nameidata *nd) { int rc = 0; @@ -205,7 +205,7 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode, * note: * EACCESS: user needs search+write permission on the parent directory */ -static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) +static int jfs_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode) { int rc = 0; tid_t tid; /* transaction id */ @@ -1353,7 +1353,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, * FUNCTION: Create a special file (device) */ static int jfs_mknod(struct inode *dir, struct dentry *dentry, - int mode, dev_t rdev) + umode_t mode, dev_t rdev) { struct jfs_inode_info *jfs_ip; struct btstack btstack; diff --git a/fs/jfs/super.c b/fs/jfs/super.c index a44eff076c17..682bca642f38 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -119,7 +119,6 @@ static void jfs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); struct jfs_inode_info *ji = JFS_IP(inode); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(jfs_inode_cachep, ji); } @@ -609,9 +608,9 @@ static int jfs_sync_fs(struct super_block *sb, int wait) return 0; } -static int jfs_show_options(struct seq_file *seq, struct vfsmount *vfs) +static int jfs_show_options(struct seq_file *seq, struct dentry *root) { - struct jfs_sb_info *sbi = JFS_SBI(vfs->mnt_sb); + struct jfs_sb_info *sbi = JFS_SBI(root->d_sb); if (sbi->uid != -1) seq_printf(seq, ",uid=%d", sbi->uid); diff --git a/fs/libfs.c b/fs/libfs.c index f6d411eef1e7..5b2dbb3ba4fc 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -12,7 +12,7 @@ #include <linux/mutex.h> #include <linux/exportfs.h> #include <linux/writeback.h> -#include <linux/buffer_head.h> +#include <linux/buffer_head.h> /* sync_mapping_buffers */ #include <asm/uaccess.h> diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index 1ca0679c80bf..2240d384d787 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -403,7 +403,7 @@ nlmsvc_match_sb(void *datap, struct nlm_file *file) { struct super_block *sb = datap; - return sb == file->f_file->f_path.mnt->mnt_sb; + return sb == file->f_file->f_path.dentry->d_sb; } /** diff --git a/fs/logfs/dir.c b/fs/logfs/dir.c index b7d7f67cee5a..501043e8966c 100644 --- a/fs/logfs/dir.c +++ b/fs/logfs/dir.c @@ -482,7 +482,7 @@ out: return ret; } -static int logfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int logfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct inode *inode; @@ -501,7 +501,7 @@ static int logfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) return __logfs_create(dir, dentry, inode, NULL, 0); } -static int logfs_create(struct inode *dir, struct dentry *dentry, int mode, +static int logfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { struct inode *inode; @@ -517,7 +517,7 @@ static int logfs_create(struct inode *dir, struct dentry *dentry, int mode, return __logfs_create(dir, dentry, inode, NULL, 0); } -static int logfs_mknod(struct inode *dir, struct dentry *dentry, int mode, +static int logfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { struct inode *inode; diff --git a/fs/logfs/inode.c b/fs/logfs/inode.c index 7e441ad5f792..388df1aa35e5 100644 --- a/fs/logfs/inode.c +++ b/fs/logfs/inode.c @@ -144,7 +144,6 @@ struct inode *logfs_safe_iget(struct super_block *sb, ino_t ino, int *is_cached) static void logfs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(logfs_inode_cache, logfs_inode(inode)); } @@ -324,7 +323,7 @@ static void logfs_set_ino_generation(struct super_block *sb, mutex_unlock(&super->s_journal_mutex); } -struct inode *logfs_new_inode(struct inode *dir, int mode) +struct inode *logfs_new_inode(struct inode *dir, umode_t mode) { struct super_block *sb = dir->i_sb; struct inode *inode; diff --git a/fs/logfs/logfs.h b/fs/logfs/logfs.h index 398ecff6e548..926373866a55 100644 --- a/fs/logfs/logfs.h +++ b/fs/logfs/logfs.h @@ -520,7 +520,7 @@ extern const struct super_operations logfs_super_operations; struct inode *logfs_iget(struct super_block *sb, ino_t ino); struct inode *logfs_safe_iget(struct super_block *sb, ino_t ino, int *cookie); void logfs_safe_iput(struct inode *inode, int cookie); -struct inode *logfs_new_inode(struct inode *dir, int mode); +struct inode *logfs_new_inode(struct inode *dir, umode_t mode); struct inode *logfs_new_meta_inode(struct super_block *sb, u64 ino); struct inode *logfs_read_meta_inode(struct super_block *sb, u64 ino); int logfs_init_inode_cache(void); diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c index ef175cb8cfd8..4bc50dac8e97 100644 --- a/fs/minix/bitmap.c +++ b/fs/minix/bitmap.c @@ -209,7 +209,7 @@ void minix_free_inode(struct inode * inode) mark_buffer_dirty(bh); } -struct inode *minix_new_inode(const struct inode *dir, int mode, int *error) +struct inode *minix_new_inode(const struct inode *dir, umode_t mode, int *error) { struct super_block *sb = dir->i_sb; struct minix_sb_info *sbi = minix_sb(sb); diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 4d46a6a59070..fa8b612b8ce2 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -71,7 +71,6 @@ static struct inode *minix_alloc_inode(struct super_block *sb) static void minix_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(minix_inode_cachep, minix_i(inode)); } diff --git a/fs/minix/minix.h b/fs/minix/minix.h index 26bbd55e82ea..c889ef0aa571 100644 --- a/fs/minix/minix.h +++ b/fs/minix/minix.h @@ -46,7 +46,7 @@ struct minix_sb_info { extern struct inode *minix_iget(struct super_block *, unsigned long); extern struct minix_inode * minix_V1_raw_inode(struct super_block *, ino_t, struct buffer_head **); extern struct minix2_inode * minix_V2_raw_inode(struct super_block *, ino_t, struct buffer_head **); -extern struct inode * minix_new_inode(const struct inode *, int, int *); +extern struct inode * minix_new_inode(const struct inode *, umode_t, int *); extern void minix_free_inode(struct inode * inode); extern unsigned long minix_count_free_inodes(struct super_block *sb); extern int minix_new_block(struct inode * inode); diff --git a/fs/minix/namei.c b/fs/minix/namei.c index 6e6777f1b4b2..2f76e38c2065 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -36,7 +36,7 @@ static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, st return NULL; } -static int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, dev_t rdev) +static int minix_mknod(struct inode * dir, struct dentry *dentry, umode_t mode, dev_t rdev) { int error; struct inode *inode; @@ -54,7 +54,7 @@ static int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, dev_ return error; } -static int minix_create(struct inode * dir, struct dentry *dentry, int mode, +static int minix_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { return minix_mknod(dir, dentry, mode, 0); @@ -103,7 +103,7 @@ static int minix_link(struct dentry * old_dentry, struct inode * dir, return add_nondir(dentry, inode); } -static int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode) +static int minix_mkdir(struct inode * dir, struct dentry *dentry, umode_t mode) { struct inode * inode; int err = -EMLINK; diff --git a/fs/mount.h b/fs/mount.h new file mode 100644 index 000000000000..4ef36d93e5a2 --- /dev/null +++ b/fs/mount.h @@ -0,0 +1,76 @@ +#include <linux/mount.h> +#include <linux/seq_file.h> +#include <linux/poll.h> + +struct mnt_namespace { + atomic_t count; + struct mount * root; + struct list_head list; + wait_queue_head_t poll; + int event; +}; + +struct mnt_pcp { + int mnt_count; + int mnt_writers; +}; + +struct mount { + struct list_head mnt_hash; + struct mount *mnt_parent; + struct dentry *mnt_mountpoint; + struct vfsmount mnt; +#ifdef CONFIG_SMP + struct mnt_pcp __percpu *mnt_pcp; + atomic_t mnt_longterm; /* how many of the refs are longterm */ +#else + int mnt_count; + int mnt_writers; +#endif + struct list_head mnt_mounts; /* list of children, anchored here */ + struct list_head mnt_child; /* and going through their mnt_child */ + struct list_head mnt_instance; /* mount instance on sb->s_mounts */ + const char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */ + struct list_head mnt_list; + struct list_head mnt_expire; /* link in fs-specific expiry list */ + struct list_head mnt_share; /* circular list of shared mounts */ + struct list_head mnt_slave_list;/* list of slave mounts */ + struct list_head mnt_slave; /* slave list entry */ + struct mount *mnt_master; /* slave is on master->mnt_slave_list */ + struct mnt_namespace *mnt_ns; /* containing namespace */ +#ifdef CONFIG_FSNOTIFY + struct hlist_head mnt_fsnotify_marks; + __u32 mnt_fsnotify_mask; +#endif + int mnt_id; /* mount identifier */ + int mnt_group_id; /* peer group identifier */ + int mnt_expiry_mark; /* true if marked for expiry */ + int mnt_pinned; + int mnt_ghosts; +}; + +static inline struct mount *real_mount(struct vfsmount *mnt) +{ + return container_of(mnt, struct mount, mnt); +} + +static inline int mnt_has_parent(struct mount *mnt) +{ + return mnt != mnt->mnt_parent; +} + +extern struct mount *__lookup_mnt(struct vfsmount *, struct dentry *, int); + +static inline void get_mnt_ns(struct mnt_namespace *ns) +{ + atomic_inc(&ns->count); +} + +struct proc_mounts { + struct seq_file m; /* must be the first element */ + struct mnt_namespace *ns; + struct path root; + int (*show)(struct seq_file *, struct vfsmount *); +}; + +extern const struct seq_operations mounts_op; diff --git a/fs/namei.c b/fs/namei.c index 5008f01787f5..c283a1ec008e 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -36,6 +36,7 @@ #include <asm/uaccess.h> #include "internal.h" +#include "mount.h" /* [Feb-1997 T. Schoebel-Theuer] * Fundamental changes in the pathname lookup mechanisms (namei) @@ -676,36 +677,38 @@ follow_link(struct path *link, struct nameidata *nd, void **p) static int follow_up_rcu(struct path *path) { - struct vfsmount *parent; + struct mount *mnt = real_mount(path->mnt); + struct mount *parent; struct dentry *mountpoint; - parent = path->mnt->mnt_parent; - if (parent == path->mnt) + parent = mnt->mnt_parent; + if (&parent->mnt == path->mnt) return 0; - mountpoint = path->mnt->mnt_mountpoint; + mountpoint = mnt->mnt_mountpoint; path->dentry = mountpoint; - path->mnt = parent; + path->mnt = &parent->mnt; return 1; } int follow_up(struct path *path) { - struct vfsmount *parent; + struct mount *mnt = real_mount(path->mnt); + struct mount *parent; struct dentry *mountpoint; br_read_lock(vfsmount_lock); - parent = path->mnt->mnt_parent; - if (parent == path->mnt) { + parent = mnt->mnt_parent; + if (&parent->mnt == path->mnt) { br_read_unlock(vfsmount_lock); return 0; } - mntget(parent); - mountpoint = dget(path->mnt->mnt_mountpoint); + mntget(&parent->mnt); + mountpoint = dget(mnt->mnt_mountpoint); br_read_unlock(vfsmount_lock); dput(path->dentry); path->dentry = mountpoint; mntput(path->mnt); - path->mnt = parent; + path->mnt = &parent->mnt; return 1; } @@ -884,7 +887,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, struct inode **inode) { for (;;) { - struct vfsmount *mounted; + struct mount *mounted; /* * Don't forget we might have a non-mountpoint managed dentry * that wants to block transit. @@ -898,8 +901,8 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, mounted = __lookup_mnt(path->mnt, path->dentry, 1); if (!mounted) break; - path->mnt = mounted; - path->dentry = mounted->mnt_root; + path->mnt = &mounted->mnt; + path->dentry = mounted->mnt.mnt_root; nd->flags |= LOOKUP_JUMPED; nd->seq = read_seqcount_begin(&path->dentry->d_seq); /* @@ -915,12 +918,12 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, static void follow_mount_rcu(struct nameidata *nd) { while (d_mountpoint(nd->path.dentry)) { - struct vfsmount *mounted; + struct mount *mounted; mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry, 1); if (!mounted) break; - nd->path.mnt = mounted; - nd->path.dentry = mounted->mnt_root; + nd->path.mnt = &mounted->mnt; + nd->path.dentry = mounted->mnt.mnt_root; nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); } } @@ -1976,7 +1979,7 @@ void unlock_rename(struct dentry *p1, struct dentry *p2) } } -int vfs_create(struct inode *dir, struct dentry *dentry, int mode, +int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { int error = may_create(dir, dentry); @@ -2177,7 +2180,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path, /* Negative dentry, just create the file */ if (!dentry->d_inode) { - int mode = op->mode; + umode_t mode = op->mode; if (!IS_POSIXACL(dir->d_inode)) mode &= ~current_umask(); /* @@ -2444,7 +2447,7 @@ struct dentry *user_path_create(int dfd, const char __user *pathname, struct pat } EXPORT_SYMBOL(user_path_create); -int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) +int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) { int error = may_create(dir, dentry); @@ -2472,7 +2475,7 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) return error; } -static int may_mknod(mode_t mode) +static int may_mknod(umode_t mode) { switch (mode & S_IFMT) { case S_IFREG: @@ -2489,7 +2492,7 @@ static int may_mknod(mode_t mode) } } -SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, int, mode, +SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode, unsigned, dev) { struct dentry *dentry; @@ -2536,12 +2539,12 @@ out_dput: return error; } -SYSCALL_DEFINE3(mknod, const char __user *, filename, int, mode, unsigned, dev) +SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, dev) { return sys_mknodat(AT_FDCWD, filename, mode, dev); } -int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { int error = may_create(dir, dentry); @@ -2562,7 +2565,7 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) return error; } -SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, int, mode) +SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode) { struct dentry *dentry; struct path path; @@ -2590,7 +2593,7 @@ out_dput: return error; } -SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode) +SYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode) { return sys_mkdirat(AT_FDCWD, pathname, mode); } diff --git a/fs/namespace.c b/fs/namespace.c index cfc6d4448aa5..7e6f2c9dc7c4 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -9,30 +9,17 @@ */ #include <linux/syscalls.h> -#include <linux/slab.h> -#include <linux/sched.h> -#include <linux/spinlock.h> -#include <linux/percpu.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/acct.h> +#include <linux/export.h> #include <linux/capability.h> -#include <linux/cpumask.h> -#include <linux/module.h> -#include <linux/sysfs.h> -#include <linux/seq_file.h> #include <linux/mnt_namespace.h> #include <linux/namei.h> -#include <linux/nsproxy.h> #include <linux/security.h> -#include <linux/mount.h> -#include <linux/ramfs.h> -#include <linux/log2.h> #include <linux/idr.h> -#include <linux/fs_struct.h> -#include <linux/fsnotify.h> -#include <asm/uaccess.h> -#include <asm/unistd.h> +#include <linux/acct.h> /* acct_auto_close_mnt */ +#include <linux/ramfs.h> /* init_rootfs */ +#include <linux/fs_struct.h> /* get_fs_root et.al. */ +#include <linux/fsnotify.h> /* fsnotify_vfsmount_delete */ +#include <linux/uaccess.h> #include "pnode.h" #include "internal.h" @@ -78,7 +65,7 @@ static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) * allocation is serialized by namespace_sem, but we need the spinlock to * serialize with freeing. */ -static int mnt_alloc_id(struct vfsmount *mnt) +static int mnt_alloc_id(struct mount *mnt) { int res; @@ -95,7 +82,7 @@ retry: return res; } -static void mnt_free_id(struct vfsmount *mnt) +static void mnt_free_id(struct mount *mnt) { int id = mnt->mnt_id; spin_lock(&mnt_id_lock); @@ -110,7 +97,7 @@ static void mnt_free_id(struct vfsmount *mnt) * * mnt_group_ida is protected by namespace_sem */ -static int mnt_alloc_group_id(struct vfsmount *mnt) +static int mnt_alloc_group_id(struct mount *mnt) { int res; @@ -129,7 +116,7 @@ static int mnt_alloc_group_id(struct vfsmount *mnt) /* * Release a peer group ID */ -void mnt_release_group_id(struct vfsmount *mnt) +void mnt_release_group_id(struct mount *mnt) { int id = mnt->mnt_group_id; ida_remove(&mnt_group_ida, id); @@ -141,7 +128,7 @@ void mnt_release_group_id(struct vfsmount *mnt) /* * vfsmount lock must be held for read */ -static inline void mnt_add_count(struct vfsmount *mnt, int n) +static inline void mnt_add_count(struct mount *mnt, int n) { #ifdef CONFIG_SMP this_cpu_add(mnt->mnt_pcp->mnt_count, n); @@ -152,35 +139,10 @@ static inline void mnt_add_count(struct vfsmount *mnt, int n) #endif } -static inline void mnt_set_count(struct vfsmount *mnt, int n) -{ -#ifdef CONFIG_SMP - this_cpu_write(mnt->mnt_pcp->mnt_count, n); -#else - mnt->mnt_count = n; -#endif -} - -/* - * vfsmount lock must be held for read - */ -static inline void mnt_inc_count(struct vfsmount *mnt) -{ - mnt_add_count(mnt, 1); -} - -/* - * vfsmount lock must be held for read - */ -static inline void mnt_dec_count(struct vfsmount *mnt) -{ - mnt_add_count(mnt, -1); -} - /* * vfsmount lock must be held for write */ -unsigned int mnt_get_count(struct vfsmount *mnt) +unsigned int mnt_get_count(struct mount *mnt) { #ifdef CONFIG_SMP unsigned int count = 0; @@ -196,9 +158,9 @@ unsigned int mnt_get_count(struct vfsmount *mnt) #endif } -static struct vfsmount *alloc_vfsmnt(const char *name) +static struct mount *alloc_vfsmnt(const char *name) { - struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); + struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); if (mnt) { int err; @@ -277,7 +239,7 @@ int __mnt_is_readonly(struct vfsmount *mnt) } EXPORT_SYMBOL_GPL(__mnt_is_readonly); -static inline void mnt_inc_writers(struct vfsmount *mnt) +static inline void mnt_inc_writers(struct mount *mnt) { #ifdef CONFIG_SMP this_cpu_inc(mnt->mnt_pcp->mnt_writers); @@ -286,7 +248,7 @@ static inline void mnt_inc_writers(struct vfsmount *mnt) #endif } -static inline void mnt_dec_writers(struct vfsmount *mnt) +static inline void mnt_dec_writers(struct mount *mnt) { #ifdef CONFIG_SMP this_cpu_dec(mnt->mnt_pcp->mnt_writers); @@ -295,7 +257,7 @@ static inline void mnt_dec_writers(struct vfsmount *mnt) #endif } -static unsigned int mnt_get_writers(struct vfsmount *mnt) +static unsigned int mnt_get_writers(struct mount *mnt) { #ifdef CONFIG_SMP unsigned int count = 0; @@ -311,6 +273,15 @@ static unsigned int mnt_get_writers(struct vfsmount *mnt) #endif } +static int mnt_is_readonly(struct vfsmount *mnt) +{ + if (mnt->mnt_sb->s_readonly_remount) + return 1; + /* Order wrt setting s_flags/s_readonly_remount in do_remount() */ + smp_rmb(); + return __mnt_is_readonly(mnt); +} + /* * Most r/o checks on a fs are for operations that take * discrete amounts of time, like a write() or unlink(). @@ -321,7 +292,7 @@ static unsigned int mnt_get_writers(struct vfsmount *mnt) */ /** * mnt_want_write - get write access to a mount - * @mnt: the mount on which to take a write + * @m: the mount on which to take a write * * This tells the low-level filesystem that a write is * about to be performed to it, and makes sure that @@ -329,8 +300,9 @@ static unsigned int mnt_get_writers(struct vfsmount *mnt) * the write operation is finished, mnt_drop_write() * must be called. This is effectively a refcount. */ -int mnt_want_write(struct vfsmount *mnt) +int mnt_want_write(struct vfsmount *m) { + struct mount *mnt = real_mount(m); int ret = 0; preempt_disable(); @@ -341,7 +313,7 @@ int mnt_want_write(struct vfsmount *mnt) * incremented count after it has set MNT_WRITE_HOLD. */ smp_mb(); - while (mnt->mnt_flags & MNT_WRITE_HOLD) + while (mnt->mnt.mnt_flags & MNT_WRITE_HOLD) cpu_relax(); /* * After the slowpath clears MNT_WRITE_HOLD, mnt_is_readonly will @@ -349,7 +321,7 @@ int mnt_want_write(struct vfsmount *mnt) * MNT_WRITE_HOLD is cleared. */ smp_rmb(); - if (__mnt_is_readonly(mnt)) { + if (mnt_is_readonly(m)) { mnt_dec_writers(mnt); ret = -EROFS; goto out; @@ -378,7 +350,7 @@ int mnt_clone_write(struct vfsmount *mnt) if (__mnt_is_readonly(mnt)) return -EROFS; preempt_disable(); - mnt_inc_writers(mnt); + mnt_inc_writers(real_mount(mnt)); preempt_enable(); return 0; } @@ -412,17 +384,23 @@ EXPORT_SYMBOL_GPL(mnt_want_write_file); void mnt_drop_write(struct vfsmount *mnt) { preempt_disable(); - mnt_dec_writers(mnt); + mnt_dec_writers(real_mount(mnt)); preempt_enable(); } EXPORT_SYMBOL_GPL(mnt_drop_write); -static int mnt_make_readonly(struct vfsmount *mnt) +void mnt_drop_write_file(struct file *file) +{ + mnt_drop_write(file->f_path.mnt); +} +EXPORT_SYMBOL(mnt_drop_write_file); + +static int mnt_make_readonly(struct mount *mnt) { int ret = 0; br_write_lock(vfsmount_lock); - mnt->mnt_flags |= MNT_WRITE_HOLD; + mnt->mnt.mnt_flags |= MNT_WRITE_HOLD; /* * After storing MNT_WRITE_HOLD, we'll read the counters. This store * should be visible before we do. @@ -448,25 +426,61 @@ static int mnt_make_readonly(struct vfsmount *mnt) if (mnt_get_writers(mnt) > 0) ret = -EBUSY; else - mnt->mnt_flags |= MNT_READONLY; + mnt->mnt.mnt_flags |= MNT_READONLY; /* * MNT_READONLY must become visible before ~MNT_WRITE_HOLD, so writers * that become unheld will see MNT_READONLY. */ smp_wmb(); - mnt->mnt_flags &= ~MNT_WRITE_HOLD; + mnt->mnt.mnt_flags &= ~MNT_WRITE_HOLD; br_write_unlock(vfsmount_lock); return ret; } -static void __mnt_unmake_readonly(struct vfsmount *mnt) +static void __mnt_unmake_readonly(struct mount *mnt) { br_write_lock(vfsmount_lock); - mnt->mnt_flags &= ~MNT_READONLY; + mnt->mnt.mnt_flags &= ~MNT_READONLY; br_write_unlock(vfsmount_lock); } -static void free_vfsmnt(struct vfsmount *mnt) +int sb_prepare_remount_readonly(struct super_block *sb) +{ + struct mount *mnt; + int err = 0; + + /* Racy optimization. Recheck the counter under MNT_WRITE_HOLD */ + if (atomic_long_read(&sb->s_remove_count)) + return -EBUSY; + + br_write_lock(vfsmount_lock); + list_for_each_entry(mnt, &sb->s_mounts, mnt_instance) { + if (!(mnt->mnt.mnt_flags & MNT_READONLY)) { + mnt->mnt.mnt_flags |= MNT_WRITE_HOLD; + smp_mb(); + if (mnt_get_writers(mnt) > 0) { + err = -EBUSY; + break; + } + } + } + if (!err && atomic_long_read(&sb->s_remove_count)) + err = -EBUSY; + + if (!err) { + sb->s_readonly_remount = 1; + smp_wmb(); + } + list_for_each_entry(mnt, &sb->s_mounts, mnt_instance) { + if (mnt->mnt.mnt_flags & MNT_WRITE_HOLD) + mnt->mnt.mnt_flags &= ~MNT_WRITE_HOLD; + } + br_write_unlock(vfsmount_lock); + + return err; +} + +static void free_vfsmnt(struct mount *mnt) { kfree(mnt->mnt_devname); mnt_free_id(mnt); @@ -481,20 +495,20 @@ static void free_vfsmnt(struct vfsmount *mnt) * @dir. If @dir is set return the first mount else return the last mount. * vfsmount_lock must be held for read or write. */ -struct vfsmount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry, +struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry, int dir) { struct list_head *head = mount_hashtable + hash(mnt, dentry); struct list_head *tmp = head; - struct vfsmount *p, *found = NULL; + struct mount *p, *found = NULL; for (;;) { tmp = dir ? tmp->next : tmp->prev; p = NULL; if (tmp == head) break; - p = list_entry(tmp, struct vfsmount, mnt_hash); - if (p->mnt_parent == mnt && p->mnt_mountpoint == dentry) { + p = list_entry(tmp, struct mount, mnt_hash); + if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry) { found = p; break; } @@ -508,16 +522,21 @@ struct vfsmount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry, */ struct vfsmount *lookup_mnt(struct path *path) { - struct vfsmount *child_mnt; + struct mount *child_mnt; br_read_lock(vfsmount_lock); - if ((child_mnt = __lookup_mnt(path->mnt, path->dentry, 1))) - mntget(child_mnt); - br_read_unlock(vfsmount_lock); - return child_mnt; + child_mnt = __lookup_mnt(path->mnt, path->dentry, 1); + if (child_mnt) { + mnt_add_count(child_mnt, 1); + br_read_unlock(vfsmount_lock); + return &child_mnt->mnt; + } else { + br_read_unlock(vfsmount_lock); + return NULL; + } } -static inline int check_mnt(struct vfsmount *mnt) +static inline int check_mnt(struct mount *mnt) { return mnt->mnt_ns == current->nsproxy->mnt_ns; } @@ -548,12 +567,12 @@ static void __touch_mnt_namespace(struct mnt_namespace *ns) * Clear dentry's mounted state if it has no remaining mounts. * vfsmount_lock must be held for write. */ -static void dentry_reset_mounted(struct vfsmount *mnt, struct dentry *dentry) +static void dentry_reset_mounted(struct dentry *dentry) { unsigned u; for (u = 0; u < HASH_SIZE; u++) { - struct vfsmount *p; + struct mount *p; list_for_each_entry(p, &mount_hashtable[u], mnt_hash) { if (p->mnt_mountpoint == dentry) @@ -568,25 +587,26 @@ static void dentry_reset_mounted(struct vfsmount *mnt, struct dentry *dentry) /* * vfsmount lock must be held for write */ -static void detach_mnt(struct vfsmount *mnt, struct path *old_path) +static void detach_mnt(struct mount *mnt, struct path *old_path) { old_path->dentry = mnt->mnt_mountpoint; - old_path->mnt = mnt->mnt_parent; + old_path->mnt = &mnt->mnt_parent->mnt; mnt->mnt_parent = mnt; - mnt->mnt_mountpoint = mnt->mnt_root; + mnt->mnt_mountpoint = mnt->mnt.mnt_root; list_del_init(&mnt->mnt_child); list_del_init(&mnt->mnt_hash); - dentry_reset_mounted(old_path->mnt, old_path->dentry); + dentry_reset_mounted(old_path->dentry); } /* * vfsmount lock must be held for write */ -void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry, - struct vfsmount *child_mnt) +void mnt_set_mountpoint(struct mount *mnt, struct dentry *dentry, + struct mount *child_mnt) { - child_mnt->mnt_parent = mntget(mnt); + mnt_add_count(mnt, 1); /* essentially, that's mntget */ child_mnt->mnt_mountpoint = dget(dentry); + child_mnt->mnt_parent = mnt; spin_lock(&dentry->d_lock); dentry->d_flags |= DCACHE_MOUNTED; spin_unlock(&dentry->d_lock); @@ -595,15 +615,15 @@ void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry, /* * vfsmount lock must be held for write */ -static void attach_mnt(struct vfsmount *mnt, struct path *path) +static void attach_mnt(struct mount *mnt, struct path *path) { - mnt_set_mountpoint(path->mnt, path->dentry, mnt); + mnt_set_mountpoint(real_mount(path->mnt), path->dentry, mnt); list_add_tail(&mnt->mnt_hash, mount_hashtable + hash(path->mnt, path->dentry)); - list_add_tail(&mnt->mnt_child, &path->mnt->mnt_mounts); + list_add_tail(&mnt->mnt_child, &real_mount(path->mnt)->mnt_mounts); } -static inline void __mnt_make_longterm(struct vfsmount *mnt) +static inline void __mnt_make_longterm(struct mount *mnt) { #ifdef CONFIG_SMP atomic_inc(&mnt->mnt_longterm); @@ -611,7 +631,7 @@ static inline void __mnt_make_longterm(struct vfsmount *mnt) } /* needs vfsmount lock for write */ -static inline void __mnt_make_shortterm(struct vfsmount *mnt) +static inline void __mnt_make_shortterm(struct mount *mnt) { #ifdef CONFIG_SMP atomic_dec(&mnt->mnt_longterm); @@ -621,10 +641,10 @@ static inline void __mnt_make_shortterm(struct vfsmount *mnt) /* * vfsmount lock must be held for write */ -static void commit_tree(struct vfsmount *mnt) +static void commit_tree(struct mount *mnt) { - struct vfsmount *parent = mnt->mnt_parent; - struct vfsmount *m; + struct mount *parent = mnt->mnt_parent; + struct mount *m; LIST_HEAD(head); struct mnt_namespace *n = parent->mnt_ns; @@ -639,12 +659,12 @@ static void commit_tree(struct vfsmount *mnt) list_splice(&head, n->list.prev); list_add_tail(&mnt->mnt_hash, mount_hashtable + - hash(parent, mnt->mnt_mountpoint)); + hash(&parent->mnt, mnt->mnt_mountpoint)); list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); touch_mnt_namespace(n); } -static struct vfsmount *next_mnt(struct vfsmount *p, struct vfsmount *root) +static struct mount *next_mnt(struct mount *p, struct mount *root) { struct list_head *next = p->mnt_mounts.next; if (next == &p->mnt_mounts) { @@ -657,14 +677,14 @@ static struct vfsmount *next_mnt(struct vfsmount *p, struct vfsmount *root) p = p->mnt_parent; } } - return list_entry(next, struct vfsmount, mnt_child); + return list_entry(next, struct mount, mnt_child); } -static struct vfsmount *skip_mnt_tree(struct vfsmount *p) +static struct mount *skip_mnt_tree(struct mount *p) { struct list_head *prev = p->mnt_mounts.prev; while (prev != &p->mnt_mounts) { - p = list_entry(prev, struct vfsmount, mnt_child); + p = list_entry(prev, struct mount, mnt_child); prev = p->mnt_mounts.prev; } return p; @@ -673,7 +693,7 @@ static struct vfsmount *skip_mnt_tree(struct vfsmount *p) struct vfsmount * vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data) { - struct vfsmount *mnt; + struct mount *mnt; struct dentry *root; if (!type) @@ -684,7 +704,7 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void return ERR_PTR(-ENOMEM); if (flags & MS_KERNMOUNT) - mnt->mnt_flags = MNT_INTERNAL; + mnt->mnt.mnt_flags = MNT_INTERNAL; root = mount_fs(type, flags, name, data); if (IS_ERR(root)) { @@ -692,19 +712,22 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void return ERR_CAST(root); } - mnt->mnt_root = root; - mnt->mnt_sb = root->d_sb; - mnt->mnt_mountpoint = mnt->mnt_root; + mnt->mnt.mnt_root = root; + mnt->mnt.mnt_sb = root->d_sb; + mnt->mnt_mountpoint = mnt->mnt.mnt_root; mnt->mnt_parent = mnt; - return mnt; + br_write_lock(vfsmount_lock); + list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts); + br_write_unlock(vfsmount_lock); + return &mnt->mnt; } EXPORT_SYMBOL_GPL(vfs_kern_mount); -static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root, +static struct mount *clone_mnt(struct mount *old, struct dentry *root, int flag) { - struct super_block *sb = old->mnt_sb; - struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname); + struct super_block *sb = old->mnt.mnt_sb; + struct mount *mnt = alloc_vfsmnt(old->mnt_devname); if (mnt) { if (flag & (CL_SLAVE | CL_PRIVATE)) @@ -718,12 +741,15 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root, goto out_free; } - mnt->mnt_flags = old->mnt_flags & ~MNT_WRITE_HOLD; + mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~MNT_WRITE_HOLD; atomic_inc(&sb->s_active); - mnt->mnt_sb = sb; - mnt->mnt_root = dget(root); - mnt->mnt_mountpoint = mnt->mnt_root; + mnt->mnt.mnt_sb = sb; + mnt->mnt.mnt_root = dget(root); + mnt->mnt_mountpoint = mnt->mnt.mnt_root; mnt->mnt_parent = mnt; + br_write_lock(vfsmount_lock); + list_add_tail(&mnt->mnt_instance, &sb->s_mounts); + br_write_unlock(vfsmount_lock); if (flag & CL_SLAVE) { list_add(&mnt->mnt_slave, &old->mnt_slave_list); @@ -753,9 +779,10 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root, return NULL; } -static inline void mntfree(struct vfsmount *mnt) +static inline void mntfree(struct mount *mnt) { - struct super_block *sb = mnt->mnt_sb; + struct vfsmount *m = &mnt->mnt; + struct super_block *sb = m->mnt_sb; /* * This probably indicates that somebody messed @@ -768,32 +795,32 @@ static inline void mntfree(struct vfsmount *mnt) * so mnt_get_writers() below is safe. */ WARN_ON(mnt_get_writers(mnt)); - fsnotify_vfsmount_delete(mnt); - dput(mnt->mnt_root); + fsnotify_vfsmount_delete(m); + dput(m->mnt_root); free_vfsmnt(mnt); deactivate_super(sb); } -static void mntput_no_expire(struct vfsmount *mnt) +static void mntput_no_expire(struct mount *mnt) { put_again: #ifdef CONFIG_SMP br_read_lock(vfsmount_lock); if (likely(atomic_read(&mnt->mnt_longterm))) { - mnt_dec_count(mnt); + mnt_add_count(mnt, -1); br_read_unlock(vfsmount_lock); return; } br_read_unlock(vfsmount_lock); br_write_lock(vfsmount_lock); - mnt_dec_count(mnt); + mnt_add_count(mnt, -1); if (mnt_get_count(mnt)) { br_write_unlock(vfsmount_lock); return; } #else - mnt_dec_count(mnt); + mnt_add_count(mnt, -1); if (likely(mnt_get_count(mnt))) return; br_write_lock(vfsmount_lock); @@ -802,9 +829,10 @@ put_again: mnt_add_count(mnt, mnt->mnt_pinned + 1); mnt->mnt_pinned = 0; br_write_unlock(vfsmount_lock); - acct_auto_close_mnt(mnt); + acct_auto_close_mnt(&mnt->mnt); goto put_again; } + list_del(&mnt->mnt_instance); br_write_unlock(vfsmount_lock); mntfree(mnt); } @@ -812,10 +840,11 @@ put_again: void mntput(struct vfsmount *mnt) { if (mnt) { + struct mount *m = real_mount(mnt); /* avoid cacheline pingpong, hope gcc doesn't get "smart" */ - if (unlikely(mnt->mnt_expiry_mark)) - mnt->mnt_expiry_mark = 0; - mntput_no_expire(mnt); + if (unlikely(m->mnt_expiry_mark)) + m->mnt_expiry_mark = 0; + mntput_no_expire(m); } } EXPORT_SYMBOL(mntput); @@ -823,7 +852,7 @@ EXPORT_SYMBOL(mntput); struct vfsmount *mntget(struct vfsmount *mnt) { if (mnt) - mnt_inc_count(mnt); + mnt_add_count(real_mount(mnt), 1); return mnt; } EXPORT_SYMBOL(mntget); @@ -831,16 +860,17 @@ EXPORT_SYMBOL(mntget); void mnt_pin(struct vfsmount *mnt) { br_write_lock(vfsmount_lock); - mnt->mnt_pinned++; + real_mount(mnt)->mnt_pinned++; br_write_unlock(vfsmount_lock); } EXPORT_SYMBOL(mnt_pin); -void mnt_unpin(struct vfsmount *mnt) +void mnt_unpin(struct vfsmount *m) { + struct mount *mnt = real_mount(m); br_write_lock(vfsmount_lock); if (mnt->mnt_pinned) { - mnt_inc_count(mnt); + mnt_add_count(mnt, 1); mnt->mnt_pinned--; } br_write_unlock(vfsmount_lock); @@ -858,12 +888,12 @@ static inline void mangle(struct seq_file *m, const char *s) * * See also save_mount_options(). */ -int generic_show_options(struct seq_file *m, struct vfsmount *mnt) +int generic_show_options(struct seq_file *m, struct dentry *root) { const char *options; rcu_read_lock(); - options = rcu_dereference(mnt->mnt_sb->s_options); + options = rcu_dereference(root->d_sb->s_options); if (options != NULL && options[0]) { seq_putc(m, ','); @@ -907,10 +937,10 @@ void replace_mount_options(struct super_block *sb, char *options) EXPORT_SYMBOL(replace_mount_options); #ifdef CONFIG_PROC_FS -/* iterator */ +/* iterator; we want it to have access to namespace_sem, thus here... */ static void *m_start(struct seq_file *m, loff_t *pos) { - struct proc_mounts *p = m->private; + struct proc_mounts *p = container_of(m, struct proc_mounts, m); down_read(&namespace_sem); return seq_list_start(&p->ns->list, *pos); @@ -918,7 +948,7 @@ static void *m_start(struct seq_file *m, loff_t *pos) static void *m_next(struct seq_file *m, void *v, loff_t *pos) { - struct proc_mounts *p = m->private; + struct proc_mounts *p = container_of(m, struct proc_mounts, m); return seq_list_next(v, &p->ns->list, pos); } @@ -928,219 +958,18 @@ static void m_stop(struct seq_file *m, void *v) up_read(&namespace_sem); } -int mnt_had_events(struct proc_mounts *p) +static int m_show(struct seq_file *m, void *v) { - struct mnt_namespace *ns = p->ns; - int res = 0; - - br_read_lock(vfsmount_lock); - if (p->m.poll_event != ns->event) { - p->m.poll_event = ns->event; - res = 1; - } - br_read_unlock(vfsmount_lock); - - return res; -} - -struct proc_fs_info { - int flag; - const char *str; -}; - -static int show_sb_opts(struct seq_file *m, struct super_block *sb) -{ - static const struct proc_fs_info fs_info[] = { - { MS_SYNCHRONOUS, ",sync" }, - { MS_DIRSYNC, ",dirsync" }, - { MS_MANDLOCK, ",mand" }, - { 0, NULL } - }; - const struct proc_fs_info *fs_infop; - - for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { - if (sb->s_flags & fs_infop->flag) - seq_puts(m, fs_infop->str); - } - - return security_sb_show_options(m, sb); -} - -static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt) -{ - static const struct proc_fs_info mnt_info[] = { - { MNT_NOSUID, ",nosuid" }, - { MNT_NODEV, ",nodev" }, - { MNT_NOEXEC, ",noexec" }, - { MNT_NOATIME, ",noatime" }, - { MNT_NODIRATIME, ",nodiratime" }, - { MNT_RELATIME, ",relatime" }, - { 0, NULL } - }; - const struct proc_fs_info *fs_infop; - - for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) { - if (mnt->mnt_flags & fs_infop->flag) - seq_puts(m, fs_infop->str); - } -} - -static void show_type(struct seq_file *m, struct super_block *sb) -{ - mangle(m, sb->s_type->name); - if (sb->s_subtype && sb->s_subtype[0]) { - seq_putc(m, '.'); - mangle(m, sb->s_subtype); - } -} - -static int show_vfsmnt(struct seq_file *m, void *v) -{ - struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); - int err = 0; - struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; - - if (mnt->mnt_sb->s_op->show_devname) { - err = mnt->mnt_sb->s_op->show_devname(m, mnt); - if (err) - goto out; - } else { - mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); - } - seq_putc(m, ' '); - seq_path(m, &mnt_path, " \t\n\\"); - seq_putc(m, ' '); - show_type(m, mnt->mnt_sb); - seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw"); - err = show_sb_opts(m, mnt->mnt_sb); - if (err) - goto out; - show_mnt_opts(m, mnt); - if (mnt->mnt_sb->s_op->show_options) - err = mnt->mnt_sb->s_op->show_options(m, mnt); - seq_puts(m, " 0 0\n"); -out: - return err; + struct proc_mounts *p = container_of(m, struct proc_mounts, m); + struct mount *r = list_entry(v, struct mount, mnt_list); + return p->show(m, &r->mnt); } const struct seq_operations mounts_op = { .start = m_start, .next = m_next, .stop = m_stop, - .show = show_vfsmnt -}; - -static int show_mountinfo(struct seq_file *m, void *v) -{ - struct proc_mounts *p = m->private; - struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); - struct super_block *sb = mnt->mnt_sb; - struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; - struct path root = p->root; - int err = 0; - - seq_printf(m, "%i %i %u:%u ", mnt->mnt_id, mnt->mnt_parent->mnt_id, - MAJOR(sb->s_dev), MINOR(sb->s_dev)); - if (sb->s_op->show_path) - err = sb->s_op->show_path(m, mnt); - else - seq_dentry(m, mnt->mnt_root, " \t\n\\"); - if (err) - goto out; - seq_putc(m, ' '); - - /* mountpoints outside of chroot jail will give SEQ_SKIP on this */ - err = seq_path_root(m, &mnt_path, &root, " \t\n\\"); - if (err) - goto out; - - seq_puts(m, mnt->mnt_flags & MNT_READONLY ? " ro" : " rw"); - show_mnt_opts(m, mnt); - - /* Tagged fields ("foo:X" or "bar") */ - if (IS_MNT_SHARED(mnt)) - seq_printf(m, " shared:%i", mnt->mnt_group_id); - if (IS_MNT_SLAVE(mnt)) { - int master = mnt->mnt_master->mnt_group_id; - int dom = get_dominating_id(mnt, &p->root); - seq_printf(m, " master:%i", master); - if (dom && dom != master) - seq_printf(m, " propagate_from:%i", dom); - } - if (IS_MNT_UNBINDABLE(mnt)) - seq_puts(m, " unbindable"); - - /* Filesystem specific data */ - seq_puts(m, " - "); - show_type(m, sb); - seq_putc(m, ' '); - if (sb->s_op->show_devname) - err = sb->s_op->show_devname(m, mnt); - else - mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); - if (err) - goto out; - seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw"); - err = show_sb_opts(m, sb); - if (err) - goto out; - if (sb->s_op->show_options) - err = sb->s_op->show_options(m, mnt); - seq_putc(m, '\n'); -out: - return err; -} - -const struct seq_operations mountinfo_op = { - .start = m_start, - .next = m_next, - .stop = m_stop, - .show = show_mountinfo, -}; - -static int show_vfsstat(struct seq_file *m, void *v) -{ - struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); - struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; - int err = 0; - - /* device */ - if (mnt->mnt_sb->s_op->show_devname) { - seq_puts(m, "device "); - err = mnt->mnt_sb->s_op->show_devname(m, mnt); - } else { - if (mnt->mnt_devname) { - seq_puts(m, "device "); - mangle(m, mnt->mnt_devname); - } else - seq_puts(m, "no device"); - } - - /* mount point */ - seq_puts(m, " mounted on "); - seq_path(m, &mnt_path, " \t\n\\"); - seq_putc(m, ' '); - - /* file system type */ - seq_puts(m, "with fstype "); - show_type(m, mnt->mnt_sb); - - /* optional statistics */ - if (mnt->mnt_sb->s_op->show_stats) { - seq_putc(m, ' '); - if (!err) - err = mnt->mnt_sb->s_op->show_stats(m, mnt); - } - - seq_putc(m, '\n'); - return err; -} - -const struct seq_operations mountstats_op = { - .start = m_start, - .next = m_next, - .stop = m_stop, - .show = show_vfsstat, + .show = m_show, }; #endif /* CONFIG_PROC_FS */ @@ -1152,11 +981,13 @@ const struct seq_operations mountstats_op = { * open files, pwds, chroots or sub mounts that are * busy. */ -int may_umount_tree(struct vfsmount *mnt) +int may_umount_tree(struct vfsmount *m) { + struct mount *mnt = real_mount(m); int actual_refs = 0; int minimum_refs = 0; - struct vfsmount *p; + struct mount *p; + BUG_ON(!m); /* write lock needed for mnt_get_count */ br_write_lock(vfsmount_lock); @@ -1192,7 +1023,7 @@ int may_umount(struct vfsmount *mnt) int ret = 1; down_read(&namespace_sem); br_write_lock(vfsmount_lock); - if (propagate_mount_busy(mnt, 2)) + if (propagate_mount_busy(real_mount(mnt), 2)) ret = 0; br_write_unlock(vfsmount_lock); up_read(&namespace_sem); @@ -1203,25 +1034,25 @@ EXPORT_SYMBOL(may_umount); void release_mounts(struct list_head *head) { - struct vfsmount *mnt; + struct mount *mnt; while (!list_empty(head)) { - mnt = list_first_entry(head, struct vfsmount, mnt_hash); + mnt = list_first_entry(head, struct mount, mnt_hash); list_del_init(&mnt->mnt_hash); - if (mnt->mnt_parent != mnt) { + if (mnt_has_parent(mnt)) { struct dentry *dentry; - struct vfsmount *m; + struct mount *m; br_write_lock(vfsmount_lock); dentry = mnt->mnt_mountpoint; m = mnt->mnt_parent; - mnt->mnt_mountpoint = mnt->mnt_root; + mnt->mnt_mountpoint = mnt->mnt.mnt_root; mnt->mnt_parent = mnt; m->mnt_ghosts--; br_write_unlock(vfsmount_lock); dput(dentry); - mntput(m); + mntput(&m->mnt); } - mntput(mnt); + mntput(&mnt->mnt); } } @@ -1229,10 +1060,10 @@ void release_mounts(struct list_head *head) * vfsmount lock must be held for write * namespace_sem must be held for write */ -void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) +void umount_tree(struct mount *mnt, int propagate, struct list_head *kill) { LIST_HEAD(tmp_list); - struct vfsmount *p; + struct mount *p; for (p = mnt; p; p = next_mnt(p, mnt)) list_move(&p->mnt_hash, &tmp_list); @@ -1247,24 +1078,24 @@ void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) p->mnt_ns = NULL; __mnt_make_shortterm(p); list_del_init(&p->mnt_child); - if (p->mnt_parent != p) { + if (mnt_has_parent(p)) { p->mnt_parent->mnt_ghosts++; - dentry_reset_mounted(p->mnt_parent, p->mnt_mountpoint); + dentry_reset_mounted(p->mnt_mountpoint); } change_mnt_propagation(p, MS_PRIVATE); } list_splice(&tmp_list, kill); } -static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts); +static void shrink_submounts(struct mount *mnt, struct list_head *umounts); -static int do_umount(struct vfsmount *mnt, int flags) +static int do_umount(struct mount *mnt, int flags) { - struct super_block *sb = mnt->mnt_sb; + struct super_block *sb = mnt->mnt.mnt_sb; int retval; LIST_HEAD(umount_list); - retval = security_sb_umount(mnt, flags); + retval = security_sb_umount(&mnt->mnt, flags); if (retval) return retval; @@ -1275,7 +1106,7 @@ static int do_umount(struct vfsmount *mnt, int flags) * (2) the usage count == 1 [parent vfsmount] + 1 [sys_umount] */ if (flags & MNT_EXPIRE) { - if (mnt == current->fs->root.mnt || + if (&mnt->mnt == current->fs->root.mnt || flags & (MNT_FORCE | MNT_DETACH)) return -EINVAL; @@ -1317,7 +1148,7 @@ static int do_umount(struct vfsmount *mnt, int flags) * /reboot - static binary that would close all descriptors and * call reboot(9). Then init(8) could umount root and exec /reboot. */ - if (mnt == current->fs->root.mnt && !(flags & MNT_DETACH)) { + if (&mnt->mnt == current->fs->root.mnt && !(flags & MNT_DETACH)) { /* * Special case for "unmounting" root ... * we just try to remount it readonly. @@ -1359,6 +1190,7 @@ static int do_umount(struct vfsmount *mnt, int flags) SYSCALL_DEFINE2(umount, char __user *, name, int, flags) { struct path path; + struct mount *mnt; int retval; int lookup_flags = 0; @@ -1371,21 +1203,22 @@ SYSCALL_DEFINE2(umount, char __user *, name, int, flags) retval = user_path_at(AT_FDCWD, name, lookup_flags, &path); if (retval) goto out; + mnt = real_mount(path.mnt); retval = -EINVAL; if (path.dentry != path.mnt->mnt_root) goto dput_and_out; - if (!check_mnt(path.mnt)) + if (!check_mnt(mnt)) goto dput_and_out; retval = -EPERM; if (!capable(CAP_SYS_ADMIN)) goto dput_and_out; - retval = do_umount(path.mnt, flags); + retval = do_umount(mnt, flags); dput_and_out: /* we mustn't call path_put() as that would clear mnt_expiry_mark */ dput(path.dentry); - mntput_no_expire(path.mnt); + mntput_no_expire(mnt); out: return retval; } @@ -1420,10 +1253,10 @@ static int mount_is_safe(struct path *path) #endif } -struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry, +struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, int flag) { - struct vfsmount *res, *p, *q, *r, *s; + struct mount *res, *p, *q, *r; struct path path; if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(mnt)) @@ -1436,6 +1269,7 @@ struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry, p = mnt; list_for_each_entry(r, &mnt->mnt_mounts, mnt_child) { + struct mount *s; if (!is_subdir(r->mnt_mountpoint, dentry)) continue; @@ -1449,9 +1283,9 @@ struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry, q = q->mnt_parent; } p = s; - path.mnt = q; + path.mnt = &q->mnt; path.dentry = p->mnt_mountpoint; - q = clone_mnt(p, p->mnt_root, flag); + q = clone_mnt(p, p->mnt.mnt_root, flag); if (!q) goto Enomem; br_write_lock(vfsmount_lock); @@ -1474,11 +1308,12 @@ Enomem: struct vfsmount *collect_mounts(struct path *path) { - struct vfsmount *tree; + struct mount *tree; down_write(&namespace_sem); - tree = copy_tree(path->mnt, path->dentry, CL_COPY_ALL | CL_PRIVATE); + tree = copy_tree(real_mount(path->mnt), path->dentry, + CL_COPY_ALL | CL_PRIVATE); up_write(&namespace_sem); - return tree; + return tree ? &tree->mnt : NULL; } void drop_collected_mounts(struct vfsmount *mnt) @@ -1486,7 +1321,7 @@ void drop_collected_mounts(struct vfsmount *mnt) LIST_HEAD(umount_list); down_write(&namespace_sem); br_write_lock(vfsmount_lock); - umount_tree(mnt, 0, &umount_list); + umount_tree(real_mount(mnt), 0, &umount_list); br_write_unlock(vfsmount_lock); up_write(&namespace_sem); release_mounts(&umount_list); @@ -1495,21 +1330,21 @@ void drop_collected_mounts(struct vfsmount *mnt) int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg, struct vfsmount *root) { - struct vfsmount *mnt; + struct mount *mnt; int res = f(root, arg); if (res) return res; - list_for_each_entry(mnt, &root->mnt_list, mnt_list) { - res = f(mnt, arg); + list_for_each_entry(mnt, &real_mount(root)->mnt_list, mnt_list) { + res = f(&mnt->mnt, arg); if (res) return res; } return 0; } -static void cleanup_group_ids(struct vfsmount *mnt, struct vfsmount *end) +static void cleanup_group_ids(struct mount *mnt, struct mount *end) { - struct vfsmount *p; + struct mount *p; for (p = mnt; p != end; p = next_mnt(p, mnt)) { if (p->mnt_group_id && !IS_MNT_SHARED(p)) @@ -1517,9 +1352,9 @@ static void cleanup_group_ids(struct vfsmount *mnt, struct vfsmount *end) } } -static int invent_group_ids(struct vfsmount *mnt, bool recurse) +static int invent_group_ids(struct mount *mnt, bool recurse) { - struct vfsmount *p; + struct mount *p; for (p = mnt; p; p = recurse ? next_mnt(p, mnt) : NULL) { if (!p->mnt_group_id && !IS_MNT_SHARED(p)) { @@ -1597,13 +1432,13 @@ static int invent_group_ids(struct vfsmount *mnt, bool recurse) * Must be called without spinlocks held, since this function can sleep * in allocations. */ -static int attach_recursive_mnt(struct vfsmount *source_mnt, +static int attach_recursive_mnt(struct mount *source_mnt, struct path *path, struct path *parent_path) { LIST_HEAD(tree_list); - struct vfsmount *dest_mnt = path->mnt; + struct mount *dest_mnt = real_mount(path->mnt); struct dentry *dest_dentry = path->dentry; - struct vfsmount *child, *p; + struct mount *child, *p; int err; if (IS_MNT_SHARED(dest_mnt)) { @@ -1624,7 +1459,7 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt, if (parent_path) { detach_mnt(source_mnt, parent_path); attach_mnt(source_mnt, path); - touch_mnt_namespace(parent_path->mnt->mnt_ns); + touch_mnt_namespace(source_mnt->mnt_ns); } else { mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt); commit_tree(source_mnt); @@ -1672,13 +1507,13 @@ static void unlock_mount(struct path *path) mutex_unlock(&path->dentry->d_inode->i_mutex); } -static int graft_tree(struct vfsmount *mnt, struct path *path) +static int graft_tree(struct mount *mnt, struct path *path) { - if (mnt->mnt_sb->s_flags & MS_NOUSER) + if (mnt->mnt.mnt_sb->s_flags & MS_NOUSER) return -EINVAL; if (S_ISDIR(path->dentry->d_inode->i_mode) != - S_ISDIR(mnt->mnt_root->d_inode->i_mode)) + S_ISDIR(mnt->mnt.mnt_root->d_inode->i_mode)) return -ENOTDIR; if (d_unlinked(path->dentry)) @@ -1709,7 +1544,8 @@ static int flags_to_propagation_type(int flags) */ static int do_change_type(struct path *path, int flag) { - struct vfsmount *m, *mnt = path->mnt; + struct mount *m; + struct mount *mnt = real_mount(path->mnt); int recurse = flag & MS_REC; int type; int err = 0; @@ -1749,7 +1585,7 @@ static int do_loopback(struct path *path, char *old_name, { LIST_HEAD(umount_list); struct path old_path; - struct vfsmount *mnt = NULL; + struct mount *mnt = NULL, *old; int err = mount_is_safe(path); if (err) return err; @@ -1763,18 +1599,20 @@ static int do_loopback(struct path *path, char *old_name, if (err) goto out; + old = real_mount(old_path.mnt); + err = -EINVAL; - if (IS_MNT_UNBINDABLE(old_path.mnt)) + if (IS_MNT_UNBINDABLE(old)) goto out2; - if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt)) + if (!check_mnt(real_mount(path->mnt)) || !check_mnt(old)) goto out2; err = -ENOMEM; if (recurse) - mnt = copy_tree(old_path.mnt, old_path.dentry, 0); + mnt = copy_tree(old, old_path.dentry, 0); else - mnt = clone_mnt(old_path.mnt, old_path.dentry, 0); + mnt = clone_mnt(old, old_path.dentry, 0); if (!mnt) goto out2; @@ -1804,9 +1642,9 @@ static int change_mount_flags(struct vfsmount *mnt, int ms_flags) return 0; if (readonly_request) - error = mnt_make_readonly(mnt); + error = mnt_make_readonly(real_mount(mnt)); else - __mnt_unmake_readonly(mnt); + __mnt_unmake_readonly(real_mount(mnt)); return error; } @@ -1820,11 +1658,12 @@ static int do_remount(struct path *path, int flags, int mnt_flags, { int err; struct super_block *sb = path->mnt->mnt_sb; + struct mount *mnt = real_mount(path->mnt); if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (!check_mnt(path->mnt)) + if (!check_mnt(mnt)) return -EINVAL; if (path->dentry != path->mnt->mnt_root) @@ -1841,22 +1680,22 @@ static int do_remount(struct path *path, int flags, int mnt_flags, err = do_remount_sb(sb, flags, data, 0); if (!err) { br_write_lock(vfsmount_lock); - mnt_flags |= path->mnt->mnt_flags & MNT_PROPAGATION_MASK; - path->mnt->mnt_flags = mnt_flags; + mnt_flags |= mnt->mnt.mnt_flags & MNT_PROPAGATION_MASK; + mnt->mnt.mnt_flags = mnt_flags; br_write_unlock(vfsmount_lock); } up_write(&sb->s_umount); if (!err) { br_write_lock(vfsmount_lock); - touch_mnt_namespace(path->mnt->mnt_ns); + touch_mnt_namespace(mnt->mnt_ns); br_write_unlock(vfsmount_lock); } return err; } -static inline int tree_contains_unbindable(struct vfsmount *mnt) +static inline int tree_contains_unbindable(struct mount *mnt) { - struct vfsmount *p; + struct mount *p; for (p = mnt; p; p = next_mnt(p, mnt)) { if (IS_MNT_UNBINDABLE(p)) return 1; @@ -1867,7 +1706,8 @@ static inline int tree_contains_unbindable(struct vfsmount *mnt) static int do_move_mount(struct path *path, char *old_name) { struct path old_path, parent_path; - struct vfsmount *p; + struct mount *p; + struct mount *old; int err = 0; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -1881,8 +1721,11 @@ static int do_move_mount(struct path *path, char *old_name) if (err < 0) goto out; + old = real_mount(old_path.mnt); + p = real_mount(path->mnt); + err = -EINVAL; - if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt)) + if (!check_mnt(p) || !check_mnt(old)) goto out1; if (d_unlinked(path->dentry)) @@ -1892,7 +1735,7 @@ static int do_move_mount(struct path *path, char *old_name) if (old_path.dentry != old_path.mnt->mnt_root) goto out1; - if (old_path.mnt == old_path.mnt->mnt_parent) + if (!mnt_has_parent(old)) goto out1; if (S_ISDIR(path->dentry->d_inode->i_mode) != @@ -1901,28 +1744,26 @@ static int do_move_mount(struct path *path, char *old_name) /* * Don't move a mount residing in a shared parent. */ - if (old_path.mnt->mnt_parent && - IS_MNT_SHARED(old_path.mnt->mnt_parent)) + if (IS_MNT_SHARED(old->mnt_parent)) goto out1; /* * Don't move a mount tree containing unbindable mounts to a destination * mount which is shared. */ - if (IS_MNT_SHARED(path->mnt) && - tree_contains_unbindable(old_path.mnt)) + if (IS_MNT_SHARED(p) && tree_contains_unbindable(old)) goto out1; err = -ELOOP; - for (p = path->mnt; p->mnt_parent != p; p = p->mnt_parent) - if (p == old_path.mnt) + for (; mnt_has_parent(p); p = p->mnt_parent) + if (p == old) goto out1; - err = attach_recursive_mnt(old_path.mnt, path, &parent_path); + err = attach_recursive_mnt(old, path, &parent_path); if (err) goto out1; /* if the mount is moved, it should no longer be expire * automatically */ - list_del_init(&old_path.mnt->mnt_expire); + list_del_init(&old->mnt_expire); out1: unlock_mount(path); out: @@ -1955,7 +1796,7 @@ static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype) return ERR_PTR(err); } -struct vfsmount * +static struct vfsmount * do_kern_mount(const char *fstype, int flags, const char *name, void *data) { struct file_system_type *type = get_fs_type(fstype); @@ -1969,12 +1810,11 @@ do_kern_mount(const char *fstype, int flags, const char *name, void *data) put_filesystem(type); return mnt; } -EXPORT_SYMBOL_GPL(do_kern_mount); /* * add a mount into a namespace's mount tree */ -static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags) +static int do_add_mount(struct mount *newmnt, struct path *path, int mnt_flags) { int err; @@ -1985,20 +1825,20 @@ static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flag return err; err = -EINVAL; - if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt)) + if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(real_mount(path->mnt))) goto unlock; /* Refuse the same filesystem on the same mount point */ err = -EBUSY; - if (path->mnt->mnt_sb == newmnt->mnt_sb && + if (path->mnt->mnt_sb == newmnt->mnt.mnt_sb && path->mnt->mnt_root == path->dentry) goto unlock; err = -EINVAL; - if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode)) + if (S_ISLNK(newmnt->mnt.mnt_root->d_inode->i_mode)) goto unlock; - newmnt->mnt_flags = mnt_flags; + newmnt->mnt.mnt_flags = mnt_flags; err = graft_tree(newmnt, path); unlock: @@ -2027,7 +1867,7 @@ static int do_new_mount(struct path *path, char *type, int flags, if (IS_ERR(mnt)) return PTR_ERR(mnt); - err = do_add_mount(mnt, path, mnt_flags); + err = do_add_mount(real_mount(mnt), path, mnt_flags); if (err) mntput(mnt); return err; @@ -2035,11 +1875,12 @@ static int do_new_mount(struct path *path, char *type, int flags, int finish_automount(struct vfsmount *m, struct path *path) { + struct mount *mnt = real_mount(m); int err; /* The new mount record should have at least 2 refs to prevent it being * expired before we get a chance to add it */ - BUG_ON(mnt_get_count(m) < 2); + BUG_ON(mnt_get_count(mnt) < 2); if (m->mnt_sb == path->mnt->mnt_sb && m->mnt_root == path->dentry) { @@ -2047,15 +1888,15 @@ int finish_automount(struct vfsmount *m, struct path *path) goto fail; } - err = do_add_mount(m, path, path->mnt->mnt_flags | MNT_SHRINKABLE); + err = do_add_mount(mnt, path, path->mnt->mnt_flags | MNT_SHRINKABLE); if (!err) return 0; fail: /* remove m from any expiration list it may be on */ - if (!list_empty(&m->mnt_expire)) { + if (!list_empty(&mnt->mnt_expire)) { down_write(&namespace_sem); br_write_lock(vfsmount_lock); - list_del_init(&m->mnt_expire); + list_del_init(&mnt->mnt_expire); br_write_unlock(vfsmount_lock); up_write(&namespace_sem); } @@ -2074,7 +1915,7 @@ void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list) down_write(&namespace_sem); br_write_lock(vfsmount_lock); - list_add_tail(&mnt->mnt_expire, expiry_list); + list_add_tail(&real_mount(mnt)->mnt_expire, expiry_list); br_write_unlock(vfsmount_lock); up_write(&namespace_sem); @@ -2088,7 +1929,7 @@ EXPORT_SYMBOL(mnt_set_expiry); */ void mark_mounts_for_expiry(struct list_head *mounts) { - struct vfsmount *mnt, *next; + struct mount *mnt, *next; LIST_HEAD(graveyard); LIST_HEAD(umounts); @@ -2111,7 +1952,7 @@ void mark_mounts_for_expiry(struct list_head *mounts) list_move(&mnt->mnt_expire, &graveyard); } while (!list_empty(&graveyard)) { - mnt = list_first_entry(&graveyard, struct vfsmount, mnt_expire); + mnt = list_first_entry(&graveyard, struct mount, mnt_expire); touch_mnt_namespace(mnt->mnt_ns); umount_tree(mnt, 1, &umounts); } @@ -2129,9 +1970,9 @@ EXPORT_SYMBOL_GPL(mark_mounts_for_expiry); * search the list of submounts for a given mountpoint, and move any * shrinkable submounts to the 'graveyard' list. */ -static int select_submounts(struct vfsmount *parent, struct list_head *graveyard) +static int select_submounts(struct mount *parent, struct list_head *graveyard) { - struct vfsmount *this_parent = parent; + struct mount *this_parent = parent; struct list_head *next; int found = 0; @@ -2140,10 +1981,10 @@ repeat: resume: while (next != &this_parent->mnt_mounts) { struct list_head *tmp = next; - struct vfsmount *mnt = list_entry(tmp, struct vfsmount, mnt_child); + struct mount *mnt = list_entry(tmp, struct mount, mnt_child); next = tmp->next; - if (!(mnt->mnt_flags & MNT_SHRINKABLE)) + if (!(mnt->mnt.mnt_flags & MNT_SHRINKABLE)) continue; /* * Descend a level if the d_mounts list is non-empty. @@ -2175,15 +2016,15 @@ resume: * * vfsmount_lock must be held for write */ -static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts) +static void shrink_submounts(struct mount *mnt, struct list_head *umounts) { LIST_HEAD(graveyard); - struct vfsmount *m; + struct mount *m; /* extract submounts of 'mountpoint' from the expiration list */ while (select_submounts(mnt, &graveyard)) { while (!list_empty(&graveyard)) { - m = list_first_entry(&graveyard, struct vfsmount, + m = list_first_entry(&graveyard, struct mount, mnt_expire); touch_mnt_namespace(m->mnt_ns); umount_tree(m, 1, umounts); @@ -2370,12 +2211,13 @@ static struct mnt_namespace *alloc_mnt_ns(void) void mnt_make_longterm(struct vfsmount *mnt) { - __mnt_make_longterm(mnt); + __mnt_make_longterm(real_mount(mnt)); } -void mnt_make_shortterm(struct vfsmount *mnt) +void mnt_make_shortterm(struct vfsmount *m) { #ifdef CONFIG_SMP + struct mount *mnt = real_mount(m); if (atomic_add_unless(&mnt->mnt_longterm, -1, 1)) return; br_write_lock(vfsmount_lock); @@ -2393,7 +2235,9 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, { struct mnt_namespace *new_ns; struct vfsmount *rootmnt = NULL, *pwdmnt = NULL; - struct vfsmount *p, *q; + struct mount *p, *q; + struct mount *old = mnt_ns->root; + struct mount *new; new_ns = alloc_mnt_ns(); if (IS_ERR(new_ns)) @@ -2401,15 +2245,15 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, down_write(&namespace_sem); /* First pass: copy the tree topology */ - new_ns->root = copy_tree(mnt_ns->root, mnt_ns->root->mnt_root, - CL_COPY_ALL | CL_EXPIRE); - if (!new_ns->root) { + new = copy_tree(old, old->mnt.mnt_root, CL_COPY_ALL | CL_EXPIRE); + if (!new) { up_write(&namespace_sem); kfree(new_ns); return ERR_PTR(-ENOMEM); } + new_ns->root = new; br_write_lock(vfsmount_lock); - list_add_tail(&new_ns->list, &new_ns->root->mnt_list); + list_add_tail(&new_ns->list, &new->mnt_list); br_write_unlock(vfsmount_lock); /* @@ -2417,27 +2261,27 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, * as belonging to new namespace. We have already acquired a private * fs_struct, so tsk->fs->lock is not needed. */ - p = mnt_ns->root; - q = new_ns->root; + p = old; + q = new; while (p) { q->mnt_ns = new_ns; __mnt_make_longterm(q); if (fs) { - if (p == fs->root.mnt) { - fs->root.mnt = mntget(q); + if (&p->mnt == fs->root.mnt) { + fs->root.mnt = mntget(&q->mnt); __mnt_make_longterm(q); - mnt_make_shortterm(p); - rootmnt = p; + mnt_make_shortterm(&p->mnt); + rootmnt = &p->mnt; } - if (p == fs->pwd.mnt) { - fs->pwd.mnt = mntget(q); + if (&p->mnt == fs->pwd.mnt) { + fs->pwd.mnt = mntget(&q->mnt); __mnt_make_longterm(q); - mnt_make_shortterm(p); - pwdmnt = p; + mnt_make_shortterm(&p->mnt); + pwdmnt = &p->mnt; } } - p = next_mnt(p, mnt_ns->root); - q = next_mnt(q, new_ns->root); + p = next_mnt(p, old); + q = next_mnt(q, new); } up_write(&namespace_sem); @@ -2470,22 +2314,20 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, * create_mnt_ns - creates a private namespace and adds a root filesystem * @mnt: pointer to the new root filesystem mountpoint */ -struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt) +static struct mnt_namespace *create_mnt_ns(struct vfsmount *m) { - struct mnt_namespace *new_ns; - - new_ns = alloc_mnt_ns(); + struct mnt_namespace *new_ns = alloc_mnt_ns(); if (!IS_ERR(new_ns)) { + struct mount *mnt = real_mount(m); mnt->mnt_ns = new_ns; __mnt_make_longterm(mnt); new_ns->root = mnt; - list_add(&new_ns->list, &new_ns->root->mnt_list); + list_add(&new_ns->list, &mnt->mnt_list); } else { - mntput(mnt); + mntput(m); } return new_ns; } -EXPORT_SYMBOL(create_mnt_ns); struct dentry *mount_subtree(struct vfsmount *mnt, const char *name) { @@ -2559,6 +2401,31 @@ out_type: } /* + * Return true if path is reachable from root + * + * namespace_sem or vfsmount_lock is held + */ +bool is_path_reachable(struct mount *mnt, struct dentry *dentry, + const struct path *root) +{ + while (&mnt->mnt != root->mnt && mnt_has_parent(mnt)) { + dentry = mnt->mnt_mountpoint; + mnt = mnt->mnt_parent; + } + return &mnt->mnt == root->mnt && is_subdir(dentry, root->dentry); +} + +int path_is_under(struct path *path1, struct path *path2) +{ + int res; + br_read_lock(vfsmount_lock); + res = is_path_reachable(real_mount(path1->mnt), path1->dentry, path2); + br_read_unlock(vfsmount_lock); + return res; +} +EXPORT_SYMBOL(path_is_under); + +/* * pivot_root Semantics: * Moves the root file system of the current process to the directory put_old, * makes new_root as the new root file system of the current process, and sets @@ -2586,8 +2453,8 @@ out_type: SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, const char __user *, put_old) { - struct vfsmount *tmp; struct path new, old, parent_path, root_parent, root; + struct mount *new_mnt, *root_mnt; int error; if (!capable(CAP_SYS_ADMIN)) @@ -2611,11 +2478,13 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, goto out3; error = -EINVAL; - if (IS_MNT_SHARED(old.mnt) || - IS_MNT_SHARED(new.mnt->mnt_parent) || - IS_MNT_SHARED(root.mnt->mnt_parent)) + new_mnt = real_mount(new.mnt); + root_mnt = real_mount(root.mnt); + if (IS_MNT_SHARED(real_mount(old.mnt)) || + IS_MNT_SHARED(new_mnt->mnt_parent) || + IS_MNT_SHARED(root_mnt->mnt_parent)) goto out4; - if (!check_mnt(root.mnt) || !check_mnt(new.mnt)) + if (!check_mnt(root_mnt) || !check_mnt(new_mnt)) goto out4; error = -ENOENT; if (d_unlinked(new.dentry)) @@ -2629,33 +2498,22 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, error = -EINVAL; if (root.mnt->mnt_root != root.dentry) goto out4; /* not a mountpoint */ - if (root.mnt->mnt_parent == root.mnt) + if (!mnt_has_parent(root_mnt)) goto out4; /* not attached */ if (new.mnt->mnt_root != new.dentry) goto out4; /* not a mountpoint */ - if (new.mnt->mnt_parent == new.mnt) + if (!mnt_has_parent(new_mnt)) goto out4; /* not attached */ /* make sure we can reach put_old from new_root */ - tmp = old.mnt; - if (tmp != new.mnt) { - for (;;) { - if (tmp->mnt_parent == tmp) - goto out4; /* already mounted on put_old */ - if (tmp->mnt_parent == new.mnt) - break; - tmp = tmp->mnt_parent; - } - if (!is_subdir(tmp->mnt_mountpoint, new.dentry)) - goto out4; - } else if (!is_subdir(old.dentry, new.dentry)) + if (!is_path_reachable(real_mount(old.mnt), old.dentry, &new)) goto out4; br_write_lock(vfsmount_lock); - detach_mnt(new.mnt, &parent_path); - detach_mnt(root.mnt, &root_parent); + detach_mnt(new_mnt, &parent_path); + detach_mnt(root_mnt, &root_parent); /* mount old root on put_old */ - attach_mnt(root.mnt, &old); + attach_mnt(root_mnt, &old); /* mount new_root on / */ - attach_mnt(new.mnt, &root_parent); + attach_mnt(new_mnt, &root_parent); touch_mnt_namespace(current->nsproxy->mnt_ns); br_write_unlock(vfsmount_lock); chroot_fs_refs(&root, &new); @@ -2693,8 +2551,8 @@ static void __init init_mount_tree(void) init_task.nsproxy->mnt_ns = ns; get_mnt_ns(ns); - root.mnt = ns->root; - root.dentry = ns->root->mnt_root; + root.mnt = mnt; + root.dentry = mnt->mnt_root; set_fs_pwd(current->fs, &root); set_fs_root(current->fs, &root); @@ -2707,7 +2565,7 @@ void __init mnt_init(void) init_rwsem(&namespace_sem); - mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct vfsmount), + mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct mount), 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); mount_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC); @@ -2747,7 +2605,6 @@ void put_mnt_ns(struct mnt_namespace *ns) release_mounts(&umount_list); kfree(ns); } -EXPORT_SYMBOL(put_mnt_ns); struct vfsmount *kern_mount_data(struct file_system_type *type, void *data) { @@ -2776,5 +2633,5 @@ EXPORT_SYMBOL(kern_unmount); bool our_mnt(struct vfsmount *mnt) { - return check_mnt(mnt); + return check_mnt(real_mount(mnt)); } diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 9c51f621e901..aeed93a6bde0 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -30,15 +30,15 @@ static void ncp_do_readdir(struct file *, void *, filldir_t, static int ncp_readdir(struct file *, void *, filldir_t); -static int ncp_create(struct inode *, struct dentry *, int, struct nameidata *); +static int ncp_create(struct inode *, struct dentry *, umode_t, struct nameidata *); static struct dentry *ncp_lookup(struct inode *, struct dentry *, struct nameidata *); static int ncp_unlink(struct inode *, struct dentry *); -static int ncp_mkdir(struct inode *, struct dentry *, int); +static int ncp_mkdir(struct inode *, struct dentry *, umode_t); static int ncp_rmdir(struct inode *, struct dentry *); static int ncp_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); static int ncp_mknod(struct inode * dir, struct dentry *dentry, - int mode, dev_t rdev); + umode_t mode, dev_t rdev); #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS) extern int ncp_symlink(struct inode *, struct dentry *, const char *); #else @@ -919,7 +919,7 @@ out_close: goto out; } -int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode, +int ncp_create_new(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev, __le32 attributes) { struct ncp_server *server = NCP_SERVER(dir); @@ -928,7 +928,7 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode, int opmode; __u8 __name[NCP_MAXPATHLEN + 1]; - PPRINTK("ncp_create_new: creating %s/%s, mode=%x\n", + PPRINTK("ncp_create_new: creating %s/%s, mode=%hx\n", dentry->d_parent->d_name.name, dentry->d_name.name, mode); ncp_age_dentry(server, dentry); @@ -979,13 +979,13 @@ out: return error; } -static int ncp_create(struct inode *dir, struct dentry *dentry, int mode, +static int ncp_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { return ncp_create_new(dir, dentry, mode, 0, 0); } -static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int ncp_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct ncp_entry_info finfo; struct ncp_server *server = NCP_SERVER(dir); @@ -1201,12 +1201,12 @@ out: } static int ncp_mknod(struct inode * dir, struct dentry *dentry, - int mode, dev_t rdev) + umode_t mode, dev_t rdev) { if (!new_valid_dev(rdev)) return -EINVAL; if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber)) { - DPRINTK(KERN_DEBUG "ncp_mknod: mode = 0%o\n", mode); + DPRINTK(KERN_DEBUG "ncp_mknod: mode = 0%ho\n", mode); return ncp_create_new(dir, dentry, mode, rdev, 0); } return -EPERM; /* Strange, but true */ diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index cbd1a61c110a..3d1e34f8a68e 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -44,7 +44,7 @@ static void ncp_evict_inode(struct inode *); static void ncp_put_super(struct super_block *); static int ncp_statfs(struct dentry *, struct kstatfs *); -static int ncp_show_options(struct seq_file *, struct vfsmount *); +static int ncp_show_options(struct seq_file *, struct dentry *); static struct kmem_cache * ncp_inode_cachep; @@ -60,7 +60,6 @@ static struct inode *ncp_alloc_inode(struct super_block *sb) static void ncp_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode)); } @@ -323,9 +322,9 @@ static void ncp_stop_tasks(struct ncp_server *server) { flush_work_sync(&server->timeout_tq); } -static int ncp_show_options(struct seq_file *seq, struct vfsmount *mnt) +static int ncp_show_options(struct seq_file *seq, struct dentry *root) { - struct ncp_server *server = NCP_SBP(mnt->mnt_sb); + struct ncp_server *server = NCP_SBP(root->d_sb); unsigned int tmp; if (server->m.uid != 0) diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c index 790e92a9ec63..6958adfaff08 100644 --- a/fs/ncpfs/ioctl.c +++ b/fs/ncpfs/ioctl.c @@ -901,7 +901,7 @@ long ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ret = __ncp_ioctl(inode, cmd, arg); outDropWrite: if (need_drop_write) - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); out: return ret; } diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h index 09881e6aa5ad..32c06587351a 100644 --- a/fs/ncpfs/ncplib_kernel.h +++ b/fs/ncpfs/ncplib_kernel.h @@ -114,7 +114,7 @@ int ncp_dirhandle_alloc(struct ncp_server *, __u8 vol, __le32 dirent, __u8 *dirh int ncp_dirhandle_free(struct ncp_server *, __u8 dirhandle); int ncp_create_new(struct inode *dir, struct dentry *dentry, - int mode, dev_t rdev, __le32 attributes); + umode_t mode, dev_t rdev, __le32 attributes); static inline int ncp_is_nfs_extras(struct ncp_server* server, unsigned int volnum) { #ifdef CONFIG_NCPFS_NFS_NS diff --git a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c index 661f861d80c6..52439ddc8de0 100644 --- a/fs/ncpfs/symlink.c +++ b/fs/ncpfs/symlink.c @@ -108,7 +108,7 @@ int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { char *rawlink; int length, err, i, outlen; int kludge; - int mode; + umode_t mode; __le32 attr; unsigned int hdr; diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index ac2899098147..fd9a872fada0 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -47,13 +47,13 @@ static int nfs_opendir(struct inode *, struct file *); static int nfs_closedir(struct inode *, struct file *); static int nfs_readdir(struct file *, void *, filldir_t); static struct dentry *nfs_lookup(struct inode *, struct dentry *, struct nameidata *); -static int nfs_create(struct inode *, struct dentry *, int, struct nameidata *); -static int nfs_mkdir(struct inode *, struct dentry *, int); +static int nfs_create(struct inode *, struct dentry *, umode_t, struct nameidata *); +static int nfs_mkdir(struct inode *, struct dentry *, umode_t); static int nfs_rmdir(struct inode *, struct dentry *); static int nfs_unlink(struct inode *, struct dentry *); static int nfs_symlink(struct inode *, struct dentry *, const char *); static int nfs_link(struct dentry *, struct inode *, struct dentry *); -static int nfs_mknod(struct inode *, struct dentry *, int, dev_t); +static int nfs_mknod(struct inode *, struct dentry *, umode_t, dev_t); static int nfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); static int nfs_fsync_dir(struct file *, loff_t, loff_t, int); @@ -112,7 +112,7 @@ const struct inode_operations nfs3_dir_inode_operations = { #ifdef CONFIG_NFS_V4 static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *); -static int nfs_open_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd); +static int nfs_open_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd); const struct inode_operations nfs4_dir_inode_operations = { .create = nfs_open_create, .lookup = nfs_atomic_lookup, @@ -1368,18 +1368,7 @@ static fmode_t flags_to_mode(int flags) static struct nfs_open_context *create_nfs_open_context(struct dentry *dentry, int open_flags) { - struct nfs_open_context *ctx; - struct rpc_cred *cred; - fmode_t fmode = flags_to_mode(open_flags); - - cred = rpc_lookup_cred(); - if (IS_ERR(cred)) - return ERR_CAST(cred); - ctx = alloc_nfs_open_context(dentry, cred, fmode); - put_rpccred(cred); - if (ctx == NULL) - return ERR_PTR(-ENOMEM); - return ctx; + return alloc_nfs_open_context(dentry, flags_to_mode(open_flags)); } static int do_open(struct inode *inode, struct file *filp) @@ -1584,8 +1573,8 @@ no_open: return nfs_lookup_revalidate(dentry, nd); } -static int nfs_open_create(struct inode *dir, struct dentry *dentry, int mode, - struct nameidata *nd) +static int nfs_open_create(struct inode *dir, struct dentry *dentry, + umode_t mode, struct nameidata *nd) { struct nfs_open_context *ctx = NULL; struct iattr attr; @@ -1675,8 +1664,8 @@ out_error: * that the operation succeeded on the server, but an error in the * reply path made it appear to have failed. */ -static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, - struct nameidata *nd) +static int nfs_create(struct inode *dir, struct dentry *dentry, + umode_t mode, struct nameidata *nd) { struct iattr attr; int error; @@ -1704,7 +1693,7 @@ out_err: * See comments for nfs_proc_create regarding failed operations. */ static int -nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) +nfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { struct iattr attr; int status; @@ -1730,7 +1719,7 @@ out_err: /* * See comments for nfs_proc_create regarding failed operations. */ -static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int nfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct iattr attr; int error; diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 50a15fa8cf98..6f00086e340f 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -629,23 +629,28 @@ void nfs_close_context(struct nfs_open_context *ctx, int is_sync) nfs_revalidate_inode(server, inode); } -struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rpc_cred *cred, fmode_t f_mode) +struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, fmode_t f_mode) { struct nfs_open_context *ctx; + struct rpc_cred *cred = rpc_lookup_cred(); + if (IS_ERR(cred)) + return ERR_CAST(cred); ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); - if (ctx != NULL) { - nfs_sb_active(dentry->d_sb); - ctx->dentry = dget(dentry); - ctx->cred = get_rpccred(cred); - ctx->state = NULL; - ctx->mode = f_mode; - ctx->flags = 0; - ctx->error = 0; - nfs_init_lock_context(&ctx->lock_context); - ctx->lock_context.open_context = ctx; - INIT_LIST_HEAD(&ctx->list); + if (!ctx) { + put_rpccred(cred); + return ERR_PTR(-ENOMEM); } + nfs_sb_active(dentry->d_sb); + ctx->dentry = dget(dentry); + ctx->cred = cred; + ctx->state = NULL; + ctx->mode = f_mode; + ctx->flags = 0; + ctx->error = 0; + nfs_init_lock_context(&ctx->lock_context); + ctx->lock_context.open_context = ctx; + INIT_LIST_HEAD(&ctx->list); return ctx; } @@ -738,15 +743,10 @@ static void nfs_file_clear_open_context(struct file *filp) int nfs_open(struct inode *inode, struct file *filp) { struct nfs_open_context *ctx; - struct rpc_cred *cred; - cred = rpc_lookup_cred(); - if (IS_ERR(cred)) - return PTR_ERR(cred); - ctx = alloc_nfs_open_context(filp->f_path.dentry, cred, filp->f_mode); - put_rpccred(cred); - if (ctx == NULL) - return -ENOMEM; + ctx = alloc_nfs_open_context(filp->f_path.dentry, filp->f_mode); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); nfs_file_set_open_context(filp, ctx); put_nfs_open_context(ctx); nfs_fscache_set_inode_cookie(inode, filp); @@ -1464,7 +1464,6 @@ struct inode *nfs_alloc_inode(struct super_block *sb) static void nfs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(nfs_inode_cachep, NFS_I(inode)); } diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 134777406ee3..e463967aafb8 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -41,7 +41,6 @@ #include <linux/lockd/bind.h> #include <linux/seq_file.h> #include <linux/mount.h> -#include <linux/mnt_namespace.h> #include <linux/namei.h> #include <linux/nfs_idmap.h> #include <linux/vfs.h> @@ -263,10 +262,10 @@ static match_table_t nfs_local_lock_tokens = { static void nfs_umount_begin(struct super_block *); static int nfs_statfs(struct dentry *, struct kstatfs *); -static int nfs_show_options(struct seq_file *, struct vfsmount *); -static int nfs_show_devname(struct seq_file *, struct vfsmount *); -static int nfs_show_path(struct seq_file *, struct vfsmount *); -static int nfs_show_stats(struct seq_file *, struct vfsmount *); +static int nfs_show_options(struct seq_file *, struct dentry *); +static int nfs_show_devname(struct seq_file *, struct dentry *); +static int nfs_show_path(struct seq_file *, struct dentry *); +static int nfs_show_stats(struct seq_file *, struct dentry *); static struct dentry *nfs_fs_mount(struct file_system_type *, int, const char *, void *); static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type, @@ -721,9 +720,9 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, /* * Describe the mount options on this VFS mountpoint */ -static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) +static int nfs_show_options(struct seq_file *m, struct dentry *root) { - struct nfs_server *nfss = NFS_SB(mnt->mnt_sb); + struct nfs_server *nfss = NFS_SB(root->d_sb); nfs_show_mount_options(m, nfss, 0); @@ -761,14 +760,14 @@ static void show_pnfs(struct seq_file *m, struct nfs_server *server) {} #endif #endif -static int nfs_show_devname(struct seq_file *m, struct vfsmount *mnt) +static int nfs_show_devname(struct seq_file *m, struct dentry *root) { char *page = (char *) __get_free_page(GFP_KERNEL); char *devname, *dummy; int err = 0; if (!page) return -ENOMEM; - devname = nfs_path(&dummy, mnt->mnt_root, page, PAGE_SIZE); + devname = nfs_path(&dummy, root, page, PAGE_SIZE); if (IS_ERR(devname)) err = PTR_ERR(devname); else @@ -777,7 +776,7 @@ static int nfs_show_devname(struct seq_file *m, struct vfsmount *mnt) return err; } -static int nfs_show_path(struct seq_file *m, struct vfsmount *mnt) +static int nfs_show_path(struct seq_file *m, struct dentry *dentry) { seq_puts(m, "/"); return 0; @@ -786,10 +785,10 @@ static int nfs_show_path(struct seq_file *m, struct vfsmount *mnt) /* * Present statistical information for this VFS mountpoint */ -static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) +static int nfs_show_stats(struct seq_file *m, struct dentry *root) { int i, cpu; - struct nfs_server *nfss = NFS_SB(mnt->mnt_sb); + struct nfs_server *nfss = NFS_SB(root->d_sb); struct rpc_auth *auth = nfss->client->cl_auth; struct nfs_iostats totals = { }; @@ -799,10 +798,10 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) * Display all mount option settings */ seq_printf(m, "\n\topts:\t"); - seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? "ro" : "rw"); - seq_puts(m, mnt->mnt_sb->s_flags & MS_SYNCHRONOUS ? ",sync" : ""); - seq_puts(m, mnt->mnt_sb->s_flags & MS_NOATIME ? ",noatime" : ""); - seq_puts(m, mnt->mnt_sb->s_flags & MS_NODIRATIME ? ",nodiratime" : ""); + seq_puts(m, root->d_sb->s_flags & MS_RDONLY ? "ro" : "rw"); + seq_puts(m, root->d_sb->s_flags & MS_SYNCHRONOUS ? ",sync" : ""); + seq_puts(m, root->d_sb->s_flags & MS_NOATIME ? ",noatime" : ""); + seq_puts(m, root->d_sb->s_flags & MS_NODIRATIME ? ",nodiratime" : ""); nfs_show_mount_options(m, nfss, 1); seq_printf(m, "\n\tage:\t%lu", (jiffies - nfss->mount_time) / HZ); @@ -2788,11 +2787,15 @@ static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt, const char *export_path) { struct dentry *dentry; - int ret = nfs_referral_loop_protect(); + int err; - if (ret) { + if (IS_ERR(root_mnt)) + return ERR_CAST(root_mnt); + + err = nfs_referral_loop_protect(); + if (err) { mntput(root_mnt); - return ERR_PTR(ret); + return ERR_PTR(err); } dentry = mount_subtree(root_mnt, export_path); @@ -2816,9 +2819,7 @@ static struct dentry *nfs4_try_mount(int flags, const char *dev_name, data->nfs_server.hostname); data->nfs_server.export_path = export_path; - res = ERR_CAST(root_mnt); - if (!IS_ERR(root_mnt)) - res = nfs_follow_remote_path(root_mnt, export_path); + res = nfs_follow_remote_path(root_mnt, export_path); dfprintk(MOUNT, "<-- nfs4_try_mount() = %ld%s\n", IS_ERR(res) ? PTR_ERR(res) : 0, @@ -3079,9 +3080,7 @@ static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, flags, data, data->hostname); data->mnt_path = export_path; - res = ERR_CAST(root_mnt); - if (!IS_ERR(root_mnt)) - res = nfs_follow_remote_path(root_mnt, export_path); + res = nfs_follow_remote_path(root_mnt, export_path); dprintk("<-- nfs4_referral_mount() = %ld%s\n", IS_ERR(res) ? PTR_ERR(res) : 0, IS_ERR(res) ? " [error]" : ""); diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index fa383361bc61..c5e28ed8bca0 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -838,7 +838,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, return status; } } - status = mnt_want_write(cstate->current_fh.fh_export->ex_path.mnt); + status = fh_want_write(&cstate->current_fh); if (status) return status; status = nfs_ok; @@ -856,7 +856,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr, 0, (time_t)0); out: - mnt_drop_write(cstate->current_fh.fh_export->ex_path.mnt); + fh_drop_write(&cstate->current_fh); return status; } diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index ed083b9a731b..80a0be9ed008 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -147,11 +147,11 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) status = -EEXIST; if (dentry->d_inode) goto out_put; - status = mnt_want_write(rec_file->f_path.mnt); + status = mnt_want_write_file(rec_file); if (status) goto out_put; status = vfs_mkdir(dir->d_inode, dentry, S_IRWXU); - mnt_drop_write(rec_file->f_path.mnt); + mnt_drop_write_file(rec_file); out_put: dput(dentry); out_unlock: @@ -268,7 +268,7 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp) if (!rec_file || !clp->cl_firststate) return; - status = mnt_want_write(rec_file->f_path.mnt); + status = mnt_want_write_file(rec_file); if (status) goto out; clp->cl_firststate = 0; @@ -281,7 +281,7 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp) nfs4_reset_creds(original_cred); if (status == 0) vfs_fsync(rec_file, 0); - mnt_drop_write(rec_file->f_path.mnt); + mnt_drop_write_file(rec_file); out: if (status) printk("NFSD: Failed to remove expired client state directory" @@ -311,13 +311,13 @@ nfsd4_recdir_purge_old(void) { if (!rec_file) return; - status = mnt_want_write(rec_file->f_path.mnt); + status = mnt_want_write_file(rec_file); if (status) goto out; status = nfsd4_list_rec_dir(purge_old); if (status == 0) vfs_fsync(rec_file, 0); - mnt_drop_write(rec_file->f_path.mnt); + mnt_drop_write_file(rec_file); out: if (status) printk("nfsd4: failed to purge old clients from recovery" diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index c45a2ea4a090..bb4a11d58a5a 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -272,7 +272,7 @@ static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size) * 2. Is that directory a mount point, or * 3. Is that directory the root of an exported file system? */ - error = nlmsvc_unlock_all_by_sb(path.mnt->mnt_sb); + error = nlmsvc_unlock_all_by_sb(path.dentry->d_sb); path_put(&path); return error; diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index c763de5c1157..68454e75fce9 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -59,7 +59,7 @@ static int nfsd_acceptable(void *expv, struct dentry *dentry) * the write call). */ static inline __be32 -nfsd_mode_check(struct svc_rqst *rqstp, umode_t mode, int requested) +nfsd_mode_check(struct svc_rqst *rqstp, umode_t mode, umode_t requested) { mode &= S_IFMT; @@ -293,7 +293,7 @@ out: * include/linux/nfsd/nfsd.h. */ __be32 -fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) +fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access) { struct svc_export *exp; struct dentry *dentry; diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h index c16f8d8331b5..e5e6707ba687 100644 --- a/fs/nfsd/nfsfh.h +++ b/fs/nfsd/nfsfh.h @@ -102,7 +102,7 @@ extern char * SVCFH_fmt(struct svc_fh *fhp); /* * Function prototypes */ -__be32 fh_verify(struct svc_rqst *, struct svc_fh *, int, int); +__be32 fh_verify(struct svc_rqst *, struct svc_fh *, umode_t, int); __be32 fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, struct svc_fh *); __be32 fh_update(struct svc_fh *); void fh_put(struct svc_fh *); diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 7a2e442623c8..d25a723b68ad 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -307,7 +307,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, struct dentry *dentry; struct inode *inode; int accmode = NFSD_MAY_SATTR; - int ftype = 0; + umode_t ftype = 0; __be32 err; int host_err; int size_change = 0; @@ -730,7 +730,7 @@ static int nfsd_open_break_lease(struct inode *inode, int access) * N.B. After this call fhp needs an fh_put */ __be32 -nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, +nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access, struct file **filp) { struct dentry *dentry; @@ -1300,7 +1300,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, goto out; } - host_err = mnt_want_write(fhp->fh_export->ex_path.mnt); + host_err = fh_want_write(fhp); if (host_err) goto out_nfserr; @@ -1325,7 +1325,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, break; } if (host_err < 0) { - mnt_drop_write(fhp->fh_export->ex_path.mnt); + fh_drop_write(fhp); goto out_nfserr; } @@ -1339,7 +1339,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, err2 = nfserrno(commit_metadata(fhp)); if (err2) err = err2; - mnt_drop_write(fhp->fh_export->ex_path.mnt); + fh_drop_write(fhp); /* * Update the file handle to get the new inode info. */ @@ -1430,7 +1430,7 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, v_atime = verifier[1]&0x7fffffff; } - host_err = mnt_want_write(fhp->fh_export->ex_path.mnt); + host_err = fh_want_write(fhp); if (host_err) goto out_nfserr; if (dchild->d_inode) { @@ -1469,13 +1469,13 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, case NFS3_CREATE_GUARDED: err = nfserr_exist; } - mnt_drop_write(fhp->fh_export->ex_path.mnt); + fh_drop_write(fhp); goto out; } host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL); if (host_err < 0) { - mnt_drop_write(fhp->fh_export->ex_path.mnt); + fh_drop_write(fhp); goto out_nfserr; } if (created) @@ -1503,7 +1503,7 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, if (!err) err = nfserrno(commit_metadata(fhp)); - mnt_drop_write(fhp->fh_export->ex_path.mnt); + fh_drop_write(fhp); /* * Update the filehandle to get the new inode info. */ @@ -1600,7 +1600,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, if (IS_ERR(dnew)) goto out_nfserr; - host_err = mnt_want_write(fhp->fh_export->ex_path.mnt); + host_err = fh_want_write(fhp); if (host_err) goto out_nfserr; @@ -1621,7 +1621,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, err = nfserrno(commit_metadata(fhp)); fh_unlock(fhp); - mnt_drop_write(fhp->fh_export->ex_path.mnt); + fh_drop_write(fhp); cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp); dput(dnew); @@ -1674,7 +1674,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, dold = tfhp->fh_dentry; - host_err = mnt_want_write(tfhp->fh_export->ex_path.mnt); + host_err = fh_want_write(tfhp); if (host_err) { err = nfserrno(host_err); goto out_dput; @@ -1699,7 +1699,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, err = nfserrno(host_err); } out_drop_write: - mnt_drop_write(tfhp->fh_export->ex_path.mnt); + fh_drop_write(tfhp); out_dput: dput(dnew); out_unlock: @@ -1776,7 +1776,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, host_err = -EXDEV; if (ffhp->fh_export->ex_path.mnt != tfhp->fh_export->ex_path.mnt) goto out_dput_new; - host_err = mnt_want_write(ffhp->fh_export->ex_path.mnt); + host_err = fh_want_write(ffhp); if (host_err) goto out_dput_new; @@ -1795,7 +1795,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, host_err = commit_metadata(ffhp); } out_drop_write: - mnt_drop_write(ffhp->fh_export->ex_path.mnt); + fh_drop_write(ffhp); out_dput_new: dput(ndentry); out_dput_old: @@ -1854,7 +1854,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, if (!type) type = rdentry->d_inode->i_mode & S_IFMT; - host_err = mnt_want_write(fhp->fh_export->ex_path.mnt); + host_err = fh_want_write(fhp); if (host_err) goto out_put; @@ -1868,7 +1868,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, if (!host_err) host_err = commit_metadata(fhp); out_drop_write: - mnt_drop_write(fhp->fh_export->ex_path.mnt); + fh_drop_write(fhp); out_put: dput(rdentry); @@ -2270,7 +2270,7 @@ nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl) } else size = 0; - error = mnt_want_write(fhp->fh_export->ex_path.mnt); + error = fh_want_write(fhp); if (error) goto getout; if (size) @@ -2284,7 +2284,7 @@ nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl) error = 0; } } - mnt_drop_write(fhp->fh_export->ex_path.mnt); + fh_drop_write(fhp); getout: kfree(value); diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index 3f54ad03bb2b..1dcd238e11a0 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h @@ -66,7 +66,7 @@ __be32 do_nfsd_create(struct svc_rqst *, struct svc_fh *, __be32 nfsd_commit(struct svc_rqst *, struct svc_fh *, loff_t, unsigned long); #endif /* CONFIG_NFSD_V3 */ -__be32 nfsd_open(struct svc_rqst *, struct svc_fh *, int, +__be32 nfsd_open(struct svc_rqst *, struct svc_fh *, umode_t, int, struct file **); void nfsd_close(struct file *); __be32 nfsd_read(struct svc_rqst *, struct svc_fh *, @@ -106,4 +106,14 @@ struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int); int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *); #endif +static inline int fh_want_write(struct svc_fh *fh) +{ + return mnt_want_write(fh->fh_export->ex_path.mnt); +} + +static inline void fh_drop_write(struct svc_fh *fh) +{ + mnt_drop_write(fh->fh_export->ex_path.mnt); +} + #endif /* LINUX_NFSD_VFS_H */ diff --git a/fs/nilfs2/dir.c b/fs/nilfs2/dir.c index 3a1923943b14..ca35b3a46d17 100644 --- a/fs/nilfs2/dir.c +++ b/fs/nilfs2/dir.c @@ -251,7 +251,7 @@ nilfs_type_by_mode[S_IFMT >> S_SHIFT] = { static void nilfs_set_de_type(struct nilfs_dir_entry *de, struct inode *inode) { - mode_t mode = inode->i_mode; + umode_t mode = inode->i_mode; de->file_type = nilfs_type_by_mode[(mode & S_IFMT)>>S_SHIFT]; } diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index b50ffb72e5b3..8f7b95ac1f7e 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -291,7 +291,7 @@ const struct address_space_operations nilfs_aops = { .is_partially_uptodate = block_is_partially_uptodate, }; -struct inode *nilfs_new_inode(struct inode *dir, int mode) +struct inode *nilfs_new_inode(struct inode *dir, umode_t mode) { struct super_block *sb = dir->i_sb; struct the_nilfs *nilfs = sb->s_fs_info; diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index ac258beeda3c..886649627c3d 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -27,7 +27,7 @@ #include <linux/uaccess.h> /* copy_from_user(), copy_to_user() */ #include <linux/vmalloc.h> #include <linux/compat.h> /* compat_ptr() */ -#include <linux/mount.h> /* mnt_want_write(), mnt_drop_write() */ +#include <linux/mount.h> /* mnt_want_write_file(), mnt_drop_write_file() */ #include <linux/buffer_head.h> #include <linux/nilfs2_fs.h> #include "nilfs.h" @@ -119,7 +119,7 @@ static int nilfs_ioctl_setflags(struct inode *inode, struct file *filp, if (get_user(flags, (int __user *)argp)) return -EFAULT; - ret = mnt_want_write(filp->f_path.mnt); + ret = mnt_want_write_file(filp); if (ret) return ret; @@ -154,7 +154,7 @@ static int nilfs_ioctl_setflags(struct inode *inode, struct file *filp, ret = nilfs_transaction_commit(inode->i_sb); out: mutex_unlock(&inode->i_mutex); - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); return ret; } @@ -174,7 +174,7 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - ret = mnt_want_write(filp->f_path.mnt); + ret = mnt_want_write_file(filp); if (ret) return ret; @@ -194,7 +194,7 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp, up_read(&inode->i_sb->s_umount); out: - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); return ret; } @@ -210,7 +210,7 @@ nilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - ret = mnt_want_write(filp->f_path.mnt); + ret = mnt_want_write_file(filp); if (ret) return ret; @@ -225,7 +225,7 @@ nilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp, else nilfs_transaction_commit(inode->i_sb); /* never fails */ out: - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); return ret; } @@ -591,7 +591,7 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - ret = mnt_want_write(filp->f_path.mnt); + ret = mnt_want_write_file(filp); if (ret) return ret; @@ -675,7 +675,7 @@ out_free: vfree(kbufs[n]); kfree(kbufs[4]); out: - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); return ret; } @@ -710,7 +710,7 @@ static int nilfs_ioctl_resize(struct inode *inode, struct file *filp, if (!capable(CAP_SYS_ADMIN)) goto out; - ret = mnt_want_write(filp->f_path.mnt); + ret = mnt_want_write_file(filp); if (ret) goto out; @@ -721,7 +721,7 @@ static int nilfs_ioctl_resize(struct inode *inode, struct file *filp, ret = nilfs_resize_fs(inode->i_sb, newsize); out_drop_write: - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); out: return ret; } diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c index 768982de10e4..1cd3f624dffc 100644 --- a/fs/nilfs2/namei.c +++ b/fs/nilfs2/namei.c @@ -84,7 +84,7 @@ nilfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) * If the create succeeds, we fill in the inode information * with d_instantiate(). */ -static int nilfs_create(struct inode *dir, struct dentry *dentry, int mode, +static int nilfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { struct inode *inode; @@ -112,7 +112,7 @@ static int nilfs_create(struct inode *dir, struct dentry *dentry, int mode, } static int -nilfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) +nilfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { struct inode *inode; struct nilfs_transaction_info ti; @@ -213,7 +213,7 @@ static int nilfs_link(struct dentry *old_dentry, struct inode *dir, return err; } -static int nilfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int nilfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct inode *inode; struct nilfs_transaction_info ti; diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index 3777d138f895..250add84da76 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h @@ -246,7 +246,7 @@ int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *, struct nilfs_argv *, /* inode.c */ void nilfs_inode_add_blocks(struct inode *inode, int n); void nilfs_inode_sub_blocks(struct inode *inode, int n); -extern struct inode *nilfs_new_inode(struct inode *, int); +extern struct inode *nilfs_new_inode(struct inode *, umode_t); extern void nilfs_free_inode(struct inode *); extern int nilfs_get_block(struct inode *, sector_t, struct buffer_head *, int); extern void nilfs_set_inode_flags(struct inode *); diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 8351c44a7320..08e3d4f9df18 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -175,8 +175,6 @@ static void nilfs_i_callback(struct rcu_head *head) struct inode *inode = container_of(head, struct inode, i_rcu); struct nilfs_mdt_info *mdi = NILFS_MDT(inode); - INIT_LIST_HEAD(&inode->i_dentry); - if (mdi) { kfree(mdi->mi_bgl); /* kfree(NULL) is safe */ kfree(mdi); @@ -650,11 +648,11 @@ static int nilfs_statfs(struct dentry *dentry, struct kstatfs *buf) return 0; } -static int nilfs_show_options(struct seq_file *seq, struct vfsmount *vfs) +static int nilfs_show_options(struct seq_file *seq, struct dentry *dentry) { - struct super_block *sb = vfs->mnt_sb; + struct super_block *sb = dentry->d_sb; struct the_nilfs *nilfs = sb->s_fs_info; - struct nilfs_root *root = NILFS_I(vfs->mnt_root->d_inode)->i_root; + struct nilfs_root *root = NILFS_I(dentry->d_inode)->i_root; if (!nilfs_test_opt(nilfs, BARRIER)) seq_puts(seq, ",nobarrier"); diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 9fde1c00a296..3568c8a8b138 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -16,6 +16,8 @@ #include <asm/ioctls.h> +#include "../../mount.h" + #define FANOTIFY_DEFAULT_MAX_EVENTS 16384 #define FANOTIFY_DEFAULT_MAX_MARKS 8192 #define FANOTIFY_DEFAULT_MAX_LISTENERS 128 @@ -546,7 +548,7 @@ static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group, removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags); fsnotify_put_mark(fsn_mark); - if (removed & mnt->mnt_fsnotify_mask) + if (removed & real_mount(mnt)->mnt_fsnotify_mask) fsnotify_recalc_vfsmount_mask(mnt); return 0; @@ -623,7 +625,7 @@ static int fanotify_add_vfsmount_mark(struct fsnotify_group *group, } added = fanotify_mark_add_to_mask(fsn_mark, mask, flags); - if (added & ~mnt->mnt_fsnotify_mask) + if (added & ~real_mount(mnt)->mnt_fsnotify_mask) fsnotify_recalc_vfsmount_mask(mnt); err: fsnotify_put_mark(fsn_mark); diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 79b47cbb5cd8..ccb14d3fc0de 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -26,6 +26,7 @@ #include <linux/fsnotify_backend.h> #include "fsnotify.h" +#include "../mount.h" /* * Clear all of the marks on an inode when it is being evicted from core @@ -205,13 +206,13 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, struct fsnotify_mark *inode_mark = NULL, *vfsmount_mark = NULL; struct fsnotify_group *inode_group, *vfsmount_group; struct fsnotify_event *event = NULL; - struct vfsmount *mnt; + struct mount *mnt; int idx, ret = 0; /* global tests shouldn't care about events on child only the specific event */ __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD); if (data_is == FSNOTIFY_EVENT_PATH) - mnt = ((struct path *)data)->mnt; + mnt = real_mount(((struct path *)data)->mnt); else mnt = NULL; @@ -262,11 +263,11 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, /* we didn't use the vfsmount_mark */ vfsmount_group = NULL; } else if (vfsmount_group > inode_group) { - ret = send_to_group(to_tell, mnt, NULL, vfsmount_mark, mask, data, + ret = send_to_group(to_tell, &mnt->mnt, NULL, vfsmount_mark, mask, data, data_is, cookie, file_name, &event); inode_group = NULL; } else { - ret = send_to_group(to_tell, mnt, inode_mark, vfsmount_mark, + ret = send_to_group(to_tell, &mnt->mnt, inode_mark, vfsmount_mark, mask, data, data_is, cookie, file_name, &event); } diff --git a/fs/notify/vfsmount_mark.c b/fs/notify/vfsmount_mark.c index 778fe6cae3b0..b7b4b0e8554f 100644 --- a/fs/notify/vfsmount_mark.c +++ b/fs/notify/vfsmount_mark.c @@ -28,15 +28,17 @@ #include <linux/fsnotify_backend.h> #include "fsnotify.h" +#include "../mount.h" void fsnotify_clear_marks_by_mount(struct vfsmount *mnt) { struct fsnotify_mark *mark, *lmark; struct hlist_node *pos, *n; + struct mount *m = real_mount(mnt); LIST_HEAD(free_list); spin_lock(&mnt->mnt_root->d_lock); - hlist_for_each_entry_safe(mark, pos, n, &mnt->mnt_fsnotify_marks, m.m_list) { + hlist_for_each_entry_safe(mark, pos, n, &m->mnt_fsnotify_marks, m.m_list) { list_add(&mark->m.free_m_list, &free_list); hlist_del_init_rcu(&mark->m.m_list); fsnotify_get_mark(mark); @@ -59,15 +61,16 @@ void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group) */ static void fsnotify_recalc_vfsmount_mask_locked(struct vfsmount *mnt) { + struct mount *m = real_mount(mnt); struct fsnotify_mark *mark; struct hlist_node *pos; __u32 new_mask = 0; assert_spin_locked(&mnt->mnt_root->d_lock); - hlist_for_each_entry(mark, pos, &mnt->mnt_fsnotify_marks, m.m_list) + hlist_for_each_entry(mark, pos, &m->mnt_fsnotify_marks, m.m_list) new_mask |= mark->mask; - mnt->mnt_fsnotify_mask = new_mask; + m->mnt_fsnotify_mask = new_mask; } /* @@ -101,12 +104,13 @@ void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark) static struct fsnotify_mark *fsnotify_find_vfsmount_mark_locked(struct fsnotify_group *group, struct vfsmount *mnt) { + struct mount *m = real_mount(mnt); struct fsnotify_mark *mark; struct hlist_node *pos; assert_spin_locked(&mnt->mnt_root->d_lock); - hlist_for_each_entry(mark, pos, &mnt->mnt_fsnotify_marks, m.m_list) { + hlist_for_each_entry(mark, pos, &m->mnt_fsnotify_marks, m.m_list) { if (mark->group == group) { fsnotify_get_mark(mark); return mark; @@ -140,6 +144,7 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, struct fsnotify_group *group, struct vfsmount *mnt, int allow_dups) { + struct mount *m = real_mount(mnt); struct fsnotify_mark *lmark; struct hlist_node *node, *last = NULL; int ret = 0; @@ -154,13 +159,13 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, mark->m.mnt = mnt; /* is mark the first mark? */ - if (hlist_empty(&mnt->mnt_fsnotify_marks)) { - hlist_add_head_rcu(&mark->m.m_list, &mnt->mnt_fsnotify_marks); + if (hlist_empty(&m->mnt_fsnotify_marks)) { + hlist_add_head_rcu(&mark->m.m_list, &m->mnt_fsnotify_marks); goto out; } /* should mark be in the middle of the current list? */ - hlist_for_each_entry(lmark, node, &mnt->mnt_fsnotify_marks, m.m_list) { + hlist_for_each_entry(lmark, node, &m->mnt_fsnotify_marks, m.m_list) { last = node; if ((lmark->group == group) && !allow_dups) { diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 97e2dacbc867..2eaa66652944 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -335,7 +335,6 @@ struct inode *ntfs_alloc_big_inode(struct super_block *sb) static void ntfs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(ntfs_big_inode_cache, NTFS_I(inode)); } @@ -2301,16 +2300,16 @@ void ntfs_evict_big_inode(struct inode *vi) /** * ntfs_show_options - show mount options in /proc/mounts * @sf: seq_file in which to write our mount options - * @mnt: vfs mount whose mount options to display + * @root: root of the mounted tree whose mount options to display * * Called by the VFS once for each mounted ntfs volume when someone reads * /proc/mounts in order to display the NTFS specific mount options of each - * mount. The mount options of the vfs mount @mnt are written to the seq file + * mount. The mount options of fs specified by @root are written to the seq file * @sf and success is returned. */ -int ntfs_show_options(struct seq_file *sf, struct vfsmount *mnt) +int ntfs_show_options(struct seq_file *sf, struct dentry *root) { - ntfs_volume *vol = NTFS_SB(mnt->mnt_sb); + ntfs_volume *vol = NTFS_SB(root->d_sb); int i; seq_printf(sf, ",uid=%i", vol->uid); diff --git a/fs/ntfs/inode.h b/fs/ntfs/inode.h index fe8e7e928889..db29695f845c 100644 --- a/fs/ntfs/inode.h +++ b/fs/ntfs/inode.h @@ -298,7 +298,7 @@ extern void ntfs_clear_extent_inode(ntfs_inode *ni); extern int ntfs_read_inode_mount(struct inode *vi); -extern int ntfs_show_options(struct seq_file *sf, struct vfsmount *mnt); +extern int ntfs_show_options(struct seq_file *sf, struct dentry *root); #ifdef NTFS_RW diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index b52706da4645..608be4516091 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -104,7 +104,7 @@ static bool parse_options(ntfs_volume *vol, char *opt) int errors = 0, sloppy = 0; uid_t uid = (uid_t)-1; gid_t gid = (gid_t)-1; - mode_t fmask = (mode_t)-1, dmask = (mode_t)-1; + umode_t fmask = (umode_t)-1, dmask = (umode_t)-1; int mft_zone_multiplier = -1, on_errors = -1; int show_sys_files = -1, case_sensitive = -1, disable_sparse = -1; struct nls_table *nls_map = NULL, *old_nls; @@ -287,9 +287,9 @@ no_mount_options: vol->uid = uid; if (gid != (gid_t)-1) vol->gid = gid; - if (fmask != (mode_t)-1) + if (fmask != (umode_t)-1) vol->fmask = fmask; - if (dmask != (mode_t)-1) + if (dmask != (umode_t)-1) vol->dmask = dmask; if (show_sys_files != -1) { if (show_sys_files) diff --git a/fs/ntfs/volume.h b/fs/ntfs/volume.h index 406ab55dfb32..15e3ba8d521a 100644 --- a/fs/ntfs/volume.h +++ b/fs/ntfs/volume.h @@ -48,8 +48,8 @@ typedef struct { unsigned long flags; /* Miscellaneous flags, see below. */ uid_t uid; /* uid that files will be mounted as. */ gid_t gid; /* gid that files will be mounted as. */ - mode_t fmask; /* The mask for file permissions. */ - mode_t dmask; /* The mask for directory + umode_t fmask; /* The mask for file permissions. */ + umode_t dmask; /* The mask for directory permissions. */ u8 mft_zone_multiplier; /* Initial mft zone multiplier. */ u8 on_errors; /* What to do on filesystem errors. */ diff --git a/fs/ocfs2/cluster/netdebug.c b/fs/ocfs2/cluster/netdebug.c index dc45deb19e68..73ba81928bce 100644 --- a/fs/ocfs2/cluster/netdebug.c +++ b/fs/ocfs2/cluster/netdebug.c @@ -553,7 +553,7 @@ void o2net_debugfs_exit(void) int o2net_debugfs_init(void) { - mode_t mode = S_IFREG|S_IRUSR; + umode_t mode = S_IFREG|S_IRUSR; o2net_dentry = debugfs_create_dir(O2NET_DEBUG_DIR, NULL); if (o2net_dentry) diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c index b42076797049..abfac0d7ae9c 100644 --- a/fs/ocfs2/dlmfs/dlmfs.c +++ b/fs/ocfs2/dlmfs/dlmfs.c @@ -354,7 +354,6 @@ static struct inode *dlmfs_alloc_inode(struct super_block *sb) static void dlmfs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(dlmfs_inode_cache, DLMFS_I(inode)); } @@ -401,16 +400,14 @@ static struct backing_dev_info dlmfs_backing_dev_info = { static struct inode *dlmfs_get_root_inode(struct super_block *sb) { struct inode *inode = new_inode(sb); - int mode = S_IFDIR | 0755; + umode_t mode = S_IFDIR | 0755; struct dlmfs_inode_private *ip; if (inode) { ip = DLMFS_I(inode); inode->i_ino = get_next_ino(); - inode->i_mode = mode; - inode->i_uid = current_fsuid(); - inode->i_gid = current_fsgid(); + inode_init_owner(inode, NULL, mode); inode->i_mapping->backing_dev_info = &dlmfs_backing_dev_info; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; inc_nlink(inode); @@ -424,7 +421,7 @@ static struct inode *dlmfs_get_root_inode(struct super_block *sb) static struct inode *dlmfs_get_inode(struct inode *parent, struct dentry *dentry, - int mode) + umode_t mode) { struct super_block *sb = parent->i_sb; struct inode * inode = new_inode(sb); @@ -434,9 +431,7 @@ static struct inode *dlmfs_get_inode(struct inode *parent, return NULL; inode->i_ino = get_next_ino(); - inode->i_mode = mode; - inode->i_uid = current_fsuid(); - inode->i_gid = current_fsgid(); + inode_init_owner(inode, parent, mode); inode->i_mapping->backing_dev_info = &dlmfs_backing_dev_info; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; @@ -473,13 +468,6 @@ static struct inode *dlmfs_get_inode(struct inode *parent, inc_nlink(inode); break; } - - if (parent->i_mode & S_ISGID) { - inode->i_gid = parent->i_gid; - if (S_ISDIR(mode)) - inode->i_mode |= S_ISGID; - } - return inode; } @@ -489,7 +477,7 @@ static struct inode *dlmfs_get_inode(struct inode *parent, /* SMP-safe */ static int dlmfs_mkdir(struct inode * dir, struct dentry * dentry, - int mode) + umode_t mode) { int status; struct inode *inode = NULL; @@ -537,7 +525,7 @@ bail: static int dlmfs_create(struct inode *dir, struct dentry *dentry, - int mode, + umode_t mode, struct nameidata *nd) { int status = 0; diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c index 726ff265b296..a6fda3c188aa 100644 --- a/fs/ocfs2/ioctl.c +++ b/fs/ocfs2/ioctl.c @@ -906,12 +906,12 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (get_user(flags, (int __user *) arg)) return -EFAULT; - status = mnt_want_write(filp->f_path.mnt); + status = mnt_want_write_file(filp); if (status) return status; status = ocfs2_set_inode_attr(inode, flags, OCFS2_FL_MODIFIABLE); - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); return status; case OCFS2_IOC_RESVSP: case OCFS2_IOC_RESVSP64: diff --git a/fs/ocfs2/move_extents.c b/fs/ocfs2/move_extents.c index 184c76b8c293..b1e3fce72ea4 100644 --- a/fs/ocfs2/move_extents.c +++ b/fs/ocfs2/move_extents.c @@ -1059,7 +1059,7 @@ int ocfs2_ioctl_move_extents(struct file *filp, void __user *argp) struct ocfs2_move_extents range; struct ocfs2_move_extents_context *context = NULL; - status = mnt_want_write(filp->f_path.mnt); + status = mnt_want_write_file(filp); if (status) return status; @@ -1145,7 +1145,7 @@ out: kfree(context); - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); return status; } diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index a8b2bfea574e..be244692550d 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -185,7 +185,7 @@ bail: return ret; } -static struct inode *ocfs2_get_init_inode(struct inode *dir, int mode) +static struct inode *ocfs2_get_init_inode(struct inode *dir, umode_t mode) { struct inode *inode; @@ -207,7 +207,7 @@ static struct inode *ocfs2_get_init_inode(struct inode *dir, int mode) static int ocfs2_mknod(struct inode *dir, struct dentry *dentry, - int mode, + umode_t mode, dev_t dev) { int status = 0; @@ -602,7 +602,7 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb, static int ocfs2_mkdir(struct inode *dir, struct dentry *dentry, - int mode) + umode_t mode) { int ret; @@ -617,7 +617,7 @@ static int ocfs2_mkdir(struct inode *dir, static int ocfs2_create(struct inode *dir, struct dentry *dentry, - int mode, + umode_t mode, struct nameidata *nd) { int ret; diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 4994f8b0e604..604e12c4e979 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -108,7 +108,7 @@ static int ocfs2_parse_options(struct super_block *sb, char *options, int is_remount); static int ocfs2_check_set_options(struct super_block *sb, struct mount_options *options); -static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt); +static int ocfs2_show_options(struct seq_file *s, struct dentry *root); 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); @@ -569,7 +569,6 @@ static struct inode *ocfs2_alloc_inode(struct super_block *sb) static void ocfs2_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(ocfs2_inode_cachep, OCFS2_I(inode)); } @@ -1534,9 +1533,9 @@ bail: return status; } -static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt) +static int ocfs2_show_options(struct seq_file *s, struct dentry *root) { - struct ocfs2_super *osb = OCFS2_SB(mnt->mnt_sb); + struct ocfs2_super *osb = OCFS2_SB(root->d_sb); unsigned long opts = osb->s_mount_opt; unsigned int local_alloc_megs; @@ -1568,8 +1567,7 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt) if (osb->preferred_slot != OCFS2_INVALID_SLOT) seq_printf(s, ",preferred_slot=%d", osb->preferred_slot); - if (!(mnt->mnt_flags & MNT_NOATIME) && !(mnt->mnt_flags & MNT_RELATIME)) - seq_printf(s, ",atime_quantum=%u", osb->s_atime_quantum); + seq_printf(s, ",atime_quantum=%u", osb->s_atime_quantum); if (osb->osb_commit_interval) seq_printf(s, ",commit=%u", diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index aa9e8777b09a..0ba9ea1e7961 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -623,7 +623,7 @@ int ocfs2_calc_security_init(struct inode *dir, int ocfs2_calc_xattr_init(struct inode *dir, struct buffer_head *dir_bh, - int mode, + umode_t mode, struct ocfs2_security_xattr_info *si, int *want_clusters, int *xattr_credits, diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h index d63cfb72316b..e5c7f15465b4 100644 --- a/fs/ocfs2/xattr.h +++ b/fs/ocfs2/xattr.h @@ -68,7 +68,7 @@ int ocfs2_calc_security_init(struct inode *, struct ocfs2_security_xattr_info *, int *, int *, struct ocfs2_alloc_context **); int ocfs2_calc_xattr_init(struct inode *, struct buffer_head *, - int, struct ocfs2_security_xattr_info *, + umode_t, struct ocfs2_security_xattr_info *, int *, int *, int *); /* diff --git a/fs/omfs/dir.c b/fs/omfs/dir.c index 98e544274390..f00576ec320f 100644 --- a/fs/omfs/dir.c +++ b/fs/omfs/dir.c @@ -255,7 +255,7 @@ static int omfs_remove(struct inode *dir, struct dentry *dentry) return 0; } -static int omfs_add_node(struct inode *dir, struct dentry *dentry, int mode) +static int omfs_add_node(struct inode *dir, struct dentry *dentry, umode_t mode) { int err; struct inode *inode = omfs_new_inode(dir, mode); @@ -279,12 +279,12 @@ out_free_inode: return err; } -static int omfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int omfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { return omfs_add_node(dir, dentry, mode | S_IFDIR); } -static int omfs_create(struct inode *dir, struct dentry *dentry, int mode, +static int omfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { return omfs_add_node(dir, dentry, mode | S_IFREG); diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c index e043c4cb9a97..6065bb0ba207 100644 --- a/fs/omfs/inode.c +++ b/fs/omfs/inode.c @@ -28,7 +28,7 @@ struct buffer_head *omfs_bread(struct super_block *sb, sector_t block) return sb_bread(sb, clus_to_blk(sbi, block)); } -struct inode *omfs_new_inode(struct inode *dir, int mode) +struct inode *omfs_new_inode(struct inode *dir, umode_t mode) { struct inode *inode; u64 new_block; diff --git a/fs/omfs/omfs.h b/fs/omfs/omfs.h index 7d414fef501a..8941f12c6b01 100644 --- a/fs/omfs/omfs.h +++ b/fs/omfs/omfs.h @@ -60,7 +60,7 @@ extern int omfs_shrink_inode(struct inode *inode); /* inode.c */ extern struct buffer_head *omfs_bread(struct super_block *sb, sector_t block); extern struct inode *omfs_iget(struct super_block *sb, ino_t inode); -extern struct inode *omfs_new_inode(struct inode *dir, int mode); +extern struct inode *omfs_new_inode(struct inode *dir, umode_t mode); extern int omfs_reserve_block(struct super_block *sb, sector_t block); extern int omfs_find_empty_block(struct super_block *sb, int mode, ino_t *ino); extern int omfs_sync_inode(struct inode *inode); diff --git a/fs/open.c b/fs/open.c index 22c41b543f2d..77becc041149 100644 --- a/fs/open.c +++ b/fs/open.c @@ -456,7 +456,7 @@ static int chmod_common(struct path *path, umode_t mode) if (error) return error; mutex_lock(&inode->i_mutex); - error = security_path_chmod(path->dentry, path->mnt, mode); + error = security_path_chmod(path, mode); if (error) goto out_unlock; newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); @@ -468,7 +468,7 @@ out_unlock: return error; } -SYSCALL_DEFINE2(fchmod, unsigned int, fd, mode_t, mode) +SYSCALL_DEFINE2(fchmod, unsigned int, fd, umode_t, mode) { struct file * file; int err = -EBADF; @@ -482,7 +482,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, mode_t, mode) return err; } -SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, mode_t, mode) +SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, umode_t, mode) { struct path path; int error; @@ -495,7 +495,7 @@ SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, mode_t, mode) return error; } -SYSCALL_DEFINE2(chmod, const char __user *, filename, mode_t, mode) +SYSCALL_DEFINE2(chmod, const char __user *, filename, umode_t, mode) { return sys_fchmodat(AT_FDCWD, filename, mode); } @@ -608,7 +608,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group) dentry = file->f_path.dentry; audit_inode(NULL, dentry); error = chown_common(&file->f_path, user, group); - mnt_drop_write(file->f_path.mnt); + mnt_drop_write_file(file); out_fput: fput(file); out: @@ -877,7 +877,7 @@ void fd_install(unsigned int fd, struct file *file) EXPORT_SYMBOL(fd_install); -static inline int build_open_flags(int flags, int mode, struct open_flags *op) +static inline int build_open_flags(int flags, umode_t mode, struct open_flags *op) { int lookup_flags = 0; int acc_mode; @@ -948,7 +948,7 @@ static inline int build_open_flags(int flags, int mode, struct open_flags *op) * have to. But in generally you should not do this, so please move * along, nothing to see here.. */ -struct file *filp_open(const char *filename, int flags, int mode) +struct file *filp_open(const char *filename, int flags, umode_t mode) { struct open_flags op; int lookup = build_open_flags(flags, mode, &op); @@ -970,7 +970,7 @@ struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt, } EXPORT_SYMBOL(file_open_root); -long do_sys_open(int dfd, const char __user *filename, int flags, int mode) +long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) { struct open_flags op; int lookup = build_open_flags(flags, mode, &op); @@ -994,7 +994,7 @@ long do_sys_open(int dfd, const char __user *filename, int flags, int mode) return fd; } -SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode) +SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode) { long ret; @@ -1008,7 +1008,7 @@ SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode) } SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, flags, - int, mode) + umode_t, mode) { long ret; @@ -1027,7 +1027,7 @@ SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, flags, * For backward compatibility? Maybe this should be moved * into arch/i386 instead? */ -SYSCALL_DEFINE2(creat, const char __user *, pathname, int, mode) +SYSCALL_DEFINE2(creat, const char __user *, pathname, umode_t, mode) { return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode); } diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c index e4e0ff7962e2..a88c03bc749d 100644 --- a/fs/openpromfs/inode.c +++ b/fs/openpromfs/inode.c @@ -346,7 +346,6 @@ static struct inode *openprom_alloc_inode(struct super_block *sb) static void openprom_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(op_inode_cachep, OP_I(inode)); } diff --git a/fs/partitions/Kconfig b/fs/partitions/Kconfig deleted file mode 100644 index cb5f0a3f1b03..000000000000 --- a/fs/partitions/Kconfig +++ /dev/null @@ -1,251 +0,0 @@ -# -# Partition configuration -# -config PARTITION_ADVANCED - bool "Advanced partition selection" - help - Say Y here if you would like to use hard disks under Linux which - were partitioned under an operating system running on a different - architecture than your Linux system. - - Note that the answer to this question won't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about foreign partitioning schemes. - - If unsure, say N. - -config ACORN_PARTITION - bool "Acorn partition support" if PARTITION_ADVANCED - default y if ARCH_ACORN - help - Support hard disks partitioned under Acorn operating systems. - -config ACORN_PARTITION_CUMANA - bool "Cumana partition support" if PARTITION_ADVANCED - default y if ARCH_ACORN - depends on ACORN_PARTITION - help - Say Y here if you would like to use hard disks under Linux which - were partitioned using the Cumana interface on Acorn machines. - -config ACORN_PARTITION_EESOX - bool "EESOX partition support" if PARTITION_ADVANCED - default y if ARCH_ACORN - depends on ACORN_PARTITION - -config ACORN_PARTITION_ICS - bool "ICS partition support" if PARTITION_ADVANCED - default y if ARCH_ACORN - depends on ACORN_PARTITION - help - Say Y here if you would like to use hard disks under Linux which - were partitioned using the ICS interface on Acorn machines. - -config ACORN_PARTITION_ADFS - bool "Native filecore partition support" if PARTITION_ADVANCED - default y if ARCH_ACORN - depends on ACORN_PARTITION - help - The Acorn Disc Filing System is the standard file system of the - RiscOS operating system which runs on Acorn's ARM-based Risc PC - systems and the Acorn Archimedes range of machines. If you say - `Y' here, Linux will support disk partitions created under ADFS. - -config ACORN_PARTITION_POWERTEC - bool "PowerTec partition support" if PARTITION_ADVANCED - default y if ARCH_ACORN - depends on ACORN_PARTITION - help - Support reading partition tables created on Acorn machines using - the PowerTec SCSI drive. - -config ACORN_PARTITION_RISCIX - bool "RISCiX partition support" if PARTITION_ADVANCED - default y if ARCH_ACORN - depends on ACORN_PARTITION - help - Once upon a time, there was a native Unix port for the Acorn series - of machines called RISCiX. If you say 'Y' here, Linux will be able - to read disks partitioned under RISCiX. - -config OSF_PARTITION - bool "Alpha OSF partition support" if PARTITION_ADVANCED - default y if ALPHA - help - Say Y here if you would like to use hard disks under Linux which - were partitioned on an Alpha machine. - -config AMIGA_PARTITION - bool "Amiga partition table support" if PARTITION_ADVANCED - default y if (AMIGA || AFFS_FS=y) - help - Say Y here if you would like to use hard disks under Linux which - were partitioned under AmigaOS. - -config ATARI_PARTITION - bool "Atari partition table support" if PARTITION_ADVANCED - default y if ATARI - help - Say Y here if you would like to use hard disks under Linux which - were partitioned under the Atari OS. - -config IBM_PARTITION - bool "IBM disk label and partition support" - depends on PARTITION_ADVANCED && S390 - help - Say Y here if you would like to be able to read the hard disk - partition table format used by IBM DASD disks operating under CMS. - Otherwise, say N. - -config MAC_PARTITION - bool "Macintosh partition map support" if PARTITION_ADVANCED - default y if (MAC || PPC_PMAC) - help - Say Y here if you would like to use hard disks under Linux which - were partitioned on a Macintosh. - -config MSDOS_PARTITION - bool "PC BIOS (MSDOS partition tables) support" if PARTITION_ADVANCED - default y - help - Say Y here. - -config BSD_DISKLABEL - bool "BSD disklabel (FreeBSD partition tables) support" - depends on PARTITION_ADVANCED && MSDOS_PARTITION - help - FreeBSD uses its own hard disk partition scheme on your PC. It - requires only one entry in the primary partition table of your disk - and manages it similarly to DOS extended partitions, putting in its - first sector a new partition table in BSD disklabel format. Saying Y - here allows you to read these disklabels and further mount FreeBSD - partitions from within Linux if you have also said Y to "UFS - file system support", above. If you don't know what all this is - about, say N. - -config MINIX_SUBPARTITION - bool "Minix subpartition support" - depends on PARTITION_ADVANCED && MSDOS_PARTITION - help - Minix 2.0.0/2.0.2 subpartition table support for Linux. - Say Y here if you want to mount and use Minix 2.0.0/2.0.2 - subpartitions. - -config SOLARIS_X86_PARTITION - bool "Solaris (x86) partition table support" - depends on PARTITION_ADVANCED && MSDOS_PARTITION - help - Like most systems, Solaris x86 uses its own hard disk partition - table format, incompatible with all others. Saying Y here allows you - to read these partition tables and further mount Solaris x86 - partitions from within Linux if you have also said Y to "UFS - file system support", above. - -config UNIXWARE_DISKLABEL - bool "Unixware slices support" - depends on PARTITION_ADVANCED && MSDOS_PARTITION - ---help--- - Like some systems, UnixWare uses its own slice table inside a - partition (VTOC - Virtual Table of Contents). Its format is - incompatible with all other OSes. Saying Y here allows you to read - VTOC and further mount UnixWare partitions read-only from within - Linux if you have also said Y to "UFS file system support" or - "System V and Coherent file system support", above. - - This is mainly used to carry data from a UnixWare box to your - Linux box via a removable medium like magneto-optical, ZIP or - removable IDE drives. Note, however, that a good portable way to - transport files and directories between unixes (and even other - operating systems) is given by the tar program ("man tar" or - preferably "info tar"). - - If you don't know what all this is about, say N. - -config LDM_PARTITION - bool "Windows Logical Disk Manager (Dynamic Disk) support" - depends on PARTITION_ADVANCED - ---help--- - Say Y here if you would like to use hard disks under Linux which - were partitioned using Windows 2000's/XP's or Vista's Logical Disk - Manager. They are also known as "Dynamic Disks". - - Note this driver only supports Dynamic Disks with a protective MBR - label, i.e. DOS partition table. It does not support GPT labelled - Dynamic Disks yet as can be created with Vista. - - Windows 2000 introduced the concept of Dynamic Disks to get around - the limitations of the PC's partitioning scheme. The Logical Disk - Manager allows the user to repartition a disk and create spanned, - mirrored, striped or RAID volumes, all without the need for - rebooting. - - Normal partitions are now called Basic Disks under Windows 2000, XP, - and Vista. - - For a fuller description read <file:Documentation/ldm.txt>. - - If unsure, say N. - -config LDM_DEBUG - bool "Windows LDM extra logging" - depends on LDM_PARTITION - help - Say Y here if you would like LDM to log verbosely. This could be - helpful if the driver doesn't work as expected and you'd like to - report a bug. - - If unsure, say N. - -config SGI_PARTITION - bool "SGI partition support" if PARTITION_ADVANCED - default y if DEFAULT_SGI_PARTITION - help - Say Y here if you would like to be able to read the hard disk - partition table format used by SGI machines. - -config ULTRIX_PARTITION - bool "Ultrix partition table support" if PARTITION_ADVANCED - default y if MACH_DECSTATION - help - Say Y here if you would like to be able to read the hard disk - partition table format used by DEC (now Compaq) Ultrix machines. - Otherwise, say N. - -config SUN_PARTITION - bool "Sun partition tables support" if PARTITION_ADVANCED - default y if (SPARC || SUN3 || SUN3X) - ---help--- - Like most systems, SunOS uses its own hard disk partition table - format, incompatible with all others. Saying Y here allows you to - read these partition tables and further mount SunOS partitions from - within Linux if you have also said Y to "UFS file system support", - above. This is mainly used to carry data from a SPARC under SunOS to - your Linux box via a removable medium like magneto-optical or ZIP - drives; note however that a good portable way to transport files and - directories between unixes (and even other operating systems) is - given by the tar program ("man tar" or preferably "info tar"). If - you don't know what all this is about, say N. - -config KARMA_PARTITION - bool "Karma Partition support" - depends on PARTITION_ADVANCED - help - Say Y here if you would like to mount the Rio Karma MP3 player, as it - uses a proprietary partition table. - -config EFI_PARTITION - bool "EFI GUID Partition support" - depends on PARTITION_ADVANCED - select CRC32 - help - Say Y here if you would like to use hard disks under Linux which - were partitioned using EFI GPT. - -config SYSV68_PARTITION - bool "SYSV68 partition table support" if PARTITION_ADVANCED - default y if VME - help - Say Y here if you would like to be able to read the hard disk - partition table format used by Motorola Delta machines (using - sysv68). - Otherwise, say N. diff --git a/fs/partitions/Makefile b/fs/partitions/Makefile deleted file mode 100644 index 03af8eac51da..000000000000 --- a/fs/partitions/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# -# Makefile for the linux kernel. -# - -obj-$(CONFIG_BLOCK) := check.o - -obj-$(CONFIG_ACORN_PARTITION) += acorn.o -obj-$(CONFIG_AMIGA_PARTITION) += amiga.o -obj-$(CONFIG_ATARI_PARTITION) += atari.o -obj-$(CONFIG_MAC_PARTITION) += mac.o -obj-$(CONFIG_LDM_PARTITION) += ldm.o -obj-$(CONFIG_MSDOS_PARTITION) += msdos.o -obj-$(CONFIG_OSF_PARTITION) += osf.o -obj-$(CONFIG_SGI_PARTITION) += sgi.o -obj-$(CONFIG_SUN_PARTITION) += sun.o -obj-$(CONFIG_ULTRIX_PARTITION) += ultrix.o -obj-$(CONFIG_IBM_PARTITION) += ibm.o -obj-$(CONFIG_EFI_PARTITION) += efi.o -obj-$(CONFIG_KARMA_PARTITION) += karma.o -obj-$(CONFIG_SYSV68_PARTITION) += sysv68.o diff --git a/fs/partitions/acorn.c b/fs/partitions/acorn.c deleted file mode 100644 index fbeb697374d5..000000000000 --- a/fs/partitions/acorn.c +++ /dev/null @@ -1,556 +0,0 @@ -/* - * linux/fs/partitions/acorn.c - * - * Copyright (c) 1996-2000 Russell King. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Scan ADFS partitions on hard disk drives. Unfortunately, there - * isn't a standard for partitioning drives on Acorn machines, so - * every single manufacturer of SCSI and IDE cards created their own - * method. - */ -#include <linux/buffer_head.h> -#include <linux/adfs_fs.h> - -#include "check.h" -#include "acorn.h" - -/* - * Partition types. (Oh for reusability) - */ -#define PARTITION_RISCIX_MFM 1 -#define PARTITION_RISCIX_SCSI 2 -#define PARTITION_LINUX 9 - -#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \ - defined(CONFIG_ACORN_PARTITION_ADFS) -static struct adfs_discrecord * -adfs_partition(struct parsed_partitions *state, char *name, char *data, - unsigned long first_sector, int slot) -{ - struct adfs_discrecord *dr; - unsigned int nr_sects; - - if (adfs_checkbblk(data)) - return NULL; - - dr = (struct adfs_discrecord *)(data + 0x1c0); - - if (dr->disc_size == 0 && dr->disc_size_high == 0) - return NULL; - - nr_sects = (le32_to_cpu(dr->disc_size_high) << 23) | - (le32_to_cpu(dr->disc_size) >> 9); - - if (name) { - strlcat(state->pp_buf, " [", PAGE_SIZE); - strlcat(state->pp_buf, name, PAGE_SIZE); - strlcat(state->pp_buf, "]", PAGE_SIZE); - } - put_partition(state, slot, first_sector, nr_sects); - return dr; -} -#endif - -#ifdef CONFIG_ACORN_PARTITION_RISCIX - -struct riscix_part { - __le32 start; - __le32 length; - __le32 one; - char name[16]; -}; - -struct riscix_record { - __le32 magic; -#define RISCIX_MAGIC cpu_to_le32(0x4a657320) - __le32 date; - struct riscix_part part[8]; -}; - -#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \ - defined(CONFIG_ACORN_PARTITION_ADFS) -static int riscix_partition(struct parsed_partitions *state, - unsigned long first_sect, int slot, - unsigned long nr_sects) -{ - Sector sect; - struct riscix_record *rr; - - rr = read_part_sector(state, first_sect, §); - if (!rr) - return -1; - - strlcat(state->pp_buf, " [RISCiX]", PAGE_SIZE); - - - if (rr->magic == RISCIX_MAGIC) { - unsigned long size = nr_sects > 2 ? 2 : nr_sects; - int part; - - strlcat(state->pp_buf, " <", PAGE_SIZE); - - put_partition(state, slot++, first_sect, size); - for (part = 0; part < 8; part++) { - if (rr->part[part].one && - memcmp(rr->part[part].name, "All\0", 4)) { - put_partition(state, slot++, - le32_to_cpu(rr->part[part].start), - le32_to_cpu(rr->part[part].length)); - strlcat(state->pp_buf, "(", PAGE_SIZE); - strlcat(state->pp_buf, rr->part[part].name, PAGE_SIZE); - strlcat(state->pp_buf, ")", PAGE_SIZE); - } - } - - strlcat(state->pp_buf, " >\n", PAGE_SIZE); - } else { - put_partition(state, slot++, first_sect, nr_sects); - } - - put_dev_sector(sect); - return slot; -} -#endif -#endif - -#define LINUX_NATIVE_MAGIC 0xdeafa1de -#define LINUX_SWAP_MAGIC 0xdeafab1e - -struct linux_part { - __le32 magic; - __le32 start_sect; - __le32 nr_sects; -}; - -#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \ - defined(CONFIG_ACORN_PARTITION_ADFS) -static int linux_partition(struct parsed_partitions *state, - unsigned long first_sect, int slot, - unsigned long nr_sects) -{ - Sector sect; - struct linux_part *linuxp; - unsigned long size = nr_sects > 2 ? 2 : nr_sects; - - strlcat(state->pp_buf, " [Linux]", PAGE_SIZE); - - put_partition(state, slot++, first_sect, size); - - linuxp = read_part_sector(state, first_sect, §); - if (!linuxp) - return -1; - - strlcat(state->pp_buf, " <", PAGE_SIZE); - while (linuxp->magic == cpu_to_le32(LINUX_NATIVE_MAGIC) || - linuxp->magic == cpu_to_le32(LINUX_SWAP_MAGIC)) { - if (slot == state->limit) - break; - put_partition(state, slot++, first_sect + - le32_to_cpu(linuxp->start_sect), - le32_to_cpu(linuxp->nr_sects)); - linuxp ++; - } - strlcat(state->pp_buf, " >", PAGE_SIZE); - - put_dev_sector(sect); - return slot; -} -#endif - -#ifdef CONFIG_ACORN_PARTITION_CUMANA -int adfspart_check_CUMANA(struct parsed_partitions *state) -{ - unsigned long first_sector = 0; - unsigned int start_blk = 0; - Sector sect; - unsigned char *data; - char *name = "CUMANA/ADFS"; - int first = 1; - int slot = 1; - - /* - * Try Cumana style partitions - sector 6 contains ADFS boot block - * with pointer to next 'drive'. - * - * There are unknowns in this code - is the 'cylinder number' of the - * next partition relative to the start of this one - I'm assuming - * it is. - * - * Also, which ID did Cumana use? - * - * This is totally unfinished, and will require more work to get it - * going. Hence it is totally untested. - */ - do { - struct adfs_discrecord *dr; - unsigned int nr_sects; - - data = read_part_sector(state, start_blk * 2 + 6, §); - if (!data) - return -1; - - if (slot == state->limit) - break; - - dr = adfs_partition(state, name, data, first_sector, slot++); - if (!dr) - break; - - name = NULL; - - nr_sects = (data[0x1fd] + (data[0x1fe] << 8)) * - (dr->heads + (dr->lowsector & 0x40 ? 1 : 0)) * - dr->secspertrack; - - if (!nr_sects) - break; - - first = 0; - first_sector += nr_sects; - start_blk += nr_sects >> (BLOCK_SIZE_BITS - 9); - nr_sects = 0; /* hmm - should be partition size */ - - switch (data[0x1fc] & 15) { - case 0: /* No partition / ADFS? */ - break; - -#ifdef CONFIG_ACORN_PARTITION_RISCIX - case PARTITION_RISCIX_SCSI: - /* RISCiX - we don't know how to find the next one. */ - slot = riscix_partition(state, first_sector, slot, - nr_sects); - break; -#endif - - case PARTITION_LINUX: - slot = linux_partition(state, first_sector, slot, - nr_sects); - break; - } - put_dev_sector(sect); - if (slot == -1) - return -1; - } while (1); - put_dev_sector(sect); - return first ? 0 : 1; -} -#endif - -#ifdef CONFIG_ACORN_PARTITION_ADFS -/* - * Purpose: allocate ADFS partitions. - * - * Params : hd - pointer to gendisk structure to store partition info. - * dev - device number to access. - * - * Returns: -1 on error, 0 for no ADFS boot sector, 1 for ok. - * - * Alloc : hda = whole drive - * hda1 = ADFS partition on first drive. - * hda2 = non-ADFS partition. - */ -int adfspart_check_ADFS(struct parsed_partitions *state) -{ - unsigned long start_sect, nr_sects, sectscyl, heads; - Sector sect; - unsigned char *data; - struct adfs_discrecord *dr; - unsigned char id; - int slot = 1; - - data = read_part_sector(state, 6, §); - if (!data) - return -1; - - dr = adfs_partition(state, "ADFS", data, 0, slot++); - if (!dr) { - put_dev_sector(sect); - return 0; - } - - heads = dr->heads + ((dr->lowsector >> 6) & 1); - sectscyl = dr->secspertrack * heads; - start_sect = ((data[0x1fe] << 8) + data[0x1fd]) * sectscyl; - id = data[0x1fc] & 15; - put_dev_sector(sect); - - /* - * Work out start of non-adfs partition. - */ - nr_sects = (state->bdev->bd_inode->i_size >> 9) - start_sect; - - if (start_sect) { - switch (id) { -#ifdef CONFIG_ACORN_PARTITION_RISCIX - case PARTITION_RISCIX_SCSI: - case PARTITION_RISCIX_MFM: - slot = riscix_partition(state, start_sect, slot, - nr_sects); - break; -#endif - - case PARTITION_LINUX: - slot = linux_partition(state, start_sect, slot, - nr_sects); - break; - } - } - strlcat(state->pp_buf, "\n", PAGE_SIZE); - return 1; -} -#endif - -#ifdef CONFIG_ACORN_PARTITION_ICS - -struct ics_part { - __le32 start; - __le32 size; -}; - -static int adfspart_check_ICSLinux(struct parsed_partitions *state, - unsigned long block) -{ - Sector sect; - unsigned char *data = read_part_sector(state, block, §); - int result = 0; - - if (data) { - if (memcmp(data, "LinuxPart", 9) == 0) - result = 1; - put_dev_sector(sect); - } - - return result; -} - -/* - * Check for a valid ICS partition using the checksum. - */ -static inline int valid_ics_sector(const unsigned char *data) -{ - unsigned long sum; - int i; - - for (i = 0, sum = 0x50617274; i < 508; i++) - sum += data[i]; - - sum -= le32_to_cpu(*(__le32 *)(&data[508])); - - return sum == 0; -} - -/* - * Purpose: allocate ICS partitions. - * Params : hd - pointer to gendisk structure to store partition info. - * dev - device number to access. - * Returns: -1 on error, 0 for no ICS table, 1 for partitions ok. - * Alloc : hda = whole drive - * hda1 = ADFS partition 0 on first drive. - * hda2 = ADFS partition 1 on first drive. - * ..etc.. - */ -int adfspart_check_ICS(struct parsed_partitions *state) -{ - const unsigned char *data; - const struct ics_part *p; - int slot; - Sector sect; - - /* - * Try ICS style partitions - sector 0 contains partition info. - */ - data = read_part_sector(state, 0, §); - if (!data) - return -1; - - if (!valid_ics_sector(data)) { - put_dev_sector(sect); - return 0; - } - - strlcat(state->pp_buf, " [ICS]", PAGE_SIZE); - - for (slot = 1, p = (const struct ics_part *)data; p->size; p++) { - u32 start = le32_to_cpu(p->start); - s32 size = le32_to_cpu(p->size); /* yes, it's signed. */ - - if (slot == state->limit) - break; - - /* - * Negative sizes tell the RISC OS ICS driver to ignore - * this partition - in effect it says that this does not - * contain an ADFS filesystem. - */ - if (size < 0) { - size = -size; - - /* - * Our own extension - We use the first sector - * of the partition to identify what type this - * partition is. We must not make this visible - * to the filesystem. - */ - if (size > 1 && adfspart_check_ICSLinux(state, start)) { - start += 1; - size -= 1; - } - } - - if (size) - put_partition(state, slot++, start, size); - } - - put_dev_sector(sect); - strlcat(state->pp_buf, "\n", PAGE_SIZE); - return 1; -} -#endif - -#ifdef CONFIG_ACORN_PARTITION_POWERTEC -struct ptec_part { - __le32 unused1; - __le32 unused2; - __le32 start; - __le32 size; - __le32 unused5; - char type[8]; -}; - -static inline int valid_ptec_sector(const unsigned char *data) -{ - unsigned char checksum = 0x2a; - int i; - - /* - * If it looks like a PC/BIOS partition, then it - * probably isn't PowerTec. - */ - if (data[510] == 0x55 && data[511] == 0xaa) - return 0; - - for (i = 0; i < 511; i++) - checksum += data[i]; - - return checksum == data[511]; -} - -/* - * Purpose: allocate ICS partitions. - * Params : hd - pointer to gendisk structure to store partition info. - * dev - device number to access. - * Returns: -1 on error, 0 for no ICS table, 1 for partitions ok. - * Alloc : hda = whole drive - * hda1 = ADFS partition 0 on first drive. - * hda2 = ADFS partition 1 on first drive. - * ..etc.. - */ -int adfspart_check_POWERTEC(struct parsed_partitions *state) -{ - Sector sect; - const unsigned char *data; - const struct ptec_part *p; - int slot = 1; - int i; - - data = read_part_sector(state, 0, §); - if (!data) - return -1; - - if (!valid_ptec_sector(data)) { - put_dev_sector(sect); - return 0; - } - - strlcat(state->pp_buf, " [POWERTEC]", PAGE_SIZE); - - for (i = 0, p = (const struct ptec_part *)data; i < 12; i++, p++) { - u32 start = le32_to_cpu(p->start); - u32 size = le32_to_cpu(p->size); - - if (size) - put_partition(state, slot++, start, size); - } - - put_dev_sector(sect); - strlcat(state->pp_buf, "\n", PAGE_SIZE); - return 1; -} -#endif - -#ifdef CONFIG_ACORN_PARTITION_EESOX -struct eesox_part { - char magic[6]; - char name[10]; - __le32 start; - __le32 unused6; - __le32 unused7; - __le32 unused8; -}; - -/* - * Guess who created this format? - */ -static const char eesox_name[] = { - 'N', 'e', 'i', 'l', ' ', - 'C', 'r', 'i', 't', 'c', 'h', 'e', 'l', 'l', ' ', ' ' -}; - -/* - * EESOX SCSI partition format. - * - * This is a goddamned awful partition format. We don't seem to store - * the size of the partition in this table, only the start addresses. - * - * There are two possibilities where the size comes from: - * 1. The individual ADFS boot block entries that are placed on the disk. - * 2. The start address of the next entry. - */ -int adfspart_check_EESOX(struct parsed_partitions *state) -{ - Sector sect; - const unsigned char *data; - unsigned char buffer[256]; - struct eesox_part *p; - sector_t start = 0; - int i, slot = 1; - - data = read_part_sector(state, 7, §); - if (!data) - return -1; - - /* - * "Decrypt" the partition table. God knows why... - */ - for (i = 0; i < 256; i++) - buffer[i] = data[i] ^ eesox_name[i & 15]; - - put_dev_sector(sect); - - for (i = 0, p = (struct eesox_part *)buffer; i < 8; i++, p++) { - sector_t next; - - if (memcmp(p->magic, "Eesox", 6)) - break; - - next = le32_to_cpu(p->start); - if (i) - put_partition(state, slot++, start, next - start); - start = next; - } - - if (i != 0) { - sector_t size; - - size = get_capacity(state->bdev->bd_disk); - put_partition(state, slot++, start, size - start); - strlcat(state->pp_buf, "\n", PAGE_SIZE); - } - - return i ? 1 : 0; -} -#endif diff --git a/fs/partitions/acorn.h b/fs/partitions/acorn.h deleted file mode 100644 index ede828529692..000000000000 --- a/fs/partitions/acorn.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * linux/fs/partitions/acorn.h - * - * Copyright (C) 1996-2001 Russell King. - * - * I _hate_ this partitioning mess - why can't we have one defined - * format, and everyone stick to it? - */ - -int adfspart_check_CUMANA(struct parsed_partitions *state); -int adfspart_check_ADFS(struct parsed_partitions *state); -int adfspart_check_ICS(struct parsed_partitions *state); -int adfspart_check_POWERTEC(struct parsed_partitions *state); -int adfspart_check_EESOX(struct parsed_partitions *state); diff --git a/fs/partitions/amiga.c b/fs/partitions/amiga.c deleted file mode 100644 index 70cbf44a1560..000000000000 --- a/fs/partitions/amiga.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * fs/partitions/amiga.c - * - * Code extracted from drivers/block/genhd.c - * - * Copyright (C) 1991-1998 Linus Torvalds - * Re-organised Feb 1998 Russell King - */ - -#include <linux/types.h> -#include <linux/affs_hardblocks.h> - -#include "check.h" -#include "amiga.h" - -static __inline__ u32 -checksum_block(__be32 *m, int size) -{ - u32 sum = 0; - - while (size--) - sum += be32_to_cpu(*m++); - return sum; -} - -int amiga_partition(struct parsed_partitions *state) -{ - Sector sect; - unsigned char *data; - struct RigidDiskBlock *rdb; - struct PartitionBlock *pb; - int start_sect, nr_sects, blk, part, res = 0; - int blksize = 1; /* Multiplier for disk block size */ - int slot = 1; - char b[BDEVNAME_SIZE]; - - for (blk = 0; ; blk++, put_dev_sector(sect)) { - if (blk == RDB_ALLOCATION_LIMIT) - goto rdb_done; - data = read_part_sector(state, blk, §); - if (!data) { - if (warn_no_part) - printk("Dev %s: unable to read RDB block %d\n", - bdevname(state->bdev, b), blk); - res = -1; - goto rdb_done; - } - if (*(__be32 *)data != cpu_to_be32(IDNAME_RIGIDDISK)) - continue; - - rdb = (struct RigidDiskBlock *)data; - if (checksum_block((__be32 *)data, be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F) == 0) - break; - /* Try again with 0xdc..0xdf zeroed, Windows might have - * trashed it. - */ - *(__be32 *)(data+0xdc) = 0; - if (checksum_block((__be32 *)data, - be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F)==0) { - printk("Warning: Trashed word at 0xd0 in block %d " - "ignored in checksum calculation\n",blk); - break; - } - - printk("Dev %s: RDB in block %d has bad checksum\n", - bdevname(state->bdev, b), blk); - } - - /* blksize is blocks per 512 byte standard block */ - blksize = be32_to_cpu( rdb->rdb_BlockBytes ) / 512; - - { - char tmp[7 + 10 + 1 + 1]; - - /* Be more informative */ - snprintf(tmp, sizeof(tmp), " RDSK (%d)", blksize * 512); - strlcat(state->pp_buf, tmp, PAGE_SIZE); - } - blk = be32_to_cpu(rdb->rdb_PartitionList); - put_dev_sector(sect); - for (part = 1; blk>0 && part<=16; part++, put_dev_sector(sect)) { - blk *= blksize; /* Read in terms partition table understands */ - data = read_part_sector(state, blk, §); - if (!data) { - if (warn_no_part) - printk("Dev %s: unable to read partition block %d\n", - bdevname(state->bdev, b), blk); - res = -1; - goto rdb_done; - } - pb = (struct PartitionBlock *)data; - blk = be32_to_cpu(pb->pb_Next); - if (pb->pb_ID != cpu_to_be32(IDNAME_PARTITION)) - continue; - if (checksum_block((__be32 *)pb, be32_to_cpu(pb->pb_SummedLongs) & 0x7F) != 0 ) - continue; - - /* Tell Kernel about it */ - - nr_sects = (be32_to_cpu(pb->pb_Environment[10]) + 1 - - be32_to_cpu(pb->pb_Environment[9])) * - be32_to_cpu(pb->pb_Environment[3]) * - be32_to_cpu(pb->pb_Environment[5]) * - blksize; - if (!nr_sects) - continue; - start_sect = be32_to_cpu(pb->pb_Environment[9]) * - be32_to_cpu(pb->pb_Environment[3]) * - be32_to_cpu(pb->pb_Environment[5]) * - blksize; - put_partition(state,slot++,start_sect,nr_sects); - { - /* Be even more informative to aid mounting */ - char dostype[4]; - char tmp[42]; - - __be32 *dt = (__be32 *)dostype; - *dt = pb->pb_Environment[16]; - if (dostype[3] < ' ') - snprintf(tmp, sizeof(tmp), " (%c%c%c^%c)", - dostype[0], dostype[1], - dostype[2], dostype[3] + '@' ); - else - snprintf(tmp, sizeof(tmp), " (%c%c%c%c)", - dostype[0], dostype[1], - dostype[2], dostype[3]); - strlcat(state->pp_buf, tmp, PAGE_SIZE); - snprintf(tmp, sizeof(tmp), "(res %d spb %d)", - be32_to_cpu(pb->pb_Environment[6]), - be32_to_cpu(pb->pb_Environment[4])); - strlcat(state->pp_buf, tmp, PAGE_SIZE); - } - res = 1; - } - strlcat(state->pp_buf, "\n", PAGE_SIZE); - -rdb_done: - return res; -} diff --git a/fs/partitions/amiga.h b/fs/partitions/amiga.h deleted file mode 100644 index d094585cadaa..000000000000 --- a/fs/partitions/amiga.h +++ /dev/null @@ -1,6 +0,0 @@ -/* - * fs/partitions/amiga.h - */ - -int amiga_partition(struct parsed_partitions *state); - diff --git a/fs/partitions/atari.c b/fs/partitions/atari.c deleted file mode 100644 index 9875b05e80a2..000000000000 --- a/fs/partitions/atari.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * fs/partitions/atari.c - * - * Code extracted from drivers/block/genhd.c - * - * Copyright (C) 1991-1998 Linus Torvalds - * Re-organised Feb 1998 Russell King - */ - -#include <linux/ctype.h> -#include "check.h" -#include "atari.h" - -/* ++guenther: this should be settable by the user ("make config")?. - */ -#define ICD_PARTS - -/* check if a partition entry looks valid -- Atari format is assumed if at - least one of the primary entries is ok this way */ -#define VALID_PARTITION(pi,hdsiz) \ - (((pi)->flg & 1) && \ - isalnum((pi)->id[0]) && isalnum((pi)->id[1]) && isalnum((pi)->id[2]) && \ - be32_to_cpu((pi)->st) <= (hdsiz) && \ - be32_to_cpu((pi)->st) + be32_to_cpu((pi)->siz) <= (hdsiz)) - -static inline int OK_id(char *s) -{ - return memcmp (s, "GEM", 3) == 0 || memcmp (s, "BGM", 3) == 0 || - memcmp (s, "LNX", 3) == 0 || memcmp (s, "SWP", 3) == 0 || - memcmp (s, "RAW", 3) == 0 ; -} - -int atari_partition(struct parsed_partitions *state) -{ - Sector sect; - struct rootsector *rs; - struct partition_info *pi; - u32 extensect; - u32 hd_size; - int slot; -#ifdef ICD_PARTS - int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */ -#endif - - rs = read_part_sector(state, 0, §); - if (!rs) - return -1; - - /* Verify this is an Atari rootsector: */ - hd_size = state->bdev->bd_inode->i_size >> 9; - if (!VALID_PARTITION(&rs->part[0], hd_size) && - !VALID_PARTITION(&rs->part[1], hd_size) && - !VALID_PARTITION(&rs->part[2], hd_size) && - !VALID_PARTITION(&rs->part[3], hd_size)) { - /* - * if there's no valid primary partition, assume that no Atari - * format partition table (there's no reliable magic or the like - * :-() - */ - put_dev_sector(sect); - return 0; - } - - pi = &rs->part[0]; - strlcat(state->pp_buf, " AHDI", PAGE_SIZE); - for (slot = 1; pi < &rs->part[4] && slot < state->limit; slot++, pi++) { - struct rootsector *xrs; - Sector sect2; - ulong partsect; - - if ( !(pi->flg & 1) ) - continue; - /* active partition */ - if (memcmp (pi->id, "XGM", 3) != 0) { - /* we don't care about other id's */ - put_partition (state, slot, be32_to_cpu(pi->st), - be32_to_cpu(pi->siz)); - continue; - } - /* extension partition */ -#ifdef ICD_PARTS - part_fmt = 1; -#endif - strlcat(state->pp_buf, " XGM<", PAGE_SIZE); - partsect = extensect = be32_to_cpu(pi->st); - while (1) { - xrs = read_part_sector(state, partsect, §2); - if (!xrs) { - printk (" block %ld read failed\n", partsect); - put_dev_sector(sect); - return -1; - } - - /* ++roman: sanity check: bit 0 of flg field must be set */ - if (!(xrs->part[0].flg & 1)) { - printk( "\nFirst sub-partition in extended partition is not valid!\n" ); - put_dev_sector(sect2); - break; - } - - put_partition(state, slot, - partsect + be32_to_cpu(xrs->part[0].st), - be32_to_cpu(xrs->part[0].siz)); - - if (!(xrs->part[1].flg & 1)) { - /* end of linked partition list */ - put_dev_sector(sect2); - break; - } - if (memcmp( xrs->part[1].id, "XGM", 3 ) != 0) { - printk("\nID of extended partition is not XGM!\n"); - put_dev_sector(sect2); - break; - } - - partsect = be32_to_cpu(xrs->part[1].st) + extensect; - put_dev_sector(sect2); - if (++slot == state->limit) { - printk( "\nMaximum number of partitions reached!\n" ); - break; - } - } - strlcat(state->pp_buf, " >", PAGE_SIZE); - } -#ifdef ICD_PARTS - if ( part_fmt!=1 ) { /* no extended partitions -> test ICD-format */ - pi = &rs->icdpart[0]; - /* sanity check: no ICD format if first partition invalid */ - if (OK_id(pi->id)) { - strlcat(state->pp_buf, " ICD<", PAGE_SIZE); - for (; pi < &rs->icdpart[8] && slot < state->limit; slot++, pi++) { - /* accept only GEM,BGM,RAW,LNX,SWP partitions */ - if (!((pi->flg & 1) && OK_id(pi->id))) - continue; - part_fmt = 2; - put_partition (state, slot, - be32_to_cpu(pi->st), - be32_to_cpu(pi->siz)); - } - strlcat(state->pp_buf, " >", PAGE_SIZE); - } - } -#endif - put_dev_sector(sect); - - strlcat(state->pp_buf, "\n", PAGE_SIZE); - - return 1; -} diff --git a/fs/partitions/atari.h b/fs/partitions/atari.h deleted file mode 100644 index fe2d32a89f36..000000000000 --- a/fs/partitions/atari.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * fs/partitions/atari.h - * Moved by Russell King from: - * - * linux/include/linux/atari_rootsec.h - * definitions for Atari Rootsector layout - * by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de) - * - * modified for ICD/Supra partitioning scheme restricted to at most 12 - * partitions - * by Guenther Kelleter (guenther@pool.informatik.rwth-aachen.de) - */ - -struct partition_info -{ - u8 flg; /* bit 0: active; bit 7: bootable */ - char id[3]; /* "GEM", "BGM", "XGM", or other */ - __be32 st; /* start of partition */ - __be32 siz; /* length of partition */ -}; - -struct rootsector -{ - char unused[0x156]; /* room for boot code */ - struct partition_info icdpart[8]; /* info for ICD-partitions 5..12 */ - char unused2[0xc]; - u32 hd_siz; /* size of disk in blocks */ - struct partition_info part[4]; - u32 bsl_st; /* start of bad sector list */ - u32 bsl_cnt; /* length of bad sector list */ - u16 checksum; /* checksum for bootable disks */ -} __attribute__((__packed__)); - -int atari_partition(struct parsed_partitions *state); diff --git a/fs/partitions/check.c b/fs/partitions/check.c deleted file mode 100644 index e3c63d1c5e13..000000000000 --- a/fs/partitions/check.c +++ /dev/null @@ -1,687 +0,0 @@ -/* - * fs/partitions/check.c - * - * Code extracted from drivers/block/genhd.c - * Copyright (C) 1991-1998 Linus Torvalds - * Re-organised Feb 1998 Russell King - * - * We now have independent partition support from the - * block drivers, which allows all the partition code to - * be grouped in one location, and it to be mostly self - * contained. - * - * Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl} - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/slab.h> -#include <linux/kmod.h> -#include <linux/ctype.h> -#include <linux/genhd.h> -#include <linux/blktrace_api.h> - -#include "check.h" - -#include "acorn.h" -#include "amiga.h" -#include "atari.h" -#include "ldm.h" -#include "mac.h" -#include "msdos.h" -#include "osf.h" -#include "sgi.h" -#include "sun.h" -#include "ibm.h" -#include "ultrix.h" -#include "efi.h" -#include "karma.h" -#include "sysv68.h" - -#ifdef CONFIG_BLK_DEV_MD -extern void md_autodetect_dev(dev_t dev); -#endif - -int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/ - -static int (*check_part[])(struct parsed_partitions *) = { - /* - * Probe partition formats with tables at disk address 0 - * that also have an ADFS boot block at 0xdc0. - */ -#ifdef CONFIG_ACORN_PARTITION_ICS - adfspart_check_ICS, -#endif -#ifdef CONFIG_ACORN_PARTITION_POWERTEC - adfspart_check_POWERTEC, -#endif -#ifdef CONFIG_ACORN_PARTITION_EESOX - adfspart_check_EESOX, -#endif - - /* - * Now move on to formats that only have partition info at - * disk address 0xdc0. Since these may also have stale - * PC/BIOS partition tables, they need to come before - * the msdos entry. - */ -#ifdef CONFIG_ACORN_PARTITION_CUMANA - adfspart_check_CUMANA, -#endif -#ifdef CONFIG_ACORN_PARTITION_ADFS - adfspart_check_ADFS, -#endif - -#ifdef CONFIG_EFI_PARTITION - efi_partition, /* this must come before msdos */ -#endif -#ifdef CONFIG_SGI_PARTITION - sgi_partition, -#endif -#ifdef CONFIG_LDM_PARTITION - ldm_partition, /* this must come before msdos */ -#endif -#ifdef CONFIG_MSDOS_PARTITION - msdos_partition, -#endif -#ifdef CONFIG_OSF_PARTITION - osf_partition, -#endif -#ifdef CONFIG_SUN_PARTITION - sun_partition, -#endif -#ifdef CONFIG_AMIGA_PARTITION - amiga_partition, -#endif -#ifdef CONFIG_ATARI_PARTITION - atari_partition, -#endif -#ifdef CONFIG_MAC_PARTITION - mac_partition, -#endif -#ifdef CONFIG_ULTRIX_PARTITION - ultrix_partition, -#endif -#ifdef CONFIG_IBM_PARTITION - ibm_partition, -#endif -#ifdef CONFIG_KARMA_PARTITION - karma_partition, -#endif -#ifdef CONFIG_SYSV68_PARTITION - sysv68_partition, -#endif - NULL -}; - -/* - * disk_name() is used by partition check code and the genhd driver. - * It formats the devicename of the indicated disk into - * the supplied buffer (of size at least 32), and returns - * a pointer to that same buffer (for convenience). - */ - -char *disk_name(struct gendisk *hd, int partno, char *buf) -{ - if (!partno) - snprintf(buf, BDEVNAME_SIZE, "%s", hd->disk_name); - else if (isdigit(hd->disk_name[strlen(hd->disk_name)-1])) - snprintf(buf, BDEVNAME_SIZE, "%sp%d", hd->disk_name, partno); - else - snprintf(buf, BDEVNAME_SIZE, "%s%d", hd->disk_name, partno); - - return buf; -} - -const char *bdevname(struct block_device *bdev, char *buf) -{ - return disk_name(bdev->bd_disk, bdev->bd_part->partno, buf); -} - -EXPORT_SYMBOL(bdevname); - -/* - * There's very little reason to use this, you should really - * have a struct block_device just about everywhere and use - * bdevname() instead. - */ -const char *__bdevname(dev_t dev, char *buffer) -{ - scnprintf(buffer, BDEVNAME_SIZE, "unknown-block(%u,%u)", - MAJOR(dev), MINOR(dev)); - return buffer; -} - -EXPORT_SYMBOL(__bdevname); - -static struct parsed_partitions * -check_partition(struct gendisk *hd, struct block_device *bdev) -{ - struct parsed_partitions *state; - int i, res, err; - - state = kzalloc(sizeof(struct parsed_partitions), GFP_KERNEL); - if (!state) - return NULL; - state->pp_buf = (char *)__get_free_page(GFP_KERNEL); - if (!state->pp_buf) { - kfree(state); - return NULL; - } - state->pp_buf[0] = '\0'; - - state->bdev = bdev; - disk_name(hd, 0, state->name); - snprintf(state->pp_buf, PAGE_SIZE, " %s:", state->name); - if (isdigit(state->name[strlen(state->name)-1])) - sprintf(state->name, "p"); - - state->limit = disk_max_parts(hd); - i = res = err = 0; - while (!res && check_part[i]) { - memset(&state->parts, 0, sizeof(state->parts)); - res = check_part[i++](state); - if (res < 0) { - /* We have hit an I/O error which we don't report now. - * But record it, and let the others do their job. - */ - err = res; - res = 0; - } - - } - if (res > 0) { - printk(KERN_INFO "%s", state->pp_buf); - - free_page((unsigned long)state->pp_buf); - return state; - } - if (state->access_beyond_eod) - err = -ENOSPC; - if (err) - /* The partition is unrecognized. So report I/O errors if there were any */ - res = err; - if (!res) - strlcat(state->pp_buf, " unknown partition table\n", PAGE_SIZE); - else if (warn_no_part) - strlcat(state->pp_buf, " unable to read partition table\n", PAGE_SIZE); - - printk(KERN_INFO "%s", state->pp_buf); - - free_page((unsigned long)state->pp_buf); - kfree(state); - return ERR_PTR(res); -} - -static ssize_t part_partition_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct hd_struct *p = dev_to_part(dev); - - return sprintf(buf, "%d\n", p->partno); -} - -static ssize_t part_start_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct hd_struct *p = dev_to_part(dev); - - return sprintf(buf, "%llu\n",(unsigned long long)p->start_sect); -} - -ssize_t part_size_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct hd_struct *p = dev_to_part(dev); - return sprintf(buf, "%llu\n",(unsigned long long)p->nr_sects); -} - -static ssize_t part_ro_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct hd_struct *p = dev_to_part(dev); - return sprintf(buf, "%d\n", p->policy ? 1 : 0); -} - -static ssize_t part_alignment_offset_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct hd_struct *p = dev_to_part(dev); - return sprintf(buf, "%llu\n", (unsigned long long)p->alignment_offset); -} - -static ssize_t part_discard_alignment_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct hd_struct *p = dev_to_part(dev); - return sprintf(buf, "%u\n", p->discard_alignment); -} - -ssize_t part_stat_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct hd_struct *p = dev_to_part(dev); - int cpu; - - cpu = part_stat_lock(); - part_round_stats(cpu, p); - part_stat_unlock(); - return sprintf(buf, - "%8lu %8lu %8llu %8u " - "%8lu %8lu %8llu %8u " - "%8u %8u %8u" - "\n", - part_stat_read(p, ios[READ]), - part_stat_read(p, merges[READ]), - (unsigned long long)part_stat_read(p, sectors[READ]), - jiffies_to_msecs(part_stat_read(p, ticks[READ])), - part_stat_read(p, ios[WRITE]), - part_stat_read(p, merges[WRITE]), - (unsigned long long)part_stat_read(p, sectors[WRITE]), - jiffies_to_msecs(part_stat_read(p, ticks[WRITE])), - part_in_flight(p), - jiffies_to_msecs(part_stat_read(p, io_ticks)), - jiffies_to_msecs(part_stat_read(p, time_in_queue))); -} - -ssize_t part_inflight_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct hd_struct *p = dev_to_part(dev); - - return sprintf(buf, "%8u %8u\n", atomic_read(&p->in_flight[0]), - atomic_read(&p->in_flight[1])); -} - -#ifdef CONFIG_FAIL_MAKE_REQUEST -ssize_t part_fail_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct hd_struct *p = dev_to_part(dev); - - return sprintf(buf, "%d\n", p->make_it_fail); -} - -ssize_t part_fail_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct hd_struct *p = dev_to_part(dev); - int i; - - if (count > 0 && sscanf(buf, "%d", &i) > 0) - p->make_it_fail = (i == 0) ? 0 : 1; - - return count; -} -#endif - -static DEVICE_ATTR(partition, S_IRUGO, part_partition_show, NULL); -static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL); -static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL); -static DEVICE_ATTR(ro, S_IRUGO, part_ro_show, NULL); -static DEVICE_ATTR(alignment_offset, S_IRUGO, part_alignment_offset_show, NULL); -static DEVICE_ATTR(discard_alignment, S_IRUGO, part_discard_alignment_show, - NULL); -static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); -static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL); -#ifdef CONFIG_FAIL_MAKE_REQUEST -static struct device_attribute dev_attr_fail = - __ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store); -#endif - -static struct attribute *part_attrs[] = { - &dev_attr_partition.attr, - &dev_attr_start.attr, - &dev_attr_size.attr, - &dev_attr_ro.attr, - &dev_attr_alignment_offset.attr, - &dev_attr_discard_alignment.attr, - &dev_attr_stat.attr, - &dev_attr_inflight.attr, -#ifdef CONFIG_FAIL_MAKE_REQUEST - &dev_attr_fail.attr, -#endif - NULL -}; - -static struct attribute_group part_attr_group = { - .attrs = part_attrs, -}; - -static const struct attribute_group *part_attr_groups[] = { - &part_attr_group, -#ifdef CONFIG_BLK_DEV_IO_TRACE - &blk_trace_attr_group, -#endif - NULL -}; - -static void part_release(struct device *dev) -{ - struct hd_struct *p = dev_to_part(dev); - free_part_stats(p); - free_part_info(p); - kfree(p); -} - -struct device_type part_type = { - .name = "partition", - .groups = part_attr_groups, - .release = part_release, -}; - -static void delete_partition_rcu_cb(struct rcu_head *head) -{ - struct hd_struct *part = container_of(head, struct hd_struct, rcu_head); - - part->start_sect = 0; - part->nr_sects = 0; - part_stat_set_all(part, 0); - put_device(part_to_dev(part)); -} - -void __delete_partition(struct hd_struct *part) -{ - call_rcu(&part->rcu_head, delete_partition_rcu_cb); -} - -void delete_partition(struct gendisk *disk, int partno) -{ - struct disk_part_tbl *ptbl = disk->part_tbl; - struct hd_struct *part; - - if (partno >= ptbl->len) - return; - - part = ptbl->part[partno]; - if (!part) - return; - - blk_free_devt(part_devt(part)); - rcu_assign_pointer(ptbl->part[partno], NULL); - rcu_assign_pointer(ptbl->last_lookup, NULL); - kobject_put(part->holder_dir); - device_del(part_to_dev(part)); - - hd_struct_put(part); -} - -static ssize_t whole_disk_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return 0; -} -static DEVICE_ATTR(whole_disk, S_IRUSR | S_IRGRP | S_IROTH, - whole_disk_show, NULL); - -struct hd_struct *add_partition(struct gendisk *disk, int partno, - sector_t start, sector_t len, int flags, - struct partition_meta_info *info) -{ - struct hd_struct *p; - dev_t devt = MKDEV(0, 0); - struct device *ddev = disk_to_dev(disk); - struct device *pdev; - struct disk_part_tbl *ptbl; - const char *dname; - int err; - - err = disk_expand_part_tbl(disk, partno); - if (err) - return ERR_PTR(err); - ptbl = disk->part_tbl; - - if (ptbl->part[partno]) - return ERR_PTR(-EBUSY); - - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (!p) - return ERR_PTR(-EBUSY); - - if (!init_part_stats(p)) { - err = -ENOMEM; - goto out_free; - } - pdev = part_to_dev(p); - - p->start_sect = start; - p->alignment_offset = - queue_limit_alignment_offset(&disk->queue->limits, start); - p->discard_alignment = - queue_limit_discard_alignment(&disk->queue->limits, start); - p->nr_sects = len; - p->partno = partno; - p->policy = get_disk_ro(disk); - - if (info) { - struct partition_meta_info *pinfo = alloc_part_info(disk); - if (!pinfo) - goto out_free_stats; - memcpy(pinfo, info, sizeof(*info)); - p->info = pinfo; - } - - dname = dev_name(ddev); - if (isdigit(dname[strlen(dname) - 1])) - dev_set_name(pdev, "%sp%d", dname, partno); - else - dev_set_name(pdev, "%s%d", dname, partno); - - device_initialize(pdev); - pdev->class = &block_class; - pdev->type = &part_type; - pdev->parent = ddev; - - err = blk_alloc_devt(p, &devt); - if (err) - goto out_free_info; - pdev->devt = devt; - - /* delay uevent until 'holders' subdir is created */ - dev_set_uevent_suppress(pdev, 1); - err = device_add(pdev); - if (err) - goto out_put; - - err = -ENOMEM; - p->holder_dir = kobject_create_and_add("holders", &pdev->kobj); - if (!p->holder_dir) - goto out_del; - - dev_set_uevent_suppress(pdev, 0); - if (flags & ADDPART_FLAG_WHOLEDISK) { - err = device_create_file(pdev, &dev_attr_whole_disk); - if (err) - goto out_del; - } - - /* everything is up and running, commence */ - rcu_assign_pointer(ptbl->part[partno], p); - - /* suppress uevent if the disk suppresses it */ - if (!dev_get_uevent_suppress(ddev)) - kobject_uevent(&pdev->kobj, KOBJ_ADD); - - hd_ref_init(p); - return p; - -out_free_info: - free_part_info(p); -out_free_stats: - free_part_stats(p); -out_free: - kfree(p); - return ERR_PTR(err); -out_del: - kobject_put(p->holder_dir); - device_del(pdev); -out_put: - put_device(pdev); - blk_free_devt(devt); - return ERR_PTR(err); -} - -static bool disk_unlock_native_capacity(struct gendisk *disk) -{ - const struct block_device_operations *bdops = disk->fops; - - if (bdops->unlock_native_capacity && - !(disk->flags & GENHD_FL_NATIVE_CAPACITY)) { - printk(KERN_CONT "enabling native capacity\n"); - bdops->unlock_native_capacity(disk); - disk->flags |= GENHD_FL_NATIVE_CAPACITY; - return true; - } else { - printk(KERN_CONT "truncated\n"); - return false; - } -} - -int rescan_partitions(struct gendisk *disk, struct block_device *bdev) -{ - struct parsed_partitions *state = NULL; - struct disk_part_iter piter; - struct hd_struct *part; - int p, highest, res; -rescan: - if (state && !IS_ERR(state)) { - kfree(state); - state = NULL; - } - - if (bdev->bd_part_count) - return -EBUSY; - res = invalidate_partition(disk, 0); - if (res) - return res; - - disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY); - while ((part = disk_part_iter_next(&piter))) - delete_partition(disk, part->partno); - disk_part_iter_exit(&piter); - - if (disk->fops->revalidate_disk) - disk->fops->revalidate_disk(disk); - check_disk_size_change(disk, bdev); - bdev->bd_invalidated = 0; - if (!get_capacity(disk) || !(state = check_partition(disk, bdev))) - return 0; - if (IS_ERR(state)) { - /* - * I/O error reading the partition table. If any - * partition code tried to read beyond EOD, retry - * after unlocking native capacity. - */ - if (PTR_ERR(state) == -ENOSPC) { - printk(KERN_WARNING "%s: partition table beyond EOD, ", - disk->disk_name); - if (disk_unlock_native_capacity(disk)) - goto rescan; - } - return -EIO; - } - /* - * If any partition code tried to read beyond EOD, try - * unlocking native capacity even if partition table is - * successfully read as we could be missing some partitions. - */ - if (state->access_beyond_eod) { - printk(KERN_WARNING - "%s: partition table partially beyond EOD, ", - disk->disk_name); - if (disk_unlock_native_capacity(disk)) - goto rescan; - } - - /* tell userspace that the media / partition table may have changed */ - kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE); - - /* Detect the highest partition number and preallocate - * disk->part_tbl. This is an optimization and not strictly - * necessary. - */ - for (p = 1, highest = 0; p < state->limit; p++) - if (state->parts[p].size) - highest = p; - - disk_expand_part_tbl(disk, highest); - - /* add partitions */ - for (p = 1; p < state->limit; p++) { - sector_t size, from; - struct partition_meta_info *info = NULL; - - size = state->parts[p].size; - if (!size) - continue; - - from = state->parts[p].from; - if (from >= get_capacity(disk)) { - printk(KERN_WARNING - "%s: p%d start %llu is beyond EOD, ", - disk->disk_name, p, (unsigned long long) from); - if (disk_unlock_native_capacity(disk)) - goto rescan; - continue; - } - - if (from + size > get_capacity(disk)) { - printk(KERN_WARNING - "%s: p%d size %llu extends beyond EOD, ", - disk->disk_name, p, (unsigned long long) size); - - if (disk_unlock_native_capacity(disk)) { - /* free state and restart */ - goto rescan; - } else { - /* - * we can not ignore partitions of broken tables - * created by for example camera firmware, but - * we limit them to the end of the disk to avoid - * creating invalid block devices - */ - size = get_capacity(disk) - from; - } - } - - if (state->parts[p].has_info) - info = &state->parts[p].info; - part = add_partition(disk, p, from, size, - state->parts[p].flags, - &state->parts[p].info); - if (IS_ERR(part)) { - printk(KERN_ERR " %s: p%d could not be added: %ld\n", - disk->disk_name, p, -PTR_ERR(part)); - continue; - } -#ifdef CONFIG_BLK_DEV_MD - if (state->parts[p].flags & ADDPART_FLAG_RAID) - md_autodetect_dev(part_to_dev(part)->devt); -#endif - } - kfree(state); - return 0; -} - -unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p) -{ - struct address_space *mapping = bdev->bd_inode->i_mapping; - struct page *page; - - page = read_mapping_page(mapping, (pgoff_t)(n >> (PAGE_CACHE_SHIFT-9)), - NULL); - if (!IS_ERR(page)) { - if (PageError(page)) - goto fail; - p->v = page; - return (unsigned char *)page_address(page) + ((n & ((1 << (PAGE_CACHE_SHIFT - 9)) - 1)) << 9); -fail: - page_cache_release(page); - } - p->v = NULL; - return NULL; -} - -EXPORT_SYMBOL(read_dev_sector); diff --git a/fs/partitions/check.h b/fs/partitions/check.h deleted file mode 100644 index d68bf4dc3bc2..000000000000 --- a/fs/partitions/check.h +++ /dev/null @@ -1,49 +0,0 @@ -#include <linux/pagemap.h> -#include <linux/blkdev.h> -#include <linux/genhd.h> - -/* - * add_gd_partition adds a partitions details to the devices partition - * description. - */ -struct parsed_partitions { - struct block_device *bdev; - char name[BDEVNAME_SIZE]; - struct { - sector_t from; - sector_t size; - int flags; - bool has_info; - struct partition_meta_info info; - } parts[DISK_MAX_PARTS]; - int next; - int limit; - bool access_beyond_eod; - char *pp_buf; -}; - -static inline void *read_part_sector(struct parsed_partitions *state, - sector_t n, Sector *p) -{ - if (n >= get_capacity(state->bdev->bd_disk)) { - state->access_beyond_eod = true; - return NULL; - } - return read_dev_sector(state->bdev, n, p); -} - -static inline void -put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size) -{ - if (n < p->limit) { - char tmp[1 + BDEVNAME_SIZE + 10 + 1]; - - p->parts[n].from = from; - p->parts[n].size = size; - snprintf(tmp, sizeof(tmp), " %s%d", p->name, n); - strlcat(p->pp_buf, tmp, PAGE_SIZE); - } -} - -extern int warn_no_part; - diff --git a/fs/partitions/efi.c b/fs/partitions/efi.c deleted file mode 100644 index 6296b403c67a..000000000000 --- a/fs/partitions/efi.c +++ /dev/null @@ -1,675 +0,0 @@ -/************************************************************ - * EFI GUID Partition Table handling - * - * http://www.uefi.org/specs/ - * http://www.intel.com/technology/efi/ - * - * efi.[ch] by Matt Domsch <Matt_Domsch@dell.com> - * Copyright 2000,2001,2002,2004 Dell Inc. - * - * 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 - * - * - * TODO: - * - * Changelog: - * Mon Nov 09 2004 Matt Domsch <Matt_Domsch@dell.com> - * - test for valid PMBR and valid PGPT before ever reading - * AGPT, allow override with 'gpt' kernel command line option. - * - check for first/last_usable_lba outside of size of disk - * - * Tue Mar 26 2002 Matt Domsch <Matt_Domsch@dell.com> - * - Ported to 2.5.7-pre1 and 2.5.7-dj2 - * - Applied patch to avoid fault in alternate header handling - * - cleaned up find_valid_gpt - * - On-disk structure and copy in memory is *always* LE now - - * swab fields as needed - * - remove print_gpt_header() - * - only use first max_p partition entries, to keep the kernel minor number - * and partition numbers tied. - * - * Mon Feb 04 2002 Matt Domsch <Matt_Domsch@dell.com> - * - Removed __PRIPTR_PREFIX - not being used - * - * Mon Jan 14 2002 Matt Domsch <Matt_Domsch@dell.com> - * - Ported to 2.5.2-pre11 + library crc32 patch Linus applied - * - * Thu Dec 6 2001 Matt Domsch <Matt_Domsch@dell.com> - * - Added compare_gpts(). - * - moved le_efi_guid_to_cpus() back into this file. GPT is the only - * thing that keeps EFI GUIDs on disk. - * - Changed gpt structure names and members to be simpler and more Linux-like. - * - * Wed Oct 17 2001 Matt Domsch <Matt_Domsch@dell.com> - * - Removed CONFIG_DEVFS_VOLUMES_UUID code entirely per Martin Wilck - * - * Wed Oct 10 2001 Matt Domsch <Matt_Domsch@dell.com> - * - Changed function comments to DocBook style per Andreas Dilger suggestion. - * - * Mon Oct 08 2001 Matt Domsch <Matt_Domsch@dell.com> - * - Change read_lba() to use the page cache per Al Viro's work. - * - print u64s properly on all architectures - * - fixed debug_printk(), now Dprintk() - * - * Mon Oct 01 2001 Matt Domsch <Matt_Domsch@dell.com> - * - Style cleanups - * - made most functions static - * - Endianness addition - * - remove test for second alternate header, as it's not per spec, - * and is unnecessary. There's now a method to read/write the last - * sector of an odd-sized disk from user space. No tools have ever - * been released which used this code, so it's effectively dead. - * - Per Asit Mallick of Intel, added a test for a valid PMBR. - * - Added kernel command line option 'gpt' to override valid PMBR test. - * - * Wed Jun 6 2001 Martin Wilck <Martin.Wilck@Fujitsu-Siemens.com> - * - added devfs volume UUID support (/dev/volumes/uuids) for - * mounting file systems by the partition GUID. - * - * Tue Dec 5 2000 Matt Domsch <Matt_Domsch@dell.com> - * - Moved crc32() to linux/lib, added efi_crc32(). - * - * Thu Nov 30 2000 Matt Domsch <Matt_Domsch@dell.com> - * - Replaced Intel's CRC32 function with an equivalent - * non-license-restricted version. - * - * Wed Oct 25 2000 Matt Domsch <Matt_Domsch@dell.com> - * - Fixed the last_lba() call to return the proper last block - * - * Thu Oct 12 2000 Matt Domsch <Matt_Domsch@dell.com> - * - Thanks to Andries Brouwer for his debugging assistance. - * - Code works, detects all the partitions. - * - ************************************************************/ -#include <linux/crc32.h> -#include <linux/ctype.h> -#include <linux/math64.h> -#include <linux/slab.h> -#include "check.h" -#include "efi.h" - -/* This allows a kernel command line option 'gpt' to override - * the test for invalid PMBR. Not __initdata because reloading - * the partition tables happens after init too. - */ -static int force_gpt; -static int __init -force_gpt_fn(char *str) -{ - force_gpt = 1; - return 1; -} -__setup("gpt", force_gpt_fn); - - -/** - * efi_crc32() - EFI version of crc32 function - * @buf: buffer to calculate crc32 of - * @len - length of buf - * - * Description: Returns EFI-style CRC32 value for @buf - * - * This function uses the little endian Ethernet polynomial - * but seeds the function with ~0, and xor's with ~0 at the end. - * Note, the EFI Specification, v1.02, has a reference to - * Dr. Dobbs Journal, May 1994 (actually it's in May 1992). - */ -static inline u32 -efi_crc32(const void *buf, unsigned long len) -{ - return (crc32(~0L, buf, len) ^ ~0L); -} - -/** - * last_lba(): return number of last logical block of device - * @bdev: block device - * - * Description: Returns last LBA value on success, 0 on error. - * This is stored (by sd and ide-geometry) in - * the part[0] entry for this disk, and is the number of - * physical sectors available on the disk. - */ -static u64 last_lba(struct block_device *bdev) -{ - if (!bdev || !bdev->bd_inode) - return 0; - return div_u64(bdev->bd_inode->i_size, - bdev_logical_block_size(bdev)) - 1ULL; -} - -static inline int -pmbr_part_valid(struct partition *part) -{ - if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT && - le32_to_cpu(part->start_sect) == 1UL) - return 1; - return 0; -} - -/** - * is_pmbr_valid(): test Protective MBR for validity - * @mbr: pointer to a legacy mbr structure - * - * Description: Returns 1 if PMBR is valid, 0 otherwise. - * Validity depends on two things: - * 1) MSDOS signature is in the last two bytes of the MBR - * 2) One partition of type 0xEE is found - */ -static int -is_pmbr_valid(legacy_mbr *mbr) -{ - int i; - if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE) - return 0; - for (i = 0; i < 4; i++) - if (pmbr_part_valid(&mbr->partition_record[i])) - return 1; - return 0; -} - -/** - * read_lba(): Read bytes from disk, starting at given LBA - * @state - * @lba - * @buffer - * @size_t - * - * Description: Reads @count bytes from @state->bdev into @buffer. - * Returns number of bytes read on success, 0 on error. - */ -static size_t read_lba(struct parsed_partitions *state, - u64 lba, u8 *buffer, size_t count) -{ - size_t totalreadcount = 0; - struct block_device *bdev = state->bdev; - sector_t n = lba * (bdev_logical_block_size(bdev) / 512); - - if (!buffer || lba > last_lba(bdev)) - return 0; - - while (count) { - int copied = 512; - Sector sect; - unsigned char *data = read_part_sector(state, n++, §); - if (!data) - break; - if (copied > count) - copied = count; - memcpy(buffer, data, copied); - put_dev_sector(sect); - buffer += copied; - totalreadcount +=copied; - count -= copied; - } - return totalreadcount; -} - -/** - * alloc_read_gpt_entries(): reads partition entries from disk - * @state - * @gpt - GPT header - * - * Description: Returns ptes on success, NULL on error. - * Allocates space for PTEs based on information found in @gpt. - * Notes: remember to free pte when you're done! - */ -static gpt_entry *alloc_read_gpt_entries(struct parsed_partitions *state, - gpt_header *gpt) -{ - size_t count; - gpt_entry *pte; - - if (!gpt) - return NULL; - - count = le32_to_cpu(gpt->num_partition_entries) * - le32_to_cpu(gpt->sizeof_partition_entry); - if (!count) - return NULL; - pte = kzalloc(count, GFP_KERNEL); - if (!pte) - return NULL; - - if (read_lba(state, le64_to_cpu(gpt->partition_entry_lba), - (u8 *) pte, - count) < count) { - kfree(pte); - pte=NULL; - return NULL; - } - return pte; -} - -/** - * alloc_read_gpt_header(): Allocates GPT header, reads into it from disk - * @state - * @lba is the Logical Block Address of the partition table - * - * Description: returns GPT header on success, NULL on error. Allocates - * and fills a GPT header starting at @ from @state->bdev. - * Note: remember to free gpt when finished with it. - */ -static gpt_header *alloc_read_gpt_header(struct parsed_partitions *state, - u64 lba) -{ - gpt_header *gpt; - unsigned ssz = bdev_logical_block_size(state->bdev); - - gpt = kzalloc(ssz, GFP_KERNEL); - if (!gpt) - return NULL; - - if (read_lba(state, lba, (u8 *) gpt, ssz) < ssz) { - kfree(gpt); - gpt=NULL; - return NULL; - } - - return gpt; -} - -/** - * is_gpt_valid() - tests one GPT header and PTEs for validity - * @state - * @lba is the logical block address of the GPT header to test - * @gpt is a GPT header ptr, filled on return. - * @ptes is a PTEs ptr, filled on return. - * - * Description: returns 1 if valid, 0 on error. - * If valid, returns pointers to newly allocated GPT header and PTEs. - */ -static int is_gpt_valid(struct parsed_partitions *state, u64 lba, - gpt_header **gpt, gpt_entry **ptes) -{ - u32 crc, origcrc; - u64 lastlba; - - if (!ptes) - return 0; - if (!(*gpt = alloc_read_gpt_header(state, lba))) - return 0; - - /* Check the GUID Partition Table signature */ - if (le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) { - pr_debug("GUID Partition Table Header signature is wrong:" - "%lld != %lld\n", - (unsigned long long)le64_to_cpu((*gpt)->signature), - (unsigned long long)GPT_HEADER_SIGNATURE); - goto fail; - } - - /* Check the GUID Partition Table header size */ - if (le32_to_cpu((*gpt)->header_size) > - bdev_logical_block_size(state->bdev)) { - pr_debug("GUID Partition Table Header size is wrong: %u > %u\n", - le32_to_cpu((*gpt)->header_size), - bdev_logical_block_size(state->bdev)); - goto fail; - } - - /* Check the GUID Partition Table CRC */ - origcrc = le32_to_cpu((*gpt)->header_crc32); - (*gpt)->header_crc32 = 0; - crc = efi_crc32((const unsigned char *) (*gpt), le32_to_cpu((*gpt)->header_size)); - - if (crc != origcrc) { - pr_debug("GUID Partition Table Header CRC is wrong: %x != %x\n", - crc, origcrc); - goto fail; - } - (*gpt)->header_crc32 = cpu_to_le32(origcrc); - - /* Check that the my_lba entry points to the LBA that contains - * the GUID Partition Table */ - if (le64_to_cpu((*gpt)->my_lba) != lba) { - pr_debug("GPT my_lba incorrect: %lld != %lld\n", - (unsigned long long)le64_to_cpu((*gpt)->my_lba), - (unsigned long long)lba); - goto fail; - } - - /* Check the first_usable_lba and last_usable_lba are - * within the disk. - */ - lastlba = last_lba(state->bdev); - if (le64_to_cpu((*gpt)->first_usable_lba) > lastlba) { - pr_debug("GPT: first_usable_lba incorrect: %lld > %lld\n", - (unsigned long long)le64_to_cpu((*gpt)->first_usable_lba), - (unsigned long long)lastlba); - goto fail; - } - if (le64_to_cpu((*gpt)->last_usable_lba) > lastlba) { - pr_debug("GPT: last_usable_lba incorrect: %lld > %lld\n", - (unsigned long long)le64_to_cpu((*gpt)->last_usable_lba), - (unsigned long long)lastlba); - goto fail; - } - - /* Check that sizeof_partition_entry has the correct value */ - if (le32_to_cpu((*gpt)->sizeof_partition_entry) != sizeof(gpt_entry)) { - pr_debug("GUID Partitition Entry Size check failed.\n"); - goto fail; - } - - if (!(*ptes = alloc_read_gpt_entries(state, *gpt))) - goto fail; - - /* Check the GUID Partition Entry Array CRC */ - crc = efi_crc32((const unsigned char *) (*ptes), - le32_to_cpu((*gpt)->num_partition_entries) * - le32_to_cpu((*gpt)->sizeof_partition_entry)); - - if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) { - pr_debug("GUID Partitition Entry Array CRC check failed.\n"); - goto fail_ptes; - } - - /* We're done, all's well */ - return 1; - - fail_ptes: - kfree(*ptes); - *ptes = NULL; - fail: - kfree(*gpt); - *gpt = NULL; - return 0; -} - -/** - * is_pte_valid() - tests one PTE for validity - * @pte is the pte to check - * @lastlba is last lba of the disk - * - * Description: returns 1 if valid, 0 on error. - */ -static inline int -is_pte_valid(const gpt_entry *pte, const u64 lastlba) -{ - if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) || - le64_to_cpu(pte->starting_lba) > lastlba || - le64_to_cpu(pte->ending_lba) > lastlba) - return 0; - return 1; -} - -/** - * compare_gpts() - Search disk for valid GPT headers and PTEs - * @pgpt is the primary GPT header - * @agpt is the alternate GPT header - * @lastlba is the last LBA number - * Description: Returns nothing. Sanity checks pgpt and agpt fields - * and prints warnings on discrepancies. - * - */ -static void -compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba) -{ - int error_found = 0; - if (!pgpt || !agpt) - return; - if (le64_to_cpu(pgpt->my_lba) != le64_to_cpu(agpt->alternate_lba)) { - printk(KERN_WARNING - "GPT:Primary header LBA != Alt. header alternate_lba\n"); - printk(KERN_WARNING "GPT:%lld != %lld\n", - (unsigned long long)le64_to_cpu(pgpt->my_lba), - (unsigned long long)le64_to_cpu(agpt->alternate_lba)); - error_found++; - } - if (le64_to_cpu(pgpt->alternate_lba) != le64_to_cpu(agpt->my_lba)) { - printk(KERN_WARNING - "GPT:Primary header alternate_lba != Alt. header my_lba\n"); - printk(KERN_WARNING "GPT:%lld != %lld\n", - (unsigned long long)le64_to_cpu(pgpt->alternate_lba), - (unsigned long long)le64_to_cpu(agpt->my_lba)); - error_found++; - } - if (le64_to_cpu(pgpt->first_usable_lba) != - le64_to_cpu(agpt->first_usable_lba)) { - printk(KERN_WARNING "GPT:first_usable_lbas don't match.\n"); - printk(KERN_WARNING "GPT:%lld != %lld\n", - (unsigned long long)le64_to_cpu(pgpt->first_usable_lba), - (unsigned long long)le64_to_cpu(agpt->first_usable_lba)); - error_found++; - } - if (le64_to_cpu(pgpt->last_usable_lba) != - le64_to_cpu(agpt->last_usable_lba)) { - printk(KERN_WARNING "GPT:last_usable_lbas don't match.\n"); - printk(KERN_WARNING "GPT:%lld != %lld\n", - (unsigned long long)le64_to_cpu(pgpt->last_usable_lba), - (unsigned long long)le64_to_cpu(agpt->last_usable_lba)); - error_found++; - } - if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) { - printk(KERN_WARNING "GPT:disk_guids don't match.\n"); - error_found++; - } - if (le32_to_cpu(pgpt->num_partition_entries) != - le32_to_cpu(agpt->num_partition_entries)) { - printk(KERN_WARNING "GPT:num_partition_entries don't match: " - "0x%x != 0x%x\n", - le32_to_cpu(pgpt->num_partition_entries), - le32_to_cpu(agpt->num_partition_entries)); - error_found++; - } - if (le32_to_cpu(pgpt->sizeof_partition_entry) != - le32_to_cpu(agpt->sizeof_partition_entry)) { - printk(KERN_WARNING - "GPT:sizeof_partition_entry values don't match: " - "0x%x != 0x%x\n", - le32_to_cpu(pgpt->sizeof_partition_entry), - le32_to_cpu(agpt->sizeof_partition_entry)); - error_found++; - } - if (le32_to_cpu(pgpt->partition_entry_array_crc32) != - le32_to_cpu(agpt->partition_entry_array_crc32)) { - printk(KERN_WARNING - "GPT:partition_entry_array_crc32 values don't match: " - "0x%x != 0x%x\n", - le32_to_cpu(pgpt->partition_entry_array_crc32), - le32_to_cpu(agpt->partition_entry_array_crc32)); - error_found++; - } - if (le64_to_cpu(pgpt->alternate_lba) != lastlba) { - printk(KERN_WARNING - "GPT:Primary header thinks Alt. header is not at the end of the disk.\n"); - printk(KERN_WARNING "GPT:%lld != %lld\n", - (unsigned long long)le64_to_cpu(pgpt->alternate_lba), - (unsigned long long)lastlba); - error_found++; - } - - if (le64_to_cpu(agpt->my_lba) != lastlba) { - printk(KERN_WARNING - "GPT:Alternate GPT header not at the end of the disk.\n"); - printk(KERN_WARNING "GPT:%lld != %lld\n", - (unsigned long long)le64_to_cpu(agpt->my_lba), - (unsigned long long)lastlba); - error_found++; - } - - if (error_found) - printk(KERN_WARNING - "GPT: Use GNU Parted to correct GPT errors.\n"); - return; -} - -/** - * find_valid_gpt() - Search disk for valid GPT headers and PTEs - * @state - * @gpt is a GPT header ptr, filled on return. - * @ptes is a PTEs ptr, filled on return. - * Description: Returns 1 if valid, 0 on error. - * If valid, returns pointers to newly allocated GPT header and PTEs. - * Validity depends on PMBR being valid (or being overridden by the - * 'gpt' kernel command line option) and finding either the Primary - * GPT header and PTEs valid, or the Alternate GPT header and PTEs - * valid. If the Primary GPT header is not valid, the Alternate GPT header - * is not checked unless the 'gpt' kernel command line option is passed. - * This protects against devices which misreport their size, and forces - * the user to decide to use the Alternate GPT. - */ -static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt, - gpt_entry **ptes) -{ - int good_pgpt = 0, good_agpt = 0, good_pmbr = 0; - gpt_header *pgpt = NULL, *agpt = NULL; - gpt_entry *pptes = NULL, *aptes = NULL; - legacy_mbr *legacymbr; - u64 lastlba; - - if (!ptes) - return 0; - - lastlba = last_lba(state->bdev); - if (!force_gpt) { - /* This will be added to the EFI Spec. per Intel after v1.02. */ - legacymbr = kzalloc(sizeof (*legacymbr), GFP_KERNEL); - if (legacymbr) { - read_lba(state, 0, (u8 *) legacymbr, - sizeof (*legacymbr)); - good_pmbr = is_pmbr_valid(legacymbr); - kfree(legacymbr); - } - if (!good_pmbr) - goto fail; - } - - good_pgpt = is_gpt_valid(state, GPT_PRIMARY_PARTITION_TABLE_LBA, - &pgpt, &pptes); - if (good_pgpt) - good_agpt = is_gpt_valid(state, - le64_to_cpu(pgpt->alternate_lba), - &agpt, &aptes); - if (!good_agpt && force_gpt) - good_agpt = is_gpt_valid(state, lastlba, &agpt, &aptes); - - /* The obviously unsuccessful case */ - if (!good_pgpt && !good_agpt) - goto fail; - - compare_gpts(pgpt, agpt, lastlba); - - /* The good cases */ - if (good_pgpt) { - *gpt = pgpt; - *ptes = pptes; - kfree(agpt); - kfree(aptes); - if (!good_agpt) { - printk(KERN_WARNING - "Alternate GPT is invalid, " - "using primary GPT.\n"); - } - return 1; - } - else if (good_agpt) { - *gpt = agpt; - *ptes = aptes; - kfree(pgpt); - kfree(pptes); - printk(KERN_WARNING - "Primary GPT is invalid, using alternate GPT.\n"); - return 1; - } - - fail: - kfree(pgpt); - kfree(agpt); - kfree(pptes); - kfree(aptes); - *gpt = NULL; - *ptes = NULL; - return 0; -} - -/** - * efi_partition(struct parsed_partitions *state) - * @state - * - * Description: called from check.c, if the disk contains GPT - * partitions, sets up partition entries in the kernel. - * - * If the first block on the disk is a legacy MBR, - * it will get handled by msdos_partition(). - * If it's a Protective MBR, we'll handle it here. - * - * We do not create a Linux partition for GPT, but - * only for the actual data partitions. - * Returns: - * -1 if unable to read the partition table - * 0 if this isn't our partition table - * 1 if successful - * - */ -int efi_partition(struct parsed_partitions *state) -{ - gpt_header *gpt = NULL; - gpt_entry *ptes = NULL; - u32 i; - unsigned ssz = bdev_logical_block_size(state->bdev) / 512; - u8 unparsed_guid[37]; - - if (!find_valid_gpt(state, &gpt, &ptes) || !gpt || !ptes) { - kfree(gpt); - kfree(ptes); - return 0; - } - - pr_debug("GUID Partition Table is valid! Yea!\n"); - - for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) { - struct partition_meta_info *info; - unsigned label_count = 0; - unsigned label_max; - u64 start = le64_to_cpu(ptes[i].starting_lba); - u64 size = le64_to_cpu(ptes[i].ending_lba) - - le64_to_cpu(ptes[i].starting_lba) + 1ULL; - - if (!is_pte_valid(&ptes[i], last_lba(state->bdev))) - continue; - - put_partition(state, i+1, start * ssz, size * ssz); - - /* If this is a RAID volume, tell md */ - if (!efi_guidcmp(ptes[i].partition_type_guid, - PARTITION_LINUX_RAID_GUID)) - state->parts[i + 1].flags = ADDPART_FLAG_RAID; - - info = &state->parts[i + 1].info; - /* Instead of doing a manual swap to big endian, reuse the - * common ASCII hex format as the interim. - */ - efi_guid_unparse(&ptes[i].unique_partition_guid, unparsed_guid); - part_pack_uuid(unparsed_guid, info->uuid); - - /* Naively convert UTF16-LE to 7 bits. */ - label_max = min(sizeof(info->volname) - 1, - sizeof(ptes[i].partition_name)); - info->volname[label_max] = 0; - while (label_count < label_max) { - u8 c = ptes[i].partition_name[label_count] & 0xff; - if (c && !isprint(c)) - c = '!'; - info->volname[label_count] = c; - label_count++; - } - state->parts[i + 1].has_info = true; - } - kfree(ptes); - kfree(gpt); - strlcat(state->pp_buf, "\n", PAGE_SIZE); - return 1; -} diff --git a/fs/partitions/efi.h b/fs/partitions/efi.h deleted file mode 100644 index b69ab729558f..000000000000 --- a/fs/partitions/efi.h +++ /dev/null @@ -1,134 +0,0 @@ -/************************************************************ - * EFI GUID Partition Table - * Per Intel EFI Specification v1.02 - * http://developer.intel.com/technology/efi/efi.htm - * - * By Matt Domsch <Matt_Domsch@dell.com> Fri Sep 22 22:15:56 CDT 2000 - * Copyright 2000,2001 Dell Inc. - * - * 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 - * - ************************************************************/ - -#ifndef FS_PART_EFI_H_INCLUDED -#define FS_PART_EFI_H_INCLUDED - -#include <linux/types.h> -#include <linux/fs.h> -#include <linux/genhd.h> -#include <linux/kernel.h> -#include <linux/major.h> -#include <linux/string.h> -#include <linux/efi.h> - -#define MSDOS_MBR_SIGNATURE 0xaa55 -#define EFI_PMBR_OSTYPE_EFI 0xEF -#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE - -#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL -#define GPT_HEADER_REVISION_V1 0x00010000 -#define GPT_PRIMARY_PARTITION_TABLE_LBA 1 - -#define PARTITION_SYSTEM_GUID \ - EFI_GUID( 0xC12A7328, 0xF81F, 0x11d2, \ - 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B) -#define LEGACY_MBR_PARTITION_GUID \ - EFI_GUID( 0x024DEE41, 0x33E7, 0x11d3, \ - 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F) -#define PARTITION_MSFT_RESERVED_GUID \ - EFI_GUID( 0xE3C9E316, 0x0B5C, 0x4DB8, \ - 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE) -#define PARTITION_BASIC_DATA_GUID \ - EFI_GUID( 0xEBD0A0A2, 0xB9E5, 0x4433, \ - 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7) -#define PARTITION_LINUX_RAID_GUID \ - EFI_GUID( 0xa19d880f, 0x05fc, 0x4d3b, \ - 0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e) -#define PARTITION_LINUX_SWAP_GUID \ - EFI_GUID( 0x0657fd6d, 0xa4ab, 0x43c4, \ - 0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f) -#define PARTITION_LINUX_LVM_GUID \ - EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \ - 0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28) - -typedef struct _gpt_header { - __le64 signature; - __le32 revision; - __le32 header_size; - __le32 header_crc32; - __le32 reserved1; - __le64 my_lba; - __le64 alternate_lba; - __le64 first_usable_lba; - __le64 last_usable_lba; - efi_guid_t disk_guid; - __le64 partition_entry_lba; - __le32 num_partition_entries; - __le32 sizeof_partition_entry; - __le32 partition_entry_array_crc32; - - /* The rest of the logical block is reserved by UEFI and must be zero. - * EFI standard handles this by: - * - * uint8_t reserved2[ BlockSize - 92 ]; - */ -} __attribute__ ((packed)) gpt_header; - -typedef struct _gpt_entry_attributes { - u64 required_to_function:1; - u64 reserved:47; - u64 type_guid_specific:16; -} __attribute__ ((packed)) gpt_entry_attributes; - -typedef struct _gpt_entry { - efi_guid_t partition_type_guid; - efi_guid_t unique_partition_guid; - __le64 starting_lba; - __le64 ending_lba; - gpt_entry_attributes attributes; - efi_char16_t partition_name[72 / sizeof (efi_char16_t)]; -} __attribute__ ((packed)) gpt_entry; - -typedef struct _legacy_mbr { - u8 boot_code[440]; - __le32 unique_mbr_signature; - __le16 unknown; - struct partition partition_record[4]; - __le16 signature; -} __attribute__ ((packed)) legacy_mbr; - -/* Functions */ -extern int efi_partition(struct parsed_partitions *state); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * -------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 4 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -4 - * c-argdecl-indent: 4 - * c-label-offset: -4 - * c-continued-statement-offset: 4 - * c-continued-brace-offset: 0 - * indent-tabs-mode: nil - * tab-width: 8 - * End: - */ diff --git a/fs/partitions/ibm.c b/fs/partitions/ibm.c deleted file mode 100644 index d513a07f44bb..000000000000 --- a/fs/partitions/ibm.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * File...........: linux/fs/partitions/ibm.c - * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> - * Volker Sameske <sameske@de.ibm.com> - * Bugreports.to..: <Linux390@de.ibm.com> - * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 - */ - -#include <linux/buffer_head.h> -#include <linux/hdreg.h> -#include <linux/slab.h> -#include <asm/dasd.h> -#include <asm/ebcdic.h> -#include <asm/uaccess.h> -#include <asm/vtoc.h> - -#include "check.h" -#include "ibm.h" - -/* - * compute the block number from a - * cyl-cyl-head-head structure - */ -static sector_t -cchh2blk (struct vtoc_cchh *ptr, struct hd_geometry *geo) { - - sector_t cyl; - __u16 head; - - /*decode cylinder and heads for large volumes */ - cyl = ptr->hh & 0xFFF0; - cyl <<= 12; - cyl |= ptr->cc; - head = ptr->hh & 0x000F; - return cyl * geo->heads * geo->sectors + - head * geo->sectors; -} - -/* - * compute the block number from a - * cyl-cyl-head-head-block structure - */ -static sector_t -cchhb2blk (struct vtoc_cchhb *ptr, struct hd_geometry *geo) { - - sector_t cyl; - __u16 head; - - /*decode cylinder and heads for large volumes */ - cyl = ptr->hh & 0xFFF0; - cyl <<= 12; - cyl |= ptr->cc; - head = ptr->hh & 0x000F; - return cyl * geo->heads * geo->sectors + - head * geo->sectors + - ptr->b; -} - -/* - */ -int ibm_partition(struct parsed_partitions *state) -{ - struct block_device *bdev = state->bdev; - int blocksize, res; - loff_t i_size, offset, size, fmt_size; - dasd_information2_t *info; - struct hd_geometry *geo; - char type[5] = {0,}; - char name[7] = {0,}; - union label_t { - struct vtoc_volume_label_cdl vol; - struct vtoc_volume_label_ldl lnx; - struct vtoc_cms_label cms; - } *label; - unsigned char *data; - Sector sect; - sector_t labelsect; - char tmp[64]; - - res = 0; - blocksize = bdev_logical_block_size(bdev); - if (blocksize <= 0) - goto out_exit; - i_size = i_size_read(bdev->bd_inode); - if (i_size == 0) - goto out_exit; - - info = kmalloc(sizeof(dasd_information2_t), GFP_KERNEL); - if (info == NULL) - goto out_exit; - geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL); - if (geo == NULL) - goto out_nogeo; - label = kmalloc(sizeof(union label_t), GFP_KERNEL); - if (label == NULL) - goto out_nolab; - - if (ioctl_by_bdev(bdev, BIODASDINFO2, (unsigned long)info) != 0 || - ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo) != 0) - goto out_freeall; - - /* - * Special case for FBA disks: label sector does not depend on - * blocksize. - */ - if ((info->cu_type == 0x6310 && info->dev_type == 0x9336) || - (info->cu_type == 0x3880 && info->dev_type == 0x3370)) - labelsect = info->label_block; - else - labelsect = info->label_block * (blocksize >> 9); - - /* - * Get volume label, extract name and type. - */ - data = read_part_sector(state, labelsect, §); - if (data == NULL) - goto out_readerr; - - memcpy(label, data, sizeof(union label_t)); - put_dev_sector(sect); - - if ((!info->FBA_layout) && (!strcmp(info->type, "ECKD"))) { - strncpy(type, label->vol.vollbl, 4); - strncpy(name, label->vol.volid, 6); - } else { - strncpy(type, label->lnx.vollbl, 4); - strncpy(name, label->lnx.volid, 6); - } - EBCASC(type, 4); - EBCASC(name, 6); - - res = 1; - - /* - * Three different formats: LDL, CDL and unformated disk - * - * identified by info->format - * - * unformated disks we do not have to care about - */ - if (info->format == DASD_FORMAT_LDL) { - if (strncmp(type, "CMS1", 4) == 0) { - /* - * VM style CMS1 labeled disk - */ - blocksize = label->cms.block_size; - if (label->cms.disk_offset != 0) { - snprintf(tmp, sizeof(tmp), "CMS1/%8s(MDSK):", name); - strlcat(state->pp_buf, tmp, PAGE_SIZE); - /* disk is reserved minidisk */ - offset = label->cms.disk_offset; - size = (label->cms.block_count - 1) - * (blocksize >> 9); - } else { - snprintf(tmp, sizeof(tmp), "CMS1/%8s:", name); - strlcat(state->pp_buf, tmp, PAGE_SIZE); - offset = (info->label_block + 1); - size = label->cms.block_count - * (blocksize >> 9); - } - put_partition(state, 1, offset*(blocksize >> 9), - size-offset*(blocksize >> 9)); - } else { - if (strncmp(type, "LNX1", 4) == 0) { - snprintf(tmp, sizeof(tmp), "LNX1/%8s:", name); - strlcat(state->pp_buf, tmp, PAGE_SIZE); - if (label->lnx.ldl_version == 0xf2) { - fmt_size = label->lnx.formatted_blocks - * (blocksize >> 9); - } else if (!strcmp(info->type, "ECKD")) { - /* formated w/o large volume support */ - fmt_size = geo->cylinders * geo->heads - * geo->sectors * (blocksize >> 9); - } else { - /* old label and no usable disk geometry - * (e.g. DIAG) */ - fmt_size = i_size >> 9; - } - size = i_size >> 9; - if (fmt_size < size) - size = fmt_size; - offset = (info->label_block + 1); - } else { - /* unlabeled disk */ - strlcat(state->pp_buf, "(nonl)", PAGE_SIZE); - size = i_size >> 9; - offset = (info->label_block + 1); - } - put_partition(state, 1, offset*(blocksize >> 9), - size-offset*(blocksize >> 9)); - } - } else if (info->format == DASD_FORMAT_CDL) { - /* - * New style CDL formatted disk - */ - sector_t blk; - int counter; - - /* - * check if VOL1 label is available - * if not, something is wrong, skipping partition detection - */ - if (strncmp(type, "VOL1", 4) == 0) { - snprintf(tmp, sizeof(tmp), "VOL1/%8s:", name); - strlcat(state->pp_buf, tmp, PAGE_SIZE); - /* - * get block number and read then go through format1 - * labels - */ - blk = cchhb2blk(&label->vol.vtoc, geo) + 1; - counter = 0; - data = read_part_sector(state, blk * (blocksize/512), - §); - while (data != NULL) { - struct vtoc_format1_label f1; - - memcpy(&f1, data, - sizeof(struct vtoc_format1_label)); - put_dev_sector(sect); - - /* skip FMT4 / FMT5 / FMT7 labels */ - if (f1.DS1FMTID == _ascebc['4'] - || f1.DS1FMTID == _ascebc['5'] - || f1.DS1FMTID == _ascebc['7'] - || f1.DS1FMTID == _ascebc['9']) { - blk++; - data = read_part_sector(state, - blk * (blocksize/512), §); - continue; - } - - /* only FMT1 and 8 labels valid at this point */ - if (f1.DS1FMTID != _ascebc['1'] && - f1.DS1FMTID != _ascebc['8']) - break; - - /* OK, we got valid partition data */ - offset = cchh2blk(&f1.DS1EXT1.llimit, geo); - size = cchh2blk(&f1.DS1EXT1.ulimit, geo) - - offset + geo->sectors; - if (counter >= state->limit) - break; - put_partition(state, counter + 1, - offset * (blocksize >> 9), - size * (blocksize >> 9)); - counter++; - blk++; - data = read_part_sector(state, - blk * (blocksize/512), §); - } - - if (!data) - /* Are we not supposed to report this ? */ - goto out_readerr; - } else - printk(KERN_WARNING "Warning, expected Label VOL1 not " - "found, treating as CDL formated Disk"); - - } - - strlcat(state->pp_buf, "\n", PAGE_SIZE); - goto out_freeall; - - -out_readerr: - res = -1; -out_freeall: - kfree(label); -out_nolab: - kfree(geo); -out_nogeo: - kfree(info); -out_exit: - return res; -} diff --git a/fs/partitions/ibm.h b/fs/partitions/ibm.h deleted file mode 100644 index 08fb0804a812..000000000000 --- a/fs/partitions/ibm.h +++ /dev/null @@ -1 +0,0 @@ -int ibm_partition(struct parsed_partitions *); diff --git a/fs/partitions/karma.c b/fs/partitions/karma.c deleted file mode 100644 index 0ea19312706b..000000000000 --- a/fs/partitions/karma.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * fs/partitions/karma.c - * Rio Karma partition info. - * - * Copyright (C) 2006 Bob Copeland (me@bobcopeland.com) - * based on osf.c - */ - -#include "check.h" -#include "karma.h" - -int karma_partition(struct parsed_partitions *state) -{ - int i; - int slot = 1; - Sector sect; - unsigned char *data; - struct disklabel { - u8 d_reserved[270]; - struct d_partition { - __le32 p_res; - u8 p_fstype; - u8 p_res2[3]; - __le32 p_offset; - __le32 p_size; - } d_partitions[2]; - u8 d_blank[208]; - __le16 d_magic; - } __attribute__((packed)) *label; - struct d_partition *p; - - data = read_part_sector(state, 0, §); - if (!data) - return -1; - - label = (struct disklabel *)data; - if (le16_to_cpu(label->d_magic) != KARMA_LABEL_MAGIC) { - put_dev_sector(sect); - return 0; - } - - p = label->d_partitions; - for (i = 0 ; i < 2; i++, p++) { - if (slot == state->limit) - break; - - if (p->p_fstype == 0x4d && le32_to_cpu(p->p_size)) { - put_partition(state, slot, le32_to_cpu(p->p_offset), - le32_to_cpu(p->p_size)); - } - slot++; - } - strlcat(state->pp_buf, "\n", PAGE_SIZE); - put_dev_sector(sect); - return 1; -} - diff --git a/fs/partitions/karma.h b/fs/partitions/karma.h deleted file mode 100644 index c764b2e9df21..000000000000 --- a/fs/partitions/karma.h +++ /dev/null @@ -1,8 +0,0 @@ -/* - * fs/partitions/karma.h - */ - -#define KARMA_LABEL_MAGIC 0xAB56 - -int karma_partition(struct parsed_partitions *state); - diff --git a/fs/partitions/ldm.c b/fs/partitions/ldm.c deleted file mode 100644 index bd8ae788f689..000000000000 --- a/fs/partitions/ldm.c +++ /dev/null @@ -1,1570 +0,0 @@ -/** - * ldm - Support for Windows Logical Disk Manager (Dynamic Disks) - * - * Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org> - * Copyright (c) 2001-2007 Anton Altaparmakov - * Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com> - * - * Documentation is available at http://www.linux-ntfs.org/doku.php?id=downloads - * - * 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 (in the main directory of the source in the file COPYING); if - * not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307 USA - */ - -#include <linux/slab.h> -#include <linux/pagemap.h> -#include <linux/stringify.h> -#include <linux/kernel.h> -#include "ldm.h" -#include "check.h" -#include "msdos.h" - -/** - * ldm_debug/info/error/crit - Output an error message - * @f: A printf format string containing the message - * @...: Variables to substitute into @f - * - * ldm_debug() writes a DEBUG level message to the syslog but only if the - * driver was compiled with debug enabled. Otherwise, the call turns into a NOP. - */ -#ifndef CONFIG_LDM_DEBUG -#define ldm_debug(...) do {} while (0) -#else -#define ldm_debug(f, a...) _ldm_printk (KERN_DEBUG, __func__, f, ##a) -#endif - -#define ldm_crit(f, a...) _ldm_printk (KERN_CRIT, __func__, f, ##a) -#define ldm_error(f, a...) _ldm_printk (KERN_ERR, __func__, f, ##a) -#define ldm_info(f, a...) _ldm_printk (KERN_INFO, __func__, f, ##a) - -static __printf(3, 4) -void _ldm_printk(const char *level, const char *function, const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - - va_start (args, fmt); - - vaf.fmt = fmt; - vaf.va = &args; - - printk("%s%s(): %pV\n", level, function, &vaf); - - va_end(args); -} - -/** - * ldm_parse_hexbyte - Convert a ASCII hex number to a byte - * @src: Pointer to at least 2 characters to convert. - * - * Convert a two character ASCII hex string to a number. - * - * Return: 0-255 Success, the byte was parsed correctly - * -1 Error, an invalid character was supplied - */ -static int ldm_parse_hexbyte (const u8 *src) -{ - unsigned int x; /* For correct wrapping */ - int h; - - /* high part */ - x = h = hex_to_bin(src[0]); - if (h < 0) - return -1; - - /* low part */ - h = hex_to_bin(src[1]); - if (h < 0) - return -1; - - return (x << 4) + h; -} - -/** - * ldm_parse_guid - Convert GUID from ASCII to binary - * @src: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba - * @dest: Memory block to hold binary GUID (16 bytes) - * - * N.B. The GUID need not be NULL terminated. - * - * Return: 'true' @dest contains binary GUID - * 'false' @dest contents are undefined - */ -static bool ldm_parse_guid (const u8 *src, u8 *dest) -{ - static const int size[] = { 4, 2, 2, 2, 6 }; - int i, j, v; - - if (src[8] != '-' || src[13] != '-' || - src[18] != '-' || src[23] != '-') - return false; - - for (j = 0; j < 5; j++, src++) - for (i = 0; i < size[j]; i++, src+=2, *dest++ = v) - if ((v = ldm_parse_hexbyte (src)) < 0) - return false; - - return true; -} - -/** - * ldm_parse_privhead - Read the LDM Database PRIVHEAD structure - * @data: Raw database PRIVHEAD structure loaded from the device - * @ph: In-memory privhead structure in which to return parsed information - * - * This parses the LDM database PRIVHEAD structure supplied in @data and - * sets up the in-memory privhead structure @ph with the obtained information. - * - * Return: 'true' @ph contains the PRIVHEAD data - * 'false' @ph contents are undefined - */ -static bool ldm_parse_privhead(const u8 *data, struct privhead *ph) -{ - bool is_vista = false; - - BUG_ON(!data || !ph); - if (MAGIC_PRIVHEAD != get_unaligned_be64(data)) { - ldm_error("Cannot find PRIVHEAD structure. LDM database is" - " corrupt. Aborting."); - return false; - } - ph->ver_major = get_unaligned_be16(data + 0x000C); - ph->ver_minor = get_unaligned_be16(data + 0x000E); - ph->logical_disk_start = get_unaligned_be64(data + 0x011B); - ph->logical_disk_size = get_unaligned_be64(data + 0x0123); - ph->config_start = get_unaligned_be64(data + 0x012B); - ph->config_size = get_unaligned_be64(data + 0x0133); - /* Version 2.11 is Win2k/XP and version 2.12 is Vista. */ - if (ph->ver_major == 2 && ph->ver_minor == 12) - is_vista = true; - if (!is_vista && (ph->ver_major != 2 || ph->ver_minor != 11)) { - ldm_error("Expected PRIVHEAD version 2.11 or 2.12, got %d.%d." - " Aborting.", ph->ver_major, ph->ver_minor); - return false; - } - ldm_debug("PRIVHEAD version %d.%d (Windows %s).", ph->ver_major, - ph->ver_minor, is_vista ? "Vista" : "2000/XP"); - if (ph->config_size != LDM_DB_SIZE) { /* 1 MiB in sectors. */ - /* Warn the user and continue, carefully. */ - ldm_info("Database is normally %u bytes, it claims to " - "be %llu bytes.", LDM_DB_SIZE, - (unsigned long long)ph->config_size); - } - if ((ph->logical_disk_size == 0) || (ph->logical_disk_start + - ph->logical_disk_size > ph->config_start)) { - ldm_error("PRIVHEAD disk size doesn't match real disk size"); - return false; - } - if (!ldm_parse_guid(data + 0x0030, ph->disk_id)) { - ldm_error("PRIVHEAD contains an invalid GUID."); - return false; - } - ldm_debug("Parsed PRIVHEAD successfully."); - return true; -} - -/** - * ldm_parse_tocblock - Read the LDM Database TOCBLOCK structure - * @data: Raw database TOCBLOCK structure loaded from the device - * @toc: In-memory toc structure in which to return parsed information - * - * This parses the LDM Database TOCBLOCK (table of contents) structure supplied - * in @data and sets up the in-memory tocblock structure @toc with the obtained - * information. - * - * N.B. The *_start and *_size values returned in @toc are not range-checked. - * - * Return: 'true' @toc contains the TOCBLOCK data - * 'false' @toc contents are undefined - */ -static bool ldm_parse_tocblock (const u8 *data, struct tocblock *toc) -{ - BUG_ON (!data || !toc); - - if (MAGIC_TOCBLOCK != get_unaligned_be64(data)) { - ldm_crit ("Cannot find TOCBLOCK, database may be corrupt."); - return false; - } - strncpy (toc->bitmap1_name, data + 0x24, sizeof (toc->bitmap1_name)); - toc->bitmap1_name[sizeof (toc->bitmap1_name) - 1] = 0; - toc->bitmap1_start = get_unaligned_be64(data + 0x2E); - toc->bitmap1_size = get_unaligned_be64(data + 0x36); - - if (strncmp (toc->bitmap1_name, TOC_BITMAP1, - sizeof (toc->bitmap1_name)) != 0) { - ldm_crit ("TOCBLOCK's first bitmap is '%s', should be '%s'.", - TOC_BITMAP1, toc->bitmap1_name); - return false; - } - strncpy (toc->bitmap2_name, data + 0x46, sizeof (toc->bitmap2_name)); - toc->bitmap2_name[sizeof (toc->bitmap2_name) - 1] = 0; - toc->bitmap2_start = get_unaligned_be64(data + 0x50); - toc->bitmap2_size = get_unaligned_be64(data + 0x58); - if (strncmp (toc->bitmap2_name, TOC_BITMAP2, - sizeof (toc->bitmap2_name)) != 0) { - ldm_crit ("TOCBLOCK's second bitmap is '%s', should be '%s'.", - TOC_BITMAP2, toc->bitmap2_name); - return false; - } - ldm_debug ("Parsed TOCBLOCK successfully."); - return true; -} - -/** - * ldm_parse_vmdb - Read the LDM Database VMDB structure - * @data: Raw database VMDB structure loaded from the device - * @vm: In-memory vmdb structure in which to return parsed information - * - * This parses the LDM Database VMDB structure supplied in @data and sets up - * the in-memory vmdb structure @vm with the obtained information. - * - * N.B. The *_start, *_size and *_seq values will be range-checked later. - * - * Return: 'true' @vm contains VMDB info - * 'false' @vm contents are undefined - */ -static bool ldm_parse_vmdb (const u8 *data, struct vmdb *vm) -{ - BUG_ON (!data || !vm); - - if (MAGIC_VMDB != get_unaligned_be32(data)) { - ldm_crit ("Cannot find the VMDB, database may be corrupt."); - return false; - } - - vm->ver_major = get_unaligned_be16(data + 0x12); - vm->ver_minor = get_unaligned_be16(data + 0x14); - if ((vm->ver_major != 4) || (vm->ver_minor != 10)) { - ldm_error ("Expected VMDB version %d.%d, got %d.%d. " - "Aborting.", 4, 10, vm->ver_major, vm->ver_minor); - return false; - } - - vm->vblk_size = get_unaligned_be32(data + 0x08); - if (vm->vblk_size == 0) { - ldm_error ("Illegal VBLK size"); - return false; - } - - vm->vblk_offset = get_unaligned_be32(data + 0x0C); - vm->last_vblk_seq = get_unaligned_be32(data + 0x04); - - ldm_debug ("Parsed VMDB successfully."); - return true; -} - -/** - * ldm_compare_privheads - Compare two privhead objects - * @ph1: First privhead - * @ph2: Second privhead - * - * This compares the two privhead structures @ph1 and @ph2. - * - * Return: 'true' Identical - * 'false' Different - */ -static bool ldm_compare_privheads (const struct privhead *ph1, - const struct privhead *ph2) -{ - BUG_ON (!ph1 || !ph2); - - return ((ph1->ver_major == ph2->ver_major) && - (ph1->ver_minor == ph2->ver_minor) && - (ph1->logical_disk_start == ph2->logical_disk_start) && - (ph1->logical_disk_size == ph2->logical_disk_size) && - (ph1->config_start == ph2->config_start) && - (ph1->config_size == ph2->config_size) && - !memcmp (ph1->disk_id, ph2->disk_id, GUID_SIZE)); -} - -/** - * ldm_compare_tocblocks - Compare two tocblock objects - * @toc1: First toc - * @toc2: Second toc - * - * This compares the two tocblock structures @toc1 and @toc2. - * - * Return: 'true' Identical - * 'false' Different - */ -static bool ldm_compare_tocblocks (const struct tocblock *toc1, - const struct tocblock *toc2) -{ - BUG_ON (!toc1 || !toc2); - - return ((toc1->bitmap1_start == toc2->bitmap1_start) && - (toc1->bitmap1_size == toc2->bitmap1_size) && - (toc1->bitmap2_start == toc2->bitmap2_start) && - (toc1->bitmap2_size == toc2->bitmap2_size) && - !strncmp (toc1->bitmap1_name, toc2->bitmap1_name, - sizeof (toc1->bitmap1_name)) && - !strncmp (toc1->bitmap2_name, toc2->bitmap2_name, - sizeof (toc1->bitmap2_name))); -} - -/** - * ldm_validate_privheads - Compare the primary privhead with its backups - * @state: Partition check state including device holding the LDM Database - * @ph1: Memory struct to fill with ph contents - * - * Read and compare all three privheads from disk. - * - * The privheads on disk show the size and location of the main disk area and - * the configuration area (the database). The values are range-checked against - * @hd, which contains the real size of the disk. - * - * Return: 'true' Success - * 'false' Error - */ -static bool ldm_validate_privheads(struct parsed_partitions *state, - struct privhead *ph1) -{ - static const int off[3] = { OFF_PRIV1, OFF_PRIV2, OFF_PRIV3 }; - struct privhead *ph[3] = { ph1 }; - Sector sect; - u8 *data; - bool result = false; - long num_sects; - int i; - - BUG_ON (!state || !ph1); - - ph[1] = kmalloc (sizeof (*ph[1]), GFP_KERNEL); - ph[2] = kmalloc (sizeof (*ph[2]), GFP_KERNEL); - if (!ph[1] || !ph[2]) { - ldm_crit ("Out of memory."); - goto out; - } - - /* off[1 & 2] are relative to ph[0]->config_start */ - ph[0]->config_start = 0; - - /* Read and parse privheads */ - for (i = 0; i < 3; i++) { - data = read_part_sector(state, ph[0]->config_start + off[i], - §); - if (!data) { - ldm_crit ("Disk read failed."); - goto out; - } - result = ldm_parse_privhead (data, ph[i]); - put_dev_sector (sect); - if (!result) { - ldm_error ("Cannot find PRIVHEAD %d.", i+1); /* Log again */ - if (i < 2) - goto out; /* Already logged */ - else - break; /* FIXME ignore for now, 3rd PH can fail on odd-sized disks */ - } - } - - num_sects = state->bdev->bd_inode->i_size >> 9; - - if ((ph[0]->config_start > num_sects) || - ((ph[0]->config_start + ph[0]->config_size) > num_sects)) { - ldm_crit ("Database extends beyond the end of the disk."); - goto out; - } - - if ((ph[0]->logical_disk_start > ph[0]->config_start) || - ((ph[0]->logical_disk_start + ph[0]->logical_disk_size) - > ph[0]->config_start)) { - ldm_crit ("Disk and database overlap."); - goto out; - } - - if (!ldm_compare_privheads (ph[0], ph[1])) { - ldm_crit ("Primary and backup PRIVHEADs don't match."); - goto out; - } - /* FIXME ignore this for now - if (!ldm_compare_privheads (ph[0], ph[2])) { - ldm_crit ("Primary and backup PRIVHEADs don't match."); - goto out; - }*/ - ldm_debug ("Validated PRIVHEADs successfully."); - result = true; -out: - kfree (ph[1]); - kfree (ph[2]); - return result; -} - -/** - * ldm_validate_tocblocks - Validate the table of contents and its backups - * @state: Partition check state including device holding the LDM Database - * @base: Offset, into @state->bdev, of the database - * @ldb: Cache of the database structures - * - * Find and compare the four tables of contents of the LDM Database stored on - * @state->bdev and return the parsed information into @toc1. - * - * The offsets and sizes of the configs are range-checked against a privhead. - * - * Return: 'true' @toc1 contains validated TOCBLOCK info - * 'false' @toc1 contents are undefined - */ -static bool ldm_validate_tocblocks(struct parsed_partitions *state, - unsigned long base, struct ldmdb *ldb) -{ - static const int off[4] = { OFF_TOCB1, OFF_TOCB2, OFF_TOCB3, OFF_TOCB4}; - struct tocblock *tb[4]; - struct privhead *ph; - Sector sect; - u8 *data; - int i, nr_tbs; - bool result = false; - - BUG_ON(!state || !ldb); - ph = &ldb->ph; - tb[0] = &ldb->toc; - tb[1] = kmalloc(sizeof(*tb[1]) * 3, GFP_KERNEL); - if (!tb[1]) { - ldm_crit("Out of memory."); - goto err; - } - tb[2] = (struct tocblock*)((u8*)tb[1] + sizeof(*tb[1])); - tb[3] = (struct tocblock*)((u8*)tb[2] + sizeof(*tb[2])); - /* - * Try to read and parse all four TOCBLOCKs. - * - * Windows Vista LDM v2.12 does not always have all four TOCBLOCKs so - * skip any that fail as long as we get at least one valid TOCBLOCK. - */ - for (nr_tbs = i = 0; i < 4; i++) { - data = read_part_sector(state, base + off[i], §); - if (!data) { - ldm_error("Disk read failed for TOCBLOCK %d.", i); - continue; - } - if (ldm_parse_tocblock(data, tb[nr_tbs])) - nr_tbs++; - put_dev_sector(sect); - } - if (!nr_tbs) { - ldm_crit("Failed to find a valid TOCBLOCK."); - goto err; - } - /* Range check the TOCBLOCK against a privhead. */ - if (((tb[0]->bitmap1_start + tb[0]->bitmap1_size) > ph->config_size) || - ((tb[0]->bitmap2_start + tb[0]->bitmap2_size) > - ph->config_size)) { - ldm_crit("The bitmaps are out of range. Giving up."); - goto err; - } - /* Compare all loaded TOCBLOCKs. */ - for (i = 1; i < nr_tbs; i++) { - if (!ldm_compare_tocblocks(tb[0], tb[i])) { - ldm_crit("TOCBLOCKs 0 and %d do not match.", i); - goto err; - } - } - ldm_debug("Validated %d TOCBLOCKs successfully.", nr_tbs); - result = true; -err: - kfree(tb[1]); - return result; -} - -/** - * ldm_validate_vmdb - Read the VMDB and validate it - * @state: Partition check state including device holding the LDM Database - * @base: Offset, into @bdev, of the database - * @ldb: Cache of the database structures - * - * Find the vmdb of the LDM Database stored on @bdev and return the parsed - * information in @ldb. - * - * Return: 'true' @ldb contains validated VBDB info - * 'false' @ldb contents are undefined - */ -static bool ldm_validate_vmdb(struct parsed_partitions *state, - unsigned long base, struct ldmdb *ldb) -{ - Sector sect; - u8 *data; - bool result = false; - struct vmdb *vm; - struct tocblock *toc; - - BUG_ON (!state || !ldb); - - vm = &ldb->vm; - toc = &ldb->toc; - - data = read_part_sector(state, base + OFF_VMDB, §); - if (!data) { - ldm_crit ("Disk read failed."); - return false; - } - - if (!ldm_parse_vmdb (data, vm)) - goto out; /* Already logged */ - - /* Are there uncommitted transactions? */ - if (get_unaligned_be16(data + 0x10) != 0x01) { - ldm_crit ("Database is not in a consistent state. Aborting."); - goto out; - } - - if (vm->vblk_offset != 512) - ldm_info ("VBLKs start at offset 0x%04x.", vm->vblk_offset); - - /* - * The last_vblkd_seq can be before the end of the vmdb, just make sure - * it is not out of bounds. - */ - if ((vm->vblk_size * vm->last_vblk_seq) > (toc->bitmap1_size << 9)) { - ldm_crit ("VMDB exceeds allowed size specified by TOCBLOCK. " - "Database is corrupt. Aborting."); - goto out; - } - - result = true; -out: - put_dev_sector (sect); - return result; -} - - -/** - * ldm_validate_partition_table - Determine whether bdev might be a dynamic disk - * @state: Partition check state including device holding the LDM Database - * - * This function provides a weak test to decide whether the device is a dynamic - * disk or not. It looks for an MS-DOS-style partition table containing at - * least one partition of type 0x42 (formerly SFS, now used by Windows for - * dynamic disks). - * - * N.B. The only possible error can come from the read_part_sector and that is - * only likely to happen if the underlying device is strange. If that IS - * the case we should return zero to let someone else try. - * - * Return: 'true' @state->bdev is a dynamic disk - * 'false' @state->bdev is not a dynamic disk, or an error occurred - */ -static bool ldm_validate_partition_table(struct parsed_partitions *state) -{ - Sector sect; - u8 *data; - struct partition *p; - int i; - bool result = false; - - BUG_ON(!state); - - data = read_part_sector(state, 0, §); - if (!data) { - ldm_info ("Disk read failed."); - return false; - } - - if (*(__le16*) (data + 0x01FE) != cpu_to_le16 (MSDOS_LABEL_MAGIC)) - goto out; - - p = (struct partition*)(data + 0x01BE); - for (i = 0; i < 4; i++, p++) - if (SYS_IND (p) == LDM_PARTITION) { - result = true; - break; - } - - if (result) - ldm_debug ("Found W2K dynamic disk partition type."); - -out: - put_dev_sector (sect); - return result; -} - -/** - * ldm_get_disk_objid - Search a linked list of vblk's for a given Disk Id - * @ldb: Cache of the database structures - * - * The LDM Database contains a list of all partitions on all dynamic disks. - * The primary PRIVHEAD, at the beginning of the physical disk, tells us - * the GUID of this disk. This function searches for the GUID in a linked - * list of vblk's. - * - * Return: Pointer, A matching vblk was found - * NULL, No match, or an error - */ -static struct vblk * ldm_get_disk_objid (const struct ldmdb *ldb) -{ - struct list_head *item; - - BUG_ON (!ldb); - - list_for_each (item, &ldb->v_disk) { - struct vblk *v = list_entry (item, struct vblk, list); - if (!memcmp (v->vblk.disk.disk_id, ldb->ph.disk_id, GUID_SIZE)) - return v; - } - - return NULL; -} - -/** - * ldm_create_data_partitions - Create data partitions for this device - * @pp: List of the partitions parsed so far - * @ldb: Cache of the database structures - * - * The database contains ALL the partitions for ALL disk groups, so we need to - * filter out this specific disk. Using the disk's object id, we can find all - * the partitions in the database that belong to this disk. - * - * Add each partition in our database, to the parsed_partitions structure. - * - * N.B. This function creates the partitions in the order it finds partition - * objects in the linked list. - * - * Return: 'true' Partition created - * 'false' Error, probably a range checking problem - */ -static bool ldm_create_data_partitions (struct parsed_partitions *pp, - const struct ldmdb *ldb) -{ - struct list_head *item; - struct vblk *vb; - struct vblk *disk; - struct vblk_part *part; - int part_num = 1; - - BUG_ON (!pp || !ldb); - - disk = ldm_get_disk_objid (ldb); - if (!disk) { - ldm_crit ("Can't find the ID of this disk in the database."); - return false; - } - - strlcat(pp->pp_buf, " [LDM]", PAGE_SIZE); - - /* Create the data partitions */ - list_for_each (item, &ldb->v_part) { - vb = list_entry (item, struct vblk, list); - part = &vb->vblk.part; - - if (part->disk_id != disk->obj_id) - continue; - - put_partition (pp, part_num, ldb->ph.logical_disk_start + - part->start, part->size); - part_num++; - } - - strlcat(pp->pp_buf, "\n", PAGE_SIZE); - return true; -} - - -/** - * ldm_relative - Calculate the next relative offset - * @buffer: Block of data being worked on - * @buflen: Size of the block of data - * @base: Size of the previous fixed width fields - * @offset: Cumulative size of the previous variable-width fields - * - * Because many of the VBLK fields are variable-width, it's necessary - * to calculate each offset based on the previous one and the length - * of the field it pointed to. - * - * Return: -1 Error, the calculated offset exceeded the size of the buffer - * n OK, a range-checked offset into buffer - */ -static int ldm_relative(const u8 *buffer, int buflen, int base, int offset) -{ - - base += offset; - if (!buffer || offset < 0 || base > buflen) { - if (!buffer) - ldm_error("!buffer"); - if (offset < 0) - ldm_error("offset (%d) < 0", offset); - if (base > buflen) - ldm_error("base (%d) > buflen (%d)", base, buflen); - return -1; - } - if (base + buffer[base] >= buflen) { - ldm_error("base (%d) + buffer[base] (%d) >= buflen (%d)", base, - buffer[base], buflen); - return -1; - } - return buffer[base] + offset + 1; -} - -/** - * ldm_get_vnum - Convert a variable-width, big endian number, into cpu order - * @block: Pointer to the variable-width number to convert - * - * Large numbers in the LDM Database are often stored in a packed format. Each - * number is prefixed by a one byte width marker. All numbers in the database - * are stored in big-endian byte order. This function reads one of these - * numbers and returns the result - * - * N.B. This function DOES NOT perform any range checking, though the most - * it will read is eight bytes. - * - * Return: n A number - * 0 Zero, or an error occurred - */ -static u64 ldm_get_vnum (const u8 *block) -{ - u64 tmp = 0; - u8 length; - - BUG_ON (!block); - - length = *block++; - - if (length && length <= 8) - while (length--) - tmp = (tmp << 8) | *block++; - else - ldm_error ("Illegal length %d.", length); - - return tmp; -} - -/** - * ldm_get_vstr - Read a length-prefixed string into a buffer - * @block: Pointer to the length marker - * @buffer: Location to copy string to - * @buflen: Size of the output buffer - * - * Many of the strings in the LDM Database are not NULL terminated. Instead - * they are prefixed by a one byte length marker. This function copies one of - * these strings into a buffer. - * - * N.B. This function DOES NOT perform any range checking on the input. - * If the buffer is too small, the output will be truncated. - * - * Return: 0, Error and @buffer contents are undefined - * n, String length in characters (excluding NULL) - * buflen-1, String was truncated. - */ -static int ldm_get_vstr (const u8 *block, u8 *buffer, int buflen) -{ - int length; - - BUG_ON (!block || !buffer); - - length = block[0]; - if (length >= buflen) { - ldm_error ("Truncating string %d -> %d.", length, buflen); - length = buflen - 1; - } - memcpy (buffer, block + 1, length); - buffer[length] = 0; - return length; -} - - -/** - * ldm_parse_cmp3 - Read a raw VBLK Component object into a vblk structure - * @buffer: Block of data being worked on - * @buflen: Size of the block of data - * @vb: In-memory vblk in which to return information - * - * Read a raw VBLK Component object (version 3) into a vblk structure. - * - * Return: 'true' @vb contains a Component VBLK - * 'false' @vb contents are not defined - */ -static bool ldm_parse_cmp3 (const u8 *buffer, int buflen, struct vblk *vb) -{ - int r_objid, r_name, r_vstate, r_child, r_parent, r_stripe, r_cols, len; - struct vblk_comp *comp; - - BUG_ON (!buffer || !vb); - - r_objid = ldm_relative (buffer, buflen, 0x18, 0); - r_name = ldm_relative (buffer, buflen, 0x18, r_objid); - r_vstate = ldm_relative (buffer, buflen, 0x18, r_name); - r_child = ldm_relative (buffer, buflen, 0x1D, r_vstate); - r_parent = ldm_relative (buffer, buflen, 0x2D, r_child); - - if (buffer[0x12] & VBLK_FLAG_COMP_STRIPE) { - r_stripe = ldm_relative (buffer, buflen, 0x2E, r_parent); - r_cols = ldm_relative (buffer, buflen, 0x2E, r_stripe); - len = r_cols; - } else { - r_stripe = 0; - r_cols = 0; - len = r_parent; - } - if (len < 0) - return false; - - len += VBLK_SIZE_CMP3; - if (len != get_unaligned_be32(buffer + 0x14)) - return false; - - comp = &vb->vblk.comp; - ldm_get_vstr (buffer + 0x18 + r_name, comp->state, - sizeof (comp->state)); - comp->type = buffer[0x18 + r_vstate]; - comp->children = ldm_get_vnum (buffer + 0x1D + r_vstate); - comp->parent_id = ldm_get_vnum (buffer + 0x2D + r_child); - comp->chunksize = r_stripe ? ldm_get_vnum (buffer+r_parent+0x2E) : 0; - - return true; -} - -/** - * ldm_parse_dgr3 - Read a raw VBLK Disk Group object into a vblk structure - * @buffer: Block of data being worked on - * @buflen: Size of the block of data - * @vb: In-memory vblk in which to return information - * - * Read a raw VBLK Disk Group object (version 3) into a vblk structure. - * - * Return: 'true' @vb contains a Disk Group VBLK - * 'false' @vb contents are not defined - */ -static int ldm_parse_dgr3 (const u8 *buffer, int buflen, struct vblk *vb) -{ - int r_objid, r_name, r_diskid, r_id1, r_id2, len; - struct vblk_dgrp *dgrp; - - BUG_ON (!buffer || !vb); - - r_objid = ldm_relative (buffer, buflen, 0x18, 0); - r_name = ldm_relative (buffer, buflen, 0x18, r_objid); - r_diskid = ldm_relative (buffer, buflen, 0x18, r_name); - - if (buffer[0x12] & VBLK_FLAG_DGR3_IDS) { - r_id1 = ldm_relative (buffer, buflen, 0x24, r_diskid); - r_id2 = ldm_relative (buffer, buflen, 0x24, r_id1); - len = r_id2; - } else { - r_id1 = 0; - r_id2 = 0; - len = r_diskid; - } - if (len < 0) - return false; - - len += VBLK_SIZE_DGR3; - if (len != get_unaligned_be32(buffer + 0x14)) - return false; - - dgrp = &vb->vblk.dgrp; - ldm_get_vstr (buffer + 0x18 + r_name, dgrp->disk_id, - sizeof (dgrp->disk_id)); - return true; -} - -/** - * ldm_parse_dgr4 - Read a raw VBLK Disk Group object into a vblk structure - * @buffer: Block of data being worked on - * @buflen: Size of the block of data - * @vb: In-memory vblk in which to return information - * - * Read a raw VBLK Disk Group object (version 4) into a vblk structure. - * - * Return: 'true' @vb contains a Disk Group VBLK - * 'false' @vb contents are not defined - */ -static bool ldm_parse_dgr4 (const u8 *buffer, int buflen, struct vblk *vb) -{ - char buf[64]; - int r_objid, r_name, r_id1, r_id2, len; - struct vblk_dgrp *dgrp; - - BUG_ON (!buffer || !vb); - - r_objid = ldm_relative (buffer, buflen, 0x18, 0); - r_name = ldm_relative (buffer, buflen, 0x18, r_objid); - - if (buffer[0x12] & VBLK_FLAG_DGR4_IDS) { - r_id1 = ldm_relative (buffer, buflen, 0x44, r_name); - r_id2 = ldm_relative (buffer, buflen, 0x44, r_id1); - len = r_id2; - } else { - r_id1 = 0; - r_id2 = 0; - len = r_name; - } - if (len < 0) - return false; - - len += VBLK_SIZE_DGR4; - if (len != get_unaligned_be32(buffer + 0x14)) - return false; - - dgrp = &vb->vblk.dgrp; - - ldm_get_vstr (buffer + 0x18 + r_objid, buf, sizeof (buf)); - return true; -} - -/** - * ldm_parse_dsk3 - Read a raw VBLK Disk object into a vblk structure - * @buffer: Block of data being worked on - * @buflen: Size of the block of data - * @vb: In-memory vblk in which to return information - * - * Read a raw VBLK Disk object (version 3) into a vblk structure. - * - * Return: 'true' @vb contains a Disk VBLK - * 'false' @vb contents are not defined - */ -static bool ldm_parse_dsk3 (const u8 *buffer, int buflen, struct vblk *vb) -{ - int r_objid, r_name, r_diskid, r_altname, len; - struct vblk_disk *disk; - - BUG_ON (!buffer || !vb); - - r_objid = ldm_relative (buffer, buflen, 0x18, 0); - r_name = ldm_relative (buffer, buflen, 0x18, r_objid); - r_diskid = ldm_relative (buffer, buflen, 0x18, r_name); - r_altname = ldm_relative (buffer, buflen, 0x18, r_diskid); - len = r_altname; - if (len < 0) - return false; - - len += VBLK_SIZE_DSK3; - if (len != get_unaligned_be32(buffer + 0x14)) - return false; - - disk = &vb->vblk.disk; - ldm_get_vstr (buffer + 0x18 + r_diskid, disk->alt_name, - sizeof (disk->alt_name)); - if (!ldm_parse_guid (buffer + 0x19 + r_name, disk->disk_id)) - return false; - - return true; -} - -/** - * ldm_parse_dsk4 - Read a raw VBLK Disk object into a vblk structure - * @buffer: Block of data being worked on - * @buflen: Size of the block of data - * @vb: In-memory vblk in which to return information - * - * Read a raw VBLK Disk object (version 4) into a vblk structure. - * - * Return: 'true' @vb contains a Disk VBLK - * 'false' @vb contents are not defined - */ -static bool ldm_parse_dsk4 (const u8 *buffer, int buflen, struct vblk *vb) -{ - int r_objid, r_name, len; - struct vblk_disk *disk; - - BUG_ON (!buffer || !vb); - - r_objid = ldm_relative (buffer, buflen, 0x18, 0); - r_name = ldm_relative (buffer, buflen, 0x18, r_objid); - len = r_name; - if (len < 0) - return false; - - len += VBLK_SIZE_DSK4; - if (len != get_unaligned_be32(buffer + 0x14)) - return false; - - disk = &vb->vblk.disk; - memcpy (disk->disk_id, buffer + 0x18 + r_name, GUID_SIZE); - return true; -} - -/** - * ldm_parse_prt3 - Read a raw VBLK Partition object into a vblk structure - * @buffer: Block of data being worked on - * @buflen: Size of the block of data - * @vb: In-memory vblk in which to return information - * - * Read a raw VBLK Partition object (version 3) into a vblk structure. - * - * Return: 'true' @vb contains a Partition VBLK - * 'false' @vb contents are not defined - */ -static bool ldm_parse_prt3(const u8 *buffer, int buflen, struct vblk *vb) -{ - int r_objid, r_name, r_size, r_parent, r_diskid, r_index, len; - struct vblk_part *part; - - BUG_ON(!buffer || !vb); - r_objid = ldm_relative(buffer, buflen, 0x18, 0); - if (r_objid < 0) { - ldm_error("r_objid %d < 0", r_objid); - return false; - } - r_name = ldm_relative(buffer, buflen, 0x18, r_objid); - if (r_name < 0) { - ldm_error("r_name %d < 0", r_name); - return false; - } - r_size = ldm_relative(buffer, buflen, 0x34, r_name); - if (r_size < 0) { - ldm_error("r_size %d < 0", r_size); - return false; - } - r_parent = ldm_relative(buffer, buflen, 0x34, r_size); - if (r_parent < 0) { - ldm_error("r_parent %d < 0", r_parent); - return false; - } - r_diskid = ldm_relative(buffer, buflen, 0x34, r_parent); - if (r_diskid < 0) { - ldm_error("r_diskid %d < 0", r_diskid); - return false; - } - if (buffer[0x12] & VBLK_FLAG_PART_INDEX) { - r_index = ldm_relative(buffer, buflen, 0x34, r_diskid); - if (r_index < 0) { - ldm_error("r_index %d < 0", r_index); - return false; - } - len = r_index; - } else { - r_index = 0; - len = r_diskid; - } - if (len < 0) { - ldm_error("len %d < 0", len); - return false; - } - len += VBLK_SIZE_PRT3; - if (len > get_unaligned_be32(buffer + 0x14)) { - ldm_error("len %d > BE32(buffer + 0x14) %d", len, - get_unaligned_be32(buffer + 0x14)); - return false; - } - part = &vb->vblk.part; - part->start = get_unaligned_be64(buffer + 0x24 + r_name); - part->volume_offset = get_unaligned_be64(buffer + 0x2C + r_name); - part->size = ldm_get_vnum(buffer + 0x34 + r_name); - part->parent_id = ldm_get_vnum(buffer + 0x34 + r_size); - part->disk_id = ldm_get_vnum(buffer + 0x34 + r_parent); - if (vb->flags & VBLK_FLAG_PART_INDEX) - part->partnum = buffer[0x35 + r_diskid]; - else - part->partnum = 0; - return true; -} - -/** - * ldm_parse_vol5 - Read a raw VBLK Volume object into a vblk structure - * @buffer: Block of data being worked on - * @buflen: Size of the block of data - * @vb: In-memory vblk in which to return information - * - * Read a raw VBLK Volume object (version 5) into a vblk structure. - * - * Return: 'true' @vb contains a Volume VBLK - * 'false' @vb contents are not defined - */ -static bool ldm_parse_vol5(const u8 *buffer, int buflen, struct vblk *vb) -{ - int r_objid, r_name, r_vtype, r_disable_drive_letter, r_child, r_size; - int r_id1, r_id2, r_size2, r_drive, len; - struct vblk_volu *volu; - - BUG_ON(!buffer || !vb); - r_objid = ldm_relative(buffer, buflen, 0x18, 0); - if (r_objid < 0) { - ldm_error("r_objid %d < 0", r_objid); - return false; - } - r_name = ldm_relative(buffer, buflen, 0x18, r_objid); - if (r_name < 0) { - ldm_error("r_name %d < 0", r_name); - return false; - } - r_vtype = ldm_relative(buffer, buflen, 0x18, r_name); - if (r_vtype < 0) { - ldm_error("r_vtype %d < 0", r_vtype); - return false; - } - r_disable_drive_letter = ldm_relative(buffer, buflen, 0x18, r_vtype); - if (r_disable_drive_letter < 0) { - ldm_error("r_disable_drive_letter %d < 0", - r_disable_drive_letter); - return false; - } - r_child = ldm_relative(buffer, buflen, 0x2D, r_disable_drive_letter); - if (r_child < 0) { - ldm_error("r_child %d < 0", r_child); - return false; - } - r_size = ldm_relative(buffer, buflen, 0x3D, r_child); - if (r_size < 0) { - ldm_error("r_size %d < 0", r_size); - return false; - } - if (buffer[0x12] & VBLK_FLAG_VOLU_ID1) { - r_id1 = ldm_relative(buffer, buflen, 0x52, r_size); - if (r_id1 < 0) { - ldm_error("r_id1 %d < 0", r_id1); - return false; - } - } else - r_id1 = r_size; - if (buffer[0x12] & VBLK_FLAG_VOLU_ID2) { - r_id2 = ldm_relative(buffer, buflen, 0x52, r_id1); - if (r_id2 < 0) { - ldm_error("r_id2 %d < 0", r_id2); - return false; - } - } else - r_id2 = r_id1; - if (buffer[0x12] & VBLK_FLAG_VOLU_SIZE) { - r_size2 = ldm_relative(buffer, buflen, 0x52, r_id2); - if (r_size2 < 0) { - ldm_error("r_size2 %d < 0", r_size2); - return false; - } - } else - r_size2 = r_id2; - if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) { - r_drive = ldm_relative(buffer, buflen, 0x52, r_size2); - if (r_drive < 0) { - ldm_error("r_drive %d < 0", r_drive); - return false; - } - } else - r_drive = r_size2; - len = r_drive; - if (len < 0) { - ldm_error("len %d < 0", len); - return false; - } - len += VBLK_SIZE_VOL5; - if (len > get_unaligned_be32(buffer + 0x14)) { - ldm_error("len %d > BE32(buffer + 0x14) %d", len, - get_unaligned_be32(buffer + 0x14)); - return false; - } - volu = &vb->vblk.volu; - ldm_get_vstr(buffer + 0x18 + r_name, volu->volume_type, - sizeof(volu->volume_type)); - memcpy(volu->volume_state, buffer + 0x18 + r_disable_drive_letter, - sizeof(volu->volume_state)); - volu->size = ldm_get_vnum(buffer + 0x3D + r_child); - volu->partition_type = buffer[0x41 + r_size]; - memcpy(volu->guid, buffer + 0x42 + r_size, sizeof(volu->guid)); - if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) { - ldm_get_vstr(buffer + 0x52 + r_size, volu->drive_hint, - sizeof(volu->drive_hint)); - } - return true; -} - -/** - * ldm_parse_vblk - Read a raw VBLK object into a vblk structure - * @buf: Block of data being worked on - * @len: Size of the block of data - * @vb: In-memory vblk in which to return information - * - * Read a raw VBLK object into a vblk structure. This function just reads the - * information common to all VBLK types, then delegates the rest of the work to - * helper functions: ldm_parse_*. - * - * Return: 'true' @vb contains a VBLK - * 'false' @vb contents are not defined - */ -static bool ldm_parse_vblk (const u8 *buf, int len, struct vblk *vb) -{ - bool result = false; - int r_objid; - - BUG_ON (!buf || !vb); - - r_objid = ldm_relative (buf, len, 0x18, 0); - if (r_objid < 0) { - ldm_error ("VBLK header is corrupt."); - return false; - } - - vb->flags = buf[0x12]; - vb->type = buf[0x13]; - vb->obj_id = ldm_get_vnum (buf + 0x18); - ldm_get_vstr (buf+0x18+r_objid, vb->name, sizeof (vb->name)); - - switch (vb->type) { - case VBLK_CMP3: result = ldm_parse_cmp3 (buf, len, vb); break; - case VBLK_DSK3: result = ldm_parse_dsk3 (buf, len, vb); break; - case VBLK_DSK4: result = ldm_parse_dsk4 (buf, len, vb); break; - case VBLK_DGR3: result = ldm_parse_dgr3 (buf, len, vb); break; - case VBLK_DGR4: result = ldm_parse_dgr4 (buf, len, vb); break; - case VBLK_PRT3: result = ldm_parse_prt3 (buf, len, vb); break; - case VBLK_VOL5: result = ldm_parse_vol5 (buf, len, vb); break; - } - - if (result) - ldm_debug ("Parsed VBLK 0x%llx (type: 0x%02x) ok.", - (unsigned long long) vb->obj_id, vb->type); - else - ldm_error ("Failed to parse VBLK 0x%llx (type: 0x%02x).", - (unsigned long long) vb->obj_id, vb->type); - - return result; -} - - -/** - * ldm_ldmdb_add - Adds a raw VBLK entry to the ldmdb database - * @data: Raw VBLK to add to the database - * @len: Size of the raw VBLK - * @ldb: Cache of the database structures - * - * The VBLKs are sorted into categories. Partitions are also sorted by offset. - * - * N.B. This function does not check the validity of the VBLKs. - * - * Return: 'true' The VBLK was added - * 'false' An error occurred - */ -static bool ldm_ldmdb_add (u8 *data, int len, struct ldmdb *ldb) -{ - struct vblk *vb; - struct list_head *item; - - BUG_ON (!data || !ldb); - - vb = kmalloc (sizeof (*vb), GFP_KERNEL); - if (!vb) { - ldm_crit ("Out of memory."); - return false; - } - - if (!ldm_parse_vblk (data, len, vb)) { - kfree(vb); - return false; /* Already logged */ - } - - /* Put vblk into the correct list. */ - switch (vb->type) { - case VBLK_DGR3: - case VBLK_DGR4: - list_add (&vb->list, &ldb->v_dgrp); - break; - case VBLK_DSK3: - case VBLK_DSK4: - list_add (&vb->list, &ldb->v_disk); - break; - case VBLK_VOL5: - list_add (&vb->list, &ldb->v_volu); - break; - case VBLK_CMP3: - list_add (&vb->list, &ldb->v_comp); - break; - case VBLK_PRT3: - /* Sort by the partition's start sector. */ - list_for_each (item, &ldb->v_part) { - struct vblk *v = list_entry (item, struct vblk, list); - if ((v->vblk.part.disk_id == vb->vblk.part.disk_id) && - (v->vblk.part.start > vb->vblk.part.start)) { - list_add_tail (&vb->list, &v->list); - return true; - } - } - list_add_tail (&vb->list, &ldb->v_part); - break; - } - return true; -} - -/** - * ldm_frag_add - Add a VBLK fragment to a list - * @data: Raw fragment to be added to the list - * @size: Size of the raw fragment - * @frags: Linked list of VBLK fragments - * - * Fragmented VBLKs may not be consecutive in the database, so they are placed - * in a list so they can be pieced together later. - * - * Return: 'true' Success, the VBLK was added to the list - * 'false' Error, a problem occurred - */ -static bool ldm_frag_add (const u8 *data, int size, struct list_head *frags) -{ - struct frag *f; - struct list_head *item; - int rec, num, group; - - BUG_ON (!data || !frags); - - if (size < 2 * VBLK_SIZE_HEAD) { - ldm_error("Value of size is to small."); - return false; - } - - group = get_unaligned_be32(data + 0x08); - rec = get_unaligned_be16(data + 0x0C); - num = get_unaligned_be16(data + 0x0E); - if ((num < 1) || (num > 4)) { - ldm_error ("A VBLK claims to have %d parts.", num); - return false; - } - if (rec >= num) { - ldm_error("REC value (%d) exceeds NUM value (%d)", rec, num); - return false; - } - - list_for_each (item, frags) { - f = list_entry (item, struct frag, list); - if (f->group == group) - goto found; - } - - f = kmalloc (sizeof (*f) + size*num, GFP_KERNEL); - if (!f) { - ldm_crit ("Out of memory."); - return false; - } - - f->group = group; - f->num = num; - f->rec = rec; - f->map = 0xFF << num; - - list_add_tail (&f->list, frags); -found: - if (rec >= f->num) { - ldm_error("REC value (%d) exceeds NUM value (%d)", rec, f->num); - return false; - } - - if (f->map & (1 << rec)) { - ldm_error ("Duplicate VBLK, part %d.", rec); - f->map &= 0x7F; /* Mark the group as broken */ - return false; - } - - f->map |= (1 << rec); - - data += VBLK_SIZE_HEAD; - size -= VBLK_SIZE_HEAD; - - memcpy (f->data+rec*(size-VBLK_SIZE_HEAD)+VBLK_SIZE_HEAD, data, size); - - return true; -} - -/** - * ldm_frag_free - Free a linked list of VBLK fragments - * @list: Linked list of fragments - * - * Free a linked list of VBLK fragments - * - * Return: none - */ -static void ldm_frag_free (struct list_head *list) -{ - struct list_head *item, *tmp; - - BUG_ON (!list); - - list_for_each_safe (item, tmp, list) - kfree (list_entry (item, struct frag, list)); -} - -/** - * ldm_frag_commit - Validate fragmented VBLKs and add them to the database - * @frags: Linked list of VBLK fragments - * @ldb: Cache of the database structures - * - * Now that all the fragmented VBLKs have been collected, they must be added to - * the database for later use. - * - * Return: 'true' All the fragments we added successfully - * 'false' One or more of the fragments we invalid - */ -static bool ldm_frag_commit (struct list_head *frags, struct ldmdb *ldb) -{ - struct frag *f; - struct list_head *item; - - BUG_ON (!frags || !ldb); - - list_for_each (item, frags) { - f = list_entry (item, struct frag, list); - - if (f->map != 0xFF) { - ldm_error ("VBLK group %d is incomplete (0x%02x).", - f->group, f->map); - return false; - } - - if (!ldm_ldmdb_add (f->data, f->num*ldb->vm.vblk_size, ldb)) - return false; /* Already logged */ - } - return true; -} - -/** - * ldm_get_vblks - Read the on-disk database of VBLKs into memory - * @state: Partition check state including device holding the LDM Database - * @base: Offset, into @state->bdev, of the database - * @ldb: Cache of the database structures - * - * To use the information from the VBLKs, they need to be read from the disk, - * unpacked and validated. We cache them in @ldb according to their type. - * - * Return: 'true' All the VBLKs were read successfully - * 'false' An error occurred - */ -static bool ldm_get_vblks(struct parsed_partitions *state, unsigned long base, - struct ldmdb *ldb) -{ - int size, perbuf, skip, finish, s, v, recs; - u8 *data = NULL; - Sector sect; - bool result = false; - LIST_HEAD (frags); - - BUG_ON(!state || !ldb); - - size = ldb->vm.vblk_size; - perbuf = 512 / size; - skip = ldb->vm.vblk_offset >> 9; /* Bytes to sectors */ - finish = (size * ldb->vm.last_vblk_seq) >> 9; - - for (s = skip; s < finish; s++) { /* For each sector */ - data = read_part_sector(state, base + OFF_VMDB + s, §); - if (!data) { - ldm_crit ("Disk read failed."); - goto out; - } - - for (v = 0; v < perbuf; v++, data+=size) { /* For each vblk */ - if (MAGIC_VBLK != get_unaligned_be32(data)) { - ldm_error ("Expected to find a VBLK."); - goto out; - } - - recs = get_unaligned_be16(data + 0x0E); /* Number of records */ - if (recs == 1) { - if (!ldm_ldmdb_add (data, size, ldb)) - goto out; /* Already logged */ - } else if (recs > 1) { - if (!ldm_frag_add (data, size, &frags)) - goto out; /* Already logged */ - } - /* else Record is not in use, ignore it. */ - } - put_dev_sector (sect); - data = NULL; - } - - result = ldm_frag_commit (&frags, ldb); /* Failures, already logged */ -out: - if (data) - put_dev_sector (sect); - ldm_frag_free (&frags); - - return result; -} - -/** - * ldm_free_vblks - Free a linked list of vblk's - * @lh: Head of a linked list of struct vblk - * - * Free a list of vblk's and free the memory used to maintain the list. - * - * Return: none - */ -static void ldm_free_vblks (struct list_head *lh) -{ - struct list_head *item, *tmp; - - BUG_ON (!lh); - - list_for_each_safe (item, tmp, lh) - kfree (list_entry (item, struct vblk, list)); -} - - -/** - * ldm_partition - Find out whether a device is a dynamic disk and handle it - * @state: Partition check state including device holding the LDM Database - * - * This determines whether the device @bdev is a dynamic disk and if so creates - * the partitions necessary in the gendisk structure pointed to by @hd. - * - * We create a dummy device 1, which contains the LDM database, and then create - * each partition described by the LDM database in sequence as devices 2+. For - * example, if the device is hda, we would have: hda1: LDM database, hda2, hda3, - * and so on: the actual data containing partitions. - * - * Return: 1 Success, @state->bdev is a dynamic disk and we handled it - * 0 Success, @state->bdev is not a dynamic disk - * -1 An error occurred before enough information had been read - * Or @state->bdev is a dynamic disk, but it may be corrupted - */ -int ldm_partition(struct parsed_partitions *state) -{ - struct ldmdb *ldb; - unsigned long base; - int result = -1; - - BUG_ON(!state); - - /* Look for signs of a Dynamic Disk */ - if (!ldm_validate_partition_table(state)) - return 0; - - ldb = kmalloc (sizeof (*ldb), GFP_KERNEL); - if (!ldb) { - ldm_crit ("Out of memory."); - goto out; - } - - /* Parse and check privheads. */ - if (!ldm_validate_privheads(state, &ldb->ph)) - goto out; /* Already logged */ - - /* All further references are relative to base (database start). */ - base = ldb->ph.config_start; - - /* Parse and check tocs and vmdb. */ - if (!ldm_validate_tocblocks(state, base, ldb) || - !ldm_validate_vmdb(state, base, ldb)) - goto out; /* Already logged */ - - /* Initialize vblk lists in ldmdb struct */ - INIT_LIST_HEAD (&ldb->v_dgrp); - INIT_LIST_HEAD (&ldb->v_disk); - INIT_LIST_HEAD (&ldb->v_volu); - INIT_LIST_HEAD (&ldb->v_comp); - INIT_LIST_HEAD (&ldb->v_part); - - if (!ldm_get_vblks(state, base, ldb)) { - ldm_crit ("Failed to read the VBLKs from the database."); - goto cleanup; - } - - /* Finally, create the data partition devices. */ - if (ldm_create_data_partitions(state, ldb)) { - ldm_debug ("Parsed LDM database successfully."); - result = 1; - } - /* else Already logged */ - -cleanup: - ldm_free_vblks (&ldb->v_dgrp); - ldm_free_vblks (&ldb->v_disk); - ldm_free_vblks (&ldb->v_volu); - ldm_free_vblks (&ldb->v_comp); - ldm_free_vblks (&ldb->v_part); -out: - kfree (ldb); - return result; -} diff --git a/fs/partitions/ldm.h b/fs/partitions/ldm.h deleted file mode 100644 index 374242c0971a..000000000000 --- a/fs/partitions/ldm.h +++ /dev/null @@ -1,215 +0,0 @@ -/** - * ldm - Part of the Linux-NTFS project. - * - * Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org> - * Copyright (c) 2001-2007 Anton Altaparmakov - * Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com> - * - * Documentation is available at http://www.linux-ntfs.org/doku.php?id=downloads - * - * 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 (in the main directory of the Linux-NTFS source - * in the file COPYING); if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _FS_PT_LDM_H_ -#define _FS_PT_LDM_H_ - -#include <linux/types.h> -#include <linux/list.h> -#include <linux/genhd.h> -#include <linux/fs.h> -#include <asm/unaligned.h> -#include <asm/byteorder.h> - -struct parsed_partitions; - -/* Magic numbers in CPU format. */ -#define MAGIC_VMDB 0x564D4442 /* VMDB */ -#define MAGIC_VBLK 0x56424C4B /* VBLK */ -#define MAGIC_PRIVHEAD 0x5052495648454144ULL /* PRIVHEAD */ -#define MAGIC_TOCBLOCK 0x544F43424C4F434BULL /* TOCBLOCK */ - -/* The defined vblk types. */ -#define VBLK_VOL5 0x51 /* Volume, version 5 */ -#define VBLK_CMP3 0x32 /* Component, version 3 */ -#define VBLK_PRT3 0x33 /* Partition, version 3 */ -#define VBLK_DSK3 0x34 /* Disk, version 3 */ -#define VBLK_DSK4 0x44 /* Disk, version 4 */ -#define VBLK_DGR3 0x35 /* Disk Group, version 3 */ -#define VBLK_DGR4 0x45 /* Disk Group, version 4 */ - -/* vblk flags indicating extra information will be present */ -#define VBLK_FLAG_COMP_STRIPE 0x10 -#define VBLK_FLAG_PART_INDEX 0x08 -#define VBLK_FLAG_DGR3_IDS 0x08 -#define VBLK_FLAG_DGR4_IDS 0x08 -#define VBLK_FLAG_VOLU_ID1 0x08 -#define VBLK_FLAG_VOLU_ID2 0x20 -#define VBLK_FLAG_VOLU_SIZE 0x80 -#define VBLK_FLAG_VOLU_DRIVE 0x02 - -/* size of a vblk's static parts */ -#define VBLK_SIZE_HEAD 16 -#define VBLK_SIZE_CMP3 22 /* Name and version */ -#define VBLK_SIZE_DGR3 12 -#define VBLK_SIZE_DGR4 44 -#define VBLK_SIZE_DSK3 12 -#define VBLK_SIZE_DSK4 45 -#define VBLK_SIZE_PRT3 28 -#define VBLK_SIZE_VOL5 58 - -/* component types */ -#define COMP_STRIPE 0x01 /* Stripe-set */ -#define COMP_BASIC 0x02 /* Basic disk */ -#define COMP_RAID 0x03 /* Raid-set */ - -/* Other constants. */ -#define LDM_DB_SIZE 2048 /* Size in sectors (= 1MiB). */ - -#define OFF_PRIV1 6 /* Offset of the first privhead - relative to the start of the - device in sectors */ - -/* Offsets to structures within the LDM Database in sectors. */ -#define OFF_PRIV2 1856 /* Backup private headers. */ -#define OFF_PRIV3 2047 - -#define OFF_TOCB1 1 /* Tables of contents. */ -#define OFF_TOCB2 2 -#define OFF_TOCB3 2045 -#define OFF_TOCB4 2046 - -#define OFF_VMDB 17 /* List of partitions. */ - -#define LDM_PARTITION 0x42 /* Formerly SFS (Landis). */ - -#define TOC_BITMAP1 "config" /* Names of the two defined */ -#define TOC_BITMAP2 "log" /* bitmaps in the TOCBLOCK. */ - -/* Borrowed from msdos.c */ -#define SYS_IND(p) (get_unaligned(&(p)->sys_ind)) - -struct frag { /* VBLK Fragment handling */ - struct list_head list; - u32 group; - u8 num; /* Total number of records */ - u8 rec; /* This is record number n */ - u8 map; /* Which portions are in use */ - u8 data[0]; -}; - -/* In memory LDM database structures. */ - -#define GUID_SIZE 16 - -struct privhead { /* Offsets and sizes are in sectors. */ - u16 ver_major; - u16 ver_minor; - u64 logical_disk_start; - u64 logical_disk_size; - u64 config_start; - u64 config_size; - u8 disk_id[GUID_SIZE]; -}; - -struct tocblock { /* We have exactly two bitmaps. */ - u8 bitmap1_name[16]; - u64 bitmap1_start; - u64 bitmap1_size; - u8 bitmap2_name[16]; - u64 bitmap2_start; - u64 bitmap2_size; -}; - -struct vmdb { /* VMDB: The database header */ - u16 ver_major; - u16 ver_minor; - u32 vblk_size; - u32 vblk_offset; - u32 last_vblk_seq; -}; - -struct vblk_comp { /* VBLK Component */ - u8 state[16]; - u64 parent_id; - u8 type; - u8 children; - u16 chunksize; -}; - -struct vblk_dgrp { /* VBLK Disk Group */ - u8 disk_id[64]; -}; - -struct vblk_disk { /* VBLK Disk */ - u8 disk_id[GUID_SIZE]; - u8 alt_name[128]; -}; - -struct vblk_part { /* VBLK Partition */ - u64 start; - u64 size; /* start, size and vol_off in sectors */ - u64 volume_offset; - u64 parent_id; - u64 disk_id; - u8 partnum; -}; - -struct vblk_volu { /* VBLK Volume */ - u8 volume_type[16]; - u8 volume_state[16]; - u8 guid[16]; - u8 drive_hint[4]; - u64 size; - u8 partition_type; -}; - -struct vblk_head { /* VBLK standard header */ - u32 group; - u16 rec; - u16 nrec; -}; - -struct vblk { /* Generalised VBLK */ - u8 name[64]; - u64 obj_id; - u32 sequence; - u8 flags; - u8 type; - union { - struct vblk_comp comp; - struct vblk_dgrp dgrp; - struct vblk_disk disk; - struct vblk_part part; - struct vblk_volu volu; - } vblk; - struct list_head list; -}; - -struct ldmdb { /* Cache of the database */ - struct privhead ph; - struct tocblock toc; - struct vmdb vm; - struct list_head v_dgrp; - struct list_head v_disk; - struct list_head v_volu; - struct list_head v_comp; - struct list_head v_part; -}; - -int ldm_partition(struct parsed_partitions *state); - -#endif /* _FS_PT_LDM_H_ */ - diff --git a/fs/partitions/mac.c b/fs/partitions/mac.c deleted file mode 100644 index 11f688bd76c5..000000000000 --- a/fs/partitions/mac.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * fs/partitions/mac.c - * - * Code extracted from drivers/block/genhd.c - * Copyright (C) 1991-1998 Linus Torvalds - * Re-organised Feb 1998 Russell King - */ - -#include <linux/ctype.h> -#include "check.h" -#include "mac.h" - -#ifdef CONFIG_PPC_PMAC -#include <asm/machdep.h> -extern void note_bootable_part(dev_t dev, int part, int goodness); -#endif - -/* - * Code to understand MacOS partition tables. - */ - -static inline void mac_fix_string(char *stg, int len) -{ - int i; - - for (i = len - 1; i >= 0 && stg[i] == ' '; i--) - stg[i] = 0; -} - -int mac_partition(struct parsed_partitions *state) -{ - Sector sect; - unsigned char *data; - int slot, blocks_in_map; - unsigned secsize; -#ifdef CONFIG_PPC_PMAC - int found_root = 0; - int found_root_goodness = 0; -#endif - struct mac_partition *part; - struct mac_driver_desc *md; - - /* Get 0th block and look at the first partition map entry. */ - md = read_part_sector(state, 0, §); - if (!md) - return -1; - if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC) { - put_dev_sector(sect); - return 0; - } - secsize = be16_to_cpu(md->block_size); - put_dev_sector(sect); - data = read_part_sector(state, secsize/512, §); - if (!data) - return -1; - part = (struct mac_partition *) (data + secsize%512); - if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) { - put_dev_sector(sect); - return 0; /* not a MacOS disk */ - } - blocks_in_map = be32_to_cpu(part->map_count); - if (blocks_in_map < 0 || blocks_in_map >= DISK_MAX_PARTS) { - put_dev_sector(sect); - return 0; - } - strlcat(state->pp_buf, " [mac]", PAGE_SIZE); - for (slot = 1; slot <= blocks_in_map; ++slot) { - int pos = slot * secsize; - put_dev_sector(sect); - data = read_part_sector(state, pos/512, §); - if (!data) - return -1; - part = (struct mac_partition *) (data + pos%512); - if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) - break; - put_partition(state, slot, - be32_to_cpu(part->start_block) * (secsize/512), - be32_to_cpu(part->block_count) * (secsize/512)); - - if (!strnicmp(part->type, "Linux_RAID", 10)) - state->parts[slot].flags = ADDPART_FLAG_RAID; -#ifdef CONFIG_PPC_PMAC - /* - * If this is the first bootable partition, tell the - * setup code, in case it wants to make this the root. - */ - if (machine_is(powermac)) { - int goodness = 0; - - mac_fix_string(part->processor, 16); - mac_fix_string(part->name, 32); - mac_fix_string(part->type, 32); - - if ((be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE) - && strcasecmp(part->processor, "powerpc") == 0) - goodness++; - - if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0 - || (strnicmp(part->type, "Linux", 5) == 0 - && strcasecmp(part->type, "Linux_swap") != 0)) { - int i, l; - - goodness++; - l = strlen(part->name); - if (strcmp(part->name, "/") == 0) - goodness++; - for (i = 0; i <= l - 4; ++i) { - if (strnicmp(part->name + i, "root", - 4) == 0) { - goodness += 2; - break; - } - } - if (strnicmp(part->name, "swap", 4) == 0) - goodness--; - } - - if (goodness > found_root_goodness) { - found_root = slot; - found_root_goodness = goodness; - } - } -#endif /* CONFIG_PPC_PMAC */ - } -#ifdef CONFIG_PPC_PMAC - if (found_root_goodness) - note_bootable_part(state->bdev->bd_dev, found_root, - found_root_goodness); -#endif - - put_dev_sector(sect); - strlcat(state->pp_buf, "\n", PAGE_SIZE); - return 1; -} diff --git a/fs/partitions/mac.h b/fs/partitions/mac.h deleted file mode 100644 index 3c7d98436380..000000000000 --- a/fs/partitions/mac.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * fs/partitions/mac.h - */ - -#define MAC_PARTITION_MAGIC 0x504d - -/* type field value for A/UX or other Unix partitions */ -#define APPLE_AUX_TYPE "Apple_UNIX_SVR2" - -struct mac_partition { - __be16 signature; /* expected to be MAC_PARTITION_MAGIC */ - __be16 res1; - __be32 map_count; /* # blocks in partition map */ - __be32 start_block; /* absolute starting block # of partition */ - __be32 block_count; /* number of blocks in partition */ - char name[32]; /* partition name */ - char type[32]; /* string type description */ - __be32 data_start; /* rel block # of first data block */ - __be32 data_count; /* number of data blocks */ - __be32 status; /* partition status bits */ - __be32 boot_start; - __be32 boot_size; - __be32 boot_load; - __be32 boot_load2; - __be32 boot_entry; - __be32 boot_entry2; - __be32 boot_cksum; - char processor[16]; /* identifies ISA of boot */ - /* there is more stuff after this that we don't need */ -}; - -#define MAC_STATUS_BOOTABLE 8 /* partition is bootable */ - -#define MAC_DRIVER_MAGIC 0x4552 - -/* Driver descriptor structure, in block 0 */ -struct mac_driver_desc { - __be16 signature; /* expected to be MAC_DRIVER_MAGIC */ - __be16 block_size; - __be32 block_count; - /* ... more stuff */ -}; - -int mac_partition(struct parsed_partitions *state); diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c deleted file mode 100644 index 5f79a6677c69..000000000000 --- a/fs/partitions/msdos.c +++ /dev/null @@ -1,552 +0,0 @@ -/* - * fs/partitions/msdos.c - * - * Code extracted from drivers/block/genhd.c - * Copyright (C) 1991-1998 Linus Torvalds - * - * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug - * in the early extended-partition checks and added DM partitions - * - * Support for DiskManager v6.0x added by Mark Lord, - * with information provided by OnTrack. This now works for linux fdisk - * and LILO, as well as loadlin and bootln. Note that disks other than - * /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1). - * - * More flexible handling of extended partitions - aeb, 950831 - * - * Check partition table on IDE disks for common CHS translations - * - * Re-organised Feb 1998 Russell King - */ -#include <linux/msdos_fs.h> - -#include "check.h" -#include "msdos.h" -#include "efi.h" - -/* - * Many architectures don't like unaligned accesses, while - * the nr_sects and start_sect partition table entries are - * at a 2 (mod 4) address. - */ -#include <asm/unaligned.h> - -#define SYS_IND(p) get_unaligned(&p->sys_ind) - -static inline sector_t nr_sects(struct partition *p) -{ - return (sector_t)get_unaligned_le32(&p->nr_sects); -} - -static inline sector_t start_sect(struct partition *p) -{ - return (sector_t)get_unaligned_le32(&p->start_sect); -} - -static inline int is_extended_partition(struct partition *p) -{ - return (SYS_IND(p) == DOS_EXTENDED_PARTITION || - SYS_IND(p) == WIN98_EXTENDED_PARTITION || - SYS_IND(p) == LINUX_EXTENDED_PARTITION); -} - -#define MSDOS_LABEL_MAGIC1 0x55 -#define MSDOS_LABEL_MAGIC2 0xAA - -static inline int -msdos_magic_present(unsigned char *p) -{ - return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2); -} - -/* Value is EBCDIC 'IBMA' */ -#define AIX_LABEL_MAGIC1 0xC9 -#define AIX_LABEL_MAGIC2 0xC2 -#define AIX_LABEL_MAGIC3 0xD4 -#define AIX_LABEL_MAGIC4 0xC1 -static int aix_magic_present(struct parsed_partitions *state, unsigned char *p) -{ - struct partition *pt = (struct partition *) (p + 0x1be); - Sector sect; - unsigned char *d; - int slot, ret = 0; - - if (!(p[0] == AIX_LABEL_MAGIC1 && - p[1] == AIX_LABEL_MAGIC2 && - p[2] == AIX_LABEL_MAGIC3 && - p[3] == AIX_LABEL_MAGIC4)) - return 0; - /* Assume the partition table is valid if Linux partitions exists */ - for (slot = 1; slot <= 4; slot++, pt++) { - if (pt->sys_ind == LINUX_SWAP_PARTITION || - pt->sys_ind == LINUX_RAID_PARTITION || - pt->sys_ind == LINUX_DATA_PARTITION || - pt->sys_ind == LINUX_LVM_PARTITION || - is_extended_partition(pt)) - return 0; - } - d = read_part_sector(state, 7, §); - if (d) { - if (d[0] == '_' && d[1] == 'L' && d[2] == 'V' && d[3] == 'M') - ret = 1; - put_dev_sector(sect); - }; - return ret; -} - -/* - * Create devices for each logical partition in an extended partition. - * The logical partitions form a linked list, with each entry being - * a partition table with two entries. The first entry - * is the real data partition (with a start relative to the partition - * table start). The second is a pointer to the next logical partition - * (with a start relative to the entire extended partition). - * We do not create a Linux partition for the partition tables, but - * only for the actual data partitions. - */ - -static void parse_extended(struct parsed_partitions *state, - sector_t first_sector, sector_t first_size) -{ - struct partition *p; - Sector sect; - unsigned char *data; - sector_t this_sector, this_size; - sector_t sector_size = bdev_logical_block_size(state->bdev) / 512; - int loopct = 0; /* number of links followed - without finding a data partition */ - int i; - - this_sector = first_sector; - this_size = first_size; - - while (1) { - if (++loopct > 100) - return; - if (state->next == state->limit) - return; - data = read_part_sector(state, this_sector, §); - if (!data) - return; - - if (!msdos_magic_present(data + 510)) - goto done; - - p = (struct partition *) (data + 0x1be); - - /* - * Usually, the first entry is the real data partition, - * the 2nd entry is the next extended partition, or empty, - * and the 3rd and 4th entries are unused. - * However, DRDOS sometimes has the extended partition as - * the first entry (when the data partition is empty), - * and OS/2 seems to use all four entries. - */ - - /* - * First process the data partition(s) - */ - for (i=0; i<4; i++, p++) { - sector_t offs, size, next; - if (!nr_sects(p) || is_extended_partition(p)) - continue; - - /* Check the 3rd and 4th entries - - these sometimes contain random garbage */ - offs = start_sect(p)*sector_size; - size = nr_sects(p)*sector_size; - next = this_sector + offs; - if (i >= 2) { - if (offs + size > this_size) - continue; - if (next < first_sector) - continue; - if (next + size > first_sector + first_size) - continue; - } - - put_partition(state, state->next, next, size); - if (SYS_IND(p) == LINUX_RAID_PARTITION) - state->parts[state->next].flags = ADDPART_FLAG_RAID; - loopct = 0; - if (++state->next == state->limit) - goto done; - } - /* - * Next, process the (first) extended partition, if present. - * (So far, there seems to be no reason to make - * parse_extended() recursive and allow a tree - * of extended partitions.) - * It should be a link to the next logical partition. - */ - p -= 4; - for (i=0; i<4; i++, p++) - if (nr_sects(p) && is_extended_partition(p)) - break; - if (i == 4) - goto done; /* nothing left to do */ - - this_sector = first_sector + start_sect(p) * sector_size; - this_size = nr_sects(p) * sector_size; - put_dev_sector(sect); - } -done: - put_dev_sector(sect); -} - -/* james@bpgc.com: Solaris has a nasty indicator: 0x82 which also - indicates linux swap. Be careful before believing this is Solaris. */ - -static void parse_solaris_x86(struct parsed_partitions *state, - sector_t offset, sector_t size, int origin) -{ -#ifdef CONFIG_SOLARIS_X86_PARTITION - Sector sect; - struct solaris_x86_vtoc *v; - int i; - short max_nparts; - - v = read_part_sector(state, offset + 1, §); - if (!v) - return; - if (le32_to_cpu(v->v_sanity) != SOLARIS_X86_VTOC_SANE) { - put_dev_sector(sect); - return; - } - { - char tmp[1 + BDEVNAME_SIZE + 10 + 11 + 1]; - - snprintf(tmp, sizeof(tmp), " %s%d: <solaris:", state->name, origin); - strlcat(state->pp_buf, tmp, PAGE_SIZE); - } - if (le32_to_cpu(v->v_version) != 1) { - char tmp[64]; - - snprintf(tmp, sizeof(tmp), " cannot handle version %d vtoc>\n", - le32_to_cpu(v->v_version)); - strlcat(state->pp_buf, tmp, PAGE_SIZE); - put_dev_sector(sect); - return; - } - /* Ensure we can handle previous case of VTOC with 8 entries gracefully */ - max_nparts = le16_to_cpu (v->v_nparts) > 8 ? SOLARIS_X86_NUMSLICE : 8; - for (i=0; i<max_nparts && state->next<state->limit; i++) { - struct solaris_x86_slice *s = &v->v_slice[i]; - char tmp[3 + 10 + 1 + 1]; - - if (s->s_size == 0) - continue; - snprintf(tmp, sizeof(tmp), " [s%d]", i); - strlcat(state->pp_buf, tmp, PAGE_SIZE); - /* solaris partitions are relative to current MS-DOS - * one; must add the offset of the current partition */ - put_partition(state, state->next++, - le32_to_cpu(s->s_start)+offset, - le32_to_cpu(s->s_size)); - } - put_dev_sector(sect); - strlcat(state->pp_buf, " >\n", PAGE_SIZE); -#endif -} - -#if defined(CONFIG_BSD_DISKLABEL) -/* - * Create devices for BSD partitions listed in a disklabel, under a - * dos-like partition. See parse_extended() for more information. - */ -static void parse_bsd(struct parsed_partitions *state, - sector_t offset, sector_t size, int origin, char *flavour, - int max_partitions) -{ - Sector sect; - struct bsd_disklabel *l; - struct bsd_partition *p; - char tmp[64]; - - l = read_part_sector(state, offset + 1, §); - if (!l) - return; - if (le32_to_cpu(l->d_magic) != BSD_DISKMAGIC) { - put_dev_sector(sect); - return; - } - - snprintf(tmp, sizeof(tmp), " %s%d: <%s:", state->name, origin, flavour); - strlcat(state->pp_buf, tmp, PAGE_SIZE); - - if (le16_to_cpu(l->d_npartitions) < max_partitions) - max_partitions = le16_to_cpu(l->d_npartitions); - for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) { - sector_t bsd_start, bsd_size; - - if (state->next == state->limit) - break; - if (p->p_fstype == BSD_FS_UNUSED) - continue; - bsd_start = le32_to_cpu(p->p_offset); - bsd_size = le32_to_cpu(p->p_size); - if (offset == bsd_start && size == bsd_size) - /* full parent partition, we have it already */ - continue; - if (offset > bsd_start || offset+size < bsd_start+bsd_size) { - strlcat(state->pp_buf, "bad subpartition - ignored\n", PAGE_SIZE); - continue; - } - put_partition(state, state->next++, bsd_start, bsd_size); - } - put_dev_sector(sect); - if (le16_to_cpu(l->d_npartitions) > max_partitions) { - snprintf(tmp, sizeof(tmp), " (ignored %d more)", - le16_to_cpu(l->d_npartitions) - max_partitions); - strlcat(state->pp_buf, tmp, PAGE_SIZE); - } - strlcat(state->pp_buf, " >\n", PAGE_SIZE); -} -#endif - -static void parse_freebsd(struct parsed_partitions *state, - sector_t offset, sector_t size, int origin) -{ -#ifdef CONFIG_BSD_DISKLABEL - parse_bsd(state, offset, size, origin, "bsd", BSD_MAXPARTITIONS); -#endif -} - -static void parse_netbsd(struct parsed_partitions *state, - sector_t offset, sector_t size, int origin) -{ -#ifdef CONFIG_BSD_DISKLABEL - parse_bsd(state, offset, size, origin, "netbsd", BSD_MAXPARTITIONS); -#endif -} - -static void parse_openbsd(struct parsed_partitions *state, - sector_t offset, sector_t size, int origin) -{ -#ifdef CONFIG_BSD_DISKLABEL - parse_bsd(state, offset, size, origin, "openbsd", - OPENBSD_MAXPARTITIONS); -#endif -} - -/* - * Create devices for Unixware partitions listed in a disklabel, under a - * dos-like partition. See parse_extended() for more information. - */ -static void parse_unixware(struct parsed_partitions *state, - sector_t offset, sector_t size, int origin) -{ -#ifdef CONFIG_UNIXWARE_DISKLABEL - Sector sect; - struct unixware_disklabel *l; - struct unixware_slice *p; - - l = read_part_sector(state, offset + 29, §); - if (!l) - return; - if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC || - le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) { - put_dev_sector(sect); - return; - } - { - char tmp[1 + BDEVNAME_SIZE + 10 + 12 + 1]; - - snprintf(tmp, sizeof(tmp), " %s%d: <unixware:", state->name, origin); - strlcat(state->pp_buf, tmp, PAGE_SIZE); - } - p = &l->vtoc.v_slice[1]; - /* I omit the 0th slice as it is the same as whole disk. */ - while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) { - if (state->next == state->limit) - break; - - if (p->s_label != UNIXWARE_FS_UNUSED) - put_partition(state, state->next++, - le32_to_cpu(p->start_sect), - le32_to_cpu(p->nr_sects)); - p++; - } - put_dev_sector(sect); - strlcat(state->pp_buf, " >\n", PAGE_SIZE); -#endif -} - -/* - * Minix 2.0.0/2.0.2 subpartition support. - * Anand Krishnamurthy <anandk@wiproge.med.ge.com> - * Rajeev V. Pillai <rajeevvp@yahoo.com> - */ -static void parse_minix(struct parsed_partitions *state, - sector_t offset, sector_t size, int origin) -{ -#ifdef CONFIG_MINIX_SUBPARTITION - Sector sect; - unsigned char *data; - struct partition *p; - int i; - - data = read_part_sector(state, offset, §); - if (!data) - return; - - p = (struct partition *)(data + 0x1be); - - /* The first sector of a Minix partition can have either - * a secondary MBR describing its subpartitions, or - * the normal boot sector. */ - if (msdos_magic_present (data + 510) && - SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */ - char tmp[1 + BDEVNAME_SIZE + 10 + 9 + 1]; - - snprintf(tmp, sizeof(tmp), " %s%d: <minix:", state->name, origin); - strlcat(state->pp_buf, tmp, PAGE_SIZE); - for (i = 0; i < MINIX_NR_SUBPARTITIONS; i++, p++) { - if (state->next == state->limit) - break; - /* add each partition in use */ - if (SYS_IND(p) == MINIX_PARTITION) - put_partition(state, state->next++, - start_sect(p), nr_sects(p)); - } - strlcat(state->pp_buf, " >\n", PAGE_SIZE); - } - put_dev_sector(sect); -#endif /* CONFIG_MINIX_SUBPARTITION */ -} - -static struct { - unsigned char id; - void (*parse)(struct parsed_partitions *, sector_t, sector_t, int); -} subtypes[] = { - {FREEBSD_PARTITION, parse_freebsd}, - {NETBSD_PARTITION, parse_netbsd}, - {OPENBSD_PARTITION, parse_openbsd}, - {MINIX_PARTITION, parse_minix}, - {UNIXWARE_PARTITION, parse_unixware}, - {SOLARIS_X86_PARTITION, parse_solaris_x86}, - {NEW_SOLARIS_X86_PARTITION, parse_solaris_x86}, - {0, NULL}, -}; - -int msdos_partition(struct parsed_partitions *state) -{ - sector_t sector_size = bdev_logical_block_size(state->bdev) / 512; - Sector sect; - unsigned char *data; - struct partition *p; - struct fat_boot_sector *fb; - int slot; - - data = read_part_sector(state, 0, §); - if (!data) - return -1; - if (!msdos_magic_present(data + 510)) { - put_dev_sector(sect); - return 0; - } - - if (aix_magic_present(state, data)) { - put_dev_sector(sect); - strlcat(state->pp_buf, " [AIX]", PAGE_SIZE); - return 0; - } - - /* - * Now that the 55aa signature is present, this is probably - * either the boot sector of a FAT filesystem or a DOS-type - * partition table. Reject this in case the boot indicator - * is not 0 or 0x80. - */ - p = (struct partition *) (data + 0x1be); - for (slot = 1; slot <= 4; slot++, p++) { - if (p->boot_ind != 0 && p->boot_ind != 0x80) { - /* - * Even without a valid boot inidicator value - * its still possible this is valid FAT filesystem - * without a partition table. - */ - fb = (struct fat_boot_sector *) data; - if (slot == 1 && fb->reserved && fb->fats - && fat_valid_media(fb->media)) { - strlcat(state->pp_buf, "\n", PAGE_SIZE); - put_dev_sector(sect); - return 1; - } else { - put_dev_sector(sect); - return 0; - } - } - } - -#ifdef CONFIG_EFI_PARTITION - p = (struct partition *) (data + 0x1be); - for (slot = 1 ; slot <= 4 ; slot++, p++) { - /* If this is an EFI GPT disk, msdos should ignore it. */ - if (SYS_IND(p) == EFI_PMBR_OSTYPE_EFI_GPT) { - put_dev_sector(sect); - return 0; - } - } -#endif - p = (struct partition *) (data + 0x1be); - - /* - * Look for partitions in two passes: - * First find the primary and DOS-type extended partitions. - * On the second pass look inside *BSD, Unixware and Solaris partitions. - */ - - state->next = 5; - for (slot = 1 ; slot <= 4 ; slot++, p++) { - sector_t start = start_sect(p)*sector_size; - sector_t size = nr_sects(p)*sector_size; - if (!size) - continue; - if (is_extended_partition(p)) { - /* - * prevent someone doing mkfs or mkswap on an - * extended partition, but leave room for LILO - * FIXME: this uses one logical sector for > 512b - * sector, although it may not be enough/proper. - */ - sector_t n = 2; - n = min(size, max(sector_size, n)); - put_partition(state, slot, start, n); - - strlcat(state->pp_buf, " <", PAGE_SIZE); - parse_extended(state, start, size); - strlcat(state->pp_buf, " >", PAGE_SIZE); - continue; - } - put_partition(state, slot, start, size); - if (SYS_IND(p) == LINUX_RAID_PARTITION) - state->parts[slot].flags = ADDPART_FLAG_RAID; - if (SYS_IND(p) == DM6_PARTITION) - strlcat(state->pp_buf, "[DM]", PAGE_SIZE); - if (SYS_IND(p) == EZD_PARTITION) - strlcat(state->pp_buf, "[EZD]", PAGE_SIZE); - } - - strlcat(state->pp_buf, "\n", PAGE_SIZE); - - /* second pass - output for each on a separate line */ - p = (struct partition *) (0x1be + data); - for (slot = 1 ; slot <= 4 ; slot++, p++) { - unsigned char id = SYS_IND(p); - int n; - - if (!nr_sects(p)) - continue; - - for (n = 0; subtypes[n].parse && id != subtypes[n].id; n++) - ; - - if (!subtypes[n].parse) - continue; - subtypes[n].parse(state, start_sect(p) * sector_size, - nr_sects(p) * sector_size, slot); - } - put_dev_sector(sect); - return 1; -} diff --git a/fs/partitions/msdos.h b/fs/partitions/msdos.h deleted file mode 100644 index 38c781c490b3..000000000000 --- a/fs/partitions/msdos.h +++ /dev/null @@ -1,8 +0,0 @@ -/* - * fs/partitions/msdos.h - */ - -#define MSDOS_LABEL_MAGIC 0xAA55 - -int msdos_partition(struct parsed_partitions *state); - diff --git a/fs/partitions/osf.c b/fs/partitions/osf.c deleted file mode 100644 index 764b86a01965..000000000000 --- a/fs/partitions/osf.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * fs/partitions/osf.c - * - * Code extracted from drivers/block/genhd.c - * - * Copyright (C) 1991-1998 Linus Torvalds - * Re-organised Feb 1998 Russell King - */ - -#include "check.h" -#include "osf.h" - -#define MAX_OSF_PARTITIONS 18 - -int osf_partition(struct parsed_partitions *state) -{ - int i; - int slot = 1; - unsigned int npartitions; - Sector sect; - unsigned char *data; - struct disklabel { - __le32 d_magic; - __le16 d_type,d_subtype; - u8 d_typename[16]; - u8 d_packname[16]; - __le32 d_secsize; - __le32 d_nsectors; - __le32 d_ntracks; - __le32 d_ncylinders; - __le32 d_secpercyl; - __le32 d_secprtunit; - __le16 d_sparespertrack; - __le16 d_sparespercyl; - __le32 d_acylinders; - __le16 d_rpm, d_interleave, d_trackskew, d_cylskew; - __le32 d_headswitch, d_trkseek, d_flags; - __le32 d_drivedata[5]; - __le32 d_spare[5]; - __le32 d_magic2; - __le16 d_checksum; - __le16 d_npartitions; - __le32 d_bbsize, d_sbsize; - struct d_partition { - __le32 p_size; - __le32 p_offset; - __le32 p_fsize; - u8 p_fstype; - u8 p_frag; - __le16 p_cpg; - } d_partitions[MAX_OSF_PARTITIONS]; - } * label; - struct d_partition * partition; - - data = read_part_sector(state, 0, §); - if (!data) - return -1; - - label = (struct disklabel *) (data+64); - partition = label->d_partitions; - if (le32_to_cpu(label->d_magic) != DISKLABELMAGIC) { - put_dev_sector(sect); - return 0; - } - if (le32_to_cpu(label->d_magic2) != DISKLABELMAGIC) { - put_dev_sector(sect); - return 0; - } - npartitions = le16_to_cpu(label->d_npartitions); - if (npartitions > MAX_OSF_PARTITIONS) { - put_dev_sector(sect); - return 0; - } - for (i = 0 ; i < npartitions; i++, partition++) { - if (slot == state->limit) - break; - if (le32_to_cpu(partition->p_size)) - put_partition(state, slot, - le32_to_cpu(partition->p_offset), - le32_to_cpu(partition->p_size)); - slot++; - } - strlcat(state->pp_buf, "\n", PAGE_SIZE); - put_dev_sector(sect); - return 1; -} diff --git a/fs/partitions/osf.h b/fs/partitions/osf.h deleted file mode 100644 index 20ed2315ec16..000000000000 --- a/fs/partitions/osf.h +++ /dev/null @@ -1,7 +0,0 @@ -/* - * fs/partitions/osf.h - */ - -#define DISKLABELMAGIC (0x82564557UL) - -int osf_partition(struct parsed_partitions *state); diff --git a/fs/partitions/sgi.c b/fs/partitions/sgi.c deleted file mode 100644 index ea8a86dceaf4..000000000000 --- a/fs/partitions/sgi.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * fs/partitions/sgi.c - * - * Code extracted from drivers/block/genhd.c - */ - -#include "check.h" -#include "sgi.h" - -struct sgi_disklabel { - __be32 magic_mushroom; /* Big fat spliff... */ - __be16 root_part_num; /* Root partition number */ - __be16 swap_part_num; /* Swap partition number */ - s8 boot_file[16]; /* Name of boot file for ARCS */ - u8 _unused0[48]; /* Device parameter useless crapola.. */ - struct sgi_volume { - s8 name[8]; /* Name of volume */ - __be32 block_num; /* Logical block number */ - __be32 num_bytes; /* How big, in bytes */ - } volume[15]; - struct sgi_partition { - __be32 num_blocks; /* Size in logical blocks */ - __be32 first_block; /* First logical block */ - __be32 type; /* Type of this partition */ - } partitions[16]; - __be32 csum; /* Disk label checksum */ - __be32 _unused1; /* Padding */ -}; - -int sgi_partition(struct parsed_partitions *state) -{ - int i, csum; - __be32 magic; - int slot = 1; - unsigned int start, blocks; - __be32 *ui, cs; - Sector sect; - struct sgi_disklabel *label; - struct sgi_partition *p; - char b[BDEVNAME_SIZE]; - - label = read_part_sector(state, 0, §); - if (!label) - return -1; - p = &label->partitions[0]; - magic = label->magic_mushroom; - if(be32_to_cpu(magic) != SGI_LABEL_MAGIC) { - /*printk("Dev %s SGI disklabel: bad magic %08x\n", - bdevname(bdev, b), be32_to_cpu(magic));*/ - put_dev_sector(sect); - return 0; - } - ui = ((__be32 *) (label + 1)) - 1; - for(csum = 0; ui >= ((__be32 *) label);) { - cs = *ui--; - csum += be32_to_cpu(cs); - } - if(csum) { - printk(KERN_WARNING "Dev %s SGI disklabel: csum bad, label corrupted\n", - bdevname(state->bdev, b)); - put_dev_sector(sect); - return 0; - } - /* All SGI disk labels have 16 partitions, disks under Linux only - * have 15 minor's. Luckily there are always a few zero length - * partitions which we don't care about so we never overflow the - * current_minor. - */ - for(i = 0; i < 16; i++, p++) { - blocks = be32_to_cpu(p->num_blocks); - start = be32_to_cpu(p->first_block); - if (blocks) { - put_partition(state, slot, start, blocks); - if (be32_to_cpu(p->type) == LINUX_RAID_PARTITION) - state->parts[slot].flags = ADDPART_FLAG_RAID; - } - slot++; - } - strlcat(state->pp_buf, "\n", PAGE_SIZE); - put_dev_sector(sect); - return 1; -} diff --git a/fs/partitions/sgi.h b/fs/partitions/sgi.h deleted file mode 100644 index b9553ebdd5a9..000000000000 --- a/fs/partitions/sgi.h +++ /dev/null @@ -1,8 +0,0 @@ -/* - * fs/partitions/sgi.h - */ - -extern int sgi_partition(struct parsed_partitions *state); - -#define SGI_LABEL_MAGIC 0x0be5a941 - diff --git a/fs/partitions/sun.c b/fs/partitions/sun.c deleted file mode 100644 index b5b6fcfb3d36..000000000000 --- a/fs/partitions/sun.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * fs/partitions/sun.c - * - * Code extracted from drivers/block/genhd.c - * - * Copyright (C) 1991-1998 Linus Torvalds - * Re-organised Feb 1998 Russell King - */ - -#include "check.h" -#include "sun.h" - -int sun_partition(struct parsed_partitions *state) -{ - int i; - __be16 csum; - int slot = 1; - __be16 *ush; - Sector sect; - struct sun_disklabel { - unsigned char info[128]; /* Informative text string */ - struct sun_vtoc { - __be32 version; /* Layout version */ - char volume[8]; /* Volume name */ - __be16 nparts; /* Number of partitions */ - struct sun_info { /* Partition hdrs, sec 2 */ - __be16 id; - __be16 flags; - } infos[8]; - __be16 padding; /* Alignment padding */ - __be32 bootinfo[3]; /* Info needed by mboot */ - __be32 sanity; /* To verify vtoc sanity */ - __be32 reserved[10]; /* Free space */ - __be32 timestamp[8]; /* Partition timestamp */ - } vtoc; - __be32 write_reinstruct; /* sectors to skip, writes */ - __be32 read_reinstruct; /* sectors to skip, reads */ - unsigned char spare[148]; /* Padding */ - __be16 rspeed; /* Disk rotational speed */ - __be16 pcylcount; /* Physical cylinder count */ - __be16 sparecyl; /* extra sects per cylinder */ - __be16 obs1; /* gap1 */ - __be16 obs2; /* gap2 */ - __be16 ilfact; /* Interleave factor */ - __be16 ncyl; /* Data cylinder count */ - __be16 nacyl; /* Alt. cylinder count */ - __be16 ntrks; /* Tracks per cylinder */ - __be16 nsect; /* Sectors per track */ - __be16 obs3; /* bhead - Label head offset */ - __be16 obs4; /* ppart - Physical Partition */ - struct sun_partition { - __be32 start_cylinder; - __be32 num_sectors; - } partitions[8]; - __be16 magic; /* Magic number */ - __be16 csum; /* Label xor'd checksum */ - } * label; - struct sun_partition *p; - unsigned long spc; - char b[BDEVNAME_SIZE]; - int use_vtoc; - int nparts; - - label = read_part_sector(state, 0, §); - if (!label) - return -1; - - p = label->partitions; - if (be16_to_cpu(label->magic) != SUN_LABEL_MAGIC) { -/* printk(KERN_INFO "Dev %s Sun disklabel: bad magic %04x\n", - bdevname(bdev, b), be16_to_cpu(label->magic)); */ - put_dev_sector(sect); - return 0; - } - /* Look at the checksum */ - ush = ((__be16 *) (label+1)) - 1; - for (csum = 0; ush >= ((__be16 *) label);) - csum ^= *ush--; - if (csum) { - printk("Dev %s Sun disklabel: Csum bad, label corrupted\n", - bdevname(state->bdev, b)); - put_dev_sector(sect); - return 0; - } - - /* Check to see if we can use the VTOC table */ - use_vtoc = ((be32_to_cpu(label->vtoc.sanity) == SUN_VTOC_SANITY) && - (be32_to_cpu(label->vtoc.version) == 1) && - (be16_to_cpu(label->vtoc.nparts) <= 8)); - - /* Use 8 partition entries if not specified in validated VTOC */ - nparts = (use_vtoc) ? be16_to_cpu(label->vtoc.nparts) : 8; - - /* - * 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); - spc = be16_to_cpu(label->ntrks) * be16_to_cpu(label->nsect); - for (i = 0; i < nparts; i++, p++) { - unsigned long st_sector; - unsigned int num_sectors; - - st_sector = be32_to_cpu(p->start_cylinder) * spc; - num_sectors = be32_to_cpu(p->num_sectors); - if (num_sectors) { - put_partition(state, slot, st_sector, num_sectors); - state->parts[slot].flags = 0; - if (use_vtoc) { - if (be16_to_cpu(label->vtoc.infos[i].id) == LINUX_RAID_PARTITION) - state->parts[slot].flags |= ADDPART_FLAG_RAID; - else if (be16_to_cpu(label->vtoc.infos[i].id) == SUN_WHOLE_DISK) - state->parts[slot].flags |= ADDPART_FLAG_WHOLEDISK; - } - } - slot++; - } - strlcat(state->pp_buf, "\n", PAGE_SIZE); - put_dev_sector(sect); - return 1; -} diff --git a/fs/partitions/sun.h b/fs/partitions/sun.h deleted file mode 100644 index 2424baa8319f..000000000000 --- a/fs/partitions/sun.h +++ /dev/null @@ -1,8 +0,0 @@ -/* - * fs/partitions/sun.h - */ - -#define SUN_LABEL_MAGIC 0xDABE -#define SUN_VTOC_SANITY 0x600DDEEE - -int sun_partition(struct parsed_partitions *state); diff --git a/fs/partitions/sysv68.c b/fs/partitions/sysv68.c deleted file mode 100644 index 9627ccffc1c4..000000000000 --- a/fs/partitions/sysv68.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * fs/partitions/sysv68.c - * - * Copyright (C) 2007 Philippe De Muyter <phdm@macqel.be> - */ - -#include "check.h" -#include "sysv68.h" - -/* - * Volume ID structure: on first 256-bytes sector of disk - */ - -struct volumeid { - u8 vid_unused[248]; - u8 vid_mac[8]; /* ASCII string "MOTOROLA" */ -}; - -/* - * config block: second 256-bytes sector on disk - */ - -struct dkconfig { - u8 ios_unused0[128]; - __be32 ios_slcblk; /* Slice table block number */ - __be16 ios_slccnt; /* Number of entries in slice table */ - u8 ios_unused1[122]; -}; - -/* - * combined volumeid and dkconfig block - */ - -struct dkblk0 { - struct volumeid dk_vid; - struct dkconfig dk_ios; -}; - -/* - * Slice Table Structure - */ - -struct slice { - __be32 nblocks; /* slice size (in blocks) */ - __be32 blkoff; /* block offset of slice */ -}; - - -int sysv68_partition(struct parsed_partitions *state) -{ - int i, slices; - int slot = 1; - Sector sect; - unsigned char *data; - struct dkblk0 *b; - struct slice *slice; - char tmp[64]; - - data = read_part_sector(state, 0, §); - if (!data) - return -1; - - b = (struct dkblk0 *)data; - if (memcmp(b->dk_vid.vid_mac, "MOTOROLA", sizeof(b->dk_vid.vid_mac))) { - put_dev_sector(sect); - return 0; - } - slices = be16_to_cpu(b->dk_ios.ios_slccnt); - i = be32_to_cpu(b->dk_ios.ios_slcblk); - put_dev_sector(sect); - - data = read_part_sector(state, i, §); - if (!data) - return -1; - - slices -= 1; /* last slice is the whole disk */ - snprintf(tmp, sizeof(tmp), "sysV68: %s(s%u)", state->name, slices); - strlcat(state->pp_buf, tmp, PAGE_SIZE); - slice = (struct slice *)data; - for (i = 0; i < slices; i++, slice++) { - if (slot == state->limit) - break; - if (be32_to_cpu(slice->nblocks)) { - put_partition(state, slot, - be32_to_cpu(slice->blkoff), - be32_to_cpu(slice->nblocks)); - snprintf(tmp, sizeof(tmp), "(s%u)", i); - strlcat(state->pp_buf, tmp, PAGE_SIZE); - } - slot++; - } - strlcat(state->pp_buf, "\n", PAGE_SIZE); - put_dev_sector(sect); - return 1; -} diff --git a/fs/partitions/sysv68.h b/fs/partitions/sysv68.h deleted file mode 100644 index bf2f5ffa97ac..000000000000 --- a/fs/partitions/sysv68.h +++ /dev/null @@ -1 +0,0 @@ -extern int sysv68_partition(struct parsed_partitions *state); diff --git a/fs/partitions/ultrix.c b/fs/partitions/ultrix.c deleted file mode 100644 index 8dbaf9f77a99..000000000000 --- a/fs/partitions/ultrix.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * fs/partitions/ultrix.c - * - * Code extracted from drivers/block/genhd.c - * - * Re-organised Jul 1999 Russell King - */ - -#include "check.h" -#include "ultrix.h" - -int ultrix_partition(struct parsed_partitions *state) -{ - int i; - Sector sect; - unsigned char *data; - struct ultrix_disklabel { - s32 pt_magic; /* magic no. indicating part. info exits */ - s32 pt_valid; /* set by driver if pt is current */ - struct pt_info { - s32 pi_nblocks; /* no. of sectors */ - u32 pi_blkoff; /* block offset for start */ - } pt_part[8]; - } *label; - -#define PT_MAGIC 0x032957 /* Partition magic number */ -#define PT_VALID 1 /* Indicates if struct is valid */ - - data = read_part_sector(state, (16384 - sizeof(*label))/512, §); - if (!data) - return -1; - - label = (struct ultrix_disklabel *)(data + 512 - sizeof(*label)); - - if (label->pt_magic == PT_MAGIC && label->pt_valid == PT_VALID) { - for (i=0; i<8; i++) - if (label->pt_part[i].pi_nblocks) - put_partition(state, i+1, - label->pt_part[i].pi_blkoff, - label->pt_part[i].pi_nblocks); - put_dev_sector(sect); - strlcat(state->pp_buf, "\n", PAGE_SIZE); - return 1; - } else { - put_dev_sector(sect); - return 0; - } -} diff --git a/fs/partitions/ultrix.h b/fs/partitions/ultrix.h deleted file mode 100644 index a3cc00b2bded..000000000000 --- a/fs/partitions/ultrix.h +++ /dev/null @@ -1,5 +0,0 @@ -/* - * fs/partitions/ultrix.h - */ - -int ultrix_partition(struct parsed_partitions *state); diff --git a/fs/pipe.c b/fs/pipe.c index 4065f07366b3..f0e485d54e64 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -1290,11 +1290,4 @@ static int __init init_pipe_fs(void) return err; } -static void __exit exit_pipe_fs(void) -{ - kern_unmount(pipe_mnt); - unregister_filesystem(&pipe_fs_type); -} - fs_initcall(init_pipe_fs); -module_exit(exit_pipe_fs); diff --git a/fs/pnode.c b/fs/pnode.c index d42514e32380..ab5fa9e1a79a 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -13,45 +13,30 @@ #include "pnode.h" /* return the next shared peer mount of @p */ -static inline struct vfsmount *next_peer(struct vfsmount *p) +static inline struct mount *next_peer(struct mount *p) { - return list_entry(p->mnt_share.next, struct vfsmount, mnt_share); + return list_entry(p->mnt_share.next, struct mount, mnt_share); } -static inline struct vfsmount *first_slave(struct vfsmount *p) +static inline struct mount *first_slave(struct mount *p) { - return list_entry(p->mnt_slave_list.next, struct vfsmount, mnt_slave); + return list_entry(p->mnt_slave_list.next, struct mount, mnt_slave); } -static inline struct vfsmount *next_slave(struct vfsmount *p) +static inline struct mount *next_slave(struct mount *p) { - return list_entry(p->mnt_slave.next, struct vfsmount, mnt_slave); + return list_entry(p->mnt_slave.next, struct mount, mnt_slave); } -/* - * Return true if path is reachable from root - * - * namespace_sem is held, and mnt is attached - */ -static bool is_path_reachable(struct vfsmount *mnt, struct dentry *dentry, - const struct path *root) -{ - while (mnt != root->mnt && mnt->mnt_parent != mnt) { - dentry = mnt->mnt_mountpoint; - mnt = mnt->mnt_parent; - } - return mnt == root->mnt && is_subdir(dentry, root->dentry); -} - -static struct vfsmount *get_peer_under_root(struct vfsmount *mnt, - struct mnt_namespace *ns, - const struct path *root) +static struct mount *get_peer_under_root(struct mount *mnt, + struct mnt_namespace *ns, + const struct path *root) { - struct vfsmount *m = mnt; + struct mount *m = mnt; do { /* Check the namespace first for optimization */ - if (m->mnt_ns == ns && is_path_reachable(m, m->mnt_root, root)) + if (m->mnt_ns == ns && is_path_reachable(m, m->mnt.mnt_root, root)) return m; m = next_peer(m); @@ -66,12 +51,12 @@ static struct vfsmount *get_peer_under_root(struct vfsmount *mnt, * * Caller must hold namespace_sem */ -int get_dominating_id(struct vfsmount *mnt, const struct path *root) +int get_dominating_id(struct mount *mnt, const struct path *root) { - struct vfsmount *m; + struct mount *m; for (m = mnt->mnt_master; m != NULL; m = m->mnt_master) { - struct vfsmount *d = get_peer_under_root(m, mnt->mnt_ns, root); + struct mount *d = get_peer_under_root(m, mnt->mnt_ns, root); if (d) return d->mnt_group_id; } @@ -79,10 +64,10 @@ int get_dominating_id(struct vfsmount *mnt, const struct path *root) return 0; } -static int do_make_slave(struct vfsmount *mnt) +static int do_make_slave(struct mount *mnt) { - struct vfsmount *peer_mnt = mnt, *master = mnt->mnt_master; - struct vfsmount *slave_mnt; + struct mount *peer_mnt = mnt, *master = mnt->mnt_master; + struct mount *slave_mnt; /* * slave 'mnt' to a peer mount that has the @@ -90,7 +75,7 @@ static int do_make_slave(struct vfsmount *mnt) * slave it to anything that is available. */ while ((peer_mnt = next_peer(peer_mnt)) != mnt && - peer_mnt->mnt_root != mnt->mnt_root) ; + peer_mnt->mnt.mnt_root != mnt->mnt.mnt_root) ; if (peer_mnt == mnt) { peer_mnt = next_peer(mnt); @@ -116,7 +101,7 @@ static int do_make_slave(struct vfsmount *mnt) struct list_head *p = &mnt->mnt_slave_list; while (!list_empty(p)) { slave_mnt = list_first_entry(p, - struct vfsmount, mnt_slave); + struct mount, mnt_slave); list_del_init(&slave_mnt->mnt_slave); slave_mnt->mnt_master = NULL; } @@ -129,7 +114,7 @@ static int do_make_slave(struct vfsmount *mnt) /* * vfsmount lock must be held for write */ -void change_mnt_propagation(struct vfsmount *mnt, int type) +void change_mnt_propagation(struct mount *mnt, int type) { if (type == MS_SHARED) { set_mnt_shared(mnt); @@ -140,9 +125,9 @@ void change_mnt_propagation(struct vfsmount *mnt, int type) list_del_init(&mnt->mnt_slave); mnt->mnt_master = NULL; if (type == MS_UNBINDABLE) - mnt->mnt_flags |= MNT_UNBINDABLE; + mnt->mnt.mnt_flags |= MNT_UNBINDABLE; else - mnt->mnt_flags &= ~MNT_UNBINDABLE; + mnt->mnt.mnt_flags &= ~MNT_UNBINDABLE; } } @@ -156,20 +141,19 @@ void change_mnt_propagation(struct vfsmount *mnt, int type) * vfsmount found while iterating with propagation_next() is * a peer of one we'd found earlier. */ -static struct vfsmount *propagation_next(struct vfsmount *m, - struct vfsmount *origin) +static struct mount *propagation_next(struct mount *m, + struct mount *origin) { /* are there any slaves of this mount? */ if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list)) return first_slave(m); while (1) { - struct vfsmount *next; - struct vfsmount *master = m->mnt_master; + struct mount *master = m->mnt_master; if (master == origin->mnt_master) { - next = next_peer(m); - return ((next == origin) ? NULL : next); + struct mount *next = next_peer(m); + return (next == origin) ? NULL : next; } else if (m->mnt_slave.next != &master->mnt_slave_list) return next_slave(m); @@ -187,13 +171,13 @@ static struct vfsmount *propagation_next(struct vfsmount *m, * @type return CL_SLAVE if the new mount has to be * cloned as a slave. */ -static struct vfsmount *get_source(struct vfsmount *dest, - struct vfsmount *last_dest, - struct vfsmount *last_src, - int *type) +static struct mount *get_source(struct mount *dest, + struct mount *last_dest, + struct mount *last_src, + int *type) { - struct vfsmount *p_last_src = NULL; - struct vfsmount *p_last_dest = NULL; + struct mount *p_last_src = NULL; + struct mount *p_last_dest = NULL; while (last_dest != dest->mnt_master) { p_last_dest = last_dest; @@ -233,33 +217,33 @@ static struct vfsmount *get_source(struct vfsmount *dest, * @source_mnt: source mount. * @tree_list : list of heads of trees to be attached. */ -int propagate_mnt(struct vfsmount *dest_mnt, struct dentry *dest_dentry, - struct vfsmount *source_mnt, struct list_head *tree_list) +int propagate_mnt(struct mount *dest_mnt, struct dentry *dest_dentry, + struct mount *source_mnt, struct list_head *tree_list) { - struct vfsmount *m, *child; + struct mount *m, *child; int ret = 0; - struct vfsmount *prev_dest_mnt = dest_mnt; - struct vfsmount *prev_src_mnt = source_mnt; + struct mount *prev_dest_mnt = dest_mnt; + struct mount *prev_src_mnt = source_mnt; LIST_HEAD(tmp_list); LIST_HEAD(umount_list); for (m = propagation_next(dest_mnt, dest_mnt); m; m = propagation_next(m, dest_mnt)) { int type; - struct vfsmount *source; + struct mount *source; if (IS_MNT_NEW(m)) continue; source = get_source(m, prev_dest_mnt, prev_src_mnt, &type); - if (!(child = copy_tree(source, source->mnt_root, type))) { + if (!(child = copy_tree(source, source->mnt.mnt_root, type))) { ret = -ENOMEM; list_splice(tree_list, tmp_list.prev); goto out; } - if (is_subdir(dest_dentry, m->mnt_root)) { + if (is_subdir(dest_dentry, m->mnt.mnt_root)) { mnt_set_mountpoint(m, dest_dentry, child); list_add_tail(&child->mnt_hash, tree_list); } else { @@ -275,7 +259,7 @@ int propagate_mnt(struct vfsmount *dest_mnt, struct dentry *dest_dentry, out: br_write_lock(vfsmount_lock); while (!list_empty(&tmp_list)) { - child = list_first_entry(&tmp_list, struct vfsmount, mnt_hash); + child = list_first_entry(&tmp_list, struct mount, mnt_hash); umount_tree(child, 0, &umount_list); } br_write_unlock(vfsmount_lock); @@ -286,7 +270,7 @@ out: /* * return true if the refcount is greater than count */ -static inline int do_refcount_check(struct vfsmount *mnt, int count) +static inline int do_refcount_check(struct mount *mnt, int count) { int mycount = mnt_get_count(mnt) - mnt->mnt_ghosts; return (mycount > count); @@ -302,10 +286,10 @@ static inline int do_refcount_check(struct vfsmount *mnt, int count) * * vfsmount lock must be held for write */ -int propagate_mount_busy(struct vfsmount *mnt, int refcnt) +int propagate_mount_busy(struct mount *mnt, int refcnt) { - struct vfsmount *m, *child; - struct vfsmount *parent = mnt->mnt_parent; + struct mount *m, *child; + struct mount *parent = mnt->mnt_parent; int ret = 0; if (mnt == parent) @@ -321,7 +305,7 @@ int propagate_mount_busy(struct vfsmount *mnt, int refcnt) for (m = propagation_next(parent, parent); m; m = propagation_next(m, parent)) { - child = __lookup_mnt(m, mnt->mnt_mountpoint, 0); + child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint, 0); if (child && list_empty(&child->mnt_mounts) && (ret = do_refcount_check(child, 1))) break; @@ -333,17 +317,17 @@ int propagate_mount_busy(struct vfsmount *mnt, int refcnt) * NOTE: unmounting 'mnt' naturally propagates to all other mounts its * parent propagates to. */ -static void __propagate_umount(struct vfsmount *mnt) +static void __propagate_umount(struct mount *mnt) { - struct vfsmount *parent = mnt->mnt_parent; - struct vfsmount *m; + struct mount *parent = mnt->mnt_parent; + struct mount *m; BUG_ON(parent == mnt); for (m = propagation_next(parent, parent); m; m = propagation_next(m, parent)) { - struct vfsmount *child = __lookup_mnt(m, + struct mount *child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint, 0); /* * umount the child only if the child has no @@ -363,7 +347,7 @@ static void __propagate_umount(struct vfsmount *mnt) */ int propagate_umount(struct list_head *list) { - struct vfsmount *mnt; + struct mount *mnt; list_for_each_entry(mnt, list, mnt_hash) __propagate_umount(mnt); diff --git a/fs/pnode.h b/fs/pnode.h index 1ea4ae1efcd3..65c60979d541 100644 --- a/fs/pnode.h +++ b/fs/pnode.h @@ -9,13 +9,13 @@ #define _LINUX_PNODE_H #include <linux/list.h> -#include <linux/mount.h> +#include "mount.h" -#define IS_MNT_SHARED(mnt) (mnt->mnt_flags & MNT_SHARED) -#define IS_MNT_SLAVE(mnt) (mnt->mnt_master) -#define IS_MNT_NEW(mnt) (!mnt->mnt_ns) -#define CLEAR_MNT_SHARED(mnt) (mnt->mnt_flags &= ~MNT_SHARED) -#define IS_MNT_UNBINDABLE(mnt) (mnt->mnt_flags & MNT_UNBINDABLE) +#define IS_MNT_SHARED(m) ((m)->mnt.mnt_flags & MNT_SHARED) +#define IS_MNT_SLAVE(m) ((m)->mnt_master) +#define IS_MNT_NEW(m) (!(m)->mnt_ns) +#define CLEAR_MNT_SHARED(m) ((m)->mnt.mnt_flags &= ~MNT_SHARED) +#define IS_MNT_UNBINDABLE(m) ((m)->mnt.mnt_flags & MNT_UNBINDABLE) #define CL_EXPIRE 0x01 #define CL_SLAVE 0x02 @@ -23,17 +23,25 @@ #define CL_MAKE_SHARED 0x08 #define CL_PRIVATE 0x10 -static inline void set_mnt_shared(struct vfsmount *mnt) +static inline void set_mnt_shared(struct mount *mnt) { - mnt->mnt_flags &= ~MNT_SHARED_MASK; - mnt->mnt_flags |= MNT_SHARED; + mnt->mnt.mnt_flags &= ~MNT_SHARED_MASK; + mnt->mnt.mnt_flags |= MNT_SHARED; } -void change_mnt_propagation(struct vfsmount *, int); -int propagate_mnt(struct vfsmount *, struct dentry *, struct vfsmount *, +void change_mnt_propagation(struct mount *, int); +int propagate_mnt(struct mount *, struct dentry *, struct mount *, struct list_head *); int propagate_umount(struct list_head *); -int propagate_mount_busy(struct vfsmount *, int); -void mnt_release_group_id(struct vfsmount *); -int get_dominating_id(struct vfsmount *mnt, const struct path *root); +int propagate_mount_busy(struct mount *, int); +void mnt_release_group_id(struct mount *); +int get_dominating_id(struct mount *mnt, const struct path *root); +unsigned int mnt_get_count(struct mount *mnt); +void mnt_set_mountpoint(struct mount *, struct dentry *, + struct mount *); +void release_mounts(struct list_head *); +void umount_tree(struct mount *, int, struct list_head *); +struct mount *copy_tree(struct mount *, struct dentry *, int); +bool is_path_reachable(struct mount *, struct dentry *, + const struct path *root); #endif /* _LINUX_PNODE_H */ diff --git a/fs/proc/base.c b/fs/proc/base.c index 851ba3dcdc29..a1dddda999f2 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -101,7 +101,7 @@ struct pid_entry { char *name; int len; - mode_t mode; + umode_t mode; const struct inode_operations *iop; const struct file_operations *fop; union proc_op op; @@ -631,120 +631,6 @@ static const struct inode_operations proc_def_inode_operations = { .setattr = proc_setattr, }; -static int mounts_open_common(struct inode *inode, struct file *file, - const struct seq_operations *op) -{ - struct task_struct *task = get_proc_task(inode); - struct nsproxy *nsp; - struct mnt_namespace *ns = NULL; - struct path root; - struct proc_mounts *p; - int ret = -EINVAL; - - if (task) { - rcu_read_lock(); - nsp = task_nsproxy(task); - if (nsp) { - ns = nsp->mnt_ns; - if (ns) - get_mnt_ns(ns); - } - rcu_read_unlock(); - if (ns && get_task_root(task, &root) == 0) - ret = 0; - put_task_struct(task); - } - - if (!ns) - goto err; - if (ret) - goto err_put_ns; - - ret = -ENOMEM; - p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); - if (!p) - goto err_put_path; - - file->private_data = &p->m; - ret = seq_open(file, op); - if (ret) - goto err_free; - - p->m.private = p; - p->ns = ns; - p->root = root; - p->m.poll_event = ns->event; - - return 0; - - err_free: - kfree(p); - err_put_path: - path_put(&root); - err_put_ns: - put_mnt_ns(ns); - err: - return ret; -} - -static int mounts_release(struct inode *inode, struct file *file) -{ - struct proc_mounts *p = file->private_data; - path_put(&p->root); - put_mnt_ns(p->ns); - return seq_release(inode, file); -} - -static unsigned mounts_poll(struct file *file, poll_table *wait) -{ - struct proc_mounts *p = file->private_data; - unsigned res = POLLIN | POLLRDNORM; - - poll_wait(file, &p->ns->poll, wait); - if (mnt_had_events(p)) - res |= POLLERR | POLLPRI; - - return res; -} - -static int mounts_open(struct inode *inode, struct file *file) -{ - return mounts_open_common(inode, file, &mounts_op); -} - -static const struct file_operations proc_mounts_operations = { - .open = mounts_open, - .read = seq_read, - .llseek = seq_lseek, - .release = mounts_release, - .poll = mounts_poll, -}; - -static int mountinfo_open(struct inode *inode, struct file *file) -{ - return mounts_open_common(inode, file, &mountinfo_op); -} - -static const struct file_operations proc_mountinfo_operations = { - .open = mountinfo_open, - .read = seq_read, - .llseek = seq_lseek, - .release = mounts_release, - .poll = mounts_poll, -}; - -static int mountstats_open(struct inode *inode, struct file *file) -{ - return mounts_open_common(inode, file, &mountstats_op); -} - -static const struct file_operations proc_mountstats_operations = { - .open = mountstats_open, - .read = seq_read, - .llseek = seq_lseek, - .release = mounts_release, -}; - #define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */ static ssize_t proc_info_read(struct file * file, char __user * buf, diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 10090d9c7ad5..2edf34f2eb61 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -597,7 +597,7 @@ static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent, const char *name, - mode_t mode, + umode_t mode, nlink_t nlink) { struct proc_dir_entry *ent = NULL; @@ -659,7 +659,7 @@ struct proc_dir_entry *proc_symlink(const char *name, } EXPORT_SYMBOL(proc_symlink); -struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode, +struct proc_dir_entry *proc_mkdir_mode(const char *name, umode_t mode, struct proc_dir_entry *parent) { struct proc_dir_entry *ent; @@ -699,7 +699,7 @@ struct proc_dir_entry *proc_mkdir(const char *name, } EXPORT_SYMBOL(proc_mkdir); -struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, +struct proc_dir_entry *create_proc_entry(const char *name, umode_t mode, struct proc_dir_entry *parent) { struct proc_dir_entry *ent; @@ -728,7 +728,7 @@ struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, } EXPORT_SYMBOL(create_proc_entry); -struct proc_dir_entry *proc_create_data(const char *name, mode_t mode, +struct proc_dir_entry *proc_create_data(const char *name, umode_t mode, struct proc_dir_entry *parent, const struct file_operations *proc_fops, void *data) diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 7737c5468a40..51a176622b8f 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -77,7 +77,6 @@ static struct inode *proc_alloc_inode(struct super_block *sb) static void proc_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(proc_inode_cachep, PROC_I(inode)); } diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c index be177f702acb..27da860115c6 100644 --- a/fs/proc/namespaces.c +++ b/fs/proc/namespaces.c @@ -9,7 +9,6 @@ #include <linux/file.h> #include <linux/utsname.h> #include <net/net_namespace.h> -#include <linux/mnt_namespace.h> #include <linux/ipc_namespace.h> #include <linux/pid_namespace.h> #include "internal.h" diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c index f738024ccc8e..06e1cc17caf6 100644 --- a/fs/proc/proc_net.c +++ b/fs/proc/proc_net.c @@ -179,7 +179,7 @@ const struct file_operations proc_net_operations = { struct proc_dir_entry *proc_net_fops_create(struct net *net, - const char *name, mode_t mode, const struct file_operations *fops) + const char *name, umode_t mode, const struct file_operations *fops) { return proc_create(name, mode, net->proc_net, fops); } diff --git a/fs/proc_namespace.c b/fs/proc_namespace.c new file mode 100644 index 000000000000..12412852d88a --- /dev/null +++ b/fs/proc_namespace.c @@ -0,0 +1,333 @@ +/* + * fs/proc_namespace.c - handling of /proc/<pid>/{mounts,mountinfo,mountstats} + * + * In fact, that's a piece of procfs; it's *almost* isolated from + * the rest of fs/proc, but has rather close relationships with + * fs/namespace.c, thus here instead of fs/proc + * + */ +#include <linux/mnt_namespace.h> +#include <linux/nsproxy.h> +#include <linux/security.h> +#include <linux/fs_struct.h> +#include "proc/internal.h" /* only for get_proc_task() in ->open() */ + +#include "pnode.h" +#include "internal.h" + +static unsigned mounts_poll(struct file *file, poll_table *wait) +{ + struct proc_mounts *p = file->private_data; + struct mnt_namespace *ns = p->ns; + unsigned res = POLLIN | POLLRDNORM; + + poll_wait(file, &p->ns->poll, wait); + + br_read_lock(vfsmount_lock); + if (p->m.poll_event != ns->event) { + p->m.poll_event = ns->event; + res |= POLLERR | POLLPRI; + } + br_read_unlock(vfsmount_lock); + + return res; +} + +struct proc_fs_info { + int flag; + const char *str; +}; + +static int show_sb_opts(struct seq_file *m, struct super_block *sb) +{ + static const struct proc_fs_info fs_info[] = { + { MS_SYNCHRONOUS, ",sync" }, + { MS_DIRSYNC, ",dirsync" }, + { MS_MANDLOCK, ",mand" }, + { 0, NULL } + }; + const struct proc_fs_info *fs_infop; + + for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { + if (sb->s_flags & fs_infop->flag) + seq_puts(m, fs_infop->str); + } + + return security_sb_show_options(m, sb); +} + +static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt) +{ + static const struct proc_fs_info mnt_info[] = { + { MNT_NOSUID, ",nosuid" }, + { MNT_NODEV, ",nodev" }, + { MNT_NOEXEC, ",noexec" }, + { MNT_NOATIME, ",noatime" }, + { MNT_NODIRATIME, ",nodiratime" }, + { MNT_RELATIME, ",relatime" }, + { 0, NULL } + }; + const struct proc_fs_info *fs_infop; + + for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) { + if (mnt->mnt_flags & fs_infop->flag) + seq_puts(m, fs_infop->str); + } +} + +static inline void mangle(struct seq_file *m, const char *s) +{ + seq_escape(m, s, " \t\n\\"); +} + +static void show_type(struct seq_file *m, struct super_block *sb) +{ + mangle(m, sb->s_type->name); + if (sb->s_subtype && sb->s_subtype[0]) { + seq_putc(m, '.'); + mangle(m, sb->s_subtype); + } +} + +static int show_vfsmnt(struct seq_file *m, struct vfsmount *mnt) +{ + struct mount *r = real_mount(mnt); + int err = 0; + struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; + struct super_block *sb = mnt_path.dentry->d_sb; + + if (sb->s_op->show_devname) { + err = sb->s_op->show_devname(m, mnt_path.dentry); + if (err) + goto out; + } else { + mangle(m, r->mnt_devname ? r->mnt_devname : "none"); + } + seq_putc(m, ' '); + seq_path(m, &mnt_path, " \t\n\\"); + seq_putc(m, ' '); + show_type(m, sb); + seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw"); + err = show_sb_opts(m, sb); + if (err) + goto out; + show_mnt_opts(m, mnt); + if (sb->s_op->show_options) + err = sb->s_op->show_options(m, mnt_path.dentry); + seq_puts(m, " 0 0\n"); +out: + return err; +} + +static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt) +{ + struct proc_mounts *p = m->private; + struct mount *r = real_mount(mnt); + struct super_block *sb = mnt->mnt_sb; + struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; + struct path root = p->root; + int err = 0; + + seq_printf(m, "%i %i %u:%u ", r->mnt_id, r->mnt_parent->mnt_id, + MAJOR(sb->s_dev), MINOR(sb->s_dev)); + if (sb->s_op->show_path) + err = sb->s_op->show_path(m, mnt->mnt_root); + else + seq_dentry(m, mnt->mnt_root, " \t\n\\"); + if (err) + goto out; + seq_putc(m, ' '); + + /* mountpoints outside of chroot jail will give SEQ_SKIP on this */ + err = seq_path_root(m, &mnt_path, &root, " \t\n\\"); + if (err) + goto out; + + seq_puts(m, mnt->mnt_flags & MNT_READONLY ? " ro" : " rw"); + show_mnt_opts(m, mnt); + + /* Tagged fields ("foo:X" or "bar") */ + if (IS_MNT_SHARED(r)) + seq_printf(m, " shared:%i", r->mnt_group_id); + if (IS_MNT_SLAVE(r)) { + int master = r->mnt_master->mnt_group_id; + int dom = get_dominating_id(r, &p->root); + seq_printf(m, " master:%i", master); + if (dom && dom != master) + seq_printf(m, " propagate_from:%i", dom); + } + if (IS_MNT_UNBINDABLE(r)) + seq_puts(m, " unbindable"); + + /* Filesystem specific data */ + seq_puts(m, " - "); + show_type(m, sb); + seq_putc(m, ' '); + if (sb->s_op->show_devname) + err = sb->s_op->show_devname(m, mnt->mnt_root); + else + mangle(m, r->mnt_devname ? r->mnt_devname : "none"); + if (err) + goto out; + seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw"); + err = show_sb_opts(m, sb); + if (err) + goto out; + if (sb->s_op->show_options) + err = sb->s_op->show_options(m, mnt->mnt_root); + seq_putc(m, '\n'); +out: + return err; +} + +static int show_vfsstat(struct seq_file *m, struct vfsmount *mnt) +{ + struct mount *r = real_mount(mnt); + struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; + struct super_block *sb = mnt_path.dentry->d_sb; + int err = 0; + + /* device */ + if (sb->s_op->show_devname) { + seq_puts(m, "device "); + err = sb->s_op->show_devname(m, mnt_path.dentry); + } else { + if (r->mnt_devname) { + seq_puts(m, "device "); + mangle(m, r->mnt_devname); + } else + seq_puts(m, "no device"); + } + + /* mount point */ + seq_puts(m, " mounted on "); + seq_path(m, &mnt_path, " \t\n\\"); + seq_putc(m, ' '); + + /* file system type */ + seq_puts(m, "with fstype "); + show_type(m, sb); + + /* optional statistics */ + if (sb->s_op->show_stats) { + seq_putc(m, ' '); + if (!err) + err = sb->s_op->show_stats(m, mnt_path.dentry); + } + + seq_putc(m, '\n'); + return err; +} + +static int mounts_open_common(struct inode *inode, struct file *file, + int (*show)(struct seq_file *, struct vfsmount *)) +{ + struct task_struct *task = get_proc_task(inode); + struct nsproxy *nsp; + struct mnt_namespace *ns = NULL; + struct path root; + struct proc_mounts *p; + int ret = -EINVAL; + + if (!task) + goto err; + + rcu_read_lock(); + nsp = task_nsproxy(task); + if (!nsp) { + rcu_read_unlock(); + put_task_struct(task); + goto err; + } + ns = nsp->mnt_ns; + if (!ns) { + rcu_read_unlock(); + put_task_struct(task); + goto err; + } + get_mnt_ns(ns); + rcu_read_unlock(); + task_lock(task); + if (!task->fs) { + task_unlock(task); + put_task_struct(task); + ret = -ENOENT; + goto err_put_ns; + } + get_fs_root(task->fs, &root); + task_unlock(task); + put_task_struct(task); + + ret = -ENOMEM; + p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); + if (!p) + goto err_put_path; + + file->private_data = &p->m; + ret = seq_open(file, &mounts_op); + if (ret) + goto err_free; + + p->m.private = p; + p->ns = ns; + p->root = root; + p->m.poll_event = ns->event; + p->show = show; + + return 0; + + err_free: + kfree(p); + err_put_path: + path_put(&root); + err_put_ns: + put_mnt_ns(ns); + err: + return ret; +} + +static int mounts_release(struct inode *inode, struct file *file) +{ + struct proc_mounts *p = file->private_data; + path_put(&p->root); + put_mnt_ns(p->ns); + return seq_release(inode, file); +} + +static int mounts_open(struct inode *inode, struct file *file) +{ + return mounts_open_common(inode, file, show_vfsmnt); +} + +static int mountinfo_open(struct inode *inode, struct file *file) +{ + return mounts_open_common(inode, file, show_mountinfo); +} + +static int mountstats_open(struct inode *inode, struct file *file) +{ + return mounts_open_common(inode, file, show_vfsstat); +} + +const struct file_operations proc_mounts_operations = { + .open = mounts_open, + .read = seq_read, + .llseek = seq_lseek, + .release = mounts_release, + .poll = mounts_poll, +}; + +const struct file_operations proc_mountinfo_operations = { + .open = mountinfo_open, + .read = seq_read, + .llseek = seq_lseek, + .release = mounts_release, + .poll = mounts_poll, +}; + +const struct file_operations proc_mountstats_operations = { + .open = mountstats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = mounts_release, +}; diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 3bdd21418432..b90c7967fcae 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -427,7 +427,6 @@ static struct inode *qnx4_alloc_inode(struct super_block *sb) static void qnx4_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(qnx4_inode_cachep, qnx4_i(inode)); } diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 5b572c89e6c4..5ec59b20cf76 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -73,7 +73,6 @@ #include <linux/security.h> #include <linux/kmod.h> #include <linux/namei.h> -#include <linux/buffer_head.h> #include <linux/capability.h> #include <linux/quotaops.h> #include "../internal.h" /* ugh */ @@ -2199,7 +2198,7 @@ int dquot_quota_on(struct super_block *sb, int type, int format_id, if (error) return error; /* Quota file not on the same filesystem? */ - if (path->mnt->mnt_sb != sb) + if (path->dentry->d_sb != sb) error = -EXDEV; else error = vfs_load_quota_inode(path->dentry->d_inode, type, diff --git a/fs/quota/quota.c b/fs/quota/quota.c index 35f4b0ecdeb3..7898cd688a00 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -13,7 +13,6 @@ #include <linux/kernel.h> #include <linux/security.h> #include <linux/syscalls.h> -#include <linux/buffer_head.h> #include <linux/capability.h> #include <linux/quotaops.h> #include <linux/types.h> diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index 462ceb38fec6..aec766abe3af 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -52,7 +52,7 @@ static struct backing_dev_info ramfs_backing_dev_info = { }; struct inode *ramfs_get_inode(struct super_block *sb, - const struct inode *dir, int mode, dev_t dev) + const struct inode *dir, umode_t mode, dev_t dev) { struct inode * inode = new_inode(sb); @@ -92,7 +92,7 @@ struct inode *ramfs_get_inode(struct super_block *sb, */ /* SMP-safe */ static int -ramfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) +ramfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) { struct inode * inode = ramfs_get_inode(dir->i_sb, dir, mode, dev); int error = -ENOSPC; @@ -106,7 +106,7 @@ ramfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) return error; } -static int ramfs_mkdir(struct inode * dir, struct dentry * dentry, int mode) +static int ramfs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode) { int retval = ramfs_mknod(dir, dentry, mode | S_IFDIR, 0); if (!retval) @@ -114,7 +114,7 @@ static int ramfs_mkdir(struct inode * dir, struct dentry * dentry, int mode) return retval; } -static int ramfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) +static int ramfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { return ramfs_mknod(dir, dentry, mode | S_IFREG, 0); } diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c index d1aca1df4f92..a945cd265228 100644 --- a/fs/reiserfs/bitmap.c +++ b/fs/reiserfs/bitmap.c @@ -13,6 +13,7 @@ #include <linux/reiserfs_fs_sb.h> #include <linux/reiserfs_fs_i.h> #include <linux/quotaops.h> +#include <linux/seq_file.h> #define PREALLOCATION_SIZE 9 @@ -634,6 +635,96 @@ int reiserfs_parse_alloc_options(struct super_block *s, char *options) return 0; } +static void print_sep(struct seq_file *seq, int *first) +{ + if (!*first) + seq_puts(seq, ":"); + else + *first = 0; +} + +void show_alloc_options(struct seq_file *seq, struct super_block *s) +{ + int first = 1; + + if (SB_ALLOC_OPTS(s) == ((1 << _ALLOC_skip_busy) | + (1 << _ALLOC_dirid_groups) | (1 << _ALLOC_packing_groups))) + return; + + seq_puts(seq, ",alloc="); + + if (TEST_OPTION(concentrating_formatted_nodes, s)) { + print_sep(seq, &first); + if (REISERFS_SB(s)->s_alloc_options.border != 10) { + seq_printf(seq, "concentrating_formatted_nodes=%d", + 100 / REISERFS_SB(s)->s_alloc_options.border); + } else + seq_puts(seq, "concentrating_formatted_nodes"); + } + if (TEST_OPTION(displacing_large_files, s)) { + print_sep(seq, &first); + if (REISERFS_SB(s)->s_alloc_options.large_file_size != 16) { + seq_printf(seq, "displacing_large_files=%lu", + REISERFS_SB(s)->s_alloc_options.large_file_size); + } else + seq_puts(seq, "displacing_large_files"); + } + if (TEST_OPTION(displacing_new_packing_localities, s)) { + print_sep(seq, &first); + seq_puts(seq, "displacing_new_packing_localities"); + } + if (TEST_OPTION(old_hashed_relocation, s)) { + print_sep(seq, &first); + seq_puts(seq, "old_hashed_relocation"); + } + if (TEST_OPTION(new_hashed_relocation, s)) { + print_sep(seq, &first); + seq_puts(seq, "new_hashed_relocation"); + } + if (TEST_OPTION(dirid_groups, s)) { + print_sep(seq, &first); + seq_puts(seq, "dirid_groups"); + } + if (TEST_OPTION(oid_groups, s)) { + print_sep(seq, &first); + seq_puts(seq, "oid_groups"); + } + if (TEST_OPTION(packing_groups, s)) { + print_sep(seq, &first); + seq_puts(seq, "packing_groups"); + } + if (TEST_OPTION(hashed_formatted_nodes, s)) { + print_sep(seq, &first); + seq_puts(seq, "hashed_formatted_nodes"); + } + if (TEST_OPTION(skip_busy, s)) { + print_sep(seq, &first); + seq_puts(seq, "skip_busy"); + } + if (TEST_OPTION(hundredth_slices, s)) { + print_sep(seq, &first); + seq_puts(seq, "hundredth_slices"); + } + if (TEST_OPTION(old_way, s)) { + print_sep(seq, &first); + seq_puts(seq, "old_way"); + } + if (TEST_OPTION(displace_based_on_dirid, s)) { + print_sep(seq, &first); + seq_puts(seq, "displace_based_on_dirid"); + } + if (REISERFS_SB(s)->s_alloc_options.preallocmin != 0) { + print_sep(seq, &first); + seq_printf(seq, "preallocmin=%d", + REISERFS_SB(s)->s_alloc_options.preallocmin); + } + if (REISERFS_SB(s)->s_alloc_options.preallocsize != 17) { + print_sep(seq, &first); + seq_printf(seq, "preallocsize=%d", + REISERFS_SB(s)->s_alloc_options.preallocsize); + } +} + static inline void new_hashed_relocation(reiserfs_blocknr_hint_t * hint) { char *hash_in; diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 950f13af0951..9e8cd5acd79c 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -1766,7 +1766,7 @@ static int reiserfs_new_symlink(struct reiserfs_transaction_handle *th, struct i for the fresh inode. This can only be done outside a transaction, so if we return non-zero, we also end the transaction. */ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, - struct inode *dir, int mode, const char *symname, + struct inode *dir, umode_t mode, const char *symname, /* 0 for regular, EMTRY_DIR_SIZE for dirs, strlen (symname) for symlinks) */ loff_t i_size, struct dentry *dentry, diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c index 4e153051bc75..950e3d1b5c9e 100644 --- a/fs/reiserfs/ioctl.c +++ b/fs/reiserfs/ioctl.c @@ -55,7 +55,7 @@ long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) break; } - err = mnt_want_write(filp->f_path.mnt); + err = mnt_want_write_file(filp); if (err) break; @@ -96,7 +96,7 @@ long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); setflags_out: - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); break; } case REISERFS_IOC_GETVERSION: @@ -107,7 +107,7 @@ setflags_out: err = -EPERM; break; } - err = mnt_want_write(filp->f_path.mnt); + err = mnt_want_write_file(filp); if (err) break; if (get_user(inode->i_generation, (int __user *)arg)) { @@ -117,7 +117,7 @@ setflags_out: inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); setversion_out: - mnt_drop_write(filp->f_path.mnt); + mnt_drop_write_file(filp); break; default: err = -ENOTTY; diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index 80058e8ce361..146378865239 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -559,7 +559,7 @@ static int drop_new_inode(struct inode *inode) ** outside of a transaction, so we had to pull some bits of ** reiserfs_new_inode out into this func. */ -static int new_inode_init(struct inode *inode, struct inode *dir, int mode) +static int new_inode_init(struct inode *inode, struct inode *dir, umode_t mode) { /* Make inode invalid - just in case we are going to drop it before * the initialization happens */ @@ -572,7 +572,7 @@ static int new_inode_init(struct inode *inode, struct inode *dir, int mode) return 0; } -static int reiserfs_create(struct inode *dir, struct dentry *dentry, int mode, +static int reiserfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { int retval; @@ -643,7 +643,7 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, int mode, return retval; } -static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode, +static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { int retval; @@ -721,7 +721,7 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode, return retval; } -static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { int retval; struct inode *inode; diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 14363b96b6af..19c454e61b79 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -28,6 +28,7 @@ #include <linux/mount.h> #include <linux/namei.h> #include <linux/crc32.h> +#include <linux/seq_file.h> struct file_system_type reiserfs_fs_type; @@ -61,6 +62,7 @@ static int is_any_reiserfs_magic_string(struct reiserfs_super_block *rs) static int reiserfs_remount(struct super_block *s, int *flags, char *data); static int reiserfs_statfs(struct dentry *dentry, struct kstatfs *buf); +void show_alloc_options(struct seq_file *seq, struct super_block *s); static int reiserfs_sync_fs(struct super_block *s, int wait) { @@ -532,7 +534,6 @@ static struct inode *reiserfs_alloc_inode(struct super_block *sb) static void reiserfs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(reiserfs_inode_cachep, REISERFS_I(inode)); } @@ -597,6 +598,82 @@ out: reiserfs_write_unlock_once(inode->i_sb, lock_depth); } +static int reiserfs_show_options(struct seq_file *seq, struct dentry *root) +{ + struct super_block *s = root->d_sb; + struct reiserfs_journal *journal = SB_JOURNAL(s); + long opts = REISERFS_SB(s)->s_mount_opt; + + if (opts & (1 << REISERFS_LARGETAIL)) + seq_puts(seq, ",tails=on"); + else if (!(opts & (1 << REISERFS_SMALLTAIL))) + seq_puts(seq, ",notail"); + /* tails=small is default so we don't show it */ + + if (!(opts & (1 << REISERFS_BARRIER_FLUSH))) + seq_puts(seq, ",barrier=none"); + /* barrier=flush is default so we don't show it */ + + if (opts & (1 << REISERFS_ERROR_CONTINUE)) + seq_puts(seq, ",errors=continue"); + else if (opts & (1 << REISERFS_ERROR_PANIC)) + seq_puts(seq, ",errors=panic"); + /* errors=ro is default so we don't show it */ + + if (opts & (1 << REISERFS_DATA_LOG)) + seq_puts(seq, ",data=journal"); + else if (opts & (1 << REISERFS_DATA_WRITEBACK)) + seq_puts(seq, ",data=writeback"); + /* data=ordered is default so we don't show it */ + + if (opts & (1 << REISERFS_ATTRS)) + seq_puts(seq, ",attrs"); + + if (opts & (1 << REISERFS_XATTRS_USER)) + seq_puts(seq, ",user_xattr"); + + if (opts & (1 << REISERFS_EXPOSE_PRIVROOT)) + seq_puts(seq, ",expose_privroot"); + + if (opts & (1 << REISERFS_POSIXACL)) + seq_puts(seq, ",acl"); + + if (REISERFS_SB(s)->s_jdev) + seq_printf(seq, ",jdev=%s", REISERFS_SB(s)->s_jdev); + + if (journal->j_max_commit_age != journal->j_default_max_commit_age) + seq_printf(seq, ",commit=%d", journal->j_max_commit_age); + +#ifdef CONFIG_QUOTA + if (REISERFS_SB(s)->s_qf_names[USRQUOTA]) + seq_printf(seq, ",usrjquota=%s", REISERFS_SB(s)->s_qf_names[USRQUOTA]); + else if (opts & (1 << REISERFS_USRQUOTA)) + seq_puts(seq, ",usrquota"); + if (REISERFS_SB(s)->s_qf_names[GRPQUOTA]) + seq_printf(seq, ",grpjquota=%s", REISERFS_SB(s)->s_qf_names[GRPQUOTA]); + else if (opts & (1 << REISERFS_GRPQUOTA)) + seq_puts(seq, ",grpquota"); + if (REISERFS_SB(s)->s_jquota_fmt) { + if (REISERFS_SB(s)->s_jquota_fmt == QFMT_VFS_OLD) + seq_puts(seq, ",jqfmt=vfsold"); + else if (REISERFS_SB(s)->s_jquota_fmt == QFMT_VFS_V0) + seq_puts(seq, ",jqfmt=vfsv0"); + } +#endif + + /* Block allocator options */ + if (opts & (1 << REISERFS_NO_BORDER)) + seq_puts(seq, ",block-allocator=noborder"); + if (opts & (1 << REISERFS_NO_UNHASHED_RELOCATION)) + seq_puts(seq, ",block-allocator=no_unhashed_relocation"); + if (opts & (1 << REISERFS_HASHED_RELOCATION)) + seq_puts(seq, ",block-allocator=hashed_relocation"); + if (opts & (1 << REISERFS_TEST4)) + seq_puts(seq, ",block-allocator=test4"); + show_alloc_options(seq, s); + return 0; +} + #ifdef CONFIG_QUOTA static ssize_t reiserfs_quota_write(struct super_block *, int, const char *, size_t, loff_t); @@ -617,7 +694,7 @@ static const struct super_operations reiserfs_sops = { .unfreeze_fs = reiserfs_unfreeze, .statfs = reiserfs_statfs, .remount_fs = reiserfs_remount, - .show_options = generic_show_options, + .show_options = reiserfs_show_options, #ifdef CONFIG_QUOTA .quota_read = reiserfs_quota_read, .quota_write = reiserfs_quota_write, @@ -915,9 +992,9 @@ static int reiserfs_parse_options(struct super_block *s, char *options, /* strin {"jdev",.arg_required = 'j',.values = NULL}, {"nolargeio",.arg_required = 'w',.values = NULL}, {"commit",.arg_required = 'c',.values = NULL}, - {"usrquota",.setmask = 1 << REISERFS_QUOTA}, - {"grpquota",.setmask = 1 << REISERFS_QUOTA}, - {"noquota",.clrmask = 1 << REISERFS_QUOTA}, + {"usrquota",.setmask = 1 << REISERFS_USRQUOTA}, + {"grpquota",.setmask = 1 << REISERFS_GRPQUOTA}, + {"noquota",.clrmask = 1 << REISERFS_USRQUOTA | 1 << REISERFS_GRPQUOTA}, {"errors",.arg_required = 'e',.values = error_actions}, {"usrjquota",.arg_required = 'u' | (1 << REISERFS_OPT_ALLOWEMPTY),.values = NULL}, @@ -1031,12 +1108,19 @@ static int reiserfs_parse_options(struct super_block *s, char *options, /* strin return 0; } strcpy(qf_names[qtype], arg); - *mount_options |= 1 << REISERFS_QUOTA; + if (qtype == USRQUOTA) + *mount_options |= 1 << REISERFS_USRQUOTA; + else + *mount_options |= 1 << REISERFS_GRPQUOTA; } else { if (qf_names[qtype] != REISERFS_SB(s)->s_qf_names[qtype]) kfree(qf_names[qtype]); qf_names[qtype] = NULL; + if (qtype == USRQUOTA) + *mount_options &= ~(1 << REISERFS_USRQUOTA); + else + *mount_options &= ~(1 << REISERFS_GRPQUOTA); } } if (c == 'f') { @@ -1075,9 +1159,10 @@ static int reiserfs_parse_options(struct super_block *s, char *options, /* strin "journaled quota format not specified."); return 0; } - /* This checking is not precise wrt the quota type but for our purposes it is sufficient */ - if (!(*mount_options & (1 << REISERFS_QUOTA)) - && sb_any_quota_loaded(s)) { + if ((!(*mount_options & (1 << REISERFS_USRQUOTA)) && + sb_has_quota_loaded(s, USRQUOTA)) || + (!(*mount_options & (1 << REISERFS_GRPQUOTA)) && + sb_has_quota_loaded(s, GRPQUOTA))) { reiserfs_warning(s, "super-6516", "quota options must " "be present when quota is turned on."); return 0; @@ -1225,7 +1310,8 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) safe_mask |= 1 << REISERFS_ERROR_RO; safe_mask |= 1 << REISERFS_ERROR_CONTINUE; safe_mask |= 1 << REISERFS_ERROR_PANIC; - safe_mask |= 1 << REISERFS_QUOTA; + safe_mask |= 1 << REISERFS_USRQUOTA; + safe_mask |= 1 << REISERFS_GRPQUOTA; /* Update the bitmask, taking care to keep * the bits we're not allowed to change here */ @@ -1672,6 +1758,14 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) &commit_max_age, qf_names, &qfmt) == 0) { goto error; } + if (jdev_name && jdev_name[0]) { + REISERFS_SB(s)->s_jdev = kstrdup(jdev_name, GFP_KERNEL); + if (!REISERFS_SB(s)->s_jdev) { + SWARN(silent, s, "", "Cannot allocate memory for " + "journal device name"); + goto error; + } + } #ifdef CONFIG_QUOTA handle_quota_files(s, qf_names, &qfmt); #endif @@ -2054,12 +2148,13 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, int err; struct inode *inode; struct reiserfs_transaction_handle th; + int opt = type == USRQUOTA ? REISERFS_USRQUOTA : REISERFS_GRPQUOTA; - if (!(REISERFS_SB(sb)->s_mount_opt & (1 << REISERFS_QUOTA))) + if (!(REISERFS_SB(sb)->s_mount_opt & (1 << opt))) return -EINVAL; /* Quotafile not on the same filesystem? */ - if (path->mnt->mnt_sb != sb) { + if (path->dentry->d_sb != sb) { err = -EXDEV; goto out; } diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index 6bc346c160e7..c24deda8a8bc 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -66,7 +66,7 @@ static int xattr_create(struct inode *dir, struct dentry *dentry, int mode) } #endif -static int xattr_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int xattr_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { BUG_ON(!mutex_is_locked(&dir->i_mutex)); return dir->i_op->mkdir(dir, dentry, mode); diff --git a/fs/romfs/super.c b/fs/romfs/super.c index 8b4089f30408..bb36ab74eb45 100644 --- a/fs/romfs/super.c +++ b/fs/romfs/super.c @@ -403,7 +403,6 @@ static struct inode *romfs_alloc_inode(struct super_block *sb) static void romfs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(romfs_inode_cachep, ROMFS_I(inode)); } diff --git a/fs/seq_file.c b/fs/seq_file.c index dba43c3ea3af..4023d6be939b 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -397,7 +397,7 @@ EXPORT_SYMBOL(seq_printf); * Returns pointer past last written character in @s, or NULL in case of * failure. */ -char *mangle_path(char *s, char *p, char *esc) +char *mangle_path(char *s, const char *p, const char *esc) { while (s <= p) { char c = *p++; @@ -427,7 +427,7 @@ EXPORT_SYMBOL(mangle_path); * return the absolute path of 'path', as represented by the * dentry / mnt pair in the path parameter. */ -int seq_path(struct seq_file *m, struct path *path, char *esc) +int seq_path(struct seq_file *m, const struct path *path, const char *esc) { char *buf; size_t size = seq_get_buf(m, &buf); @@ -450,8 +450,8 @@ EXPORT_SYMBOL(seq_path); /* * Same as seq_path, but relative to supplied root. */ -int seq_path_root(struct seq_file *m, struct path *path, struct path *root, - char *esc) +int seq_path_root(struct seq_file *m, const struct path *path, + const struct path *root, const char *esc) { char *buf; size_t size = seq_get_buf(m, &buf); @@ -480,7 +480,7 @@ int seq_path_root(struct seq_file *m, struct path *path, struct path *root, /* * returns the path of the 'dentry' from the root of its filesystem. */ -int seq_dentry(struct seq_file *m, struct dentry *dentry, char *esc) +int seq_dentry(struct seq_file *m, struct dentry *dentry, const char *esc) { char *buf; size_t size = seq_get_buf(m, &buf); diff --git a/fs/splice.c b/fs/splice.c index fa2defa8afcf..1ec0493266b3 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -25,7 +25,6 @@ #include <linux/mm_inline.h> #include <linux/swap.h> #include <linux/writeback.h> -#include <linux/buffer_head.h> #include <linux/module.h> #include <linux/syscalls.h> #include <linux/uio.h> diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 2da1715452ac..d0858c2d9a47 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -464,7 +464,6 @@ static struct inode *squashfs_alloc_inode(struct super_block *sb) static void squashfs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(squashfs_inode_cachep, squashfs_i(inode)); } diff --git a/fs/statfs.c b/fs/statfs.c index 9cf04a118965..2aa6a22e0be2 100644 --- a/fs/statfs.c +++ b/fs/statfs.c @@ -7,6 +7,7 @@ #include <linux/statfs.h> #include <linux/security.h> #include <linux/uaccess.h> +#include "internal.h" static int flags_by_mnt(int mnt_flags) { @@ -45,7 +46,7 @@ static int calculate_f_flags(struct vfsmount *mnt) flags_by_sb(mnt->mnt_sb->s_flags); } -int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf) +static int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf) { int retval; @@ -205,19 +206,23 @@ SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user return error; } -SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf) +int vfs_ustat(dev_t dev, struct kstatfs *sbuf) { - struct super_block *s; - struct ustat tmp; - struct kstatfs sbuf; + struct super_block *s = user_get_super(dev); int err; - - s = user_get_super(new_decode_dev(dev)); if (!s) return -EINVAL; - err = statfs_by_dentry(s->s_root, &sbuf); + err = statfs_by_dentry(s->s_root, sbuf); drop_super(s); + return err; +} + +SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf) +{ + struct ustat tmp; + struct kstatfs sbuf; + int err = vfs_ustat(new_decode_dev(dev), &sbuf); if (err) return err; diff --git a/fs/super.c b/fs/super.c index afd0f1ad45e0..de41e1e46f09 100644 --- a/fs/super.c +++ b/fs/super.c @@ -136,12 +136,13 @@ static struct super_block *alloc_super(struct file_system_type *type) INIT_LIST_HEAD(&s->s_files); #endif s->s_bdi = &default_backing_dev_info; - INIT_LIST_HEAD(&s->s_instances); + INIT_HLIST_NODE(&s->s_instances); INIT_HLIST_BL_HEAD(&s->s_anon); INIT_LIST_HEAD(&s->s_inodes); INIT_LIST_HEAD(&s->s_dentry_lru); INIT_LIST_HEAD(&s->s_inode_lru); spin_lock_init(&s->s_inode_lru_lock); + INIT_LIST_HEAD(&s->s_mounts); init_rwsem(&s->s_umount); mutex_init(&s->s_lock); lockdep_set_class(&s->s_umount, &type->s_umount_key); @@ -200,6 +201,7 @@ static inline void destroy_super(struct super_block *s) free_percpu(s->s_files); #endif security_sb_free(s); + WARN_ON(!list_empty(&s->s_mounts)); kfree(s->s_subtype); kfree(s->s_options); kfree(s); @@ -210,7 +212,7 @@ static inline void destroy_super(struct super_block *s) /* * Drop a superblock's refcount. The caller must hold sb_lock. */ -void __put_super(struct super_block *sb) +static void __put_super(struct super_block *sb) { if (!--sb->s_count) { list_del_init(&sb->s_list); @@ -225,7 +227,7 @@ void __put_super(struct super_block *sb) * Drops a temporary reference, frees superblock if there's no * references left. */ -void put_super(struct super_block *sb) +static void put_super(struct super_block *sb) { spin_lock(&sb_lock); __put_super(sb); @@ -328,7 +330,7 @@ static int grab_super(struct super_block *s) __releases(sb_lock) bool grab_super_passive(struct super_block *sb) { spin_lock(&sb_lock); - if (list_empty(&sb->s_instances)) { + if (hlist_unhashed(&sb->s_instances)) { spin_unlock(&sb_lock); return false; } @@ -337,7 +339,7 @@ bool grab_super_passive(struct super_block *sb) spin_unlock(&sb_lock); if (down_read_trylock(&sb->s_umount)) { - if (sb->s_root) + if (sb->s_root && (sb->s_flags & MS_BORN)) return true; up_read(&sb->s_umount); } @@ -400,7 +402,7 @@ void generic_shutdown_super(struct super_block *sb) } spin_lock(&sb_lock); /* should be initialized for __put_super_and_need_restart() */ - list_del_init(&sb->s_instances); + hlist_del_init(&sb->s_instances); spin_unlock(&sb_lock); up_write(&sb->s_umount); } @@ -420,13 +422,14 @@ struct super_block *sget(struct file_system_type *type, void *data) { struct super_block *s = NULL; + struct hlist_node *node; struct super_block *old; int err; retry: spin_lock(&sb_lock); if (test) { - list_for_each_entry(old, &type->fs_supers, s_instances) { + hlist_for_each_entry(old, node, &type->fs_supers, s_instances) { if (!test(old, data)) continue; if (!grab_super(old)) @@ -462,7 +465,7 @@ retry: s->s_type = type; strlcpy(s->s_id, type->name, sizeof(s->s_id)); list_add_tail(&s->s_list, &super_blocks); - list_add(&s->s_instances, &type->fs_supers); + hlist_add_head(&s->s_instances, &type->fs_supers); spin_unlock(&sb_lock); get_filesystem(type); register_shrinker(&s->s_shrink); @@ -497,14 +500,14 @@ void sync_supers(void) spin_lock(&sb_lock); list_for_each_entry(sb, &super_blocks, s_list) { - if (list_empty(&sb->s_instances)) + if (hlist_unhashed(&sb->s_instances)) continue; if (sb->s_op->write_super && sb->s_dirt) { sb->s_count++; spin_unlock(&sb_lock); down_read(&sb->s_umount); - if (sb->s_root && sb->s_dirt) + if (sb->s_root && sb->s_dirt && (sb->s_flags & MS_BORN)) sb->s_op->write_super(sb); up_read(&sb->s_umount); @@ -533,13 +536,13 @@ void iterate_supers(void (*f)(struct super_block *, void *), void *arg) spin_lock(&sb_lock); list_for_each_entry(sb, &super_blocks, s_list) { - if (list_empty(&sb->s_instances)) + if (hlist_unhashed(&sb->s_instances)) continue; sb->s_count++; spin_unlock(&sb_lock); down_read(&sb->s_umount); - if (sb->s_root) + if (sb->s_root && (sb->s_flags & MS_BORN)) f(sb, arg); up_read(&sb->s_umount); @@ -566,14 +569,15 @@ void iterate_supers_type(struct file_system_type *type, void (*f)(struct super_block *, void *), void *arg) { struct super_block *sb, *p = NULL; + struct hlist_node *node; spin_lock(&sb_lock); - list_for_each_entry(sb, &type->fs_supers, s_instances) { + hlist_for_each_entry(sb, node, &type->fs_supers, s_instances) { sb->s_count++; spin_unlock(&sb_lock); down_read(&sb->s_umount); - if (sb->s_root) + if (sb->s_root && (sb->s_flags & MS_BORN)) f(sb, arg); up_read(&sb->s_umount); @@ -607,14 +611,14 @@ struct super_block *get_super(struct block_device *bdev) spin_lock(&sb_lock); rescan: list_for_each_entry(sb, &super_blocks, s_list) { - if (list_empty(&sb->s_instances)) + if (hlist_unhashed(&sb->s_instances)) continue; if (sb->s_bdev == bdev) { sb->s_count++; spin_unlock(&sb_lock); down_read(&sb->s_umount); /* still alive? */ - if (sb->s_root) + if (sb->s_root && (sb->s_flags & MS_BORN)) return sb; up_read(&sb->s_umount); /* nope, got unmounted */ @@ -647,7 +651,7 @@ struct super_block *get_active_super(struct block_device *bdev) restart: spin_lock(&sb_lock); list_for_each_entry(sb, &super_blocks, s_list) { - if (list_empty(&sb->s_instances)) + if (hlist_unhashed(&sb->s_instances)) continue; if (sb->s_bdev == bdev) { if (grab_super(sb)) /* drops sb_lock */ @@ -667,14 +671,14 @@ struct super_block *user_get_super(dev_t dev) spin_lock(&sb_lock); rescan: list_for_each_entry(sb, &super_blocks, s_list) { - if (list_empty(&sb->s_instances)) + if (hlist_unhashed(&sb->s_instances)) continue; if (sb->s_dev == dev) { sb->s_count++; spin_unlock(&sb_lock); down_read(&sb->s_umount); /* still alive? */ - if (sb->s_root) + if (sb->s_root && (sb->s_flags & MS_BORN)) return sb; up_read(&sb->s_umount); /* nope, got unmounted */ @@ -719,23 +723,29 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) /* If we are remounting RDONLY and current sb is read/write, make sure there are no rw files opened */ if (remount_ro) { - if (force) + if (force) { mark_files_ro(sb); - else if (!fs_may_remount_ro(sb)) - return -EBUSY; + } else { + retval = sb_prepare_remount_readonly(sb); + if (retval) + return retval; + } } if (sb->s_op->remount_fs) { retval = sb->s_op->remount_fs(sb, &flags, data); if (retval) { if (!force) - return retval; + goto cancel_readonly; /* If forced remount, go ahead despite any errors */ WARN(1, "forced remount of a %s fs returned %i\n", sb->s_type->name, retval); } } sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK); + /* Needs to be ordered wrt mnt_is_readonly() */ + smp_wmb(); + sb->s_readonly_remount = 0; /* * Some filesystems modify their metadata via some other path than the @@ -748,6 +758,10 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) if (remount_ro && sb->s_bdev) invalidate_bdev(sb->s_bdev); return 0; + +cancel_readonly: + sb->s_readonly_remount = 0; + return retval; } static void do_emergency_remount(struct work_struct *work) @@ -756,12 +770,13 @@ static void do_emergency_remount(struct work_struct *work) spin_lock(&sb_lock); list_for_each_entry(sb, &super_blocks, s_list) { - if (list_empty(&sb->s_instances)) + if (hlist_unhashed(&sb->s_instances)) continue; sb->s_count++; spin_unlock(&sb_lock); down_write(&sb->s_umount); - if (sb->s_root && sb->s_bdev && !(sb->s_flags & MS_RDONLY)) { + if (sb->s_root && sb->s_bdev && (sb->s_flags & MS_BORN) && + !(sb->s_flags & MS_RDONLY)) { /* * What lock protects sb->s_flags?? */ @@ -1144,6 +1159,11 @@ int freeze_super(struct super_block *sb) return -EBUSY; } + if (!(sb->s_flags & MS_BORN)) { + up_write(&sb->s_umount); + return 0; /* sic - it's "nothing to do" */ + } + if (sb->s_flags & MS_RDONLY) { sb->s_frozen = SB_FREEZE_TRANS; smp_wmb(); diff --git a/fs/sync.c b/fs/sync.c index 101b8ef901d7..f3501ef39235 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -14,7 +14,6 @@ #include <linux/linkage.h> #include <linux/pagemap.h> #include <linux/quotaops.h> -#include <linux/buffer_head.h> #include <linux/backing-dev.h> #include "internal.h" diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index d4e6080b4b20..62f4fb37789e 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -518,7 +518,7 @@ out: } int sysfs_add_file_mode(struct sysfs_dirent *dir_sd, - const struct attribute *attr, int type, mode_t amode) + const struct attribute *attr, int type, umode_t amode) { umode_t mode = (amode & S_IALLUGO) | S_IFREG; struct sysfs_addrm_cxt acxt; @@ -618,7 +618,7 @@ EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); * */ int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr, - mode_t mode) + umode_t mode) { struct sysfs_dirent *sd; struct iattr newattrs; diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index 194414f8298c..dd1701caecc9 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -33,7 +33,7 @@ static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, int error = 0, i; for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++) { - mode_t mode = 0; + umode_t mode = 0; /* in update mode, we're changing the permissions or * visibility. Do this by first removing then diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index c81b22f3ace1..4a802b4a9056 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -187,7 +187,7 @@ out: return error; } -static inline void set_default_inode_attr(struct inode * inode, mode_t mode) +static inline void set_default_inode_attr(struct inode * inode, umode_t mode) { inode->i_mode = mode; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index ce29e28b766d..7484a36ee678 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -79,7 +79,7 @@ struct sysfs_dirent { }; unsigned int s_flags; - unsigned short s_mode; + umode_t s_mode; ino_t s_ino; struct sysfs_inode_attrs *s_iattr; }; @@ -229,7 +229,7 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, int type); int sysfs_add_file_mode(struct sysfs_dirent *dir_sd, - const struct attribute *attr, int type, mode_t amode); + const struct attribute *attr, int type, umode_t amode); /* * bin.c */ diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c index 0c96c98bd1db..8233b02eccae 100644 --- a/fs/sysv/ialloc.c +++ b/fs/sysv/ialloc.c @@ -132,7 +132,7 @@ void sysv_free_inode(struct inode * inode) brelse(bh); } -struct inode * sysv_new_inode(const struct inode * dir, mode_t mode) +struct inode * sysv_new_inode(const struct inode * dir, umode_t mode) { struct super_block *sb = dir->i_sb; struct sysv_sb_info *sbi = SYSV_SB(sb); diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index 25ffb3e9a3f8..3da5ce25faf0 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -336,7 +336,6 @@ static struct inode *sysv_alloc_inode(struct super_block *sb) static void sysv_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(sysv_inode_cachep, SYSV_I(inode)); } diff --git a/fs/sysv/itree.c b/fs/sysv/itree.c index fa8d43c92bb8..90b54b438789 100644 --- a/fs/sysv/itree.c +++ b/fs/sysv/itree.c @@ -442,7 +442,7 @@ static unsigned sysv_nblocks(struct super_block *s, loff_t size) int sysv_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { - struct super_block *s = mnt->mnt_sb; + struct super_block *s = dentry->d_sb; generic_fillattr(dentry->d_inode, stat); stat->blocks = (s->s_blocksize / 512) * sysv_nblocks(s, stat->size); stat->blksize = s->s_blocksize; diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index e474fbcf8bde..b217797e621b 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c @@ -61,7 +61,7 @@ static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry, st return NULL; } -static int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, dev_t rdev) +static int sysv_mknod(struct inode * dir, struct dentry * dentry, umode_t mode, dev_t rdev) { struct inode * inode; int err; @@ -80,7 +80,7 @@ static int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, dev_ return err; } -static int sysv_create(struct inode * dir, struct dentry * dentry, int mode, struct nameidata *nd) +static int sysv_create(struct inode * dir, struct dentry * dentry, umode_t mode, struct nameidata *nd) { return sysv_mknod(dir, dentry, mode, 0); } @@ -131,7 +131,7 @@ static int sysv_link(struct dentry * old_dentry, struct inode * dir, return add_nondir(dentry, inode); } -static int sysv_mkdir(struct inode * dir, struct dentry *dentry, int mode) +static int sysv_mkdir(struct inode * dir, struct dentry *dentry, umode_t mode) { struct inode * inode; int err = -EMLINK; diff --git a/fs/sysv/sysv.h b/fs/sysv/sysv.h index bb55cdb394bf..0e4b821c5691 100644 --- a/fs/sysv/sysv.h +++ b/fs/sysv/sysv.h @@ -125,7 +125,7 @@ static inline void dirty_sb(struct super_block *sb) /* ialloc.c */ extern struct sysv_inode *sysv_raw_inode(struct super_block *, unsigned, struct buffer_head **); -extern struct inode * sysv_new_inode(const struct inode *, mode_t); +extern struct inode * sysv_new_inode(const struct inode *, umode_t); extern void sysv_free_inode(struct inode *); extern unsigned long sysv_count_free_inodes(struct super_block *); diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index 683492043317..d6fe1c79f18b 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -56,7 +56,7 @@ * * This function returns the inherited flags. */ -static int inherit_flags(const struct inode *dir, int mode) +static int inherit_flags(const struct inode *dir, umode_t mode) { int flags; const struct ubifs_inode *ui = ubifs_inode(dir); @@ -86,7 +86,7 @@ static int inherit_flags(const struct inode *dir, int mode) * case of failure. */ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir, - int mode) + umode_t mode) { struct inode *inode; struct ubifs_inode *ui; @@ -253,7 +253,7 @@ out: return ERR_PTR(err); } -static int ubifs_create(struct inode *dir, struct dentry *dentry, int mode, +static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { struct inode *inode; @@ -268,7 +268,7 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, int mode, * parent directory inode. */ - dbg_gen("dent '%.*s', mode %#x in dir ino %lu", + dbg_gen("dent '%.*s', mode %#hx in dir ino %lu", dentry->d_name.len, dentry->d_name.name, mode, dir->i_ino); err = ubifs_budget_space(c, &req); @@ -712,7 +712,7 @@ out_cancel: return err; } -static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct inode *inode; struct ubifs_inode *dir_ui = ubifs_inode(dir); @@ -725,7 +725,7 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, int mode) * directory inode. */ - dbg_gen("dent '%.*s', mode %#x in dir ino %lu", + dbg_gen("dent '%.*s', mode %#hx in dir ino %lu", dentry->d_name.len, dentry->d_name.name, mode, dir->i_ino); err = ubifs_budget_space(c, &req); @@ -769,7 +769,7 @@ out_budg: } static int ubifs_mknod(struct inode *dir, struct dentry *dentry, - int mode, dev_t rdev) + umode_t mode, dev_t rdev) { struct inode *inode; struct ubifs_inode *ui; diff --git a/fs/ubifs/ioctl.c b/fs/ubifs/ioctl.c index 548acf494afd..1a7e2d8bdbe9 100644 --- a/fs/ubifs/ioctl.c +++ b/fs/ubifs/ioctl.c @@ -173,12 +173,12 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) * Make sure the file-system is read-write and make sure it * will not become read-only while we are changing the flags. */ - err = mnt_want_write(file->f_path.mnt); + err = mnt_want_write_file(file); if (err) return err; dbg_gen("set flags: %#x, i_flags %#x", flags, inode->i_flags); err = setflags(inode, flags); - mnt_drop_write(file->f_path.mnt); + mnt_drop_write_file(file); return err; } diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index ae0e76bb6ebf..63765d58445b 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -276,7 +276,6 @@ static void ubifs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); struct ubifs_inode *ui = ubifs_inode(inode); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(ubifs_inode_slab, ui); } @@ -420,9 +419,9 @@ static int ubifs_statfs(struct dentry *dentry, struct kstatfs *buf) return 0; } -static int ubifs_show_options(struct seq_file *s, struct vfsmount *mnt) +static int ubifs_show_options(struct seq_file *s, struct dentry *root) { - struct ubifs_info *c = mnt->mnt_sb->s_fs_info; + struct ubifs_info *c = root->d_sb->s_fs_info; if (c->mount_opts.unmount_mode == 2) seq_printf(s, ",fast_unmount"); diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 27f22551f805..12e94774aa88 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h @@ -1734,7 +1734,7 @@ int ubifs_setattr(struct dentry *dentry, struct iattr *attr); /* dir.c */ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir, - int mode); + umode_t mode); int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c index 6fb7e0adcda0..05ab48195be9 100644 --- a/fs/udf/ialloc.c +++ b/fs/udf/ialloc.c @@ -46,7 +46,7 @@ void udf_free_inode(struct inode *inode) udf_free_blocks(sb, NULL, &UDF_I(inode)->i_location, 0, 1); } -struct inode *udf_new_inode(struct inode *dir, int mode, int *err) +struct inode *udf_new_inode(struct inode *dir, umode_t mode, int *err) { struct super_block *sb = dir->i_sb; struct udf_sb_info *sbi = UDF_SB(sb); diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 4fd1d809738c..4598904be1bb 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -48,7 +48,7 @@ MODULE_LICENSE("GPL"); #define EXTENT_MERGE_SIZE 5 -static mode_t udf_convert_permissions(struct fileEntry *); +static umode_t udf_convert_permissions(struct fileEntry *); static int udf_update_inode(struct inode *, int); static void udf_fill_inode(struct inode *, struct buffer_head *); static int udf_sync_inode(struct inode *inode); @@ -1452,9 +1452,9 @@ static int udf_alloc_i_data(struct inode *inode, size_t size) return 0; } -static mode_t udf_convert_permissions(struct fileEntry *fe) +static umode_t udf_convert_permissions(struct fileEntry *fe) { - mode_t mode; + umode_t mode; uint32_t permissions; uint32_t flags; diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 4639e137222f..08bf46edf9c4 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -552,7 +552,7 @@ static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi, return udf_write_fi(inode, cfi, fi, fibh, NULL, NULL); } -static int udf_create(struct inode *dir, struct dentry *dentry, int mode, +static int udf_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { struct udf_fileident_bh fibh; @@ -596,7 +596,7 @@ static int udf_create(struct inode *dir, struct dentry *dentry, int mode, return 0; } -static int udf_mknod(struct inode *dir, struct dentry *dentry, int mode, +static int udf_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { struct inode *inode; @@ -640,7 +640,7 @@ out: return err; } -static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int udf_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct inode *inode; struct udf_fileident_bh fibh; diff --git a/fs/udf/super.c b/fs/udf/super.c index e185253470df..0c33225647a0 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -89,7 +89,7 @@ static void udf_open_lvid(struct super_block *); static void udf_close_lvid(struct super_block *); static unsigned int udf_count_free(struct super_block *); static int udf_statfs(struct dentry *, struct kstatfs *); -static int udf_show_options(struct seq_file *, struct vfsmount *); +static int udf_show_options(struct seq_file *, struct dentry *); struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct udf_sb_info *sbi) { @@ -138,7 +138,6 @@ static struct inode *udf_alloc_inode(struct super_block *sb) static void udf_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(udf_inode_cachep, UDF_I(inode)); } @@ -196,11 +195,11 @@ struct udf_options { unsigned int fileset; unsigned int rootdir; unsigned int flags; - mode_t umask; + umode_t umask; gid_t gid; uid_t uid; - mode_t fmode; - mode_t dmode; + umode_t fmode; + umode_t dmode; struct nls_table *nls_map; }; @@ -250,9 +249,9 @@ static int udf_sb_alloc_partition_maps(struct super_block *sb, u32 count) return 0; } -static int udf_show_options(struct seq_file *seq, struct vfsmount *mnt) +static int udf_show_options(struct seq_file *seq, struct dentry *root) { - struct super_block *sb = mnt->mnt_sb; + struct super_block *sb = root->d_sb; struct udf_sb_info *sbi = UDF_SB(sb); if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT)) @@ -280,11 +279,11 @@ static int udf_show_options(struct seq_file *seq, struct vfsmount *mnt) if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_SET)) seq_printf(seq, ",gid=%u", sbi->s_gid); if (sbi->s_umask != 0) - seq_printf(seq, ",umask=%o", sbi->s_umask); + seq_printf(seq, ",umask=%ho", sbi->s_umask); if (sbi->s_fmode != UDF_INVALID_MODE) - seq_printf(seq, ",mode=%o", sbi->s_fmode); + seq_printf(seq, ",mode=%ho", sbi->s_fmode); if (sbi->s_dmode != UDF_INVALID_MODE) - seq_printf(seq, ",dmode=%o", sbi->s_dmode); + seq_printf(seq, ",dmode=%ho", sbi->s_dmode); if (UDF_QUERY_FLAG(sb, UDF_FLAG_SESSION_SET)) seq_printf(seq, ",session=%u", sbi->s_session); if (UDF_QUERY_FLAG(sb, UDF_FLAG_LASTBLOCK_SET)) diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h index 5142a82e3276..42ad69ac9576 100644 --- a/fs/udf/udf_sb.h +++ b/fs/udf/udf_sb.h @@ -50,7 +50,7 @@ #define UDF_SPARABLE_MAP15 0x1522U #define UDF_METADATA_MAP25 0x2511U -#define UDF_INVALID_MODE ((mode_t)-1) +#define UDF_INVALID_MODE ((umode_t)-1) #pragma pack(1) /* XXX(hch): Why? This file just defines in-core structures */ @@ -127,11 +127,11 @@ struct udf_sb_info { struct buffer_head *s_lvid_bh; /* Default permissions */ - mode_t s_umask; + umode_t s_umask; gid_t s_gid; uid_t s_uid; - mode_t s_fmode; - mode_t s_dmode; + umode_t s_fmode; + umode_t s_dmode; /* Lock protecting consistency of above permission settings */ rwlock_t s_cred_lock; diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index f34e6fc0cdaa..ebe10314e512 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -215,7 +215,7 @@ extern int udf_CS0toUTF8(struct ustr *, const struct ustr *); /* ialloc.c */ extern void udf_free_inode(struct inode *); -extern struct inode *udf_new_inode(struct inode *, int, int *); +extern struct inode *udf_new_inode(struct inode *, umode_t, int *); /* truncate.c */ extern void udf_truncate_tail_extent(struct inode *); diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c index 78a4c70d46b5..4ec5c1085a87 100644 --- a/fs/ufs/ialloc.c +++ b/fs/ufs/ialloc.c @@ -170,7 +170,7 @@ static void ufs2_init_inodes_chunk(struct super_block *sb, * For other inodes, search forward from the parent directory's block * group to find a free inode. */ -struct inode * ufs_new_inode(struct inode * dir, int mode) +struct inode *ufs_new_inode(struct inode *dir, umode_t mode) { struct super_block * sb; struct ufs_sb_info * sbi; diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 879b13436fa4..9094e1d917be 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -583,7 +583,7 @@ static int ufs1_read_inode(struct inode *inode, struct ufs_inode *ufs_inode) { struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block *sb = inode->i_sb; - mode_t mode; + umode_t mode; /* * Copy data to the in-core inode. @@ -630,7 +630,7 @@ static int ufs2_read_inode(struct inode *inode, struct ufs2_inode *ufs2_inode) { struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block *sb = inode->i_sb; - mode_t mode; + umode_t mode; UFSD("Reading ufs2 inode, ino %lu\n", inode->i_ino); /* diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index 639d49162241..38cac199edff 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -70,7 +70,7 @@ static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, stru * If the create succeeds, we fill in the inode information * with d_instantiate(). */ -static int ufs_create (struct inode * dir, struct dentry * dentry, int mode, +static int ufs_create (struct inode * dir, struct dentry * dentry, umode_t mode, struct nameidata *nd) { struct inode *inode; @@ -94,7 +94,7 @@ static int ufs_create (struct inode * dir, struct dentry * dentry, int mode, return err; } -static int ufs_mknod (struct inode * dir, struct dentry *dentry, int mode, dev_t rdev) +static int ufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { struct inode *inode; int err; @@ -180,7 +180,7 @@ static int ufs_link (struct dentry * old_dentry, struct inode * dir, return error; } -static int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode) +static int ufs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode) { struct inode * inode; int err = -EMLINK; diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 3915ade6f9a8..5246ee3e5607 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -1351,9 +1351,9 @@ 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) +static int ufs_show_options(struct seq_file *seq, struct dentry *root) { - struct ufs_sb_info *sbi = UFS_SB(vfs->mnt_sb); + struct ufs_sb_info *sbi = UFS_SB(root->d_sb); unsigned mval = sbi->s_mount_opt & UFS_MOUNT_UFSTYPE; const struct match_token *tp = tokens; @@ -1425,7 +1425,6 @@ static struct inode *ufs_alloc_inode(struct super_block *sb) static void ufs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(ufs_inode_cachep, UFS_I(inode)); } diff --git a/fs/ufs/ufs.h b/fs/ufs/ufs.h index c26f2bcec264..528750b7e701 100644 --- a/fs/ufs/ufs.h +++ b/fs/ufs/ufs.h @@ -104,7 +104,7 @@ 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); +extern struct inode * ufs_new_inode (struct inode *, umode_t); /* inode.c */ extern struct inode *ufs_iget(struct super_block *, unsigned long); diff --git a/fs/xattr.c b/fs/xattr.c index 67583de8218c..82f43376c7cd 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -397,7 +397,7 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name, error = mnt_want_write_file(f); if (!error) { error = setxattr(dentry, name, value, size, flags); - mnt_drop_write(f->f_path.mnt); + mnt_drop_write_file(f); } fput(f); return error; @@ -624,7 +624,7 @@ SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name) error = mnt_want_write_file(f); if (!error) { error = removexattr(dentry, name); - mnt_drop_write(f->f_path.mnt); + mnt_drop_write_file(f); } fput(f); return error; diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index 169380e66057..dad1a31aa4fc 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c @@ -447,7 +447,7 @@ STATIC xfs_buf_t * /* allocation group buffer */ xfs_ialloc_ag_select( xfs_trans_t *tp, /* transaction pointer */ xfs_ino_t parent, /* parent directory inode number */ - mode_t mode, /* bits set to indicate file type */ + umode_t mode, /* bits set to indicate file type */ int okalloc) /* ok to allocate more space */ { xfs_buf_t *agbp; /* allocation group header buffer */ @@ -640,7 +640,7 @@ int xfs_dialloc( xfs_trans_t *tp, /* transaction pointer */ xfs_ino_t parent, /* parent inode (directory) */ - mode_t mode, /* mode bits for new inode */ + umode_t mode, /* mode bits for new inode */ int okalloc, /* ok to allocate more space */ xfs_buf_t **IO_agbp, /* in/out ag header's buffer */ boolean_t *alloc_done, /* true if we needed to replenish diff --git a/fs/xfs/xfs_ialloc.h b/fs/xfs/xfs_ialloc.h index bb5385475e1f..666a037398d6 100644 --- a/fs/xfs/xfs_ialloc.h +++ b/fs/xfs/xfs_ialloc.h @@ -81,7 +81,7 @@ int /* error */ xfs_dialloc( struct xfs_trans *tp, /* transaction pointer */ xfs_ino_t parent, /* parent inode (directory) */ - mode_t mode, /* mode bits for new inode */ + umode_t mode, /* mode bits for new inode */ int okalloc, /* ok to allocate more space */ struct xfs_buf **agbp, /* buf for a.g. inode header */ boolean_t *alloc_done, /* an allocation was done to replenish diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index 0fa98b1c70ea..3960a066d7ff 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c @@ -107,7 +107,6 @@ xfs_inode_free_callback( struct inode *inode = container_of(head, struct inode, i_rcu); struct xfs_inode *ip = XFS_I(inode); - INIT_LIST_HEAD(&inode->i_dentry); kmem_zone_free(xfs_inode_zone, ip); } diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 755ee8164880..9dda7cc32848 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -961,7 +961,7 @@ int xfs_ialloc( xfs_trans_t *tp, xfs_inode_t *pip, - mode_t mode, + umode_t mode, xfs_nlink_t nlink, xfs_dev_t rdev, prid_t prid, @@ -1002,7 +1002,7 @@ xfs_ialloc( return error; ASSERT(ip != NULL); - ip->i_d.di_mode = (__uint16_t)mode; + ip->i_d.di_mode = mode; ip->i_d.di_onlink = 0; ip->i_d.di_nlink = nlink; ASSERT(ip->i_d.di_nlink == nlink); diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index b4cd4739f98e..f0e6b151ba37 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -481,7 +481,7 @@ void xfs_inode_free(struct xfs_inode *ip); /* * xfs_inode.c prototypes. */ -int xfs_ialloc(struct xfs_trans *, xfs_inode_t *, mode_t, +int xfs_ialloc(struct xfs_trans *, xfs_inode_t *, umode_t, xfs_nlink_t, xfs_dev_t, prid_t, int, struct xfs_buf **, boolean_t *, xfs_inode_t **); diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index d99a90518909..76f3ca5cfc36 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -559,23 +559,23 @@ xfs_attrmulti_by_handle( ops[i].am_flags); break; case ATTR_OP_SET: - ops[i].am_error = mnt_want_write(parfilp->f_path.mnt); + ops[i].am_error = mnt_want_write_file(parfilp); if (ops[i].am_error) break; ops[i].am_error = xfs_attrmulti_attr_set( dentry->d_inode, attr_name, ops[i].am_attrvalue, ops[i].am_length, ops[i].am_flags); - mnt_drop_write(parfilp->f_path.mnt); + mnt_drop_write_file(parfilp); break; case ATTR_OP_REMOVE: - ops[i].am_error = mnt_want_write(parfilp->f_path.mnt); + ops[i].am_error = mnt_want_write_file(parfilp); if (ops[i].am_error) break; ops[i].am_error = xfs_attrmulti_attr_remove( dentry->d_inode, attr_name, ops[i].am_flags); - mnt_drop_write(parfilp->f_path.mnt); + mnt_drop_write_file(parfilp); break; default: ops[i].am_error = EINVAL; diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c index 54e623bfbb85..f9ccb7b7c043 100644 --- a/fs/xfs/xfs_ioctl32.c +++ b/fs/xfs/xfs_ioctl32.c @@ -454,23 +454,23 @@ xfs_compat_attrmulti_by_handle( &ops[i].am_length, ops[i].am_flags); break; case ATTR_OP_SET: - ops[i].am_error = mnt_want_write(parfilp->f_path.mnt); + ops[i].am_error = mnt_want_write_file(parfilp); if (ops[i].am_error) break; ops[i].am_error = xfs_attrmulti_attr_set( dentry->d_inode, attr_name, compat_ptr(ops[i].am_attrvalue), ops[i].am_length, ops[i].am_flags); - mnt_drop_write(parfilp->f_path.mnt); + mnt_drop_write_file(parfilp); break; case ATTR_OP_REMOVE: - ops[i].am_error = mnt_want_write(parfilp->f_path.mnt); + ops[i].am_error = mnt_want_write_file(parfilp); if (ops[i].am_error) break; ops[i].am_error = xfs_attrmulti_attr_remove( dentry->d_inode, attr_name, ops[i].am_flags); - mnt_drop_write(parfilp->f_path.mnt); + mnt_drop_write_file(parfilp); break; default: ops[i].am_error = EINVAL; diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 23ce927973a4..f9babd179223 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -168,7 +168,7 @@ STATIC int xfs_vn_mknod( struct inode *dir, struct dentry *dentry, - int mode, + umode_t mode, dev_t rdev) { struct inode *inode; @@ -231,7 +231,7 @@ STATIC int xfs_vn_create( struct inode *dir, struct dentry *dentry, - int mode, + umode_t mode, struct nameidata *nd) { return xfs_vn_mknod(dir, dentry, mode, 0); @@ -241,7 +241,7 @@ STATIC int xfs_vn_mkdir( struct inode *dir, struct dentry *dentry, - int mode) + umode_t mode) { return xfs_vn_mknod(dir, dentry, mode|S_IFDIR, 0); } @@ -366,7 +366,7 @@ xfs_vn_symlink( struct xfs_inode *cip = NULL; struct xfs_name name; int error; - mode_t mode; + umode_t mode; mode = S_IFLNK | (irix_symlink_mode ? 0777 & ~current_umask() : S_IRWXUGO); diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 8a899496fd5f..7b7669507ee3 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -1238,9 +1238,9 @@ xfs_fs_unfreeze( STATIC int xfs_fs_show_options( struct seq_file *m, - struct vfsmount *mnt) + struct dentry *root) { - return -xfs_showargs(XFS_M(mnt->mnt_sb), m); + return -xfs_showargs(XFS_M(root->d_sb), m); } /* diff --git a/fs/xfs/xfs_utils.c b/fs/xfs/xfs_utils.c index 8b32d1a4c5a1..89dbb4a50872 100644 --- a/fs/xfs/xfs_utils.c +++ b/fs/xfs/xfs_utils.c @@ -53,7 +53,7 @@ xfs_dir_ialloc( output: may be a new transaction. */ xfs_inode_t *dp, /* directory within whose allocate the inode. */ - mode_t mode, + umode_t mode, xfs_nlink_t nlink, xfs_dev_t rdev, prid_t prid, /* project id */ diff --git a/fs/xfs/xfs_utils.h b/fs/xfs/xfs_utils.h index 456fca314933..5eeab4690cfe 100644 --- a/fs/xfs/xfs_utils.h +++ b/fs/xfs/xfs_utils.h @@ -18,7 +18,7 @@ #ifndef __XFS_UTILS_H__ #define __XFS_UTILS_H__ -extern int xfs_dir_ialloc(xfs_trans_t **, xfs_inode_t *, mode_t, xfs_nlink_t, +extern int xfs_dir_ialloc(xfs_trans_t **, xfs_inode_t *, umode_t, xfs_nlink_t, xfs_dev_t, prid_t, int, xfs_inode_t **, int *); extern int xfs_droplink(xfs_trans_t *, xfs_inode_t *); extern int xfs_bumplink(xfs_trans_t *, xfs_inode_t *); diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index ce9268a2f56b..f2fea868d4db 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -822,7 +822,7 @@ int xfs_create( xfs_inode_t *dp, struct xfs_name *name, - mode_t mode, + umode_t mode, xfs_dev_t rdev, xfs_inode_t **ipp) { @@ -1481,7 +1481,7 @@ xfs_symlink( xfs_inode_t *dp, struct xfs_name *link_name, const char *target_path, - mode_t mode, + umode_t mode, xfs_inode_t **ipp) { xfs_mount_t *mp = dp->i_mount; diff --git a/fs/xfs/xfs_vnodeops.h b/fs/xfs/xfs_vnodeops.h index 35d3d513e1e9..0c877cbde142 100644 --- a/fs/xfs/xfs_vnodeops.h +++ b/fs/xfs/xfs_vnodeops.h @@ -26,7 +26,7 @@ int xfs_release(struct xfs_inode *ip); int xfs_inactive(struct xfs_inode *ip); int xfs_lookup(struct xfs_inode *dp, struct xfs_name *name, struct xfs_inode **ipp, struct xfs_name *ci_name); -int xfs_create(struct xfs_inode *dp, struct xfs_name *name, mode_t mode, +int xfs_create(struct xfs_inode *dp, struct xfs_name *name, umode_t mode, xfs_dev_t rdev, struct xfs_inode **ipp); int xfs_remove(struct xfs_inode *dp, struct xfs_name *name, struct xfs_inode *ip); @@ -35,7 +35,7 @@ int xfs_link(struct xfs_inode *tdp, struct xfs_inode *sip, 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, struct xfs_name *link_name, - const char *target_path, mode_t mode, struct xfs_inode **ipp); + const char *target_path, umode_t mode, struct xfs_inode **ipp); int xfs_set_dmattrs(struct xfs_inode *ip, u_int evmask, u_int16_t state); int xfs_change_file_space(struct xfs_inode *ip, int cmd, xfs_flock64_t *bf, xfs_off_t offset, int attr_flags); |