Commit 4b4f1d01 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (87 commits)
  nilfs2: get rid of bd_mount_sem use from nilfs
  nilfs2: correct exclusion control in nilfs_remount function
  nilfs2: simplify remaining sget() use
  nilfs2: get rid of sget use for checking if current mount is present
  nilfs2: get rid of sget use for acquiring nilfs object
  nilfs2: remove meaningless EBUSY case from nilfs_get_sb function
  remove the call to ->write_super in __sync_filesystem
  nilfs2: call nilfs2_write_super from nilfs2_sync_fs
  jffs2: call jffs2_write_super from jffs2_sync_fs
  ufs: add ->sync_fs
  sysv: add ->sync_fs
  hfsplus: add ->sync_fs
  hfs: add ->sync_fs
  fat: add ->sync_fs
  ext2: add ->sync_fs
  exofs: add ->sync_fs
  bfs: add ->sync_fs
  affs: add ->sync_fs
  sanitize ->fsync() for affs
  repair bfs_write_inode(), switch bfs to simple_fsync()
  ...
parents 875287ca aa7dfb89
...@@ -736,6 +736,8 @@ static void ncp_put_super(struct super_block *sb) ...@@ -736,6 +736,8 @@ static void ncp_put_super(struct super_block *sb)
{ {
struct ncp_server *server = NCP_SBP(sb); struct ncp_server *server = NCP_SBP(sb);
lock_kernel();
ncp_lock_server(server); ncp_lock_server(server);
ncp_disconnect(server); ncp_disconnect(server);
ncp_unlock_server(server); ncp_unlock_server(server);
...@@ -769,6 +771,8 @@ static void ncp_put_super(struct super_block *sb) ...@@ -769,6 +771,8 @@ static void ncp_put_super(struct super_block *sb)
vfree(server->packet); vfree(server->packet);
sb->s_fs_info = NULL; sb->s_fs_info = NULL;
kfree(server); kfree(server);
unlock_kernel();
} }
static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf) static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
......
...@@ -154,7 +154,7 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) ...@@ -154,7 +154,7 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
goto out; goto out;
out_follow: out_follow:
while (d_mountpoint(nd->path.dentry) && while (d_mountpoint(nd->path.dentry) &&
follow_down(&nd->path.mnt, &nd->path.dentry)) follow_down(&nd->path))
; ;
err = 0; err = 0;
goto out; goto out;
......
...@@ -1813,6 +1813,7 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data) ...@@ -1813,6 +1813,7 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
if (data == NULL) if (data == NULL)
return -ENOMEM; return -ENOMEM;
lock_kernel();
/* fill out struct with values from existing mount */ /* fill out struct with values from existing mount */
data->flags = nfss->flags; data->flags = nfss->flags;
data->rsize = nfss->rsize; data->rsize = nfss->rsize;
...@@ -1837,6 +1838,7 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data) ...@@ -1837,6 +1838,7 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
error = nfs_compare_remount_data(nfss, data); error = nfs_compare_remount_data(nfss, data);
out: out:
kfree(data); kfree(data);
unlock_kernel();
return error; return error;
} }
......
...@@ -847,9 +847,8 @@ exp_get_fsid_key(svc_client *clp, int fsid) ...@@ -847,9 +847,8 @@ exp_get_fsid_key(svc_client *clp, int fsid)
return exp_find_key(clp, FSID_NUM, fsidv, NULL); return exp_find_key(clp, FSID_NUM, fsidv, NULL);
} }
static svc_export *exp_get_by_name(svc_client *clp, struct vfsmount *mnt, static svc_export *exp_get_by_name(svc_client *clp, const struct path *path,
struct dentry *dentry, struct cache_req *reqp)
struct cache_req *reqp)
{ {
struct svc_export *exp, key; struct svc_export *exp, key;
int err; int err;
...@@ -858,8 +857,7 @@ static svc_export *exp_get_by_name(svc_client *clp, struct vfsmount *mnt, ...@@ -858,8 +857,7 @@ static svc_export *exp_get_by_name(svc_client *clp, struct vfsmount *mnt,
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
key.ex_client = clp; key.ex_client = clp;
key.ex_path.mnt = mnt; key.ex_path = *path;
key.ex_path.dentry = dentry;
exp = svc_export_lookup(&key); exp = svc_export_lookup(&key);
if (exp == NULL) if (exp == NULL)
...@@ -873,24 +871,19 @@ static svc_export *exp_get_by_name(svc_client *clp, struct vfsmount *mnt, ...@@ -873,24 +871,19 @@ static svc_export *exp_get_by_name(svc_client *clp, struct vfsmount *mnt,
/* /*
* Find the export entry for a given dentry. * Find the export entry for a given dentry.
*/ */
static struct svc_export *exp_parent(svc_client *clp, struct vfsmount *mnt, static struct svc_export *exp_parent(svc_client *clp, struct path *path)
struct dentry *dentry,
struct cache_req *reqp)
{ {
svc_export *exp; struct dentry *saved = dget(path->dentry);
svc_export *exp = exp_get_by_name(clp, path, NULL);
dget(dentry);
exp = exp_get_by_name(clp, mnt, dentry, reqp); while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) {
struct dentry *parent = dget_parent(path->dentry);
while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(dentry)) { dput(path->dentry);
struct dentry *parent; path->dentry = parent;
exp = exp_get_by_name(clp, path, NULL);
parent = dget_parent(dentry);
dput(dentry);
dentry = parent;
exp = exp_get_by_name(clp, mnt, dentry, reqp);
} }
dput(dentry); dput(path->dentry);
path->dentry = saved;
return exp; return exp;
} }
...@@ -1018,7 +1011,7 @@ exp_export(struct nfsctl_export *nxp) ...@@ -1018,7 +1011,7 @@ exp_export(struct nfsctl_export *nxp)
goto out_put_clp; goto out_put_clp;
err = -EINVAL; err = -EINVAL;
exp = exp_get_by_name(clp, path.mnt, path.dentry, NULL); exp = exp_get_by_name(clp, &path, NULL);
memset(&new, 0, sizeof(new)); memset(&new, 0, sizeof(new));
...@@ -1135,7 +1128,7 @@ exp_unexport(struct nfsctl_export *nxp) ...@@ -1135,7 +1128,7 @@ exp_unexport(struct nfsctl_export *nxp)
goto out_domain; goto out_domain;
err = -EINVAL; err = -EINVAL;
exp = exp_get_by_name(dom, path.mnt, path.dentry, NULL); exp = exp_get_by_name(dom, &path, NULL);
path_put(&path); path_put(&path);
if (IS_ERR(exp)) if (IS_ERR(exp))
goto out_domain; goto out_domain;
...@@ -1177,7 +1170,7 @@ exp_rootfh(svc_client *clp, char *name, struct knfsd_fh *f, int maxsize) ...@@ -1177,7 +1170,7 @@ exp_rootfh(svc_client *clp, char *name, struct knfsd_fh *f, int maxsize)
dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n", dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n",
name, path.dentry, clp->name, name, path.dentry, clp->name,
inode->i_sb->s_id, inode->i_ino); inode->i_sb->s_id, inode->i_ino);
exp = exp_parent(clp, path.mnt, path.dentry, NULL); exp = exp_parent(clp, &path);
if (IS_ERR(exp)) { if (IS_ERR(exp)) {
err = PTR_ERR(exp); err = PTR_ERR(exp);
goto out; goto out;
...@@ -1207,7 +1200,7 @@ static struct svc_export *exp_find(struct auth_domain *clp, int fsid_type, ...@@ -1207,7 +1200,7 @@ static struct svc_export *exp_find(struct auth_domain *clp, int fsid_type,
if (IS_ERR(ek)) if (IS_ERR(ek))
return ERR_CAST(ek); return ERR_CAST(ek);
exp = exp_get_by_name(clp, ek->ek_path.mnt, ek->ek_path.dentry, reqp); exp = exp_get_by_name(clp, &ek->ek_path, reqp);
cache_put(&ek->h, &svc_expkey_cache); cache_put(&ek->h, &svc_expkey_cache);
if (IS_ERR(exp)) if (IS_ERR(exp))
...@@ -1247,8 +1240,7 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp) ...@@ -1247,8 +1240,7 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
* use exp_get_by_name() or exp_find(). * use exp_get_by_name() or exp_find().
*/ */
struct svc_export * struct svc_export *
rqst_exp_get_by_name(struct svc_rqst *rqstp, struct vfsmount *mnt, rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path)
struct dentry *dentry)
{ {
struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT); struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
...@@ -1256,8 +1248,7 @@ rqst_exp_get_by_name(struct svc_rqst *rqstp, struct vfsmount *mnt, ...@@ -1256,8 +1248,7 @@ rqst_exp_get_by_name(struct svc_rqst *rqstp, struct vfsmount *mnt,
goto gss; goto gss;
/* First try the auth_unix client: */ /* First try the auth_unix client: */
exp = exp_get_by_name(rqstp->rq_client, mnt, dentry, exp = exp_get_by_name(rqstp->rq_client, path, &rqstp->rq_chandle);
&rqstp->rq_chandle);
if (PTR_ERR(exp) == -ENOENT) if (PTR_ERR(exp) == -ENOENT)
goto gss; goto gss;
if (IS_ERR(exp)) if (IS_ERR(exp))
...@@ -1269,8 +1260,7 @@ rqst_exp_get_by_name(struct svc_rqst *rqstp, struct vfsmount *mnt, ...@@ -1269,8 +1260,7 @@ rqst_exp_get_by_name(struct svc_rqst *rqstp, struct vfsmount *mnt,
/* Otherwise, try falling back on gss client */ /* Otherwise, try falling back on gss client */
if (rqstp->rq_gssclient == NULL) if (rqstp->rq_gssclient == NULL)
return exp; return exp;
gssexp = exp_get_by_name(rqstp->rq_gssclient, mnt, dentry, gssexp = exp_get_by_name(rqstp->rq_gssclient, path, &rqstp->rq_chandle);
&rqstp->rq_chandle);
if (PTR_ERR(gssexp) == -ENOENT) if (PTR_ERR(gssexp) == -ENOENT)
return exp; return exp;
if (!IS_ERR(exp)) if (!IS_ERR(exp))
...@@ -1309,23 +1299,19 @@ rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv) ...@@ -1309,23 +1299,19 @@ rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv)
} }
struct svc_export * struct svc_export *
rqst_exp_parent(struct svc_rqst *rqstp, struct vfsmount *mnt, rqst_exp_parent(struct svc_rqst *rqstp, struct path *path)
struct dentry *dentry)
{ {
struct svc_export *exp; struct dentry *saved = dget(path->dentry);
struct svc_export *exp = rqst_exp_get_by_name(rqstp, path);
dget(dentry);
exp = rqst_exp_get_by_name(rqstp, mnt, dentry); while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) {
struct dentry *parent = dget_parent(path->dentry);
while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(dentry)) { dput(path->dentry);
struct dentry *parent; path->dentry = parent;
exp = rqst_exp_get_by_name(rqstp, path);
parent = dget_parent(dentry);
dput(dentry);
dentry = parent;
exp = rqst_exp_get_by_name(rqstp, mnt, dentry);
} }
dput(dentry); dput(path->dentry);
path->dentry = saved;
return exp; return exp;
} }
......
...@@ -101,36 +101,35 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, ...@@ -101,36 +101,35 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
{ {
struct svc_export *exp = *expp, *exp2 = NULL; struct svc_export *exp = *expp, *exp2 = NULL;
struct dentry *dentry = *dpp; struct dentry *dentry = *dpp;
struct vfsmount *mnt = mntget(exp->ex_path.mnt); struct path path = {.mnt = mntget(exp->ex_path.mnt),
struct dentry *mounts = dget(dentry); .dentry = dget(dentry)};
int err = 0; int err = 0;
while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts)); while (d_mountpoint(path.dentry) && follow_down(&path))
;
exp2 = rqst_exp_get_by_name(rqstp, mnt, mounts); exp2 = rqst_exp_get_by_name(rqstp, &path);
if (IS_ERR(exp2)) { if (IS_ERR(exp2)) {
if (PTR_ERR(exp2) != -ENOENT) if (PTR_ERR(exp2) != -ENOENT)
err = PTR_ERR(exp2); err = PTR_ERR(exp2);
dput(mounts); path_put(&path);
mntput(mnt);
goto out; goto out;
} }
if ((exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2)) { if ((exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2)) {
/* successfully crossed mount point */ /* successfully crossed mount point */
/* /*
* This is subtle: dentry is *not* under mnt at this point. * This is subtle: path.dentry is *not* on path.mnt
* The only reason we are safe is that original mnt is pinned * at this point. The only reason we are safe is that
* down by exp, so we should dput before putting exp. * original mnt is pinned down by exp, so we should
* put path *before* putting exp
*/ */
dput(dentry); *dpp = path.dentry;
*dpp = mounts; path.dentry = dentry;
exp_put(exp);
*expp = exp2; *expp = exp2;
} else { exp2 = exp;
exp_put(exp2);
dput(mounts);
} }
mntput(mnt); path_put(&path);
exp_put(exp2);
out: out:
return err; return err;
} }
...@@ -169,28 +168,29 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -169,28 +168,29 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
/* checking mountpoint crossing is very different when stepping up */ /* checking mountpoint crossing is very different when stepping up */
struct svc_export *exp2 = NULL; struct svc_export *exp2 = NULL;
struct dentry *dp; struct dentry *dp;
struct vfsmount *mnt = mntget(exp->ex_path.mnt); struct path path = {.mnt = mntget(exp->ex_path.mnt),
dentry = dget(dparent); .dentry = dget(dparent)};
while(dentry == mnt->mnt_root && follow_up(&mnt, &dentry))
while (path.dentry == path.mnt->mnt_root &&
follow_up(&path))
; ;
dp = dget_parent(dentry); dp = dget_parent(path.dentry);
dput(dentry); dput(path.dentry);
dentry = dp; path.dentry = dp;
exp2 = rqst_exp_parent(rqstp, mnt, dentry); exp2 = rqst_exp_parent(rqstp, &path);
if (PTR_ERR(exp2) == -ENOENT) { if (PTR_ERR(exp2) == -ENOENT) {
dput(dentry);
dentry = dget(dparent); dentry = dget(dparent);
} else if (IS_ERR(exp2)) { } else if (IS_ERR(exp2)) {
host_err = PTR_ERR(exp2); host_err = PTR_ERR(exp2);
dput(dentry); path_put(&path);
mntput(mnt);
goto out_nfserr; goto out_nfserr;
} else { } else {
dentry = dget(path.dentry);
exp_put(exp); exp_put(exp);
exp = exp2; exp = exp2;
} }
mntput(mnt); path_put(&path);
} }
} else { } else {
fh_lock(fhp); fh_lock(fhp);
......
...@@ -864,11 +864,11 @@ int nilfs_cpfile_change_cpmode(struct inode *cpfile, __u64 cno, int mode) ...@@ -864,11 +864,11 @@ int nilfs_cpfile_change_cpmode(struct inode *cpfile, __u64 cno, int mode)
case NILFS_CHECKPOINT: case NILFS_CHECKPOINT:
/* /*
* Check for protecting existing snapshot mounts: * Check for protecting existing snapshot mounts:
* bd_mount_sem is used to make this operation atomic and * ns_mount_mutex is used to make this operation atomic and
* exclusive with a new mount job. Though it doesn't cover * exclusive with a new mount job. Though it doesn't cover
* umount, it's enough for the purpose. * umount, it's enough for the purpose.
*/ */
down(&nilfs->ns_bdev->bd_mount_sem); mutex_lock(&nilfs->ns_mount_mutex);
if (nilfs_checkpoint_is_mounted(nilfs, cno, 1)) { if (nilfs_checkpoint_is_mounted(nilfs, cno, 1)) {
/* Current implementation does not have to protect /* Current implementation does not have to protect
plain read-only mounts since they are exclusive plain read-only mounts since they are exclusive
...@@ -877,7 +877,7 @@ int nilfs_cpfile_change_cpmode(struct inode *cpfile, __u64 cno, int mode) ...@@ -877,7 +877,7 @@ int nilfs_cpfile_change_cpmode(struct inode *cpfile, __u64 cno, int mode)
ret = -EBUSY; ret = -EBUSY;
} else } else
ret = nilfs_cpfile_clear_snapshot(cpfile, cno); ret = nilfs_cpfile_clear_snapshot(cpfile, cno);
up(&nilfs->ns_bdev->bd_mount_sem); mutex_unlock(&nilfs->ns_mount_mutex);
return ret; return ret;
case NILFS_SNAPSHOT: case NILFS_SNAPSHOT:
return nilfs_cpfile_set_snapshot(cpfile, cno); return nilfs_cpfile_set_snapshot(cpfile, cno);
......
...@@ -60,6 +60,7 @@ struct nilfs_sb_info { ...@@ -60,6 +60,7 @@ struct nilfs_sb_info {
struct super_block *s_super; /* reverse pointer to super_block */ struct super_block *s_super; /* reverse pointer to super_block */
struct the_nilfs *s_nilfs; struct the_nilfs *s_nilfs;
struct list_head s_list; /* list head for nilfs->ns_supers */ struct list_head s_list; /* list head for nilfs->ns_supers */
atomic_t s_count; /* reference count */
/* Segment constructor */ /* Segment constructor */
struct list_head s_dirty_files; /* dirty files list */ struct list_head s_dirty_files; /* dirty files list */
......
...@@ -65,9 +65,8 @@ MODULE_DESCRIPTION("A New Implementation of the Log-structured Filesystem " ...@@ -65,9 +65,8 @@ MODULE_DESCRIPTION("A New Implementation of the Log-structured Filesystem "
"(NILFS)"); "(NILFS)");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static void nilfs_write_super(struct super_block *sb);
static int nilfs_remount(struct super_block *sb, int *flags, char *data); static int nilfs_remount(struct super_block *sb, int *flags, char *data);
static int test_exclusive_mount(struct file_system_type *fs_type,
struct block_device *bdev, int flags);
/** /**
* nilfs_error() - report failure condition on a filesystem * nilfs_error() - report failure condition on a filesystem
...@@ -315,6 +314,11 @@ static void nilfs_put_super(struct super_block *sb) ...@@ -315,6 +314,11 @@ static void nilfs_put_super(struct super_block *sb)
struct nilfs_sb_info *sbi = NILFS_SB(sb); struct nilfs_sb_info *sbi = NILFS_SB(sb);
struct the_nilfs *nilfs = sbi->s_nilfs; struct the_nilfs *nilfs = sbi->s_nilfs;
lock_kernel();
if (sb->s_dirt)
nilfs_write_super(sb);
nilfs_detach_segment_constructor(sbi); nilfs_detach_segment_constructor(sbi);
if (!(sb->s_flags & MS_RDONLY)) { if (!(sb->s_flags & MS_RDONLY)) {
...@@ -323,12 +327,18 @@ static void nilfs_put_super(struct super_block *sb) ...@@ -323,12 +327,18 @@ static void nilfs_put_super(struct super_block *sb)
nilfs_commit_super(sbi, 1); nilfs_commit_super(sbi, 1);
up_write(&nilfs->ns_sem); up_write(&nilfs->ns_sem);
} }
down_write(&nilfs->ns_super_sem);
if (nilfs->ns_current == sbi)
nilfs->ns_current = NULL;
up_write(&nilfs->ns_super_sem);
nilfs_detach_checkpoint(sbi); nilfs_detach_checkpoint(sbi);
put_nilfs(sbi->s_nilfs); put_nilfs(sbi->s_nilfs);
sbi->s_super = NULL; sbi->s_super = NULL;
sb->s_fs_info = NULL; sb->s_fs_info = NULL;
kfree(sbi); nilfs_put_sbinfo(sbi);
unlock_kernel();
} }
/** /**
...@@ -383,6 +393,8 @@ static int nilfs_sync_fs(struct super_block *sb, int wait) ...@@ -383,6 +393,8 @@ static int nilfs_sync_fs(struct super_block *sb, int wait)
{ {
int err = 0; int err = 0;
nilfs_write_super(sb);
/* This function is called when super block should be written back */ /* This function is called when super block should be written back */
if (wait) if (wait)
err = nilfs_construct_segment(sb); err = nilfs_construct_segment(sb);
...@@ -396,9 +408,9 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno) ...@@ -396,9 +408,9 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno)
struct buffer_head *bh_cp; struct buffer_head *bh_cp;
int err; int err;
down_write(&nilfs->ns_sem); down_write(&nilfs->ns_super_sem);
list_add(&sbi->s_list, &nilfs->ns_supers); list_add(&sbi->s_list, &nilfs->ns_supers);
up_write(&nilfs->ns_sem); up_write(&nilfs->ns_super_sem);
sbi->s_ifile = nilfs_mdt_new( sbi->s_ifile = nilfs_mdt_new(
nilfs, sbi->s_super, NILFS_IFILE_INO, NILFS_IFILE_GFP); nilfs, sbi->s_super, NILFS_IFILE_INO, NILFS_IFILE_GFP);
...@@ -436,9 +448,9 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno) ...@@ -436,9 +448,9 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno)
nilfs_mdt_destroy(sbi->s_ifile); nilfs_mdt_destroy(sbi->s_ifile);
sbi->s_ifile = NULL; sbi->s_ifile = NULL;
down_write(&nilfs->ns_sem); down_write(&nilfs->ns_super_sem);
list_del_init(&sbi->s_list); list_del_init(&sbi->s_list);
up_write(&nilfs->ns_sem); up_write(&nilfs->ns_super_sem);
return err; return err;
} }
...@@ -450,9 +462,9 @@ void nilfs_detach_checkpoint(struct nilfs_sb_info *sbi) ...@@ -450,9 +462,9 @@ void nilfs_detach_checkpoint(struct nilfs_sb_info *sbi)
nilfs_mdt_clear(sbi->s_ifile); nilfs_mdt_clear(sbi->s_ifile);
nilfs_mdt_destroy(sbi->s_ifile); nilfs_mdt_destroy(sbi->s_ifile);
sbi->s_ifile = NULL; sbi->s_ifile = NULL;
down_write(&nilfs->ns_sem); down_write(&nilfs->ns_super_sem);
list_del_init(&sbi->s_list); list_del_init(&sbi->s_list);
up_write(&nilfs->ns_sem); up_write(&nilfs->ns_super_sem);
} }
static int nilfs_mark_recovery_complete(struct nilfs_sb_info *sbi) static int nilfs_mark_recovery_complete(struct nilfs_sb_info *sbi)
...@@ -752,7 +764,7 @@ int nilfs_store_magic_and_option(struct super_block *sb, ...@@ -752,7 +764,7 @@ int nilfs_store_magic_and_option(struct super_block *sb,
* @silent: silent mode flag * @silent: silent mode flag
* @nilfs: the_nilfs struct * @nilfs: the_nilfs struct
* *
* This function is called exclusively by bd_mount_mutex. * This function is called exclusively by nilfs->ns_mount_mutex.
* So, the recovery process is protected from other simultaneous mounts. * So, the recovery process is protected from other simultaneous mounts.
*/ */
static int static int
...@@ -773,6 +785,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, ...@@ -773,6 +785,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent,
get_nilfs(nilfs); get_nilfs(nilfs);
sbi->s_nilfs = nilfs; sbi->s_nilfs = nilfs;
sbi->s_super = sb; sbi->s_super = sb;
atomic_set(&sbi->s_count, 1);
err = init_nilfs(nilfs, sbi, (char *)data); err = init_nilfs(nilfs, sbi, (char *)data);
if (err) if (err)
...@@ -870,6 +883,11 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, ...@@ -870,6 +883,11 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent,
goto failed_root; goto failed_root;
} }
down_write(&nilfs->ns_super_sem);
if (!nilfs_test_opt(sbi, SNAPSHOT))
nilfs->ns_current = sbi;
up_write(&nilfs->ns_super_sem);
return 0; return 0;
failed_root: failed_root:
...@@ -885,7 +903,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, ...@@ -885,7 +903,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent,
failed_sbi: failed_sbi:
put_nilfs(nilfs); put_nilfs(nilfs);
sb->s_fs_info = NULL; sb->s_fs_info = NULL;
kfree(sbi); nilfs_put_sbinfo(sbi);
return err; return err;
} }
...@@ -898,6 +916,9 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) ...@@ -898,6 +916,9 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
struct nilfs_mount_options old_opts; struct nilfs_mount_options old_opts;
int err; int err;
lock_kernel();
down_write(&nilfs->ns_super_sem);
old_sb_flags = sb->s_flags; old_sb_flags = sb->s_flags;
old_opts.mount_opt = sbi->s_mount_opt; old_opts.mount_opt = sbi->s_mount_opt;
old_opts.snapshot_cno = sbi->s_snapshot_cno; old_opts.snapshot_cno = sbi->s_snapshot_cno;
...@@ -945,14 +966,12 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) ...@@ -945,14 +966,12 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
* store the current valid flag. (It may have been changed * store the current valid flag. (It may have been changed
* by fsck since we originally mounted the partition.) * by fsck since we originally mounted the partition.)
*/ */
down(&sb->s_bdev->bd_mount_sem); if (nilfs->ns_current && nilfs->ns_current != sbi) {
/* Check existing RW-mount */
if (test_exclusive_mount(sb->s_type, sb->s_bdev, 0)) {
printk(KERN_WARNING "NILFS (device %s): couldn't " printk(KERN_WARNING "NILFS (device %s): couldn't "
"remount because a RW-mount exists.\n", "remount because an RW-mount exists.\n",
sb->s_id); sb->s_id);
err = -EBUSY; err = -EBUSY;
goto rw_remount_failed; goto restore_opts;
} }
if (sbi->s_snapshot_cno != nilfs_last_cno(nilfs)) { if (sbi->s_snapshot_cno != nilfs_last_cno(nilfs)) {
printk(KERN_WARNING "NILFS (device %s): couldn't " printk(KERN_WARNING "NILFS (device %s): couldn't "
...@@ -960,7 +979,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) ...@@ -960,7 +979,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
"the latest one.\n", "the latest one.\n",
sb->s_id); sb->s_id);
err = -EINVAL; err = -EINVAL;
goto rw_remount_failed; goto restore_opts;
} }
sb->s_flags &= ~MS_RDONLY; sb->s_flags &= ~MS_RDONLY;
nilfs_clear_opt(sbi, SNAPSHOT); nilfs_clear_opt(sbi, SNAPSHOT);
...@@ -968,28 +987,31 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) ...@@ -968,28 +987,31 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
err = nilfs_attach_segment_constructor(sbi); err = nilfs_attach_segment_constructor(sbi);
if (err) if (err)
goto rw_remount_failed; goto restore_opts;
down_write(&nilfs->ns_sem); down_write(&nilfs->ns_sem);
nilfs_setup_super(sbi); nilfs_setup_super(sbi);
up_write(&nilfs->ns_sem); up_write(&nilfs->ns_sem);
up(&sb->s_bdev->bd_mount_sem); nilfs->ns_current = sbi;
} }
out: out:
up_write(&nilfs->ns_super_sem);
unlock_kernel();
return 0; return 0;
rw_remount_failed:
up(&sb->s_bdev->bd_mount_sem);
restore_opts: restore_opts:
sb->s_flags = old_sb_flags; sb->s_flags = old_sb_flags;
sbi->s_mount_opt = old_opts.mount_opt; sbi->s_mount_opt = old_opts.mount_opt;
sbi->s_snapshot_cno = old_opts.snapshot_cno; sbi->s_snapshot_cno = old_opts.snapshot_cno;
up_write(&nilfs->ns_super_sem);
unlock_kernel();
return err; return err;
} }
struct nilfs_super_data { struct nilfs_super_data {
struct block_device *bdev; struct block_device *bdev;
struct nilfs_sb_info *sbi;
__u64 cno; __u64 cno;
int flags; int flags;
}; };
...@@ -1048,33 +1070,7 @@ static int nilfs_test_bdev_super(struct super_block *s, void *data) ...@@ -1048,33 +1070,7 @@ static int nilfs_test_bdev_super(struct super_block *s, void *data)
{ {
struct nilfs_super_data *sd = data; struct nilfs_super_data *sd = data;
return s->s_bdev == sd->bdev; return sd->sbi && s->s_fs_info == (void *)sd->sbi;
}
static int nilfs_test_bdev_super2(struct super_block *s, void *data)
{
struct nilfs_super_data *sd = data;
int ret;
if (s->s_bdev != sd->bdev)
return 0;
if (!((s->s_flags | sd->flags) & MS_RDONLY))
return 1; /* Reuse an old R/W-mode super_block */
if (s->s_flags & sd->flags & MS_RDONLY) {
if (down_read_trylock(&s->s_umount)) {
ret = s->s_root &&
(sd->cno == NILFS_SB(s)->s_snapshot_cno);
up_read(&s->s_umount);
/*
* This path is locked with sb_lock by sget().
* So, drop_super() causes deadlock.
*/
return ret;
}
}
return 0;
} }
static int static int
...@@ -1082,8 +1078,8 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, ...@@ -1082,8 +1078,8 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
const char *dev_name, void *data, struct vfsmount *mnt) const char *dev_name, void *data, struct vfsmount *mnt)
{ {
struct nilfs_super_data sd; struct nilfs_super_data sd;
struct super_block *s, *s2; struct super_block *s;
struct the_nilfs *nilfs = NULL; struct the_nilfs *nilfs;
int err, need_to_close = 1; int err, need_to_close = 1;
sd.bdev = open_bdev_exclusive(dev_name, flags, fs_type); sd.bdev = open_bdev_exclusive(dev_name, flags, fs_type);
...@@ -1095,7 +1091,6 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, ...@@ -1095,7 +1091,6 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
* much more information than normal filesystems to identify mount * much more information than normal filesystems to identify mount
* instance. For snapshot mounts, not only a mount type (ro-mount * instance. For snapshot mounts, not only a mount type (ro-mount
* or rw-mount) but also a checkpoint number is required. * or rw-mount) but also a checkpoint number is required.
* The results are passed in sget() using nilfs_super_data.
*/ */
sd.cno = 0; sd.cno = 0;
sd.flags = flags; sd.flags = flags;
...@@ -1104,64 +1099,59 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, ...@@ -1104,64 +1099,59 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
goto failed; goto failed;
} }
/* nilfs = find_or_create_nilfs(sd.bdev);
* once the super is inserted into the list by sget, s_umount if (!nilfs) {
* will protect the lockfs code from trying to start a snapshot err = -ENOMEM;
* while we are mounting goto failed;
*/
down(&sd.bdev->bd_mount_sem);
if (!sd.cno &&
(err = test_exclusive_mount(fs_type, sd.bdev, flags ^ MS_RDONLY))) {
err = (err < 0) ? : -EBUSY;
goto failed_unlock;
} }
/* mutex_lock(&nilfs->ns_mount_mutex);
* Phase-1: search any existent instance and get the_nilfs
*/
s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, &sd);
if (IS_ERR(s))
goto error_s;
if (!s->s_root) {
err = -ENOMEM;
nilfs = alloc_nilfs(sd.bdev);
if (!nilfs)
goto cancel_new;
} else {
struct nilfs_sb_info *sbi = NILFS_SB(s);
if (!sd.cno) {
/* /*
* s_umount protects super_block from unmount process; * Check if an exclusive mount exists or not.
* It covers pointers of nilfs_sb_info and the_nilfs. * Snapshot mounts coexist with a current mount
* (i.e. rw-mount or ro-mount), whereas rw-mount and
* ro-mount are mutually exclusive.
*/ */
nilfs = sbi->s_nilfs; down_read(&nilfs->ns_super_sem);
get_nilfs(nilfs); if (nilfs->ns_current &&
up_write(&s->s_umount); ((nilfs->ns_current->s_super->s_flags ^ flags)
& MS_RDONLY)) {
up_read(&nilfs->ns_super_sem);
err = -EBUSY;
goto failed_unlock;
}
up_read(&nilfs->ns_super_sem);
}
/* /*
* Phase-2: search specified snapshot or R/W mode super_block * Find existing nilfs_sb_info struct
*/ */
if (!sd.cno) sd.sbi = nilfs_find_sbinfo(nilfs, !(flags & MS_RDONLY), sd.cno);
/* trying to get the latest checkpoint. */
sd.cno = nilfs_last_cno(nilfs);
s2 = sget(fs_type, nilfs_test_bdev_super2, if (!sd.cno)
nilfs_set_bdev_super, &sd); /* trying to get the latest checkpoint. */
deactivate_super(s); sd.cno = nilfs_last_cno(nilfs);
/*
* Although deactivate_super() invokes close_bdev_exclusive() at /*
* kill_block_super(). Here, s is an existent mount; we need * Get super block instance holding the nilfs_sb_info struct.
* one more close_bdev_exclusive() call. * A new instance is allocated if no existing mount is present or
*/ * existing instance has been unmounted.
s = s2; */
if (IS_ERR(s)) s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, &sd);
goto error_s; if (sd.sbi)
nilfs_put_sbinfo(sd.sbi);
if (IS_ERR(s)) {
err = PTR_ERR(s);
goto failed_unlock;
} }
if (!s->s_root) { if (!s->s_root) {
char b[BDEVNAME_SIZE]; char b[BDEVNAME_SIZE];
/* New superblock instance created */
s->s_flags = flags; s->s_flags = flags;
strlcpy(s->s_id, bdevname(sd.bdev, b), sizeof(s->s_id)); strlcpy(s->s_id, bdevname(sd.bdev, b), sizeof(s->s_id));
sb_set_blocksize(s, block_size(sd.bdev)); sb_set_blocksize(s, block_size(sd.bdev));
...@@ -1172,26 +1162,18 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, ...@@ -1172,26 +1162,18 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
s->s_flags |= MS_ACTIVE; s->s_flags |= MS_ACTIVE;
need_to_close = 0; need_to_close = 0;
} else if (!(s->s_flags & MS_RDONLY)) {
err = -EBUSY;
} }
up(&sd.bdev->bd_mount_sem); mutex_unlock(&nilfs->ns_mount_mutex);
put_nilfs(nilfs); put_nilfs(nilfs);
if (need_to_close) if (need_to_close)
close_bdev_exclusive(sd.bdev, flags); close_bdev_exclusive(sd.bdev, flags);
simple_set_mnt(mnt, s); simple_set_mnt(mnt, s);
return 0; return 0;
error_s:
up(&sd.bdev->bd_mount_sem);
if (nilfs)
put_nilfs(nilfs);
close_bdev_exclusive(sd.bdev, flags);
return PTR_ERR(s);
failed_unlock: failed_unlock:
up(&sd.bdev->bd_mount_sem); mutex_unlock(&nilfs->ns_mount_mutex);
put_nilfs(nilfs);
failed: failed:
close_bdev_exclusive(sd.bdev, flags); close_bdev_exclusive(sd.bdev, flags);
...@@ -1199,70 +1181,18 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, ...@@ -1199,70 +1181,18 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
cancel_new: cancel_new:
/* Abandoning the newly allocated superblock */ /* Abandoning the newly allocated superblock */
up(&sd.bdev->bd_mount_sem); mutex_unlock(&nilfs->ns_mount_mutex);
if (nilfs) put_nilfs(nilfs);
put_nilfs(nilfs);
up_write(&s->s_umount); up_write(&s->s_umount);
deactivate_super(s); deactivate_super(s);
/* /*
* deactivate_super() invokes close_bdev_exclusive(). * deactivate_super() invokes close_bdev_exclusive().
* We must finish all post-cleaning before this call; * We must finish all post-cleaning before this call;
* put_nilfs() and unlocking bd_mount_sem need the block device. * put_nilfs() needs the block device.
*/ */
return err; return err;
} }
static int nilfs_test_bdev_super3(struct super_block *s, void *data)
{
struct nilfs_super_data *sd = data;
int ret;
if (s->s_bdev != sd->bdev)
return 0;
if (down_read_trylock(&s->s_umount)) {
ret = (s->s_flags & MS_RDONLY) && s->s_root &&
nilfs_test_opt(NILFS_SB(s), SNAPSHOT);
up_read(&s->s_umount);
if (ret)
return 0; /* ignore snapshot mounts */
}
return !((sd->flags ^ s->s_flags) & MS_RDONLY);
}
static int __false_bdev_super(struct super_block *s, void *data)
{
#if 0 /* XXX: workaround for lock debug. This is not good idea */
up_write(&s->s_umount);
#endif
return -EFAULT;
}
/**
* test_exclusive_mount - check whether an exclusive RW/RO mount exists or not.
* fs_type: filesystem type
* bdev: block device
* flag: 0 (check rw-mount) or MS_RDONLY (check ro-mount)
* res: pointer to an integer to store result
*
* This function must be called within a section protected by bd_mount_mutex.
*/
static int test_exclusive_mount(struct file_system_type *fs_type,
struct block_device *bdev, int flags)
{
struct super_block *s;
struct nilfs_super_data sd = { .flags = flags, .bdev = bdev };
s = sget(fs_type, nilfs_test_bdev_super3, __false_bdev_super, &sd);
if (IS_ERR(s)) {
if (PTR_ERR(s) != -EFAULT)
return PTR_ERR(s);
return 0; /* Not found */
}
up_write(&s->s_umount);
deactivate_super(s);
return 1; /* Found */
}
struct file_system_type nilfs_fs_type = { struct file_system_type nilfs_fs_type = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "nilfs2", .name = "nilfs2",
......
...@@ -35,6 +35,10 @@ ...@@ -35,6 +35,10 @@
#include "seglist.h" #include "seglist.h"
#include "segbuf.h" #include "segbuf.h"
static LIST_HEAD(nilfs_objects);
static DEFINE_SPINLOCK(nilfs_lock);
void nilfs_set_last_segment(struct the_nilfs *nilfs, void nilfs_set_last_segment(struct the_nilfs *nilfs,
sector_t start_blocknr, u64 seq, __u64 cno) sector_t start_blocknr, u64 seq, __u64 cno)
{ {
...@@ -55,7 +59,7 @@ void nilfs_set_last_segment(struct the_nilfs *nilfs, ...@@ -55,7 +59,7 @@ void nilfs_set_last_segment(struct the_nilfs *nilfs,
* Return Value: On success, pointer to the_nilfs is returned. * Return Value: On success, pointer to the_nilfs is returned.
* On error, NULL is returned. * On error, NULL is returned.
*/ */
struct the_nilfs *alloc_nilfs(struct block_device *bdev) static struct the_nilfs *alloc_nilfs(struct block_device *bdev)
{ {
struct the_nilfs *nilfs; struct the_nilfs *nilfs;
...@@ -68,7 +72,10 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev) ...@@ -68,7 +72,10 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev)
atomic_set(&nilfs->ns_writer_refcount, -1); atomic_set(&nilfs->ns_writer_refcount, -1);
atomic_set(&nilfs->ns_ndirtyblks, 0); atomic_set(&nilfs->ns_ndirtyblks, 0);
init_rwsem(&nilfs->ns_sem); init_rwsem(&nilfs->ns_sem);
init_rwsem(&nilfs->ns_super_sem);
mutex_init(&nilfs->ns_mount_mutex);
mutex_init(&nilfs->ns_writer_mutex); mutex_init(&nilfs->ns_writer_mutex);
INIT_LIST_HEAD(&nilfs->ns_list);
INIT_LIST_HEAD(&nilfs->ns_supers); INIT_LIST_HEAD(&nilfs->ns_supers);
spin_lock_init(&nilfs->ns_last_segment_lock); spin_lock_init(&nilfs->ns_last_segment_lock);
nilfs->ns_gc_inodes_h = NULL; nilfs->ns_gc_inodes_h = NULL;
...@@ -77,6 +84,45 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev) ...@@ -77,6 +84,45 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev)
return nilfs; return nilfs;
} }
/**
* find_or_create_nilfs - find or create nilfs object
* @bdev: block device to which the_nilfs is related
*
* find_nilfs() looks up an existent nilfs object created on the
* device and gets the reference count of the object. If no nilfs object
* is found on the device, a new nilfs object is allocated.
*
* Return Value: On success, pointer to the nilfs object is returned.
* On error, NULL is returned.
*/
struct the_nilfs *find_or_create_nilfs(struct block_device *bdev)
{
struct the_nilfs *nilfs, *new = NULL;
retry:
spin_lock(&nilfs_lock);
list_for_each_entry(nilfs, &nilfs_objects, ns_list) {
if (nilfs->ns_bdev == bdev) {
get_nilfs(nilfs);
spin_unlock(&nilfs_lock);
if (new)
put_nilfs(new);
return nilfs; /* existing object */
}
}
if (new) {
list_add_tail(&new->ns_list, &nilfs_objects);
spin_unlock(&nilfs_lock);
return new; /* new object */
}
spin_unlock(&nilfs_lock);
new = alloc_nilfs(bdev);
if (new)
goto retry;
return NULL; /* insufficient memory */
}
/** /**
* put_nilfs - release a reference to the_nilfs * put_nilfs - release a reference to the_nilfs
* @nilfs: the_nilfs structure to be released * @nilfs: the_nilfs structure to be released
...@@ -86,13 +132,20 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev) ...@@ -86,13 +132,20 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev)
*/ */
void put_nilfs(struct the_nilfs *nilfs) void put_nilfs(struct the_nilfs *nilfs)
{ {
if (!atomic_dec_and_test(&nilfs->ns_count)) spin_lock(&nilfs_lock);
if (!atomic_dec_and_test(&nilfs->ns_count)) {
spin_unlock(&nilfs_lock);
return; return;
}
list_del_init(&nilfs->ns_list);
spin_unlock(&nilfs_lock);
/* /*
* Increment of ns_count never occur below because the caller * Increment of ns_count never occurs below because the caller
* of get_nilfs() holds at least one reference to the_nilfs. * of get_nilfs() holds at least one reference to the_nilfs.
* Thus its exclusion control is not required here. * Thus its exclusion control is not required here.
*/ */
might_sleep(); might_sleep();
if (nilfs_loaded(nilfs)) { if (nilfs_loaded(nilfs)) {
nilfs_mdt_clear(nilfs->ns_sufile); nilfs_mdt_clear(nilfs->ns_sufile);
...@@ -613,13 +666,63 @@ int nilfs_near_disk_full(struct the_nilfs *nilfs) ...@@ -613,13 +666,63 @@ int nilfs_near_disk_full(struct the_nilfs *nilfs)
return ret; return ret;
} }
/**
* nilfs_find_sbinfo - find existing nilfs_sb_info structure
* @nilfs: nilfs object
* @rw_mount: mount type (non-zero value for read/write mount)
* @cno: checkpoint number (zero for read-only mount)
*
* nilfs_find_sbinfo() returns the nilfs_sb_info structure which
* @rw_mount and @cno (in case of snapshots) matched. If no instance
* was found, NULL is returned. Although the super block instance can
* be unmounted after this function returns, the nilfs_sb_info struct
* is kept on memory until nilfs_put_sbinfo() is called.
*/
struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *nilfs,
int rw_mount, __u64 cno)
{
struct nilfs_sb_info *sbi;
down_read(&nilfs->ns_super_sem);
/*
* The SNAPSHOT flag and sb->s_flags are supposed to be
* protected with nilfs->ns_super_sem.
*/
sbi = nilfs->ns_current;
if (rw_mount) {
if (sbi && !(sbi->s_super->s_flags & MS_RDONLY))
goto found; /* read/write mount */
else
goto out;
} else if (cno == 0) {
if (sbi && (sbi->s_super->s_flags & MS_RDONLY))
goto found; /* read-only mount */
else
goto out;
}
list_for_each_entry(sbi, &nilfs->ns_supers, s_list) {
if (nilfs_test_opt(sbi, SNAPSHOT) &&
sbi->s_snapshot_cno == cno)
goto found; /* snapshot mount */
}
out:
up_read(&nilfs->ns_super_sem);
return NULL;
found:
atomic_inc(&sbi->s_count);
up_read(&nilfs->ns_super_sem);
return sbi;
}
int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno, int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno,
int snapshot_mount) int snapshot_mount)
{ {
struct nilfs_sb_info *sbi; struct nilfs_sb_info *sbi;
int ret = 0; int ret = 0;
down_read(&nilfs->ns_sem); down_read(&nilfs->ns_super_sem);
if (cno == 0 || cno > nilfs->ns_cno) if (cno == 0 || cno > nilfs->ns_cno)
goto out_unlock; goto out_unlock;
...@@ -636,6 +739,6 @@ int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno, ...@@ -636,6 +739,6 @@ int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno,
ret++; ret++;
out_unlock: out_unlock:
up_read(&nilfs->ns_sem); up_read(&nilfs->ns_super_sem);
return ret; return ret;
} }
...@@ -43,12 +43,16 @@ enum { ...@@ -43,12 +43,16 @@ enum {
* struct the_nilfs - struct to supervise multiple nilfs mount points * struct the_nilfs - struct to supervise multiple nilfs mount points
* @ns_flags: flags * @ns_flags: flags
* @ns_count: reference count * @ns_count: reference count
* @ns_list: list head for nilfs_list
* @ns_bdev: block device * @ns_bdev: block device
* @ns_bdi: backing dev info * @ns_bdi: backing dev info
* @ns_writer: back pointer to writable nilfs_sb_info * @ns_writer: back pointer to writable nilfs_sb_info
* @ns_sem: semaphore for shared states * @ns_sem: semaphore for shared states
* @ns_super_sem: semaphore for global operations across super block instances
* @ns_mount_mutex: mutex protecting mount process of nilfs
* @ns_writer_mutex: mutex protecting ns_writer attach/detach * @ns_writer_mutex: mutex protecting ns_writer attach/detach
* @ns_writer_refcount: number of referrers on ns_writer * @ns_writer_refcount: number of referrers on ns_writer
* @ns_current: back pointer to current mount
* @ns_sbh: buffer heads of on-disk super blocks * @ns_sbh: buffer heads of on-disk super blocks
* @ns_sbp: pointers to super block data * @ns_sbp: pointers to super block data
* @ns_sbwtime: previous write time of super blocks * @ns_sbwtime: previous write time of super blocks
...@@ -88,14 +92,23 @@ enum { ...@@ -88,14 +92,23 @@ enum {
struct the_nilfs { struct the_nilfs {
unsigned long ns_flags; unsigned long ns_flags;
atomic_t ns_count; atomic_t ns_count;
struct list_head ns_list;
struct block_device *ns_bdev; struct block_device *ns_bdev;
struct backing_dev_info *ns_bdi; struct backing_dev_info *ns_bdi;
struct nilfs_sb_info *ns_writer; struct nilfs_sb_info *ns_writer;
struct rw_semaphore ns_sem; struct rw_semaphore ns_sem;
struct rw_semaphore ns_super_sem;
struct mutex ns_mount_mutex;
struct mutex ns_writer_mutex; struct mutex ns_writer_mutex;
atomic_t ns_writer_refcount; atomic_t ns_writer_refcount;
/*
* components protected by ns_super_sem
*/
struct nilfs_sb_info *ns_current;
struct list_head ns_supers;
/* /*
* used for * used for
* - loading the latest checkpoint exclusively. * - loading the latest checkpoint exclusively.
...@@ -108,7 +121,6 @@ struct the_nilfs { ...@@ -108,7 +121,6 @@ struct the_nilfs {
time_t ns_sbwtime[2]; time_t ns_sbwtime[2];
unsigned ns_sbsize; unsigned ns_sbsize;
unsigned ns_mount_state; unsigned ns_mount_state;
struct list_head ns_supers;
/* /*
* Following fields are dedicated to a writable FS-instance. * Following fields are dedicated to a writable FS-instance.
...@@ -191,11 +203,12 @@ THE_NILFS_FNS(DISCONTINUED, discontinued) ...@@ -191,11 +203,12 @@ THE_NILFS_FNS(DISCONTINUED, discontinued)
#define NILFS_ALTSB_FREQ 60 /* spare superblock */ #define NILFS_ALTSB_FREQ 60 /* spare superblock */
void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64); void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64);
struct the_nilfs *alloc_nilfs(struct block_device *); struct the_nilfs *find_or_create_nilfs(struct block_device *);
void put_nilfs(struct the_nilfs *); void put_nilfs(struct the_nilfs *);
int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *); int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *);
int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *); int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *);
int nilfs_count_free_blocks(struct the_nilfs *, sector_t *); int nilfs_count_free_blocks(struct the_nilfs *, sector_t *);
struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *, int, __u64);
int nilfs_checkpoint_is_mounted(struct the_nilfs *, __u64, int); int nilfs_checkpoint_is_mounted(struct the_nilfs *, __u64, int);
int nilfs_near_disk_full(struct the_nilfs *); int nilfs_near_disk_full(struct the_nilfs *);
void nilfs_fall_back_super_block(struct the_nilfs *); void nilfs_fall_back_super_block(struct the_nilfs *);
...@@ -238,6 +251,12 @@ nilfs_detach_writer(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) ...@@ -238,6 +251,12 @@ nilfs_detach_writer(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
mutex_unlock(&nilfs->ns_writer_mutex); mutex_unlock(&nilfs->ns_writer_mutex);
} }
static inline void nilfs_put_sbinfo(struct nilfs_sb_info *sbi)
{
if (!atomic_dec_and_test(&sbi->s_count))
kfree(sbi);
}
static inline void static inline void
nilfs_get_segment_range(struct the_nilfs *nilfs, __u64 segnum, nilfs_get_segment_range(struct the_nilfs *nilfs, __u64 segnum,
sector_t *seg_start, sector_t *seg_end) sector_t *seg_start, sector_t *seg_end)
......
...@@ -443,6 +443,8 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt) ...@@ -443,6 +443,8 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt)
ntfs_volume *vol = NTFS_SB(sb); ntfs_volume *vol = NTFS_SB(sb);
ntfs_debug("Entering with remount options string: %s", opt); ntfs_debug("Entering with remount options string: %s", opt);
lock_kernel();
#ifndef NTFS_RW #ifndef NTFS_RW
/* For read-only compiled driver, enforce read-only flag. */ /* For read-only compiled driver, enforce read-only flag. */
*flags |= MS_RDONLY; *flags |= MS_RDONLY;
...@@ -466,15 +468,18 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt) ...@@ -466,15 +468,18 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt)
if (NVolErrors(vol)) { if (NVolErrors(vol)) {
ntfs_error(sb, "Volume has errors and is read-only%s", ntfs_error(sb, "Volume has errors and is read-only%s",
es); es);
unlock_kernel();
return -EROFS; return -EROFS;
} }
if (vol->vol_flags & VOLUME_IS_DIRTY) { if (vol->vol_flags & VOLUME_IS_DIRTY) {
ntfs_error(sb, "Volume is dirty and read-only%s", es); ntfs_error(sb, "Volume is dirty and read-only%s", es);
unlock_kernel();
return -EROFS; return -EROFS;
} }
if (vol->vol_flags & VOLUME_MODIFIED_BY_CHKDSK) { if (vol->vol_flags & VOLUME_MODIFIED_BY_CHKDSK) {
ntfs_error(sb, "Volume has been modified by chkdsk " ntfs_error(sb, "Volume has been modified by chkdsk "
"and is read-only%s", es); "and is read-only%s", es);
unlock_kernel();
return -EROFS; return -EROFS;
} }
if (vol->vol_flags & VOLUME_MUST_MOUNT_RO_MASK) { if (vol->vol_flags & VOLUME_MUST_MOUNT_RO_MASK) {
...@@ -482,11 +487,13 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt) ...@@ -482,11 +487,13 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt)
"(0x%x) and is read-only%s", "(0x%x) and is read-only%s",
(unsigned)le16_to_cpu(vol->vol_flags), (unsigned)le16_to_cpu(vol->vol_flags),
es); es);
unlock_kernel();
return -EROFS; return -EROFS;
} }
if (ntfs_set_volume_flags(vol, VOLUME_IS_DIRTY)) { if (ntfs_set_volume_flags(vol, VOLUME_IS_DIRTY)) {
ntfs_error(sb, "Failed to set dirty bit in volume " ntfs_error(sb, "Failed to set dirty bit in volume "
"information flags%s", es); "information flags%s", es);
unlock_kernel();
return -EROFS; return -EROFS;
} }
#if 0 #if 0
...@@ -506,18 +513,21 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt) ...@@ -506,18 +513,21 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt)
ntfs_error(sb, "Failed to empty journal $LogFile%s", ntfs_error(sb, "Failed to empty journal $LogFile%s",
es); es);
NVolSetErrors(vol); NVolSetErrors(vol);
unlock_kernel();
return -EROFS; return -EROFS;
} }
if (!ntfs_mark_quotas_out_of_date(vol)) { if (!ntfs_mark_quotas_out_of_date(vol)) {
ntfs_error(sb, "Failed to mark quotas out of date%s", ntfs_error(sb, "Failed to mark quotas out of date%s",
es); es);
NVolSetErrors(vol); NVolSetErrors(vol);
unlock_kernel();
return -EROFS; return -EROFS;
} }
if (!ntfs_stamp_usnjrnl(vol)) { if (!ntfs_stamp_usnjrnl(vol)) {
ntfs_error(sb, "Failed to stamp transation log " ntfs_error(sb, "Failed to stamp transation log "
"($UsnJrnl)%s", es); "($UsnJrnl)%s", es);
NVolSetErrors(vol); NVolSetErrors(vol);
unlock_kernel();
return -EROFS; return -EROFS;
} }
} else if (!(sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) { } else if (!(sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) {
...@@ -533,8 +543,11 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt) ...@@ -533,8 +543,11 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt)
// TODO: Deal with *flags. // TODO: Deal with *flags.
if (!parse_options(vol, opt)) if (!parse_options(vol, opt)) {
unlock_kernel();
return -EINVAL; return -EINVAL;
}
unlock_kernel();
ntfs_debug("Done."); ntfs_debug("Done.");
return 0; return 0;
} }
...@@ -2246,6 +2259,9 @@ static void ntfs_put_super(struct super_block *sb) ...@@ -2246,6 +2259,9 @@ static void ntfs_put_super(struct super_block *sb)
ntfs_volume *vol = NTFS_SB(sb); ntfs_volume *vol = NTFS_SB(sb);
ntfs_debug("Entering."); ntfs_debug("Entering.");
lock_kernel();
#ifdef NTFS_RW #ifdef NTFS_RW
/* /*
* Commit all inodes while they are still open in case some of them * Commit all inodes while they are still open in case some of them
...@@ -2373,39 +2389,12 @@ static void ntfs_put_super(struct super_block *sb) ...@@ -2373,39 +2389,12 @@ static void ntfs_put_super(struct super_block *sb)
vol->mftmirr_ino = NULL; vol->mftmirr_ino = NULL;
} }
/* /*
* If any dirty inodes are left, throw away all mft data page cache * We should have no dirty inodes left, due to
* pages to allow a clean umount. This should never happen any more * mft.c::ntfs_mft_writepage() cleaning all the dirty pages as
* due to mft.c::ntfs_mft_writepage() cleaning all the dirty pages as * the underlying mft records are written out and cleaned.
* the underlying mft records are written out and cleaned. If it does,
* happen anyway, we want to know...
*/ */
ntfs_commit_inode(vol->mft_ino); ntfs_commit_inode(vol->mft_ino);
write_inode_now(vol->mft_ino, 1); write_inode_now(vol->mft_ino, 1);
if (sb_has_dirty_inodes(sb)) {
const char *s1, *s2;
mutex_lock(&vol->mft_ino->i_mutex);
truncate_inode_pages(vol->mft_ino->i_mapping, 0);
mutex_unlock(&vol->mft_ino->i_mutex);
write_inode_now(vol->mft_ino, 1);
if (sb_has_dirty_inodes(sb)) {
static const char *_s1 = "inodes";
static const char *_s2 = "";
s1 = _s1;
s2 = _s2;
} else {
static const char *_s1 = "mft pages";
static const char *_s2 = "They have been thrown "
"away. ";
s1 = _s1;
s2 = _s2;
}
ntfs_error(sb, "Dirty %s found at umount time. %sYou should "
"run chkdsk. Please email "
"linux-ntfs-dev@lists.sourceforge.net and say "
"that you saw this message. Thank you.", s1,
s2);
}
#endif /* NTFS_RW */ #endif /* NTFS_RW */
iput(vol->mft_ino); iput(vol->mft_ino);
...@@ -2444,7 +2433,8 @@ static void ntfs_put_super(struct super_block *sb) ...@@ -2444,7 +2433,8 @@ static void ntfs_put_super(struct super_block *sb)
} }
sb->s_fs_info = NULL; sb->s_fs_info = NULL;
kfree(vol); kfree(vol);
return;
unlock_kernel();
} }
/** /**
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/quotaops.h> #include <linux/quotaops.h>
#include <linux/smp_lock.h>
#define MLOG_MASK_PREFIX ML_SUPER #define MLOG_MASK_PREFIX ML_SUPER
#include <cluster/masklog.h> #include <cluster/masklog.h>
...@@ -126,7 +127,6 @@ static int ocfs2_get_sector(struct super_block *sb, ...@@ -126,7 +127,6 @@ static int ocfs2_get_sector(struct super_block *sb,
struct buffer_head **bh, struct buffer_head **bh,
int block, int block,
int sect_size); int sect_size);
static void ocfs2_write_super(struct super_block *sb);
static struct inode *ocfs2_alloc_inode(struct super_block *sb); static struct inode *ocfs2_alloc_inode(struct super_block *sb);
static void ocfs2_destroy_inode(struct inode *inode); static void ocfs2_destroy_inode(struct inode *inode);
static int ocfs2_susp_quotas(struct ocfs2_super *osb, int unsuspend); static int ocfs2_susp_quotas(struct ocfs2_super *osb, int unsuspend);
...@@ -141,7 +141,6 @@ static const struct super_operations ocfs2_sops = { ...@@ -141,7 +141,6 @@ static const struct super_operations ocfs2_sops = {
.clear_inode = ocfs2_clear_inode, .clear_inode = ocfs2_clear_inode,
.delete_inode = ocfs2_delete_inode, .delete_inode = ocfs2_delete_inode,
.sync_fs = ocfs2_sync_fs, .sync_fs = ocfs2_sync_fs,
.write_super = ocfs2_write_super,
.put_super = ocfs2_put_super, .put_super = ocfs2_put_super,
.remount_fs = ocfs2_remount, .remount_fs = ocfs2_remount,
.show_options = ocfs2_show_options, .show_options = ocfs2_show_options,
...@@ -365,24 +364,12 @@ static struct file_operations ocfs2_osb_debug_fops = { ...@@ -365,24 +364,12 @@ static struct file_operations ocfs2_osb_debug_fops = {
.llseek = generic_file_llseek, .llseek = generic_file_llseek,
}; };
/*
* write_super and sync_fs ripped right out of ext3.
*/
static void ocfs2_write_super(struct super_block *sb)
{
if (mutex_trylock(&sb->s_lock) != 0)
BUG();
sb->s_dirt = 0;
}
static int ocfs2_sync_fs(struct super_block *sb, int wait) static int ocfs2_sync_fs(struct super_block *sb, int wait)
{ {
int status; int status;
tid_t target; tid_t target;
struct ocfs2_super *osb = OCFS2_SB(sb); struct ocfs2_super *osb = OCFS2_SB(sb);
sb->s_dirt = 0;
if (ocfs2_is_hard_readonly(osb)) if (ocfs2_is_hard_readonly(osb))
return -EROFS; return -EROFS;
...@@ -595,6 +582,8 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data) ...@@ -595,6 +582,8 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
struct mount_options parsed_options; struct mount_options parsed_options;
struct ocfs2_super *osb = OCFS2_SB(sb); struct ocfs2_super *osb = OCFS2_SB(sb);
lock_kernel();
if (!ocfs2_parse_options(sb, data, &parsed_options, 1)) { if (!ocfs2_parse_options(sb, data, &parsed_options, 1)) {
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
...@@ -698,6 +687,7 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data) ...@@ -698,6 +687,7 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
ocfs2_set_journal_params(osb); ocfs2_set_journal_params(osb);
} }
out: out:
unlock_kernel();
return ret; return ret;
} }
...@@ -1550,9 +1540,13 @@ static void ocfs2_put_super(struct super_block *sb) ...@@ -1550,9 +1540,13 @@ static void ocfs2_put_super(struct super_block *sb)
{ {
mlog_entry("(0x%p)\n", sb); mlog_entry("(0x%p)\n", sb);
lock_kernel();
ocfs2_sync_blockdev(sb); ocfs2_sync_blockdev(sb);
ocfs2_dismount_volume(sb, 0); ocfs2_dismount_volume(sb, 0);
unlock_kernel();
mlog_exit_void(); mlog_exit_void();
} }
......
...@@ -11,21 +11,6 @@ ...@@ -11,21 +11,6 @@
#include <linux/mpage.h> #include <linux/mpage.h>
#include "omfs.h" #include "omfs.h"
static int omfs_sync_file(struct file *file, struct dentry *dentry,
int datasync)
{
struct inode *inode = dentry->d_inode;
int err;
err = sync_mapping_buffers(inode->i_mapping);
if (!(inode->i_state & I_DIRTY))
return err;
if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
return err;
err |= omfs_sync_inode(inode);
return err ? -EIO : 0;
}
static u32 omfs_max_extents(struct omfs_sb_info *sbi, int offset) static u32 omfs_max_extents(struct omfs_sb_info *sbi, int offset)
{ {
return (sbi->s_sys_blocksize - offset - return (sbi->s_sys_blocksize - offset -
...@@ -344,7 +329,7 @@ struct file_operations omfs_file_operations = { ...@@ -344,7 +329,7 @@ struct file_operations omfs_file_operations = {
.aio_read = generic_file_aio_read, .aio_read = generic_file_aio_read,
.aio_write = generic_file_aio_write, .aio_write = generic_file_aio_write,
.mmap = generic_file_mmap, .mmap = generic_file_mmap,
.fsync = omfs_sync_file, .fsync = simple_fsync,
.splice_read = generic_file_splice_read, .splice_read = generic_file_splice_read,
}; };
......
...@@ -612,7 +612,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, mode_t, mode) ...@@ -612,7 +612,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, mode_t, mode)
audit_inode(NULL, dentry); audit_inode(NULL, dentry);
err = mnt_want_write(file->f_path.mnt); err = mnt_want_write_file(file);
if (err) if (err)
goto out_putf; goto out_putf;
mutex_lock(&inode->i_mutex); mutex_lock(&inode->i_mutex);
...@@ -761,7 +761,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group) ...@@ -761,7 +761,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)
if (!file) if (!file)
goto out; goto out;
error = mnt_want_write(file->f_path.mnt); error = mnt_want_write_file(file);
if (error) if (error)
goto out_fput; goto out_fput;
dentry = file->f_path.dentry; dentry = file->f_path.dentry;
......
...@@ -92,3 +92,28 @@ struct pde_opener { ...@@ -92,3 +92,28 @@ struct pde_opener {
struct list_head lh; struct list_head lh;
}; };
void pde_users_dec(struct proc_dir_entry *pde); void pde_users_dec(struct proc_dir_entry *pde);
extern spinlock_t proc_subdir_lock;
struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *);
int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir);
unsigned long task_vsize(struct mm_struct *);
int task_statm(struct mm_struct *, int *, int *, int *, int *);
void task_mem(struct seq_file *, struct mm_struct *);
struct proc_dir_entry *de_get(struct proc_dir_entry *de);
void de_put(struct proc_dir_entry *de);
extern struct vfsmount *proc_mnt;
int proc_fill_super(struct super_block *);
struct inode *proc_get_inode(struct super_block *, unsigned int, struct proc_dir_entry *);
/*
* These are generic /proc routines that use the internal
* "struct proc_dir_entry" tree to traverse the filesystem.
*
* The /proc root directory has extended versions to take care
* of the /proc/<pid> subdirectories.
*/
int proc_readdir(struct file *, void *, filldir_t);
struct dentry *proc_lookup(struct inode *, struct dentry *, struct nameidata *);
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "internal.h"
#ifndef HAVE_ARCH_DEVTREE_FIXUPS #ifndef HAVE_ARCH_DEVTREE_FIXUPS
static inline void set_node_proc_entry(struct device_node *np, static inline void set_node_proc_entry(struct device_node *np,
......
...@@ -4,4 +4,4 @@ ...@@ -4,4 +4,4 @@
obj-$(CONFIG_QNX4FS_FS) += qnx4.o obj-$(CONFIG_QNX4FS_FS) += qnx4.o
qnx4-objs := inode.o dir.o namei.o file.o bitmap.o truncate.o fsync.o qnx4-objs := inode.o dir.o namei.o file.o bitmap.o truncate.o
...@@ -13,14 +13,9 @@ ...@@ -13,14 +13,9 @@
* 28-06-1998 by Frank Denis : qnx4_free_inode (to be fixed) . * 28-06-1998 by Frank Denis : qnx4_free_inode (to be fixed) .
*/ */
#include <linux/time.h>
#include <linux/fs.h>
#include <linux/qnx4_fs.h>
#include <linux/stat.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include "qnx4.h"
#if 0 #if 0
int qnx4_new_block(struct super_block *sb) int qnx4_new_block(struct super_block *sb)
......
...@@ -11,14 +11,9 @@ ...@@ -11,14 +11,9 @@
* 20-06-1998 by Frank Denis : Linux 2.1.99+ & dcache support. * 20-06-1998 by Frank Denis : Linux 2.1.99+ & dcache support.
*/ */
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/qnx4_fs.h>
#include <linux/stat.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include "qnx4.h"
static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir) static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir)
{ {
...@@ -84,7 +79,7 @@ const struct file_operations qnx4_dir_operations = ...@@ -84,7 +79,7 @@ const struct file_operations qnx4_dir_operations =
{ {
.read = generic_read_dir, .read = generic_read_dir,
.readdir = qnx4_readdir, .readdir = qnx4_readdir,
.fsync = file_fsync, .fsync = simple_fsync,
}; };
const struct inode_operations qnx4_dir_inode_operations = const struct inode_operations qnx4_dir_inode_operations =
......
...@@ -12,8 +12,7 @@ ...@@ -12,8 +12,7 @@
* 27-06-1998 by Frank Denis : file overwriting. * 27-06-1998 by Frank Denis : file overwriting.
*/ */
#include <linux/fs.h> #include "qnx4.h"
#include <linux/qnx4_fs.h>
/* /*
* We have mostly NULL's here: the current defaults are ok for * We have mostly NULL's here: the current defaults are ok for
...@@ -29,7 +28,7 @@ const struct file_operations qnx4_file_operations = ...@@ -29,7 +28,7 @@ const struct file_operations qnx4_file_operations =
#ifdef CONFIG_QNX4FS_RW #ifdef CONFIG_QNX4FS_RW
.write = do_sync_write, .write = do_sync_write,
.aio_write = generic_file_aio_write, .aio_write = generic_file_aio_write,
.fsync = qnx4_sync_file, .fsync = simple_fsync,
#endif #endif
}; };
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment