You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull the big VFS changes from Al Viro:
"This one is *big* and changes quite a few things around VFS. What's in there:
- the first of two really major architecture changes - death to open
intents.
The former is finally there; it was very long in making, but with
Miklos getting through really hard and messy final push in
fs/namei.c, we finally have it. Unlike his variant, this one
doesn't introduce struct opendata; what we have instead is
->atomic_open() taking preallocated struct file * and passing
everything via its fields.
Instead of returning struct file *, it returns -E... on error, 0
on success and 1 in "deal with it yourself" case (e.g. symlink
found on server, etc.).
See comments before fs/namei.c:atomic_open(). That made a lot of
goodies finally possible and quite a few are in that pile:
->lookup(), ->d_revalidate() and ->create() do not get struct
nameidata * anymore; ->lookup() and ->d_revalidate() get lookup
flags instead, ->create() gets "do we want it exclusive" flag.
With the introduction of new helper (kern_path_locked()) we are rid
of all struct nameidata instances outside of fs/namei.c; it's still
visible in namei.h, but not for long. Come the next cycle,
declaration will move either to fs/internal.h or to fs/namei.c
itself. [me, miklos, hch]
- The second major change: behaviour of final fput(). Now we have
__fput() done without any locks held by caller *and* not from deep
in call stack.
That obviously lifts a lot of constraints on the locking in there.
Moreover, it's legal now to call fput() from atomic contexts (which
has immediately simplified life for aio.c). We also don't need
anti-recursion logics in __scm_destroy() anymore.
There is a price, though - the damn thing has become partially
asynchronous. For fput() from normal process we are guaranteed
that pending __fput() will be done before the caller returns to
userland, exits or gets stopped for ptrace.
For kernel threads and atomic contexts it's done via
schedule_work(), so theoretically we might need a way to make sure
it's finished; so far only one such place had been found, but there
might be more.
There's flush_delayed_fput() (do all pending __fput()) and there's
__fput_sync() (fput() analog doing __fput() immediately). I hope
we won't need them often; see warnings in fs/file_table.c for
details. [me, based on task_work series from Oleg merged last
cycle]
- sync series from Jan
- large part of "death to sync_supers()" work from Artem; the only
bits missing here are exofs and ext4 ones. As far as I understand,
those are going via the exofs and ext4 trees resp.; once they are
in, we can put ->write_super() to the rest, along with the thread
calling it.
- preparatory bits from unionmount series (from dhowells).
- assorted cleanups and fixes all over the place, as usual.
This is not the last pile for this cycle; there's at least jlayton's
ESTALE work and fsfreeze series (the latter - in dire need of fixes,
so I'm not sure it'll make the cut this cycle). I'll probably throw
symlink/hardlink restrictions stuff from Kees into the next pile, too.
Plus there's a lot of misc patches I hadn't thrown into that one -
it's large enough as it is..."
* 'for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (127 commits)
ext4: switch EXT4_IOC_RESIZE_FS to mnt_want_write_file()
btrfs: switch btrfs_ioctl_balance() to mnt_want_write_file()
switch dentry_open() to struct path, make it grab references itself
spufs: shift dget/mntget towards dentry_open()
zoran: don't bother with struct file * in zoran_map
ecryptfs: don't reinvent the wheels, please - use struct completion
don't expose I_NEW inodes via dentry->d_inode
tidy up namei.c a bit
unobfuscate follow_up() a bit
ext3: pass custom EOF to generic_file_llseek_size()
ext4: use core vfs llseek code for dir seeks
vfs: allow custom EOF in generic_file_llseek code
vfs: Avoid unnecessary WB_SYNC_NONE writeback during sys_sync and reorder sync passes
vfs: Remove unnecessary flushing of block devices
vfs: Make sys_sync writeout also block device inodes
vfs: Create function for iterating over block devices
vfs: Reorder operations during sys_sync
quota: Move quota syncing to ->sync_fs method
quota: Split dquot_quota_sync() to writeback and cache flushing part
vfs: Move noop_backing_dev_info check from sync into writeback
...
This commit is contained in:
@@ -9,7 +9,7 @@ be able to use diff(1).
|
||||
|
||||
--------------------------- dentry_operations --------------------------
|
||||
prototypes:
|
||||
int (*d_revalidate)(struct dentry *, struct nameidata *);
|
||||
int (*d_revalidate)(struct dentry *, unsigned int);
|
||||
int (*d_hash)(const struct dentry *, const struct inode *,
|
||||
struct qstr *);
|
||||
int (*d_compare)(const struct dentry *, const struct inode *,
|
||||
@@ -37,9 +37,8 @@ d_manage: no no yes (ref-walk) maybe
|
||||
|
||||
--------------------------- inode_operations ---------------------------
|
||||
prototypes:
|
||||
int (*create) (struct inode *,struct dentry *,umode_t, struct nameidata *);
|
||||
struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameid
|
||||
ata *);
|
||||
int (*create) (struct inode *,struct dentry *,umode_t, bool);
|
||||
struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
|
||||
int (*link) (struct dentry *,struct inode *,struct dentry *);
|
||||
int (*unlink) (struct inode *,struct dentry *);
|
||||
int (*symlink) (struct inode *,struct dentry *,const char *);
|
||||
@@ -62,6 +61,9 @@ ata *);
|
||||
int (*removexattr) (struct dentry *, const char *);
|
||||
int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len);
|
||||
void (*update_time)(struct inode *, struct timespec *, int);
|
||||
int (*atomic_open)(struct inode *, struct dentry *,
|
||||
struct file *, unsigned open_flag,
|
||||
umode_t create_mode, int *opened);
|
||||
|
||||
locking rules:
|
||||
all may block
|
||||
@@ -89,6 +91,7 @@ listxattr: no
|
||||
removexattr: yes
|
||||
fiemap: no
|
||||
update_time: no
|
||||
atomic_open: yes
|
||||
|
||||
Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
|
||||
victim.
|
||||
|
||||
@@ -355,12 +355,10 @@ protects *all* the dcache state of a given dentry.
|
||||
via rcu-walk path walk (basically, if the file can have had a path name in the
|
||||
vfs namespace).
|
||||
|
||||
i_dentry and i_rcu share storage in a union, and the vfs expects
|
||||
i_dentry to be reinitialized before it is freed, so an:
|
||||
|
||||
INIT_LIST_HEAD(&inode->i_dentry);
|
||||
|
||||
must be done in the RCU callback.
|
||||
Even though i_dentry and i_rcu share storage in a union, we will
|
||||
initialize the former in inode_init_always(), so just leave it alone in
|
||||
the callback. It used to be necessary to clean it there, but not anymore
|
||||
(starting at 3.2).
|
||||
|
||||
--
|
||||
[recommended]
|
||||
@@ -433,3 +431,14 @@ release it yourself.
|
||||
d_alloc_root() is gone, along with a lot of bugs caused by code
|
||||
misusing it. Replacement: d_make_root(inode). The difference is,
|
||||
d_make_root() drops the reference to inode if dentry allocation fails.
|
||||
|
||||
--
|
||||
[mandatory]
|
||||
The witch is dead! Well, 2/3 of it, anyway. ->d_revalidate() and
|
||||
->lookup() do *not* take struct nameidata anymore; just the flags.
|
||||
--
|
||||
[mandatory]
|
||||
->create() doesn't take struct nameidata *; unlike the previous
|
||||
two, it gets "is it an O_EXCL or equivalent?" boolean argument. Note that
|
||||
local filesystems can ignore tha argument - they are guaranteed that the
|
||||
object doesn't exist. It's remote/distributed ones that might care...
|
||||
|
||||
@@ -341,8 +341,8 @@ This describes how the VFS can manipulate an inode in your
|
||||
filesystem. As of kernel 2.6.22, the following members are defined:
|
||||
|
||||
struct inode_operations {
|
||||
int (*create) (struct inode *,struct dentry *, umode_t, struct nameidata *);
|
||||
struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
|
||||
int (*create) (struct inode *,struct dentry *, umode_t, bool);
|
||||
struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
|
||||
int (*link) (struct dentry *,struct inode *,struct dentry *);
|
||||
int (*unlink) (struct inode *,struct dentry *);
|
||||
int (*symlink) (struct inode *,struct dentry *,const char *);
|
||||
@@ -364,6 +364,9 @@ struct inode_operations {
|
||||
ssize_t (*listxattr) (struct dentry *, char *, size_t);
|
||||
int (*removexattr) (struct dentry *, const char *);
|
||||
void (*update_time)(struct inode *, struct timespec *, int);
|
||||
int (*atomic_open)(struct inode *, struct dentry *,
|
||||
struct file *, unsigned open_flag,
|
||||
umode_t create_mode, int *opened);
|
||||
};
|
||||
|
||||
Again, all methods are called without any locks being held, unless
|
||||
@@ -476,6 +479,14 @@ otherwise noted.
|
||||
an inode. If this is not defined the VFS will update the inode itself
|
||||
and call mark_inode_dirty_sync.
|
||||
|
||||
atomic_open: called on the last component of an open. Using this optional
|
||||
method the filesystem can look up, possibly create and open the file in
|
||||
one atomic operation. If it cannot perform this (e.g. the file type
|
||||
turned out to be wrong) it may signal this by returning 1 instead of
|
||||
usual 0 or -ve . This method is only called if the last
|
||||
component is negative or needs lookup. Cached positive dentries are
|
||||
still handled by f_op->open().
|
||||
|
||||
The Address Space Object
|
||||
========================
|
||||
|
||||
@@ -891,7 +902,7 @@ the VFS uses a default. As of kernel 2.6.22, the following members are
|
||||
defined:
|
||||
|
||||
struct dentry_operations {
|
||||
int (*d_revalidate)(struct dentry *, struct nameidata *);
|
||||
int (*d_revalidate)(struct dentry *, unsigned int);
|
||||
int (*d_hash)(const struct dentry *, const struct inode *,
|
||||
struct qstr *);
|
||||
int (*d_compare)(const struct dentry *, const struct inode *,
|
||||
@@ -910,11 +921,11 @@ struct dentry_operations {
|
||||
dcache. Most filesystems leave this as NULL, because all their
|
||||
dentries in the dcache are valid
|
||||
|
||||
d_revalidate may be called in rcu-walk mode (nd->flags & LOOKUP_RCU).
|
||||
d_revalidate may be called in rcu-walk mode (flags & LOOKUP_RCU).
|
||||
If in rcu-walk mode, the filesystem must revalidate the dentry without
|
||||
blocking or storing to the dentry, d_parent and d_inode should not be
|
||||
used without care (because they can go NULL), instead nd->inode should
|
||||
be used.
|
||||
used without care (because they can change and, in d_inode case, even
|
||||
become NULL under us).
|
||||
|
||||
If a situation is encountered that rcu-walk cannot handle, return
|
||||
-ECHILD and it will be called again in ref-walk mode.
|
||||
|
||||
@@ -317,28 +317,23 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spufs_context_open(struct dentry *dentry, struct vfsmount *mnt)
|
||||
static int spufs_context_open(struct path *path)
|
||||
{
|
||||
int ret;
|
||||
struct file *filp;
|
||||
|
||||
ret = get_unused_fd();
|
||||
if (ret < 0) {
|
||||
dput(dentry);
|
||||
mntput(mnt);
|
||||
goto out;
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
filp = dentry_open(dentry, mnt, O_RDONLY, current_cred());
|
||||
filp = dentry_open(path, O_RDONLY, current_cred());
|
||||
if (IS_ERR(filp)) {
|
||||
put_unused_fd(ret);
|
||||
ret = PTR_ERR(filp);
|
||||
goto out;
|
||||
return PTR_ERR(filp);
|
||||
}
|
||||
|
||||
filp->f_op = &spufs_context_fops;
|
||||
fd_install(ret, filp);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -453,6 +448,7 @@ spufs_create_context(struct inode *inode, struct dentry *dentry,
|
||||
int affinity;
|
||||
struct spu_gang *gang;
|
||||
struct spu_context *neighbor;
|
||||
struct path path = {.mnt = mnt, .dentry = dentry};
|
||||
|
||||
ret = -EPERM;
|
||||
if ((flags & SPU_CREATE_NOSCHED) &&
|
||||
@@ -495,11 +491,7 @@ spufs_create_context(struct inode *inode, struct dentry *dentry,
|
||||
put_spu_context(neighbor);
|
||||
}
|
||||
|
||||
/*
|
||||
* get references for dget and mntget, will be released
|
||||
* in error path of *_open().
|
||||
*/
|
||||
ret = spufs_context_open(dget(dentry), mntget(mnt));
|
||||
ret = spufs_context_open(&path);
|
||||
if (ret < 0) {
|
||||
WARN_ON(spufs_rmdir(inode, dentry));
|
||||
if (affinity)
|
||||
@@ -556,28 +548,27 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spufs_gang_open(struct dentry *dentry, struct vfsmount *mnt)
|
||||
static int spufs_gang_open(struct path *path)
|
||||
{
|
||||
int ret;
|
||||
struct file *filp;
|
||||
|
||||
ret = get_unused_fd();
|
||||
if (ret < 0) {
|
||||
dput(dentry);
|
||||
mntput(mnt);
|
||||
goto out;
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
filp = dentry_open(dentry, mnt, O_RDONLY, current_cred());
|
||||
/*
|
||||
* get references for dget and mntget, will be released
|
||||
* in error path of *_open().
|
||||
*/
|
||||
filp = dentry_open(path, O_RDONLY, current_cred());
|
||||
if (IS_ERR(filp)) {
|
||||
put_unused_fd(ret);
|
||||
ret = PTR_ERR(filp);
|
||||
goto out;
|
||||
return PTR_ERR(filp);
|
||||
}
|
||||
|
||||
filp->f_op = &simple_dir_operations;
|
||||
fd_install(ret, filp);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -585,17 +576,14 @@ static int spufs_create_gang(struct inode *inode,
|
||||
struct dentry *dentry,
|
||||
struct vfsmount *mnt, umode_t mode)
|
||||
{
|
||||
struct path path = {.mnt = mnt, .dentry = dentry};
|
||||
int ret;
|
||||
|
||||
ret = spufs_mkgang(inode, dentry, mode & S_IRWXUGO);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* get references for dget and mntget, will be released
|
||||
* in error path of *_open().
|
||||
*/
|
||||
ret = spufs_gang_open(dget(dentry), mntget(mnt));
|
||||
ret = spufs_gang_open(&path);
|
||||
if (ret < 0) {
|
||||
int err = simple_rmdir(inode, dentry);
|
||||
WARN_ON(err);
|
||||
|
||||
+41
-57
@@ -227,33 +227,24 @@ static int handle_create(const char *nodename, umode_t mode, struct device *dev)
|
||||
|
||||
static int dev_rmdir(const char *name)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path parent;
|
||||
struct dentry *dentry;
|
||||
int err;
|
||||
|
||||
err = kern_path_parent(name, &nd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
|
||||
dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
|
||||
if (!IS_ERR(dentry)) {
|
||||
if (dentry->d_inode) {
|
||||
if (dentry->d_inode->i_private == &thread)
|
||||
err = vfs_rmdir(nd.path.dentry->d_inode,
|
||||
dentry);
|
||||
else
|
||||
err = -EPERM;
|
||||
} else {
|
||||
err = -ENOENT;
|
||||
}
|
||||
dput(dentry);
|
||||
dentry = kern_path_locked(name, &parent);
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
if (dentry->d_inode) {
|
||||
if (dentry->d_inode->i_private == &thread)
|
||||
err = vfs_rmdir(parent.dentry->d_inode, dentry);
|
||||
else
|
||||
err = -EPERM;
|
||||
} else {
|
||||
err = PTR_ERR(dentry);
|
||||
err = -ENOENT;
|
||||
}
|
||||
|
||||
mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
|
||||
path_put(&nd.path);
|
||||
dput(dentry);
|
||||
mutex_unlock(&parent.dentry->d_inode->i_mutex);
|
||||
path_put(&parent);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -305,50 +296,43 @@ static int dev_mynode(struct device *dev, struct inode *inode, struct kstat *sta
|
||||
|
||||
static int handle_remove(const char *nodename, struct device *dev)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path parent;
|
||||
struct dentry *dentry;
|
||||
struct kstat stat;
|
||||
int deleted = 1;
|
||||
int err;
|
||||
|
||||
err = kern_path_parent(nodename, &nd);
|
||||
if (err)
|
||||
return err;
|
||||
dentry = kern_path_locked(nodename, &parent);
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
|
||||
mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
|
||||
dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
|
||||
if (!IS_ERR(dentry)) {
|
||||
if (dentry->d_inode) {
|
||||
err = vfs_getattr(nd.path.mnt, dentry, &stat);
|
||||
if (!err && dev_mynode(dev, dentry->d_inode, &stat)) {
|
||||
struct iattr newattrs;
|
||||
/*
|
||||
* before unlinking this node, reset permissions
|
||||
* of possible references like hardlinks
|
||||
*/
|
||||
newattrs.ia_uid = 0;
|
||||
newattrs.ia_gid = 0;
|
||||
newattrs.ia_mode = stat.mode & ~0777;
|
||||
newattrs.ia_valid =
|
||||
ATTR_UID|ATTR_GID|ATTR_MODE;
|
||||
mutex_lock(&dentry->d_inode->i_mutex);
|
||||
notify_change(dentry, &newattrs);
|
||||
mutex_unlock(&dentry->d_inode->i_mutex);
|
||||
err = vfs_unlink(nd.path.dentry->d_inode,
|
||||
dentry);
|
||||
if (!err || err == -ENOENT)
|
||||
deleted = 1;
|
||||
}
|
||||
} else {
|
||||
err = -ENOENT;
|
||||
if (dentry->d_inode) {
|
||||
struct kstat stat;
|
||||
err = vfs_getattr(parent.mnt, dentry, &stat);
|
||||
if (!err && dev_mynode(dev, dentry->d_inode, &stat)) {
|
||||
struct iattr newattrs;
|
||||
/*
|
||||
* before unlinking this node, reset permissions
|
||||
* of possible references like hardlinks
|
||||
*/
|
||||
newattrs.ia_uid = 0;
|
||||
newattrs.ia_gid = 0;
|
||||
newattrs.ia_mode = stat.mode & ~0777;
|
||||
newattrs.ia_valid =
|
||||
ATTR_UID|ATTR_GID|ATTR_MODE;
|
||||
mutex_lock(&dentry->d_inode->i_mutex);
|
||||
notify_change(dentry, &newattrs);
|
||||
mutex_unlock(&dentry->d_inode->i_mutex);
|
||||
err = vfs_unlink(parent.dentry->d_inode, dentry);
|
||||
if (!err || err == -ENOENT)
|
||||
deleted = 1;
|
||||
}
|
||||
dput(dentry);
|
||||
} else {
|
||||
err = PTR_ERR(dentry);
|
||||
err = -ENOENT;
|
||||
}
|
||||
mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
|
||||
dput(dentry);
|
||||
mutex_unlock(&parent.dentry->d_inode->i_mutex);
|
||||
|
||||
path_put(&nd.path);
|
||||
path_put(&parent);
|
||||
if (deleted && strchr(nodename, '/'))
|
||||
delete_path(nodename);
|
||||
return err;
|
||||
|
||||
@@ -172,8 +172,10 @@ struct zoran_jpg_settings {
|
||||
struct v4l2_jpegcompression jpg_comp; /* JPEG-specific capture settings */
|
||||
};
|
||||
|
||||
struct zoran_fh;
|
||||
|
||||
struct zoran_mapping {
|
||||
struct file *file;
|
||||
struct zoran_fh *fh;
|
||||
int count;
|
||||
};
|
||||
|
||||
|
||||
@@ -2811,7 +2811,7 @@ static void
|
||||
zoran_vm_close (struct vm_area_struct *vma)
|
||||
{
|
||||
struct zoran_mapping *map = vma->vm_private_data;
|
||||
struct zoran_fh *fh = map->file->private_data;
|
||||
struct zoran_fh *fh = map->fh;
|
||||
struct zoran *zr = fh->zr;
|
||||
int i;
|
||||
|
||||
@@ -2938,7 +2938,7 @@ zoran_mmap (struct file *file,
|
||||
res = -ENOMEM;
|
||||
goto mmap_unlock_and_return;
|
||||
}
|
||||
map->file = file;
|
||||
map->fh = fh;
|
||||
map->count = 1;
|
||||
|
||||
vma->vm_ops = &zoran_vm_ops;
|
||||
|
||||
@@ -63,7 +63,7 @@ static struct dentry *mount_mtd_aux(struct file_system_type *fs_type, int flags,
|
||||
struct super_block *sb;
|
||||
int ret;
|
||||
|
||||
sb = sget(fs_type, get_sb_mtd_compare, get_sb_mtd_set, mtd);
|
||||
sb = sget(fs_type, get_sb_mtd_compare, get_sb_mtd_set, flags, mtd);
|
||||
if (IS_ERR(sb))
|
||||
goto out_error;
|
||||
|
||||
@@ -74,8 +74,6 @@ static struct dentry *mount_mtd_aux(struct file_system_type *fs_type, int flags,
|
||||
pr_debug("MTDSB: New superblock for device %d (\"%s\")\n",
|
||||
mtd->index, mtd->name);
|
||||
|
||||
sb->s_flags = flags;
|
||||
|
||||
ret = fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
|
||||
if (ret < 0) {
|
||||
deactivate_locked_super(sb);
|
||||
|
||||
+1
-1
@@ -144,7 +144,7 @@ extern void v9fs_session_close(struct v9fs_session_info *v9ses);
|
||||
extern void v9fs_session_cancel(struct v9fs_session_info *v9ses);
|
||||
extern void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses);
|
||||
extern struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct nameidata *nameidata);
|
||||
unsigned int flags);
|
||||
extern int v9fs_vfs_unlink(struct inode *i, struct dentry *d);
|
||||
extern int v9fs_vfs_rmdir(struct inode *i, struct dentry *d);
|
||||
extern int v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
|
||||
+2
-2
@@ -100,13 +100,13 @@ static void v9fs_dentry_release(struct dentry *dentry)
|
||||
}
|
||||
}
|
||||
|
||||
static int v9fs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
|
||||
static int v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
struct p9_fid *fid;
|
||||
struct inode *inode;
|
||||
struct v9fs_inode *v9inode;
|
||||
|
||||
if (nd->flags & LOOKUP_RCU)
|
||||
if (flags & LOOKUP_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
inode = dentry->d_inode;
|
||||
|
||||
+99
-71
@@ -712,88 +712,34 @@ error:
|
||||
}
|
||||
|
||||
/**
|
||||
* v9fs_vfs_create - VFS hook to create files
|
||||
* v9fs_vfs_create - VFS hook to create a regular file
|
||||
*
|
||||
* open(.., O_CREAT) is handled in v9fs_vfs_atomic_open(). This is only called
|
||||
* for mknod(2).
|
||||
*
|
||||
* @dir: directory inode that is being created
|
||||
* @dentry: dentry that is being deleted
|
||||
* @mode: create permissions
|
||||
* @nd: path information
|
||||
*
|
||||
*/
|
||||
|
||||
static int
|
||||
v9fs_vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
struct nameidata *nd)
|
||||
bool excl)
|
||||
{
|
||||
int err;
|
||||
u32 perm;
|
||||
int flags;
|
||||
struct file *filp;
|
||||
struct v9fs_inode *v9inode;
|
||||
struct v9fs_session_info *v9ses;
|
||||
struct p9_fid *fid, *inode_fid;
|
||||
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
|
||||
u32 perm = unixmode2p9mode(v9ses, mode);
|
||||
struct p9_fid *fid;
|
||||
|
||||
err = 0;
|
||||
fid = NULL;
|
||||
v9ses = v9fs_inode2v9ses(dir);
|
||||
perm = unixmode2p9mode(v9ses, mode);
|
||||
if (nd)
|
||||
flags = nd->intent.open.flags;
|
||||
else
|
||||
flags = O_RDWR;
|
||||
|
||||
fid = v9fs_create(v9ses, dir, dentry, NULL, perm,
|
||||
v9fs_uflags2omode(flags,
|
||||
v9fs_proto_dotu(v9ses)));
|
||||
if (IS_ERR(fid)) {
|
||||
err = PTR_ERR(fid);
|
||||
fid = NULL;
|
||||
goto error;
|
||||
}
|
||||
/* P9_OEXCL? */
|
||||
fid = v9fs_create(v9ses, dir, dentry, NULL, perm, P9_ORDWR);
|
||||
if (IS_ERR(fid))
|
||||
return PTR_ERR(fid);
|
||||
|
||||
v9fs_invalidate_inode_attr(dir);
|
||||
/* if we are opening a file, assign the open fid to the file */
|
||||
if (nd) {
|
||||
v9inode = V9FS_I(dentry->d_inode);
|
||||
mutex_lock(&v9inode->v_mutex);
|
||||
if (v9ses->cache && !v9inode->writeback_fid &&
|
||||
((flags & O_ACCMODE) != O_RDONLY)) {
|
||||
/*
|
||||
* clone a fid and add it to writeback_fid
|
||||
* we do it during open time instead of
|
||||
* page dirty time via write_begin/page_mkwrite
|
||||
* because we want write after unlink usecase
|
||||
* to work.
|
||||
*/
|
||||
inode_fid = v9fs_writeback_fid(dentry);
|
||||
if (IS_ERR(inode_fid)) {
|
||||
err = PTR_ERR(inode_fid);
|
||||
mutex_unlock(&v9inode->v_mutex);
|
||||
goto error;
|
||||
}
|
||||
v9inode->writeback_fid = (void *) inode_fid;
|
||||
}
|
||||
mutex_unlock(&v9inode->v_mutex);
|
||||
filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
|
||||
if (IS_ERR(filp)) {
|
||||
err = PTR_ERR(filp);
|
||||
goto error;
|
||||
}
|
||||
|
||||
filp->private_data = fid;
|
||||
#ifdef CONFIG_9P_FSCACHE
|
||||
if (v9ses->cache)
|
||||
v9fs_cache_inode_set_cookie(dentry->d_inode, filp);
|
||||
#endif
|
||||
} else
|
||||
p9_client_clunk(fid);
|
||||
p9_client_clunk(fid);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (fid)
|
||||
p9_client_clunk(fid);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -839,7 +785,7 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
|
||||
*/
|
||||
|
||||
struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct nameidata *nameidata)
|
||||
unsigned int flags)
|
||||
{
|
||||
struct dentry *res;
|
||||
struct super_block *sb;
|
||||
@@ -849,8 +795,8 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
char *name;
|
||||
int result = 0;
|
||||
|
||||
p9_debug(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n",
|
||||
dir, dentry->d_name.name, dentry, nameidata);
|
||||
p9_debug(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p flags: %x\n",
|
||||
dir, dentry->d_name.name, dentry, flags);
|
||||
|
||||
if (dentry->d_name.len > NAME_MAX)
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
@@ -910,6 +856,86 @@ error:
|
||||
return ERR_PTR(result);
|
||||
}
|
||||
|
||||
static int
|
||||
v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry,
|
||||
struct file *file, unsigned flags, umode_t mode,
|
||||
int *opened)
|
||||
{
|
||||
int err;
|
||||
u32 perm;
|
||||
struct v9fs_inode *v9inode;
|
||||
struct v9fs_session_info *v9ses;
|
||||
struct p9_fid *fid, *inode_fid;
|
||||
struct dentry *res = NULL;
|
||||
|
||||
if (d_unhashed(dentry)) {
|
||||
res = v9fs_vfs_lookup(dir, dentry, 0);
|
||||
if (IS_ERR(res))
|
||||
return PTR_ERR(res);
|
||||
|
||||
if (res)
|
||||
dentry = res;
|
||||
}
|
||||
|
||||
/* Only creates */
|
||||
if (!(flags & O_CREAT) || dentry->d_inode)
|
||||
return finish_no_open(file, res);
|
||||
|
||||
err = 0;
|
||||
fid = NULL;
|
||||
v9ses = v9fs_inode2v9ses(dir);
|
||||
perm = unixmode2p9mode(v9ses, mode);
|
||||
fid = v9fs_create(v9ses, dir, dentry, NULL, perm,
|
||||
v9fs_uflags2omode(flags,
|
||||
v9fs_proto_dotu(v9ses)));
|
||||
if (IS_ERR(fid)) {
|
||||
err = PTR_ERR(fid);
|
||||
fid = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
v9fs_invalidate_inode_attr(dir);
|
||||
v9inode = V9FS_I(dentry->d_inode);
|
||||
mutex_lock(&v9inode->v_mutex);
|
||||
if (v9ses->cache && !v9inode->writeback_fid &&
|
||||
((flags & O_ACCMODE) != O_RDONLY)) {
|
||||
/*
|
||||
* clone a fid and add it to writeback_fid
|
||||
* we do it during open time instead of
|
||||
* page dirty time via write_begin/page_mkwrite
|
||||
* because we want write after unlink usecase
|
||||
* to work.
|
||||
*/
|
||||
inode_fid = v9fs_writeback_fid(dentry);
|
||||
if (IS_ERR(inode_fid)) {
|
||||
err = PTR_ERR(inode_fid);
|
||||
mutex_unlock(&v9inode->v_mutex);
|
||||
goto error;
|
||||
}
|
||||
v9inode->writeback_fid = (void *) inode_fid;
|
||||
}
|
||||
mutex_unlock(&v9inode->v_mutex);
|
||||
err = finish_open(file, dentry, generic_file_open, opened);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
file->private_data = fid;
|
||||
#ifdef CONFIG_9P_FSCACHE
|
||||
if (v9ses->cache)
|
||||
v9fs_cache_inode_set_cookie(dentry->d_inode, file);
|
||||
#endif
|
||||
|
||||
*opened |= FILE_CREATED;
|
||||
out:
|
||||
dput(res);
|
||||
return err;
|
||||
|
||||
error:
|
||||
if (fid)
|
||||
p9_client_clunk(fid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/**
|
||||
* v9fs_vfs_unlink - VFS unlink hook to delete an inode
|
||||
* @i: inode that is being unlinked
|
||||
@@ -1488,6 +1514,7 @@ out:
|
||||
static const struct inode_operations v9fs_dir_inode_operations_dotu = {
|
||||
.create = v9fs_vfs_create,
|
||||
.lookup = v9fs_vfs_lookup,
|
||||
.atomic_open = v9fs_vfs_atomic_open,
|
||||
.symlink = v9fs_vfs_symlink,
|
||||
.link = v9fs_vfs_link,
|
||||
.unlink = v9fs_vfs_unlink,
|
||||
@@ -1502,6 +1529,7 @@ static const struct inode_operations v9fs_dir_inode_operations_dotu = {
|
||||
static const struct inode_operations v9fs_dir_inode_operations = {
|
||||
.create = v9fs_vfs_create,
|
||||
.lookup = v9fs_vfs_lookup,
|
||||
.atomic_open = v9fs_vfs_atomic_open,
|
||||
.unlink = v9fs_vfs_unlink,
|
||||
.mkdir = v9fs_vfs_mkdir,
|
||||
.rmdir = v9fs_vfs_rmdir,
|
||||
|
||||
+35
-24
@@ -230,20 +230,25 @@ int v9fs_open_to_dotl_flags(int flags)
|
||||
* @dir: directory inode that is being created
|
||||
* @dentry: dentry that is being deleted
|
||||
* @mode: create permissions
|
||||
* @nd: path information
|
||||
*
|
||||
*/
|
||||
|
||||
static int
|
||||
v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
|
||||
struct nameidata *nd)
|
||||
bool excl)
|
||||
{
|
||||
return v9fs_vfs_mknod_dotl(dir, dentry, omode, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
|
||||
struct file *file, unsigned flags, umode_t omode,
|
||||
int *opened)
|
||||
{
|
||||
int err = 0;
|
||||
gid_t gid;
|
||||
int flags;
|
||||
umode_t mode;
|
||||
char *name = NULL;
|
||||
struct file *filp;
|
||||
struct p9_qid qid;
|
||||
struct inode *inode;
|
||||
struct p9_fid *fid = NULL;
|
||||
@@ -251,18 +256,22 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
|
||||
struct p9_fid *dfid, *ofid, *inode_fid;
|
||||
struct v9fs_session_info *v9ses;
|
||||
struct posix_acl *pacl = NULL, *dacl = NULL;
|
||||
struct dentry *res = NULL;
|
||||
|
||||
if (d_unhashed(dentry)) {
|
||||
res = v9fs_vfs_lookup(dir, dentry, 0);
|
||||
if (IS_ERR(res))
|
||||
return PTR_ERR(res);
|
||||
|
||||
if (res)
|
||||
dentry = res;
|
||||
}
|
||||
|
||||
/* Only creates */
|
||||
if (!(flags & O_CREAT) || dentry->d_inode)
|
||||
return finish_no_open(file, res);
|
||||
|
||||
v9ses = v9fs_inode2v9ses(dir);
|
||||
if (nd)
|
||||
flags = nd->intent.open.flags;
|
||||
else {
|
||||
/*
|
||||
* create call without LOOKUP_OPEN is due
|
||||
* to mknod of regular files. So use mknod
|
||||
* operation.
|
||||
*/
|
||||
return v9fs_vfs_mknod_dotl(dir, dentry, omode, 0);
|
||||
}
|
||||
|
||||
name = (char *) dentry->d_name.name;
|
||||
p9_debug(P9_DEBUG_VFS, "name:%s flags:0x%x mode:0x%hx\n",
|
||||
@@ -272,7 +281,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
|
||||
if (IS_ERR(dfid)) {
|
||||
err = PTR_ERR(dfid);
|
||||
p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
|
||||
return err;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* clone a fid to use for creation */
|
||||
@@ -280,7 +289,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
|
||||
if (IS_ERR(ofid)) {
|
||||
err = PTR_ERR(ofid);
|
||||
p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
|
||||
return err;
|
||||
goto out;
|
||||
}
|
||||
|
||||
gid = v9fs_get_fsgid_for_create(dir);
|
||||
@@ -345,17 +354,18 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
|
||||
}
|
||||
mutex_unlock(&v9inode->v_mutex);
|
||||
/* Since we are opening a file, assign the open fid to the file */
|
||||
filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
|
||||
if (IS_ERR(filp)) {
|
||||
err = PTR_ERR(filp);
|
||||
err = finish_open(file, dentry, generic_file_open, opened);
|
||||
if (err)
|
||||
goto err_clunk_old_fid;
|
||||
}
|
||||
filp->private_data = ofid;
|
||||
file->private_data = ofid;
|
||||
#ifdef CONFIG_9P_FSCACHE
|
||||
if (v9ses->cache)
|
||||
v9fs_cache_inode_set_cookie(inode, filp);
|
||||
v9fs_cache_inode_set_cookie(inode, file);
|
||||
#endif
|
||||
return 0;
|
||||
*opened |= FILE_CREATED;
|
||||
out:
|
||||
dput(res);
|
||||
return err;
|
||||
|
||||
error:
|
||||
if (fid)
|
||||
@@ -364,7 +374,7 @@ err_clunk_old_fid:
|
||||
if (ofid)
|
||||
p9_client_clunk(ofid);
|
||||
v9fs_set_create_acl(NULL, &dacl, &pacl);
|
||||
return err;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -982,6 +992,7 @@ out:
|
||||
|
||||
const struct inode_operations v9fs_dir_inode_operations_dotl = {
|
||||
.create = v9fs_vfs_create_dotl,
|
||||
.atomic_open = v9fs_vfs_atomic_open_dotl,
|
||||
.lookup = v9fs_vfs_lookup,
|
||||
.link = v9fs_vfs_link_dotl,
|
||||
.symlink = v9fs_vfs_symlink_dotl,
|
||||
|
||||
+2
-2
@@ -89,7 +89,7 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
|
||||
if (v9ses->cache)
|
||||
sb->s_bdi->ra_pages = (VM_MAX_READAHEAD * 1024)/PAGE_CACHE_SIZE;
|
||||
|
||||
sb->s_flags = flags | MS_ACTIVE | MS_DIRSYNC | MS_NOATIME;
|
||||
sb->s_flags |= MS_ACTIVE | MS_DIRSYNC | MS_NOATIME;
|
||||
if (!v9ses->cache)
|
||||
sb->s_flags |= MS_SYNCHRONOUS;
|
||||
|
||||
@@ -137,7 +137,7 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
|
||||
goto close_session;
|
||||
}
|
||||
|
||||
sb = sget(fs_type, NULL, v9fs_set_super, v9ses);
|
||||
sb = sget(fs_type, NULL, v9fs_set_super, flags, v9ses);
|
||||
if (IS_ERR(sb)) {
|
||||
retval = PTR_ERR(sb);
|
||||
goto clunk_fid;
|
||||
|
||||
+1
-1
@@ -266,7 +266,7 @@ const struct dentry_operations adfs_dentry_operations = {
|
||||
};
|
||||
|
||||
static struct dentry *
|
||||
adfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
|
||||
adfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
struct inode *inode = NULL;
|
||||
struct object_info obj;
|
||||
|
||||
@@ -246,7 +246,6 @@ static struct inode *adfs_alloc_inode(struct super_block *sb)
|
||||
static void adfs_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(adfs_inode_cachep, ADFS_I(inode));
|
||||
}
|
||||
|
||||
|
||||
+9
-2
@@ -3,6 +3,7 @@
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/amigaffs.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
/* AmigaOS allows file names with up to 30 characters length.
|
||||
* Names longer than that will be silently truncated. If you
|
||||
@@ -100,6 +101,10 @@ struct affs_sb_info {
|
||||
char *s_prefix; /* Prefix for volumes and assigns. */
|
||||
char s_volume[32]; /* Volume prefix for absolute symlinks. */
|
||||
spinlock_t symlink_lock; /* protects the previous two */
|
||||
struct super_block *sb; /* the VFS superblock object */
|
||||
int work_queued; /* non-zero delayed work is queued */
|
||||
struct delayed_work sb_work; /* superblock flush delayed work */
|
||||
spinlock_t work_lock; /* protects sb_work and work_queued */
|
||||
};
|
||||
|
||||
#define SF_INTL 0x0001 /* International filesystem. */
|
||||
@@ -120,6 +125,8 @@ static inline struct affs_sb_info *AFFS_SB(struct super_block *sb)
|
||||
return sb->s_fs_info;
|
||||
}
|
||||
|
||||
void affs_mark_sb_dirty(struct super_block *sb);
|
||||
|
||||
/* amigaffs.c */
|
||||
|
||||
extern int affs_insert_hash(struct inode *inode, struct buffer_head *bh);
|
||||
@@ -146,9 +153,9 @@ extern void affs_free_bitmap(struct super_block *sb);
|
||||
/* namei.c */
|
||||
|
||||
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 struct dentry *affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int);
|
||||
extern int affs_unlink(struct inode *dir, struct dentry *dentry);
|
||||
extern int affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *);
|
||||
extern int affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool);
|
||||
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,
|
||||
|
||||
+10
-12
@@ -122,22 +122,16 @@ affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh)
|
||||
}
|
||||
|
||||
static void
|
||||
affs_fix_dcache(struct dentry *dentry, u32 entry_ino)
|
||||
affs_fix_dcache(struct inode *inode, u32 entry_ino)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
void *data = dentry->d_fsdata;
|
||||
struct list_head *head, *next;
|
||||
|
||||
struct dentry *dentry;
|
||||
struct hlist_node *p;
|
||||
spin_lock(&inode->i_lock);
|
||||
head = &inode->i_dentry;
|
||||
next = head->next;
|
||||
while (next != head) {
|
||||
dentry = list_entry(next, struct dentry, d_alias);
|
||||
hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
|
||||
if (entry_ino == (u32)(long)dentry->d_fsdata) {
|
||||
dentry->d_fsdata = data;
|
||||
dentry->d_fsdata = (void *)inode->i_ino;
|
||||
break;
|
||||
}
|
||||
next = next->next;
|
||||
}
|
||||
spin_unlock(&inode->i_lock);
|
||||
}
|
||||
@@ -177,7 +171,11 @@ affs_remove_link(struct dentry *dentry)
|
||||
}
|
||||
|
||||
affs_lock_dir(dir);
|
||||
affs_fix_dcache(dentry, link_ino);
|
||||
/*
|
||||
* if there's a dentry for that block, make it
|
||||
* refer to inode itself.
|
||||
*/
|
||||
affs_fix_dcache(inode, link_ino);
|
||||
retval = affs_remove_hash(dir, link_bh);
|
||||
if (retval) {
|
||||
affs_unlock_dir(dir);
|
||||
|
||||
+2
-2
@@ -103,7 +103,7 @@ affs_free_block(struct super_block *sb, u32 block)
|
||||
*(__be32 *)bh->b_data = cpu_to_be32(tmp - mask);
|
||||
|
||||
mark_buffer_dirty(bh);
|
||||
sb->s_dirt = 1;
|
||||
affs_mark_sb_dirty(sb);
|
||||
bm->bm_free++;
|
||||
|
||||
mutex_unlock(&sbi->s_bmlock);
|
||||
@@ -248,7 +248,7 @@ find_bit:
|
||||
*(__be32 *)bh->b_data = cpu_to_be32(tmp + mask);
|
||||
|
||||
mark_buffer_dirty(bh);
|
||||
sb->s_dirt = 1;
|
||||
affs_mark_sb_dirty(sb);
|
||||
|
||||
mutex_unlock(&sbi->s_bmlock);
|
||||
|
||||
|
||||
+2
-2
@@ -211,7 +211,7 @@ affs_find_entry(struct inode *dir, struct dentry *dentry)
|
||||
}
|
||||
|
||||
struct dentry *
|
||||
affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
|
||||
affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
struct super_block *sb = dir->i_sb;
|
||||
struct buffer_head *bh;
|
||||
@@ -255,7 +255,7 @@ affs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
}
|
||||
|
||||
int
|
||||
affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd)
|
||||
affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl)
|
||||
{
|
||||
struct super_block *sb = dir->i_sb;
|
||||
struct inode *inode;
|
||||
|
||||
+45
-25
@@ -17,6 +17,7 @@
|
||||
#include <linux/magic.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/writeback.h>
|
||||
#include "affs.h"
|
||||
|
||||
extern struct timezone sys_tz;
|
||||
@@ -25,15 +26,17 @@ static int affs_statfs(struct dentry *dentry, struct kstatfs *buf);
|
||||
static int affs_remount (struct super_block *sb, int *flags, char *data);
|
||||
|
||||
static void
|
||||
affs_commit_super(struct super_block *sb, int wait, int clean)
|
||||
affs_commit_super(struct super_block *sb, int wait)
|
||||
{
|
||||
struct affs_sb_info *sbi = AFFS_SB(sb);
|
||||
struct buffer_head *bh = sbi->s_root_bh;
|
||||
struct affs_root_tail *tail = AFFS_ROOT_TAIL(sb, bh);
|
||||
|
||||
tail->bm_flag = cpu_to_be32(clean);
|
||||
lock_buffer(bh);
|
||||
secs_to_datestamp(get_seconds(), &tail->disk_change);
|
||||
affs_fix_checksum(sb, bh);
|
||||
unlock_buffer(bh);
|
||||
|
||||
mark_buffer_dirty(bh);
|
||||
if (wait)
|
||||
sync_dirty_buffer(bh);
|
||||
@@ -45,9 +48,7 @@ affs_put_super(struct super_block *sb)
|
||||
struct affs_sb_info *sbi = AFFS_SB(sb);
|
||||
pr_debug("AFFS: put_super()\n");
|
||||
|
||||
if (!(sb->s_flags & MS_RDONLY) && sb->s_dirt)
|
||||
affs_commit_super(sb, 1, 1);
|
||||
|
||||
cancel_delayed_work_sync(&sbi->sb_work);
|
||||
kfree(sbi->s_prefix);
|
||||
affs_free_bitmap(sb);
|
||||
affs_brelse(sbi->s_root_bh);
|
||||
@@ -55,28 +56,45 @@ affs_put_super(struct super_block *sb)
|
||||
sb->s_fs_info = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
affs_write_super(struct super_block *sb)
|
||||
{
|
||||
lock_super(sb);
|
||||
if (!(sb->s_flags & MS_RDONLY))
|
||||
affs_commit_super(sb, 1, 2);
|
||||
sb->s_dirt = 0;
|
||||
unlock_super(sb);
|
||||
|
||||
pr_debug("AFFS: write_super() at %lu, clean=2\n", get_seconds());
|
||||
}
|
||||
|
||||
static int
|
||||
affs_sync_fs(struct super_block *sb, int wait)
|
||||
{
|
||||
lock_super(sb);
|
||||
affs_commit_super(sb, wait, 2);
|
||||
sb->s_dirt = 0;
|
||||
unlock_super(sb);
|
||||
affs_commit_super(sb, wait);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flush_superblock(struct work_struct *work)
|
||||
{
|
||||
struct affs_sb_info *sbi;
|
||||
struct super_block *sb;
|
||||
|
||||
sbi = container_of(work, struct affs_sb_info, sb_work.work);
|
||||
sb = sbi->sb;
|
||||
|
||||
spin_lock(&sbi->work_lock);
|
||||
sbi->work_queued = 0;
|
||||
spin_unlock(&sbi->work_lock);
|
||||
|
||||
affs_commit_super(sb, 1);
|
||||
}
|
||||
|
||||
void affs_mark_sb_dirty(struct super_block *sb)
|
||||
{
|
||||
struct affs_sb_info *sbi = AFFS_SB(sb);
|
||||
unsigned long delay;
|
||||
|
||||
if (sb->s_flags & MS_RDONLY)
|
||||
return;
|
||||
|
||||
spin_lock(&sbi->work_lock);
|
||||
if (!sbi->work_queued) {
|
||||
delay = msecs_to_jiffies(dirty_writeback_interval * 10);
|
||||
queue_delayed_work(system_long_wq, &sbi->sb_work, delay);
|
||||
sbi->work_queued = 1;
|
||||
}
|
||||
spin_unlock(&sbi->work_lock);
|
||||
}
|
||||
|
||||
static struct kmem_cache * affs_inode_cachep;
|
||||
|
||||
static struct inode *affs_alloc_inode(struct super_block *sb)
|
||||
@@ -138,7 +156,6 @@ static const struct super_operations affs_sops = {
|
||||
.write_inode = affs_write_inode,
|
||||
.evict_inode = affs_evict_inode,
|
||||
.put_super = affs_put_super,
|
||||
.write_super = affs_write_super,
|
||||
.sync_fs = affs_sync_fs,
|
||||
.statfs = affs_statfs,
|
||||
.remount_fs = affs_remount,
|
||||
@@ -305,8 +322,11 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
return -ENOMEM;
|
||||
|
||||
sb->s_fs_info = sbi;
|
||||
sbi->sb = sb;
|
||||
mutex_init(&sbi->s_bmlock);
|
||||
spin_lock_init(&sbi->symlink_lock);
|
||||
spin_lock_init(&sbi->work_lock);
|
||||
INIT_DELAYED_WORK(&sbi->sb_work, flush_superblock);
|
||||
|
||||
if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block,
|
||||
&blocksize,&sbi->s_prefix,
|
||||
@@ -531,6 +551,7 @@ affs_remount(struct super_block *sb, int *flags, char *data)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
flush_delayed_work_sync(&sbi->sb_work);
|
||||
replace_mount_options(sb, new_opts);
|
||||
|
||||
sbi->s_flags = mount_flags;
|
||||
@@ -549,10 +570,9 @@ affs_remount(struct super_block *sb, int *flags, char *data)
|
||||
if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
|
||||
return 0;
|
||||
|
||||
if (*flags & MS_RDONLY) {
|
||||
affs_write_super(sb);
|
||||
if (*flags & MS_RDONLY)
|
||||
affs_free_bitmap(sb);
|
||||
} else
|
||||
else
|
||||
res = affs_init_bitmap(sb, flags);
|
||||
|
||||
return res;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user